diff --git a/.gitignore b/.gitignore index 58bcbf8..4b5857a 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,8 @@ Icon Network Trash Folder Temporary Items .apdisk + +inc/sql_log.txt +cache/ +inc/config_db.php +inc/config_db.php \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ac8e114 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,58 @@ +# Change Log +All notable changes to this project will be documented in this file. + +## 2016-08-18 +### Added +- Staff whitelist +- Staff & Player info flag names +- crossroads.js for routing support. All pages are accessible via url now +- simple error/404 page +- It is possible to select multiple servers now +- You can add multiple DBs now and switch easy between them +- A simple cache + +## Changed +- The DB configuration is now in config_db.php. +- Server selection now works globally on all pages +- Date selection now works globally on all pages + + +## Fixed +- Dashboard Charts are shown broken with empty values +- Some layout issues + +## 2016-08-11 +### Added +- Staff page: Show only players with flags +- Mark the current nav element as active +- Table name constant for easier development + +## Changed +- Add a third option "unknown" in the Premium/F2P chart +- update js/css files +- Optimized SQL query in SSP class for better performance. WHERE is much faster then HAVING with GROUP BY + +## Fixed +- Issue #2 +- Sending muliple ajax requests in single server views + + +## 2016-08-08 +### Added +- server list (repo merge) + +### Changed +- Show also years and months in the "Hours Played" box + +### Fixed +- Connect method chart + +## 2015-08-07 +### Added +- server list (repo merge) + +### Changed +- Show the Top 10 countries (you can edit it in the config) + +### Fixed +- Connect method chart diff --git a/README.md b/README.md new file mode 100644 index 0000000..58ee4e3 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +/!\ Don't expect updates except fixes for critical bugs. I don't host TF2 servers anymore, so... + +And don't forget "GeoIPCity" for proper Location support! +If you have permission errors try to create the /cache/SQL folder manually. + +Oh and you can safely delete cache files at any time. There is no auto clean for old cache files! + +# player_analytics +This is a webpanel for the sourcemod plugin **[ANY] Player Analytics** by Dr. McKay +https://forums.alliedmods.net/showthread.php?t=230832 + +forked from Sinclair47/player_analytics https://github.com/Sinclair47/player_analytics + +If you have suggestions or you found a bug -> **contact me: thechaoscoder+player-analytics[at]gmail.com** +(replace [at] with @, bot protection) or open an issue here + +## Performance +For better SQL performance run this 2 queries: +`ALTER TABLE player_analytics ADD INDEX (server_ip, connect_date);` +`ALTER TABLE player_analytics ADD INDEX (connect_date);` + +## How to install? +Download as zip (or clone) and copy all files to your webserver. +Rename the file config_db_RENAME_ME.php to config_db.php in /inc and add your DB credentials. + +That's it! + +### Login +To activate login-only mode, edit `inc/config.php` line `16`: + +Change the value of `MUST_LOG_IN` to `true` and to disable it change it to `false`. +Add each person (SteamID) to `inc/admins.php` who is allowed to log in. + +## Connect method +> ### What is the difference between Quickplay and Quickpick? +> **Quickplay** = You click a button and get placed into a random server that has QP enabled +> **Quickpick** = You get presented a list of servers that have QP enabled, where you have to click "connect" yourself. +> +> Both are mostly non-existant in TF2 anymore (apart from MvM, which only has Quickplay). + +> _Quote from pcmaster - https://forums.alliedmods.net/showthread.php?t=230832&page=31_ + +- +> ### Why do I have some strange values for connect_method in my DB like - 20312 or asd? +> People can supply their own connection methods using the connect command. For example: +> **connect 127.0.0.1 myownreason** +> will list your connection method as "myownreason". +> +> _Quote from Dr. McKay - https://forums.alliedmods.net/showpost.php?p=2350131&postcount=256_ + +## Todo +* Add area charts to see changes over time +* Maybe add a Chart as in HLStatsX + +##Webpanel +![Player Analytics Webpanel](https://raw.githubusercontent.com/theChaosCoder/player_analytics/master/player_analytics.png) diff --git a/css/bootstrap.css b/assets/css/bootstrap.css similarity index 100% rename from css/bootstrap.css rename to assets/css/bootstrap.css diff --git a/css/bootstrap.min.css b/assets/css/bootstrap.min.css similarity index 100% rename from css/bootstrap.min.css rename to assets/css/bootstrap.min.css diff --git a/assets/css/dataTables.bootstrap.css b/assets/css/dataTables.bootstrap.css new file mode 100644 index 0000000..d103477 --- /dev/null +++ b/assets/css/dataTables.bootstrap.css @@ -0,0 +1,196 @@ +table.dataTable { + clear: both; + margin-top: 6px !important; + margin-bottom: 6px !important; + max-width: none !important; + border-collapse: separate !important; +} +table.dataTable td, +table.dataTable th { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +table.dataTable td.dataTables_empty, +table.dataTable th.dataTables_empty { + text-align: center; +} +table.dataTable.nowrap th, +table.dataTable.nowrap td { + white-space: nowrap; +} + +div.dataTables_wrapper div.dataTables_length label { + font-weight: normal; + text-align: left; + white-space: nowrap; +} +div.dataTables_wrapper div.dataTables_length select { + width: 75px; + display: inline-block; +} +div.dataTables_wrapper div.dataTables_filter { + text-align: right; +} +div.dataTables_wrapper div.dataTables_filter label { + font-weight: normal; + white-space: nowrap; + text-align: left; +} +div.dataTables_wrapper div.dataTables_filter input { + margin-left: 0.5em; + display: inline-block; + width: auto; +} +div.dataTables_wrapper div.dataTables_info { + padding-top: 8px; + white-space: nowrap; +} +div.dataTables_wrapper div.dataTables_paginate { + margin: 0; + white-space: nowrap; + text-align: right; +} +div.dataTables_wrapper div.dataTables_paginate ul.pagination { + margin: 2px 0; + white-space: nowrap; +} +div.dataTables_wrapper div.dataTables_processing { + position: absolute; + bottom: calc(50% - 70px); + left: 10%; + width: 80%; + /* margin-left: -200px; */ + /* margin-top: -26px; */ + text-align: center; + padding: 1em 0; + height: 70px; + padding-top: 22px; + text-align: center; + font-size: 1.2em; + background-color: #f5f5f5; + border: 1px solid #ddd; + border-radius: 10px; + z-index: 99; + opacity: 0.92; +} + + + +table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, +table.dataTable thead > tr > td.sorting_asc, +table.dataTable thead > tr > td.sorting_desc, +table.dataTable thead > tr > td.sorting { + padding-right: 30px; +} +table.dataTable thead > tr > th:active, +table.dataTable thead > tr > td:active { + outline: none; +} +table.dataTable thead .sorting, +table.dataTable thead .sorting_asc, +table.dataTable thead .sorting_desc, +table.dataTable thead .sorting_asc_disabled, +table.dataTable thead .sorting_desc_disabled { + cursor: pointer; + position: relative; +} +table.dataTable thead .sorting:after, +table.dataTable thead .sorting_asc:after, +table.dataTable thead .sorting_desc:after, +table.dataTable thead .sorting_asc_disabled:after, +table.dataTable thead .sorting_desc_disabled:after { + position: absolute; + bottom: 8px; + right: 8px; + display: block; + font-family: 'Glyphicons Halflings'; + opacity: 0.5; +} +table.dataTable thead .sorting:after { + opacity: 0.2; + content: "\e150"; + /* sort */ +} +table.dataTable thead .sorting_asc:after { + content: "\e155"; + /* sort-by-attributes */ +} +table.dataTable thead .sorting_desc:after { + content: "\e156"; + /* sort-by-attributes-alt */ +} +table.dataTable thead .sorting_asc_disabled:after, +table.dataTable thead .sorting_desc_disabled:after { + color: #eee; +} + +div.dataTables_scrollHead table.dataTable { + margin-bottom: 0 !important; +} + +div.dataTables_scrollBody table { + border-top: none; + margin-top: 0 !important; + margin-bottom: 0 !important; +} +div.dataTables_scrollBody table thead .sorting:after, +div.dataTables_scrollBody table thead .sorting_asc:after, +div.dataTables_scrollBody table thead .sorting_desc:after { + display: none; +} +div.dataTables_scrollBody table tbody tr:first-child th, +div.dataTables_scrollBody table tbody tr:first-child td { + border-top: none; +} + +div.dataTables_scrollFoot table { + margin-top: 0 !important; + border-top: none; +} + +@media screen and (max-width: 767px) { + div.dataTables_wrapper div.dataTables_length, + div.dataTables_wrapper div.dataTables_filter, + div.dataTables_wrapper div.dataTables_info, + div.dataTables_wrapper div.dataTables_paginate { + text-align: center; + } +} +table.dataTable.table-condensed > thead > tr > th { + padding-right: 20px; +} +table.dataTable.table-condensed .sorting:after, +table.dataTable.table-condensed .sorting_asc:after, +table.dataTable.table-condensed .sorting_desc:after { + top: 6px; + right: 6px; +} + +table.table-bordered.dataTable th, +table.table-bordered.dataTable td { + border-left-width: 0; +} +table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child, +table.table-bordered.dataTable td:last-child, +table.table-bordered.dataTable td:last-child { + border-right-width: 0; +} +table.table-bordered.dataTable tbody th, +table.table-bordered.dataTable tbody td { + border-bottom-width: 0; +} + +div.dataTables_scrollHead table.table-bordered { + border-bottom-width: 0; +} + +div.table-responsive > div.dataTables_wrapper > div.row { + margin: 0; +} +div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:first-child { + padding-left: 0; +} +div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:last-child { + padding-right: 0; +} diff --git a/css/daterangepicker.css b/assets/css/daterangepicker.css similarity index 100% rename from css/daterangepicker.css rename to assets/css/daterangepicker.css diff --git a/css/jquery-jvectormap-1.2.2.css b/assets/css/jquery-jvectormap-1.2.2.css similarity index 100% rename from css/jquery-jvectormap-1.2.2.css rename to assets/css/jquery-jvectormap-1.2.2.css diff --git a/css/morris.css b/assets/css/morris.css similarity index 100% rename from css/morris.css rename to assets/css/morris.css diff --git a/css/sb-admin-2.css b/assets/css/sb-admin-2.css similarity index 100% rename from css/sb-admin-2.css rename to assets/css/sb-admin-2.css diff --git a/assets/fonts/glyphicons-halflings-regular.eot b/assets/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000..e69de29 diff --git a/fonts/glyphicons-halflings-regular.svg b/assets/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from fonts/glyphicons-halflings-regular.svg rename to assets/fonts/glyphicons-halflings-regular.svg diff --git a/assets/fonts/glyphicons-halflings-regular.ttf b/assets/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000..e69de29 diff --git a/assets/fonts/glyphicons-halflings-regular.woff b/assets/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000..e69de29 diff --git a/assets/img/steam.png b/assets/img/steam.png new file mode 100644 index 0000000..086c315 Binary files /dev/null and b/assets/img/steam.png differ diff --git a/assets/js/app.js b/assets/js/app.js new file mode 100644 index 0000000..347fb19 --- /dev/null +++ b/assets/js/app.js @@ -0,0 +1,121 @@ +crossroads.ignoreState= true; + +// Define the routes +crossroads.addRoute('/', function() { + pageLoader( "inc/getdashboard.php" ); +}); + +crossroads.addRoute('/stats/locations', function() { + pageLoader("inc/getlocation.php"); +}); +crossroads.addRoute('/stats/connections', function() { + pageLoader( "inc/getconnections.php" ); +}); +crossroads.addRoute('/stats/players', function() { + pageLoader( "inc/getplayers.php" ); +}); +crossroads.addRoute('/stats/players/info/{steamid}', function(steamid) { + pageLoader( "inc/getplayerinfo.php?id="+steamid ); +}); +crossroads.addRoute('/stats/staff', function() { + pageLoader( "inc/getStaff.php" ); +}); +crossroads.addRoute('/stats/maps', function() { + pageLoader( "inc/getMap.php" ); +}); + + +crossroads.addRoute('/lab', function() { + pageLoader( "inc/lab.php" ); +}); +crossroads.addRoute('/lab/{tab_id}', function(tab_id) { + pageLoader( "inc/lab.php?tab_id="+tab_id ); +}); + + + +crossroads.bypassed.add(function(request) { + $( "#content" ).load( "error.php" ); + console.log(request + ' seems to be a dead end...'); +}); +crossroads.routed.add(console.log, console); //log all routes + + +function pageLoader(url) { + $('#overlay').fadeIn("fast"); + $('#content').empty(); + $('#content').load( url , function() { + $('#overlay').delay(200).fadeOut( "slow" ); + }); + //$('#overlay').delay(200).fadeOut( "slow" ); + + //var cookie = getCookie("server"); + //console.log("js cookie: " + cookie); + //$( "#header_server_ip" ).html(cookie); +} + + + + +//http://www.w3schools.com/js/js_cookies.asp +// function setCookie(cname, cvalue, exdays) { +// console.log("setcookie: "); +// var d = new Date(); +// d.setTime(d.getTime() + (exdays*24*60*60*1000)); +// console.log("D: "+ d.toGMTString()); +// var expires = "expires=" + d.toGMTString(); +// document.cookie = cname+"="+"cvalue"+"; "+expires; +// } + +// function getCookie(cname) { +// var name = cname + "="; +// var ca = document.cookie.split(';'); +// for(var i=0; i 0) { +// route = hash.split('#').pop(); +// } +// crossroads.parse(route); +// }); + +// // trigger hashchange on first page load +// window.dispatchEvent(new CustomEvent("hashchange")); diff --git a/js/bootstrap.js b/assets/js/bootstrap.js similarity index 100% rename from js/bootstrap.js rename to assets/js/bootstrap.js diff --git a/js/bootstrap.min.js b/assets/js/bootstrap.min.js similarity index 100% rename from js/bootstrap.min.js rename to assets/js/bootstrap.min.js diff --git a/assets/js/crossroads.min.js b/assets/js/crossroads.min.js new file mode 100644 index 0000000..f7b449d --- /dev/null +++ b/assets/js/crossroads.min.js @@ -0,0 +1,6 @@ +/** @license + * crossroads + * Author: Miller Medeiros | MIT License + * v0.12.2 (2015/07/31 18:37) + */ +;(function(){var a=function(a){function e(a,b){if(a.indexOf)return a.indexOf(b);var c=a.length;while(c--)if(a[c]===b)return c;return-1}function f(a,b){var c=e(a,b);c!==-1&&a.splice(c,1)}function g(a,b){return"[object "+b+"]"===Object.prototype.toString.call(a)}function h(a){return g(a,"RegExp")}function i(a){return g(a,"Array")}function j(a){return typeof a=="function"}function k(a){var b;return a===null||a==="null"?b=null:a==="true"?b=!0:a==="false"?b=!1:a===d||a==="undefined"?b=d:a===""||isNaN(a)?b=a:b=parseFloat(a),b}function l(a){var b=a.length,c=[];while(b--)c[b]=k(a[b]);return c}function m(a,b){var c=(a||"").replace("?","").split("&"),d=/([^=]+)=(.+)/,e=-1,f={},g,h,j,l;while(h=c[++e])g=h.indexOf("="),l=h.substring(0,g),j=decodeURIComponent(h.substring(g+1)),b!==!1&&(j=k(j)),l in f?i(f[l])?f[l].push(j):f[l]=[f[l],j]:f[l]=j;return f}function n(){this.bypassed=new a.Signal,this.routed=new a.Signal,this._routes=[],this._prevRoutes=[],this._piped=[],this.resetState()}function o(b,c,d,e){var f=h(b),g=e.patternLexer;this._router=e,this._pattern=b,this._paramsIds=f?null:g.getParamIds(b),this._optionalParamsIds=f?null:g.getOptionalParamsIds(b),this._matchRegexp=f?b:g.compilePattern(b,e.ignoreCase),this.matched=new a.Signal,this.switched=new a.Signal,c&&this.matched.add(c),this._priority=d||0}var b,c,d;return c=/t(.+)?/.exec("t")[1]==="",n.prototype={greedy:!1,greedyEnabled:!0,ignoreCase:!0,ignoreState:!1,shouldTypecast:!1,normalizeFn:null,resetState:function(){this._prevRoutes.length=0,this._prevMatchedRequest=null,this._prevBypassedRequest=null},create:function(){return new n},addRoute:function(a,b,c){var d=new o(a,b,c,this);return this._sortedInsert(d),d},removeRoute:function(a){f(this._routes,a),a._destroy()},removeAllRoutes:function(){var a=this.getNumRoutes();while(a--)this._routes[a]._destroy();this._routes.length=0},parse:function(a,b){a=a||"",b=b||[];if(!this.ignoreState&&(a===this._prevMatchedRequest||a===this._prevBypassedRequest))return;var c=this._getMatchedRoutes(a),d=0,e=c.length,f;if(e){this._prevMatchedRequest=a,this._notifyPrevRoutes(c,a),this._prevRoutes=c;while(d + * @author Miller Medeiros + * @version 1.2.0 (2013/11/11 03:18 PM) + * Released under the MIT License + */ +(function(){var a=function(b){var c=(function(k){var p=25,r=k.document,n=k.history,x=b.Signal,f,v,m,F,d,D,t=/#(.*)$/,j=/(\?.*)|(\#.*)/,g=/^\#/,i=(!+"\v1"),B=("onhashchange" in k)&&r.documentMode!==7,e=i&&!B,s=(location.protocol==="file:");function o(G){return String(G||"").replace(/\W/g,"\\$&")}function u(H){if(!H){return""}var G=new RegExp("^"+o(f.prependHash)+"|"+o(f.appendHash)+"$","g");return H.replace(G,"")}function E(){var G=t.exec(f.getURL());var I=(G&&G[1])||"";try{return f.raw?I:decodeURIComponent(I)}catch(H){return I}}function A(){return(d)?d.contentWindow.frameHash:null}function z(){d=r.createElement("iframe");d.src="about:blank";d.style.display="none";r.body.appendChild(d)}function h(){if(d&&v!==A()){var G=d.contentWindow.document;G.open();G.write(""+r.title+' diff --git a/inc/getStaff.php b/inc/getStaff.php new file mode 100644 index 0000000..8e00e05 --- /dev/null +++ b/inc/getStaff.php @@ -0,0 +1,111 @@ + +
+
+

Staff

+
+
+
+
+
+
+ Staff + +
+
+ + +
+
+ + +
+
+
+
+

Here you can see your flagged Users. The Users are grouped by steam id and flags. Click on a row to see all records for a specific User.

+
+ + + + + + + + + + + + + + + + + + + + +
IDNameAuthTotalDurationLast OnCountryFlagsOS
+
+
+
+
+
+ diff --git a/inc/getbottomrow.php b/inc/getbottomrow.php index ae6632e..b317719 100644 --- a/inc/getbottomrow.php +++ b/inc/getbottomrow.php @@ -6,91 +6,26 @@ die(); } -//Database Info -include 'config.php'; +require_once 'app.php'; -// Include database class -include 'database.class.php'; -if (!isset($_GET['id'])) { - $_GET['id'] = date("Y-m-d", strtotime('-7 day')).",".date("Y-m-d"); -} - -$date = explode(",", $_GET['id']); -$c_total = 0; -$m_total = 0; -$p_total = 0; - -// Instantiate database. -$database = new Database(); +// if (!isset($_GET['id'])) { +// $_GET['id'] = date("Y-m-d", strtotime('-7 day')).",".date("Y-m-d"); +// } -$database->query('SELECT `country` AS label, COUNT(`country`) AS value FROM `player_analytics` WHERE `connect_date` BETWEEN :start AND :end GROUP BY `country`'); -$database->bind(':start', $date[0]); -$database->bind(':end', $date[1]); +$database->query('SELECT `country` AS label, COUNT(*) AS value FROM `'.DB_TABLE_PA.'` '.getIpDatesSql($include_where = true).' GROUP BY `country`'); #count(*) instead of count(country) bcs we need to count also NULL values $country = $database->resultset(); -$database->query('SELECT `connect_method` AS label, COUNT(`connect_method`) AS value FROM `player_analytics` WHERE `connect_date` BETWEEN :start AND :end GROUP BY `connect_method`'); -$database->bind(':start', $date[0]); -$database->bind(':end', $date[1]); +$database->query('SELECT `connect_method` AS label, COUNT(*) AS value FROM `'.DB_TABLE_PA.'` '.getIpDatesSql($include_where = true).' GROUP BY `connect_method`'); $method = $database->resultset(); -$database->query('SELECT `premium` AS label, COUNT(`premium`) AS value FROM `player_analytics` WHERE `connect_date` BETWEEN :start AND :end GROUP BY `premium`'); -$database->bind(':start', $date[0]); -$database->bind(':end', $date[1]); +$database->query('SELECT `premium` AS label, COUNT(*) AS value FROM `'.DB_TABLE_PA.'` '.getIpDatesSql($include_where = true).' GROUP BY `premium`'); $premium = $database->resultset(); -foreach ($country as $key => $value) { - $c_total += $value['value']; -} -foreach ($method as $key => $value) { - $m_total += $value['value']; -} - -foreach ($premium as $key => $value) { - $p_total += $value['value']; -} - -foreach ($country as $key => $value) { - $country[$key]['value'] = number_format($value['value']/$c_total*100,2); -} - -foreach ($method as $key => $value) { - if (preg_match("/quickplay/", $value['label'])) { - if (!isset($id)) { - $id = $key; - $methods[$id]['label'] = 'quickplay'; - $methods[$id]['value'] = $value['value']; - } - else { - $methods[$id]['label'] = 'quickplay'; - $methods[$id]['value'] += $value['value']; - } - } - else { - $methods[$key]['label'] = $value['label']; - $methods[$key]['value'] = $value['value']; - } -} - -foreach ($methods as $key => $value) { - $methods[$key]['label'] = ConnMethod($value['label']); - $methods[$key]['value'] = number_format($value['value']/$m_total*100,2); -} - -foreach ($premium as $key => $value) { - if ($value['label'] == '1') { - $value['label'] = 'Premium'; - } - else { - $value['label'] = 'F2P'; - } - $premium[$key]['label'] = $value['label']; - if(!$p_total == 0) - $premium[$key]['value'] = number_format($value['value']/$p_total*100,2); - else - $premium[$key]['value'] = 0; -} +$country = processCountries($country, $Show_Max_Countries); +$methods = processConnectMethods($method); +$premium = processPremium($premium); $country = json_encode($country); $methods = json_encode(array_values($methods)); @@ -99,11 +34,11 @@
- Countries + Top Countries
@@ -115,7 +50,7 @@
@@ -126,7 +61,7 @@ @@ -151,20 +86,169 @@ formatter: function (y) { return y + "%" ;} }); - + + $countries_filtered[] = $top; + $c_percent += $top['value']; + } + + $countries_filtered = array_reverse($countries_filtered); #reverse array order, so the donut is build up from big to small + if(!$skip_other_country_calc) { + $countries_filtered[] = array( + 'label' => 'Other Countries', + 'value' => number_format(100 - $c_percent,2), + ); + } + $country = $countries_filtered; + } + + return $country; +} + + +function processConnectMethods($method) { + + if(empty($method)) { + return NoChartData(); + } + + $m_total = 0; + + foreach ($method as $key => $value) { + $m_total += $value['value']; + } + + + foreach ($method as $key => $value) { + if (preg_match("/quickplay/", $value['label']) || preg_match("/quickpick/", $value['label'])) { + + if (preg_match("/quickplay/", $value['label'])) { + if (!isset($id)) { + $id = $key; + + $methods[$id]['label'] = 'quickplay'; + $methods[$id]['value'] = $value['value']; + } + else { + $methods[$id]['label'] = 'quickplay'; + $methods[$id]['value'] += $value['value']; + } + } + if (preg_match("/quickpick/", $value['label'])) { + if (!isset($id2)) { + $id2 = $key; + $methods[$id2]['label'] = 'quickpick'; + $methods[$id2]['value'] = $value['value']; + } + else { + $methods[$id2]['label'] = 'quickpick'; + $methods[$id2]['value'] += $value['value']; + } + } + } + else { + $methods[$key]['label'] = $value['label']; + $methods[$key]['value'] = $value['value']; + } + } + if(isset($methods)) { + foreach ($methods as $key => $value) { + $methods[$key]['label'] = ConnMethod($value['label']); + $methods[$key]['value'] = number_format($value['value'] / $m_total * 100, 2); + + $methods_l[$key] = $methods[$key]['label']; + $methods_v[$key] = $methods[$key]['value']; + } + + #sort by value + array_multisort( + $methods_l, SORT_DESC, SORT_NUMERIC, + $methods_v, SORT_ASC, SORT_NUMERIC, + $methods + ); + } + + return $methods; + +} + + +function processPremium($premium) { + if(empty($premium)) { + return NoChartData(); + } + + $p_total = 0; + + foreach ($premium as $key => $value) { + $p_total += $value['value']; + } + + foreach ($premium as $key => $value) { + if ($value['label'] == '1') { + $value['label'] = 'Premium'; + } + elseif ($value['label'] == '0') { + $value['label'] = 'F2P'; + } + else { + $value['label'] = 'Unknown'; + } + $premium[$key]['label'] = $value['label']; + if(!$p_total == 0) + $premium[$key]['value'] = number_format($value['value']/$p_total*100,2); + else + $premium[$key]['value'] = 0; + } + + return $premium; +} + +function NoChartData() { + return array( + 0 => array( + 'label' => 'No Data', + 'value' => '0', + ) + ); +} diff --git a/inc/getconnections.php b/inc/getconnections.php index aa97a34..f4d5007 100644 --- a/inc/getconnections.php +++ b/inc/getconnections.php @@ -20,7 +20,7 @@
- +
@@ -30,9 +30,10 @@ - - + + + @@ -47,7 +48,7 @@ diff --git a/inc/getcountryinfo.php b/inc/getcountryinfo.php index bcda0da..2f225fc 100644 --- a/inc/getcountryinfo.php +++ b/inc/getcountryinfo.php @@ -18,7 +18,7 @@
-
IDMethod Duration Country OSServer
+
@@ -28,6 +28,7 @@ + @@ -42,7 +43,7 @@ diff --git a/inc/getdashboard.php b/inc/getdashboard.php index 3e587de..77d192d 100644 --- a/inc/getdashboard.php +++ b/inc/getdashboard.php @@ -7,24 +7,56 @@ } //Database Info -include 'config.php'; +require_once 'app.php'; -// Include database class -include 'database.class.php'; +//$server_ip = true; -// Instantiate database. -$database = new Database(); - -$database->query('SELECT COUNT(DISTINCT(`auth`)) AS auth, COUNT(DISTINCT(`server_ip`)) AS server, COUNT(DISTINCT(`country_code`)) AS cc, SUM(`duration`) AS duration FROM `player_analytics`'); -$info = $database->single(); +#$database->query('SELECT COUNT(`auth`) AS cons, COUNT(DISTINCT(`auth`)) AS auth, COUNT(DISTINCT(`server_ip`)) AS server, COUNT(DISTINCT(`country_code`)) AS cc, SUM(`duration`) AS duration FROM `'.DB_TABLE_PA.'` '.getIpDatesSql($include_where = true)); +$database->query('SELECT COUNT(*) AS cons, COUNT(DISTINCT(`auth`)) AS auth, COUNT(DISTINCT(`server_ip`)) AS server, COUNT(DISTINCT(`country_code`)) AS cc, count(*) AS duration FROM `'.DB_TABLE_PA.'` '.getIpDatesSql($include_where = true)); +$key = FileSystemCache::generateCacheKey(sha1(serialize(array($database->stmt(), $db))), 'SQL'); +$info = FileSystemCache::retrieve($key); +if($info === false) { + $info = $database->single(); + FileSystemCache::store($key, $info, 1000); +} +$database->query('SELECT COUNT(*) as count FROM `'.DB_TABLE_PA.'`'); +$key = FileSystemCache::generateCacheKey(sha1(serialize(array($database->stmt(), $db))), 'SQL'); +$records = FileSystemCache::retrieve($key); +if($records === false) { + $records = $database->single(); + FileSystemCache::store($key, $records, 2000); +} ?>
-

Dashboard

+ +

Dashboard -

+ +

Dashboard

+
+ +
+
+
+
+
+
+
+ +
+
+ Unique Players +
+
+
+
+
+
+
@@ -42,6 +74,26 @@
+ + +
+
+
+
+
+
+
+ +
+
+ Connections +
+
+
+
+
+
+
@@ -59,6 +111,26 @@
+ + +
+
+
+
+
+
+
+ +
+
+ Unique Regions +
+
+
+
+
+
+
@@ -76,17 +148,18 @@
+
-
+
- +
- Hours Played + Total DB records
@@ -99,15 +172,10 @@
Connections for -
-
- - - -
-
+
-
+
@@ -117,75 +185,158 @@
- + + + + \ No newline at end of file diff --git a/inc/getdashboardrange.php b/inc/getdashboardrange.php index aaf807f..235370c 100644 --- a/inc/getdashboardrange.php +++ b/inc/getdashboardrange.php @@ -6,34 +6,34 @@ die(); } -//Database Info -include 'config.php'; +require_once 'app.php'; -// Include database class -include 'database.class.php'; +// if (!isset($_GET['id'])) { +// $_GET['id'] = date("Y-m-d", strtotime('-7 day')).",".date("Y-m-d"); +// } -if (!isset($_GET['id'])) { - $_GET['id'] = date("Y-m-d", strtotime('-7 day')).",".date("Y-m-d"); -} - -$date = explode(",", $_GET['id']); +$dates = Util::getCookieJson("dates"); +#pr($dates); die; -// Instantiate database. -$database = new Database(); -if ($date[0] == $date[1]) { - $database->query('SELECT `connect_date` AS d, DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%l:00 %p") AS time, COUNT(`auth`) AS total FROM `player_analytics` WHERE `connect_date` BETWEEN :start AND :end GROUP BY DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%H")'); - $database->bind(':start', $date[0]); - $database->bind(':end', $date[1]); - $connections = $database->resultset(); +if ($dates['start'] == $dates['end']) { + $database->query('SELECT `connect_date` AS d, DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%l:00 %p") AS time, COUNT(*) AS total FROM `'.DB_TABLE_PA.'` '.getIpDatesSql($include_where = true).' GROUP BY DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%H")'); + $key = FileSystemCache::generateCacheKey(sha1(serialize(array($database->stmt(), $db))), 'SQL'); + $connections = FileSystemCache::retrieve($key); + if($connections === false) { + $connections = $database->resultset(); + FileSystemCache::store($key, $connections, 1000); + } + } else { - $database->query('SELECT `connect_date` AS d, `connect_date` AS time, COUNT(`auth`) AS total FROM `player_analytics` WHERE `connect_date` BETWEEN :start AND :end GROUP BY `connect_date`'); - $database->bind(':start', $date[0]); - $database->bind(':end', $date[1]); - $connections = $database->resultset(); + $database->query('SELECT `connect_date` AS d, `connect_date` AS time, COUNT(*) AS total FROM `'.DB_TABLE_PA.'` '.getIpDatesSql($include_where = true).' GROUP BY `connect_date`'); + $key = FileSystemCache::generateCacheKey(sha1(serialize(array($database->stmt(), $db))), 'SQL'); + $connections = FileSystemCache::retrieve($key); + if($connections === false) { + $connections = $database->resultset(); + FileSystemCache::store($key, $connections, 1000); + } } print_r(json_encode($connections)); - -?> diff --git a/inc/getdateinfo.php b/inc/getdateinfo.php index fe0b65e..67ed249 100644 --- a/inc/getdateinfo.php +++ b/inc/getdateinfo.php @@ -6,22 +6,25 @@ die(); } -//Database Info -include 'config.php'; +require_once 'app.php'; + -// Include database class -include 'database.class.php'; if (!isset($_GET['id'])) { die; } -// Instantiate database. -$database = new Database(); - -$database->query('SELECT `server_ip`, COUNT(`auth`) AS connections, COUNT(DISTINCT(`auth`)) AS players, DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%p %I:00") AS time FROM `player_analytics` WHERE `connect_date` = :id GROUP BY `server_ip`, DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%H") ORDER BY DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%H")'); -$database->bind(':id', $_GET['id']); -$connections = $database->resultset(); +if (!empty(getServerIpsSql())) { + $server_ip = $_GET['server']; + $database->query('SELECT `server_ip`, COUNT(`auth`) AS connections, COUNT(DISTINCT(`auth`)) AS players, DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%p %I:00") AS time FROM `'.DB_TABLE_PA.'` WHERE '.getServerIpsSql(false, '', 'AND').' `connect_date` = :id GROUP BY `server_ip`, DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%H") ORDER BY DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%H")'); + $database->bind(':id', $_GET['id']); + $connections = $database->resultset(); +} +else { + $database->query('SELECT `server_ip`, COUNT(`auth`) AS connections, COUNT(DISTINCT(`auth`)) AS players, DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%p %I:00") AS time FROM `'.DB_TABLE_PA.'` WHERE `connect_date` = :id GROUP BY `server_ip`, DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%H") ORDER BY DATE_FORMAT(FROM_UNIXTIME(`connect_time`), "%H")'); + $database->bind(':id', $_GET['id']); + $connections = $database->resultset(); +} ?>
- + diff --git a/inc/getlocation.php b/inc/getlocation.php index 8681540..bb2ef73 100644 --- a/inc/getlocation.php +++ b/inc/getlocation.php @@ -6,8 +6,7 @@ die(); } -//Database Info -include 'config.php'; +require_once 'app.php'; ?>
@@ -19,12 +18,6 @@
Active Countries -
-
- - - -
-
@@ -42,36 +35,3 @@ $( "#map" ).load( "inc/getlocationrange.php" ); }); - \ No newline at end of file diff --git a/inc/getlocationrange.php b/inc/getlocationrange.php index 8fec5f4..b988956 100644 --- a/inc/getlocationrange.php +++ b/inc/getlocationrange.php @@ -6,30 +6,27 @@ die(); } -//Database Info -include 'config.php'; +require_once 'app.php'; -// Include database class -include 'database.class.php'; -if (!isset($_GET['id'])) { - $_GET['id'] = date("Y-m-d", strtotime('-7 day')).",".date("Y-m-d"); -} - -$date = explode(",", $_GET['id']); +// if (!isset($_GET['id'])) { +// $_GET['id'] = date("Y-m-d", strtotime('-7 day')).",".date("Y-m-d"); +// } -// Instantiate database. -$database = new Database(); -$database->query('SELECT `country_code`, COUNT(`auth`) AS total FROM `player_analytics` WHERE `connect_date` BETWEEN :start AND :end GROUP BY `country_code`'); -$database->bind(':start', $date[0]); -$database->bind(':end', $date[1]); +$database->query('SELECT `country_code`, COUNT(`auth`) AS total FROM `'.DB_TABLE_PA.'` '.getIpDatesSql($include_where = true).' GROUP BY `country_code`'); $map = $database->resultset(); -foreach ($map as $key => $value) { - if ($value['country_code'] != NULL) { - $maps[$value['country_code']] = $value['total']; + +$maps = array(); +if(!empty($map)) { + foreach ($map as $key => $value) { + if ($value['country_code'] != NULL) { + $maps[$value['country_code']] = $value['total']; + } } +} else { + echo '

No data available.

'; } $maps = json_encode($maps); @@ -94,4 +91,4 @@ } }); }) - \ No newline at end of file + diff --git a/inc/getplayerinfo.php b/inc/getplayerinfo.php index d058d1f..0284f3c 100644 --- a/inc/getplayerinfo.php +++ b/inc/getplayerinfo.php @@ -6,18 +6,16 @@ die(); } -//Database Info -include 'config.php'; +require_once 'app.php'; -// Include database class -include 'database.class.php'; - -// Instantiate database. -$database = new Database(); - -$database->query('SELECT * FROM (SELECT * FROM `player_analytics` WHERE `auth` = :id ORDER BY `connect_time` DESC) AS a'); -$database->bind(':id', $_GET['id']); -$info = $database->resultset(); +$database->query('SELECT `server_ip`, `name`, `auth`, `connect_time`, `connect_method`, `numplayers`, `map`, `duration`, `flags`, `country`, `os` FROM `'.DB_TABLE_PA.'` WHERE auth = :auth AND '.getIpDatesSql().' ORDER BY `connect_time` DESC'); +$key = FileSystemCache::generateCacheKey(sha1(serialize(array($database->stmt(), $_GET['id'], $db))), 'SQL'); +$info = FileSystemCache::retrieve($key); +if($info === false) { + $database->bind(':auth', $_GET['id']); + $info = $database->resultset(); + FileSystemCache::store($key, $info, 1000); +} $profile = GetPlayerInformation(SteamTo64($_GET['id'])); @@ -42,11 +40,11 @@ <?php echo $profile['personaname']; ?>

SteamID

- -

Location

- + +

Last Location

+

OS

- +
@@ -58,7 +56,7 @@
-
IDPremium HTML OSServer
+
@@ -67,19 +65,19 @@ - + - - + + - + @@ -88,6 +86,11 @@ +
+
+ +
+
diff --git a/inc/getserverinfo.php b/inc/getserverinfo.php new file mode 100644 index 0000000..fbc2c92 --- /dev/null +++ b/inc/getserverinfo.php @@ -0,0 +1,210 @@ + + + +
Server Map Method IP Flags
+ + + + + + + + + + + + + + + + + + +
IDNameAuthTimeMethodDurationCountryOSServer
+
+
+ + + + + + +query('SELECT COUNT(`auth`) AS total, `country` FROM `'.DB_TABLE_PA.'` WHERE `server_ip` = :ip GROUP BY `country` ORDER BY total DESC'); + $database->bind(':ip', $server); + $regions = $database->resultset(); + +?> + + + + + + + + + + + + diff --git a/inc/lab.php b/inc/lab.php new file mode 100644 index 0000000..ef445c8 --- /dev/null +++ b/inc/lab.php @@ -0,0 +1,454 @@ + + + + + +
+
+

Laboratory

+
+
+ +
+
+
+
+ Experiments +
+
+
+

Fun with charts

+ + + +
+ +

Calender heatmap

+

Number of connections per day. Yellow (0%) => Dark Green (100%)

+
+ + + +
+ + + + + + + +

Timeline

+

Select only ONE server from the menu. Otherwise the result will look strange/overlap

+ + + + +

+
+ + + + +
+ +
+

Loading...

+ + + + +
+
+
+
+
+
diff --git a/inc/lab_data.php b/inc/lab_data.php new file mode 100644 index 0000000..2d214aa --- /dev/null +++ b/inc/lab_data.php @@ -0,0 +1,118 @@ +query('SELECT COUNT(*) AS Comparison_Type, DATE_FORMAT(connect_date, "%Y%m%d") AS Date FROM `'.DB_TABLE_PA.'` WHERE '.getServerIpsSql(false, '', 'AND').' (year(connect_date) = "'.date("Y").'" OR year(connect_date) = "'.((int)date("Y") - 1).'" OR year(connect_date) = "'.((int)date("Y") - 2).'") GROUP BY YEAR(connect_date), month(connect_date), day(connect_date) ORDER BY `Date` ASC'); + $data = $database->resultset(); + + echo json_encode($data); + break; + + case 2: + break; + + case 3: + #$date_yesterday = time() - 86400; + $flags = " AND flags != '' "; + if(isset($_GET['flags']) && $_GET['flags'] != 0) { + $flags = ""; + } + + $database->query('SELECT id, auth, name, connect_time, map, duration FROM `'.DB_TABLE_PA.'` WHERE '.getIpDatesSql(false).' '.$flags.' ORDER BY connect_time ASC'); + $timeline_data_raw = $database->resultset(); + + #$timeline_data['data'] = ""; + $timeline_data = array(); + $timeline_data_maps = array(); + + $i = $map_i = 0; + $last_map = ""; + $current_map = $next_map = ""; + $map_dateStart = ""; + + foreach($timeline_data_raw as $r) { + + # new user + $timeline_data[$i] = array( + 'id' => $r['id'], + 'userid' => $r['auth'], + 'content' => $r['name'], + 'start' => date("Y-m-d H:i:s", $r['connect_time']), + 'end' => date("Y-m-d H:i:s", ($r['connect_time'] + $r['duration'])), + 'map' => $r['map'], + 'title' => $r['auth'] + ); + + $next_map = $r["map"]; + + # new map + $map_color = ($map_i % 2 == true ? "" : "'negative'"); + #if($last_map != $r['map']) { # we are on a new map + if($current_map != $next_map) { + + $current_map = $next_map; + $s = $map_dateStart; + + if(isset($map)) { # inset map delay + $timeline_data_maps[$i] = array( + 'id' => "m".$r['id'], + 'content' => $r['map'], + 'start' => date("Y-m-d H:i:s", $s), + 'end' => date("Y-m-d H:i:s", ($r['connect_time'] + $r['duration'])), + 'map' => $r['map'], + 'type' => "background", + 'className' => $map_color, + ); + $map_i++; + } + + #$last_map = $r['map']; + $map = $current_map; + $map_dateStart = $r['connect_time']; + } + + $i++; + + # same map + if($current_map != $next_map) { + $current_map = $next_map; + } + } + + + + # merge users that are still on the server after a map change remove small time gaps between map changes + $time_gap = 180; # in sec + #$timeline_data_copy = $timeline_data; + $cnt = count($timeline_data); + for($i = 0; $i < $cnt; $i++) + { + for($j = $i + 1; $j < ($i + 40); $j++) #compare current user with the next X users. If it's the same user and we detect a map change => merge into one user & reset time. + { + if(isset($timeline_data[$j])) + { + if($timeline_data[$i]['userid'] == $timeline_data[$j]['userid']) #same user + { + $time_diff = strtotime($timeline_data[$j]['start']) - strtotime($timeline_data[$i]['end']); + if(abs($time_diff) < $time_gap) # small gap means mapchange (or quick reconnect of User) + { + $timeline_data[$j]['start'] = $timeline_data[$i]['start']; + unset($timeline_data[$i]); + break; + } + + } + } + } #for2 + } + + $final = array_merge($timeline_data, $timeline_data_maps); + echo json_encode($final); die; + pr($timeline_data); die; + break; + +} diff --git a/inc/server_processing.php b/inc/server_processing.php index 6ca342b..0e6450d 100644 --- a/inc/server_processing.php +++ b/inc/server_processing.php @@ -3,212 +3,410 @@ /*@license MIT - http://datatables.net/license_mit/ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) || !strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') +if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) || !strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { - header("Location: ../index.php?error=".urlencode("Direct access not allowed.")); - die(); + header("Location: ../index.php?error=".urlencode("Direct access not allowed.")); + die(); } -include 'config.php'; +require_once 'app.php'; -$sql_details = array( - 'user' => DB_USER, - 'pass' => DB_PASS, - 'db' => DB_NAME, - 'host' => DB_HOST, - 'port' => DB_PORT + +$current_con = $db->getCurrentDb(); +$db_conn = array( + 'user' => $current_con['username'], + 'pass' => $current_con['password'], + 'db' => $current_con['database_name'], + 'host' => $current_con['host'], + 'port' => $current_con['port'] ); +$table = DB_TABLE_PA; + +$where = getIpDatesSql(); # "global where" for all if's in here + +# Total DB count from cache +$records = 0; +$database->query('SELECT COUNT(*) as count FROM `'.DB_TABLE_PA.'`'); +$key = FileSystemCache::generateCacheKey(sha1(serialize(array($database->stmt(), $db))), 'SQL'); +$records = FileSystemCache::retrieve($key); +if($records === false) { + $records = $database->single(); + FileSystemCache::store($key, $records, 2000); +} +if(!empty($records)) { + $records = $records['count']; +} + if (isset($_GET['type']) && $_GET['type'] == 'getconnections') { - $table = 'player_analytics'; - $primaryKey = 'id'; - - $columns = array( - array( - 'db' => 'id', - 'dt' => 'id' - ), - array( - 'db' => 'name', - 'dt' => 'name', - 'formatter' => function( $d, $row ) { - return htmlentities($d); - } - ), - array( - 'db' => 'auth', - 'dt' => 'auth' - ), - array( - 'db' => 'connect_time', - 'dt' => 'connect_time', - 'formatter' => function( $d, $row ) { - return date('h:i:s a m/d/Y',$d); - } - ), - array( - 'db' => 'connect_method', - 'dt' => 'connect_method', - 'formatter' => function( $d, $row ) { - return ConnMethod($d); - } - ), - array( - 'db' => 'duration', - 'dt' => 'duration', - 'formatter' => function( $d, $row ) { - return PlaytimeCon($d); - } - ), - array( - 'db' => 'country', - 'dt' => 'country' - ), - array( - 'db' => 'premium', - 'dt' => 'premium' - ), - array( - 'db' => 'html_motd_disabled', - 'dt' => 'html_motd_disabled' - ), - array( - 'db' => 'os', - 'dt' => 'os' - ) - ); - - $joinQuery = ''; - - require('ssp.class.php'); - - echo json_encode( - SSP::simple( $_GET, $sql_details, $table, $primaryKey, $columns, $joinQuery) - ); + $primaryKey = 'id'; + + $columns = array( + array( + 'db' => 'id', + 'dt' => 'id' + ), + array( + 'db' => 'name', + 'dt' => 'name', + 'formatter' => function( $d, $row ) { + return htmlentities($d); + } + ), + array( + 'db' => 'auth', + 'dt' => 'auth' + ), + array( + 'db' => 'connect_time', + 'dt' => 'connect_time', + 'formatter' => function( $d, $row ) { + return date('h:i:s a m/d/Y',$d); + } + ), + array( + 'db' => 'connect_method', + 'dt' => 'connect_method', + 'formatter' => function( $d, $row ) { + return ConnMethod($d); + } + ), + array( + 'db' => 'duration', + 'dt' => 'duration', + 'formatter' => function( $d, $row ) { + return PlaytimeCon($d); + } + ), + array( + 'db' => 'country', + 'dt' => 'country' + ), + array( + 'db' => 'premium', + 'dt' => 'premium' + ), + array( + 'db' => 'html_motd_disabled', + 'dt' => 'html_motd_disabled' + ), + array( + 'db' => 'os', + 'dt' => 'os' + ), + array( + 'db' => 'server_ip', + 'dt' => 'server_ip' + ) + ); + + + require('ssp.class.php'); + + echo json_encode( + SSP::simple( $_GET, $db_conn, $table, $primaryKey, $columns, $joinQuery = '', $extraCondition = '', $groupBy = '', $where, $records) + ); } -if (isset($_GET['type']) && $_GET['type'] == 'getplayers') { - - $table = 'player_analytics'; - $primaryKey = 'id'; - - $columns = array( - array( - 'db' => 'id', - 'dt' => 'id' - ), - array( - 'db' => 'name', - 'dt' => 'name', - 'formatter' => function( $d, $row ) { - return htmlentities($d); - } - ), - array( - 'db' => 'auth', - 'dt' => 'auth' - ), - array( - 'db' => 'SUM(duration)', - 'dt' => 'duration', - 'formatter' => function( $d, $row ) { - return PlaytimeCon($d); - } - ), - array( - 'db' => 'COUNT(auth)', - 'dt' => 'total', - 'as' => 'total', - 'formatter' => function( $d, $row ) { - return number_format($d); - } - ), - array( - 'db' => 'MAX(connect_time)', - 'dt' => 'connect_time', - 'as' => 'connect_time', - 'formatter' => function( $d, $row ) { - return date('h:i:s a m/d/Y',$d); - } - ), - array( - 'db' => 'country', - 'dt' => 'country' - ), - array( - 'db' => 'premium', - 'dt' => 'premium' - ), - array( - 'db' => 'html_motd_disabled', - 'dt' => 'html_motd_disabled' - ), - array( - 'db' => 'os', - 'dt' => 'os' - ) - ); - - $joinQuery = ''; - $extraCondition = ''; - $groupBy = "GROUP BY auth"; - - require('ssp.class.php'); - - echo json_encode( - SSP::simple( $_GET, $sql_details, $table, $primaryKey, $columns, $joinQuery, $extraCondition, $groupBy) - ); +if (isset($_GET['type']) && ($_GET['type'] == 'getplayers' || $_GET['type'] == 'getstaff')) { + + $primaryKey = 'id'; + #print_r($_GET); die; + $columns = array( + array( + 'db' => 'id', + 'dt' => 'id' + ), + array( + 'db' => 'name', + 'dt' => 'name', + 'formatter' => function( $d, $row ) { + return htmlentities($d); + } + ), + array( + 'db' => 'auth', + 'dt' => 'auth' + ), + array( + 'db' => 'SUM(duration)', + 'dt' => 'duration', + 'formatter' => function( $d, $row ) { + return PlaytimeCon($d); + } + ), + array( + 'db' => 'COUNT(auth)', + 'dt' => 'total', + 'as' => 'total', + 'formatter' => function( $d, $row ) { + return number_format($d); + } + ), + array( + 'db' => 'MAX(connect_time)', + 'dt' => 'connect_time', + 'as' => 'connect_time', + 'formatter' => function( $d, $row ) { + return date('h:i:s a m/d/Y',$d); + } + ), + array( + 'db' => 'country', + 'dt' => 'country' + ), + array( + 'db' => 'premium', + 'dt' => 'premium' + ), + array( + 'db' => 'html_motd_disabled', + 'dt' => 'html_motd_disabled' + ), + array( + 'db' => 'os', + 'dt' => 'os' + ), + array( + 'db' => 'flags', + 'dt' => 'flags', + 'formatter' => function( $d, $row ) use (&$staff_group_names) { + return FlagToName($d, $staff_group_names); + } + ), + ); + + $groupBy = "GROUP BY auth"; + + + if($_GET['type'] == 'getstaff') { # AND flags != "" AND (flags = 'z' OR flags = 'xy') + if(!empty($where)) { + $where .= " AND "; + } + $where .= 'flags != "" '; + if(!empty($staff_whitelist)) { + $where .= " AND ("; + foreach($staff_whitelist as $flag) { + $where .= "flags = '".$flag."' OR "; + } + $where = rtrim(rtrim($where, " "), "OR"); + $where .= ")"; + } + if(!empty($staff_blacklist)) { + $where .= " AND ("; + foreach($staff_blacklist as $flag) { + $where .= "flags != '".$flag."' AND "; + } + $where = rtrim(rtrim($where, " "), "AND"); + $where .= ")"; + } + $groupBy = "GROUP BY auth, flags"; + } + + require('ssp.class.php'); + + echo json_encode( + SSP::simple( $_GET, $db_conn, $table, $primaryKey, $columns, $joinQuery = '', $extraCondition = '', $groupBy, $where, $records) + ); } if (isset($_GET['type']) && $_GET['type'] == 'getcountryinfo') { - $table = 'player_analytics'; - $primaryKey = 'id'; - - $columns = array( - array( - 'db' => 'id', - 'dt' => 'id' - ), - array( - 'db' => 'name', - 'dt' => 'name', - 'formatter' => function( $d, $row ) { - return htmlentities($d); - } - ), - array( - 'db' => 'auth', - 'dt' => 'auth' - ), - array( - 'db' => 'duration', - 'dt' => 'duration', - 'formatter' => function( $d, $row ) { - return PlaytimeCon($d); - } - ), - array( - 'db' => 'premium', - 'dt' => 'premium' - ), - array( - 'db' => 'html_motd_disabled', - 'dt' => 'html_motd_disabled' - ), - array( - 'db' => 'os', - 'dt' => 'os' - ) - ); - - $joinQuery = ''; - $extraCondition = "`country_code` = '".$_GET['id']."'"; - - require('ssp.class.php'); - - echo json_encode( - SSP::simple( $_GET, $sql_details, $table, $primaryKey, $columns, $joinQuery, $extraCondition) - ); + $primaryKey = 'id'; + + $columns = array( + array( + 'db' => 'id', + 'dt' => 'id' + ), + array( + 'db' => 'name', + 'dt' => 'name', + 'formatter' => function( $d, $row ) { + return htmlentities($d); + } + ), + array( + 'db' => 'auth', + 'dt' => 'auth' + ), + array( + 'db' => 'duration', + 'dt' => 'duration', + 'formatter' => function( $d, $row ) { + return PlaytimeCon($d); + } + ), + array( + 'db' => 'premium', + 'dt' => 'premium' + ), + array( + 'db' => 'html_motd_disabled', + 'dt' => 'html_motd_disabled' + ), + array( + 'db' => 'os', + 'dt' => 'os' + ), + array( + 'db' => 'server_ip', + 'dt' => 'server_ip' + ) + ); + + $extraCondition = "`country_code` = '".$_GET['id']."'"; + $extraCondition .= " AND " . $where; + require('ssp.class.php'); + + echo json_encode( + SSP::simple( $_GET, $db_conn, $table, $primaryKey, $columns, $joinQuery = '', $extraCondition, $groupBy = '', $where = '', $records) + ); +} + +if (isset($_GET['type']) && $_GET['type'] == 'c') { // connections for single server View + + $primaryKey = 'id'; + + $columns = array( + array( + 'db' => 'id', + 'dt' => 'id' + ), + array( + 'db' => 'name', + 'dt' => 'name', + 'formatter' => function( $d, $row ) { + return htmlentities($d); + } + ), + array( + 'db' => 'auth', + 'dt' => 'auth' + ), + array( + 'db' => 'connect_time', + 'dt' => 'connect_time', + 'formatter' => function( $d, $row ) { + return date('h:i:s a m/d/Y',$d); + } + ), + array( + 'db' => 'connect_method', + 'dt' => 'connect_method', + 'formatter' => function( $d, $row ) { + return ConnMethod($d); + } + ), + array( + 'db' => 'duration', + 'dt' => 'duration', + 'formatter' => function( $d, $row ) { + return PlaytimeCon($d); + } + ), + array( + 'db' => 'country', + 'dt' => 'country' + ), + array( + 'db' => 'premium', + 'dt' => 'premium' + ), + array( + 'db' => 'html_motd_disabled', + 'dt' => 'html_motd_disabled' + ), + array( + 'db' => 'os', + 'dt' => 'os' + ), + array( + 'db' => 'server_ip', + 'dt' => 'server_ip' + ) + ); + + #$extraCondition = "`server_ip` = '".$_GET['server']."'"; + $extraCondition = $where; + + require('ssp.class.php'); + + echo json_encode( + SSP::simple( $_GET, $db_conn, $table, $primaryKey, $columns, $joinQuery = '', $extraCondition, $groupBy = '', $where = '', $records) + ); +} + +if (isset($_GET['type']) && $_GET['type'] == 'u') { // Unique Players for single server View + + $primaryKey = 'id'; + $columns = array( + array( + 'db' => 'id', + 'dt' => 'id' + ), + array( + 'db' => 'name', + 'dt' => 'name', + 'formatter' => function( $d, $row ) { + return htmlentities($d); + } + ), + array( + 'db' => 'auth', + 'dt' => 'auth' + ), + array( + 'db' => 'SUM(duration)', + 'dt' => 'duration', + 'formatter' => function( $d, $row ) { + return PlaytimeCon($d); + } + ), + array( + 'db' => 'COUNT(auth)', + 'dt' => 'total', + 'as' => 'total', + 'formatter' => function( $d, $row ) { + return number_format($d); + } + ), + array( + 'db' => 'MAX(connect_time)', + 'dt' => 'connect_time', + 'as' => 'connect_time', + 'formatter' => function( $d, $row ) { + return date('h:i:s a m/d/Y',$d); + } + ), + array( + 'db' => 'country', + 'dt' => 'country' + ), + array( + 'db' => 'premium', + 'dt' => 'premium' + ), + array( + 'db' => 'html_motd_disabled', + 'dt' => 'html_motd_disabled' + ), + array( + 'db' => 'os', + 'dt' => 'os' + ), + array( + 'db' => 'server_ip', + 'dt' => 'server_ip' + ) + ); + + $groupBy = "GROUP BY auth"; + + require('ssp.class.php'); + + echo json_encode( + SSP::simple( $_GET, $db_conn, $table, $primaryKey, $columns, $joinQuery = '', $extraCondition = '', $groupBy, $where, $records) + ); } diff --git a/inc/ssp.class.php b/inc/ssp.class.php index 47d95a1..561d9de 100644 --- a/inc/ssp.class.php +++ b/inc/ssp.class.php @@ -135,7 +135,7 @@ static function order ( $request, $columns, $isJoin = false ) * * @return string SQL where clause */ - static function filter ( $request, $columns, &$bindings, $isJoin = false, $groupBy) + static function filter ( $request, $columns, &$bindings, $isJoin = false, $groupBy = null) { $globalSearch = array(); $columnSearch = array(); @@ -190,6 +190,7 @@ static function filter ( $request, $columns, &$bindings, $isJoin = false, $group if ( $where !== '' && $groupBy !== '' ) { $where = 'HAVING '.$where; + #$where = 'WHERE '.$where; } return $where; @@ -214,7 +215,7 @@ static function filter ( $request, $columns, &$bindings, $isJoin = false, $group * @return array Server-side processing response array * */ - static function simple ( $request, $sql_details, $table, $primaryKey, $columns, $joinQuery = NULL, $extraWhere = '', $groupBy = '') + static function simple ( $request, $sql_details, $table, $primaryKey, $columns, $joinQuery = NULL, $extraWhere = '', $groupBy = '', $where2 = '', $records = 0) { $bindings = array(); $db = SSP::sql_connect( $sql_details ); @@ -232,14 +233,34 @@ static function simple ( $request, $sql_details, $table, $primaryKey, $columns, $extraWhere = ($where) ? ' AND '.$extraWhere : ' WHERE '.$extraWhere; } + #my WHERE hack + $add_where = ''; + if(!empty($where2)) { + if(empty($where)) { + $add_where = " WHERE "; + } else { + if(substr(trim($where),0,6) == "HAVING") { + $add_where = " WHERE "; + } else { + $add_where = " AND "; + } + } + } + if(!empty($where2)) { + $add_where .= " ".$where2." "; + } + #pr($where); die; + // Main query to actually get the data if($joinQuery){ $col = SSP::pluck($columns, 'db', $joinQuery); if ($groupBy !== '') { + # echo "b1 "; $query = "SELECT SQL_CALC_FOUND_ROWS ".implode(", ", $col)." $joinQuery + $add_where $groupBy $where $extraWhere @@ -247,9 +268,11 @@ static function simple ( $request, $sql_details, $table, $primaryKey, $columns, $limit"; } else { + # echo "b2 "; $query = "SELECT SQL_CALC_FOUND_ROWS ".implode(", ", $col)." $joinQuery $where + $add_where $extraWhere $order $limit"; @@ -257,8 +280,10 @@ static function simple ( $request, $sql_details, $table, $primaryKey, $columns, } else{ if ($groupBy !== '') { + #echo "b3 "; $query = "SELECT SQL_CALC_FOUND_ROWS ".implode(", ", SSP::pluck($columns, 'db'))." FROM `$table` + $add_where $groupBy $where $extraWhere @@ -266,15 +291,18 @@ static function simple ( $request, $sql_details, $table, $primaryKey, $columns, $limit"; } else { + # echo "b4 "; $query = "SELECT SQL_CALC_FOUND_ROWS ".implode(", ", SSP::pluck($columns, 'db'))." FROM `$table` $where + $add_where $extraWhere $order $limit"; } } - + $remove_full_group_for_query = "SET sql_mode=(SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', ''))"; + SSP::sql_exec( $db, null,$remove_full_group_for_query); $data = SSP::sql_exec( $db, $bindings,$query); // Data set length after filtering @@ -284,10 +312,17 @@ static function simple ( $request, $sql_details, $table, $primaryKey, $columns, $recordsFiltered = $resFilterLength[0][0]; // Total data set length - $resTotalLength = SSP::sql_exec( $db, - "SELECT COUNT(`{$primaryKey}`) - FROM `$table`" - ); + if(isset($records) && !empty($records)) { + $records_length[0][0] = $records; + $resTotalLength = $records_length; + } else { + $resTotalLength = SSP::sql_exec( $db, + //"SELECT COUNT(`{$primaryKey}`) # count(*) is faster but counts also null values. We don't care here much about it + "SELECT COUNT(*) + FROM `$table`" + ); + } + $recordsTotal = $resTotalLength[0][0]; @@ -355,6 +390,9 @@ static function sql_exec ( $db, $bindings, $sql=null ) $stmt = $db->prepare( $sql ); #echo $sql; + #print_r($sql); die; + #$myfile = fopen("sql_log.txt", "a"); fwrite($myfile, "\n### ".date('Y-m-d H:i:s')." ### \n".$sql."\n"); fclose($myfile); + #$file = file_get_contents("sql_log.txt"); file_put_contents("sql_log.txt", "\n### ".date('Y-m-d H:i:s')." ### \n".$sql."\n" . $file); // Bind parameters if ( is_array( $bindings ) ) { diff --git a/inc/util.php b/inc/util.php new file mode 100644 index 0000000..b297fd3 --- /dev/null +++ b/inc/util.php @@ -0,0 +1,40 @@ +"; + print_r($input); + echo ""; +} + + diff --git a/index.php b/index.php index b61ac0a..7d95c6d 100644 --- a/index.php +++ b/index.php @@ -1,20 +1,50 @@ +IsUserLoggedIn()) { + header("Location: ./login.php"); + exit; + } +} + +$hide_servers = ""; +if($hide_inactive_servers_days > 0) { + $hide_servers = " WHERE connect_date > DATE_SUB(NOW(), INTERVAL $hide_inactive_servers_days DAY) "; +} +$database->query('SELECT DISTINCT `server_ip` FROM `'.DB_TABLE_PA.'` '. $hide_servers .' ORDER BY server_ip'); + +$key = FileSystemCache::generateCacheKey(sha1(serialize(array($database->stmt(), $db))), 'SQL'); +$servers = FileSystemCache::retrieve($key); +if($servers === false) { + $servers = $database->resultset(); + FileSystemCache::store($key, $servers, 100000); #300k sec = 3.4 days +} + +$force_recache = "?t2"; # change to some other random string after modding js files +?> + - Player Analytics - - - - - - - + <?php echo $Title ?> + + + + + + + + + +