' . NL); \SDV($TotalCounterAction, 'totalcounter'); // ?action=totalcounter \SDV($TotalCounterAuthLevel, 'admin'); \SDV($TotalCounterMaxItems, 30); \SDV($TotalCounterEnableLookup, 0); // default 0 \SDV($TotalCounterBarColor, '#5af'); \SDV($TotalCounterCountBots, 0); // 1.10.0 # default 0 \SDV($TotalCounterShowNumbers, 1); // default 1 \SDV($TotalCounterEnableGEOIP, 0); // default 0 \SDV($TotalCounterGeoIPData, "$WorkDir/GeoIP.dat"); \SDV($TotalCounterEnableDownload, 0); //default 0 \SDV($TotalCounterDownloadManager, "$WorkDir/.download.manager"); \SDV($TotalCounterEnableChmods, 1); // default 1 \SDV($TotalCounterEnableUsers, 0); // default 0 \SDV($TotalCounterFile, "$WorkDir/totalcounter.stat"); \SDV($TotalCounterLockfile, "$WorkDir/totalcounter.lock"); \SDV($TotalCounterLogfile, "$WorkDir/totalcounter.log"); \SDV($TotalCounterEnableLog, 0); # default 0 (off), 1 (on, captures unknowns), 2 log server details /* \SDV($TotalCounterBrowsersUnset, ''); // used to remove individual totals from file, don't use this unless you know what you are doing \SDV($TotalCounterOSesUnset, ''); // used to remove individual totals from file, don't use this unless you know what you are doing \SDV($TotalCounterLocationsUnset, ''); // used to remove individual totals from file, don't use this unless you know what you are doing \SDV($TotalCounterBotsUnset, ''); // used to remove individual totals from file, don't use this unless you know what you are doing \SDV($TotalCounterReferersUnset, ''); // used to remove individual totals from file, don't use this unless you know what you are doing */ \SDV($HTMLStylesFmt[TOTALCOUNTERNAME], ".TCbar {background-color:$TotalCounterBarColor; min-height:13px; width:13px; color:#fff;}\n" . ".TCtxtr {text-align:right;}" . ".TCtxtl {text-align:left;}" . ".TCtxth {font-weight: bold;}" . ".TCprogress {margin-left:auto; margin-right:auto;}\n" . "table.totalcounter td {font-size:x-small; text-align:center}"); \SDVA($TotalCounterMonthsShort, array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec')); \SDV($TotalCounterBlacklist['Pages'], array ()); \SDV($TotalCounterBlacklist['Users'], array ()); \SDV($TotalCounterBlacklist['Browsers'], array ()); \SDV($TotalCounterBlacklist['OSes'], array ()); \SDV($TotalCounterBlacklist['Referers'], array ()); \SDV($TotalCounterBlacklist['Locations'], array ()); \SDV($TotalCounterBlacklist['Bots'], array ()); \SDV($TotalCounterBlacklist['Languages'], array ()); ## by MateuszCzaplinski ## last day, last week, ... - data & display descriptions \SDVA($TotalCounterTimeBins, array( 'LastDay' => array( # LastDay = 24 hours; 1 hour = 60*60sec 'name'=>'Last day (hours)', 'max'=>24, 'atom'=>60*60, // name 1.10.0 'fmt'=> 'date("G",$now-$atom*($maxnr-1-$nr))' ), 'LastWeek' => array( # LastWeek = 7 days 'name'=>'Last week', 'max'=>7, 'atom'=>24*60*60, // name 1.10.0 'fmt'=> 'date("D",$now-$atom*($maxnr-1-$nr))' ), 'LastMonth' => array( 'name'=>'Last month', 'max'=>30, 'atom'=>24*60*60, // name 1.10.0 'fmt'=> 'date("j",$now-$atom*($maxnr-1-$nr))' ), 'LastYear' => array( # date('n') is the month of the year 'name'=>'Last year', 'max'=>12, 'atom'=>'n', // name 1.10.0 'fmt'=> '$TotalCounterMonthsShort[(12+(int)date("n",$now)-$maxnr+$nr)%12]' ), 'LastYears' => array( 'name'=>'Last years', 'max'=>30, 'atom'=>'Y', // name 1.10.0 'fmt'=> '(int)date("Y",$now)-($maxnr-1-$nr)' ) )); \SDVA($HandleActions, array ( $TotalCounterAction => __NAMESPACE__ . '\HandleTotalCounter' )); \SDVA($HandleAuth, array ( $TotalCounterAction => $TotalCounterAuthLevel )); \SDV($TotalCounterDebug, false); # set default debug setting # set debug flag $totalcounter_debugon = (bool) $TotalCounterDebug; # if on writes input and output to web page if ($totalcounter_debugon) { tcmsg (__FILE__, $RecipeInfo[TOTALCOUNTERNAME]['Version'] . ' using "' . $WorkDir . '" with action=' . $action . ', log=' . $TotalCounterEnableLog . ', IP lookup: '. $TotalCounterEnableLookup); } global $TotalCounter; if ($TotalCounterMaxItems <= 0) $TotalCounterMaxItems = 1; $statfile = $TotalCounterFile; $lockfile = $TotalCounterLockfile; $logfile = $TotalCounterLogfile; if (function_exists('\PSFT')) { $logfiletime = \PSFT ("%Y-%m-%d %H:%M:%S "); } else { $logfiletime = strftime ("%Y-%m-%d %H:%M:%S "); } $geoIpFile = $TotalCounterGeoIPData; // clear cached information about file clearstatcache(); // script to carry on working after the user has cancelled request or browser session closed ignore_user_abort(true); # while (file_exists($lockfile)) { # $st = stat($lockfile); # if ((time()-$st['mtime']) > 15) { # Abort("Too many visitors at the moment...please try later!"); # break; # } # } //------------------------------------------------------------------------------------ if ($TotalCounterEnableLog > 0) { $logfilehandle = fopen($logfile, 'a'); # create or open logfile for appending if ($logfilehandle === false) { tcmsg ('fopen failed', $logfile, error_get_last()); if ($totalcounter_debugon) Exit ($MessagesFmt [TOTALCOUNTERNAME]); } } if ($TotalCounterEnableLog == 2) { # write for every call, this can be very verbose if (false === fwrite($logfilehandle, $logfiletime . 'UA: "' . $_SERVER['HTTP_USER_AGENT'] . '" Rf: "' . $_SERVER['HTTP_REFERER'] . '" URf: "' . $_SERVER['HTTP_USER_REFERER'] . '" XXF: "' . $_SERVER['HTTP_X_FORWARDED_FOR'] . '" Fw: "' . $_SERVER['HTTP_FORWARDED'] . '" XFH: "' . $_SERVER['HTTP_X_FORWARDED_HOST'] . '" RH: "' . $_SERVER['REMOTE_HOST'] . '" RA: "' . $_SERVER['REMOTE_ADDR'] . "\"\n")) { tcmsg ('fwrite failed', $logfile, error_get_last()); if ($totalcounter_debugon) Exit ($MessagesFmt [TOTALCOUNTERNAME]); }; }; if (!function_exists("file_get_contents")) { function file_get_contents(string $filename) { $contents = file($filename); if (FALSE === $contents) { return FALSE; } else { return implode('', $contents); } } // end function file_get_contents } // end if if (function_exists('\ResolvePageName')) { $tc_pagename = \ResolvePageName($pagename); } else { $tc_pagename = str_replace('/', '.', $pagename); /* line changed by Chris Morison 9/3/06 */ } // end if if (empty($tc_pagename)) $tc_pagename = "$DefaultGroup.$DefaultName"; // update counts from page being browsed if ($action == 'browse') { //find users if (isset ($AuthId)) { $tc_user = $AuthId; } else { if (isset ($Author)) { $tc_user = $Author; } else { @ session_start(); if (isset ($_SESSION['authid'])) { $tc_user = $_SESSION['authid'][0]; } else { $tc_user = 'Guest (not authenticated)'; } // end isset $_SESSION } // end if else isset $Author } // end if else isset $AuthId // find web bot https://developers.whatismybrowser.com/useragents/explore/, https://bigdata-madesimple.com/top-50-open-source-web-crawlers-for-data-mining/ $tc_bot = ''; $tc_browser = ''; if (empty($_SERVER['HTTP_USER_AGENT'])) { # it happens if ($TotalCounterEnableLog >= 1) { $fwritestatus = fwrite($logfilehandle, $logfiletime . 'UA empty:"' . $_SERVER['HTTP_USER_AGENT'] . '" RH:"' . $_SERVER['REMOTE_HOST'] . '" action: ' . $action . "\"\n"); if ($fwritestatus === false) { tcmsg ('fwrite failed', $logfile, error_get_last()); } tcmsg ('HTTP_USER_AGENT', 'empty "' . $_SERVER['HTTP_USER_AGENT']. '", RH:"' . $_SERVER['REMOTE_HOST'] . '", RA:"' . $_SERVER['REMOTE_ADDR'] . '" action: ' . $action); } } elseif (preg_match('/ia_archiver/i', $_SERVER['HTTP_USER_AGENT'])) // 1.10.0 # add mode i for all regex $tc_bot = 'Alexa'; // # https://support.alexa.com/hc/en-us/articles/200450194-Alexa-s-Web-and-Site-Audit-Crawlers elseif (preg_match('/360Spider/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = '360Spider'; # elseif (preg_match('/A6-Indexer/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'A6'; # http://www.a6corp.com/a6-web-scraping-policy/ elseif (preg_match('/Abonti/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Abonti'; # http://www.abonti.com elseif (preg_match('/Adsbot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Adsbot'; # https://seostar.co/robot/ elseif (preg_match('/AhrefsBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Ahrefs'; # https://ahrefs.com/robot/ elseif (preg_match('/aiohttp/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'aiohttp'; # aiohttp elseif (preg_match('/AnyEvent/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'AnyEvent'; # http://software.schmorp.de/pkg/AnyEvent elseif (preg_match('/AppEngine-Google/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'AppEngine-Google'; # http://code.google.com/appengine elseif (preg_match('/applebot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Applebot'; # https://support.apple.com/en-us/HT204683 elseif (preg_match('/archive.org_bot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Web archive'; # https://webarchive.jira.com/wiki/display/ARIH/Robots+Exclusion+Protocol elseif (preg_match('/AntBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Ant'; # http://www.ant.com elseif (preg_match('/ask jeeves/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Ask Jeeves'; elseif (preg_match('/baiduspider/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Baidu'; // # http://www.baidu.com/search/spider.html elseif (preg_match('/becomebot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Become'; elseif (preg_match('/bibalex.org_bot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Bibalex'; # http://archive.bibalex.org/bot/ elseif (preg_match('/bingbot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Bing'; # http://www.bing.com/bingbot.htm elseif (preg_match('/BLEXBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'WebMeUp'; # http://webmeup-crawler.com/ elseif (preg_match('/CCBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Common Crawl'; # http://commoncrawl.org/faqs/ elseif (preg_match('/CensysInspect/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Censys Inspect'; # https://about.censys.io/ elseif (preg_match('/CheckMarkNetwork/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'CheckMark Network'; # http://www.checkmarknetwork.com/spider.html elseif (preg_match('/Crawlbot\/Nutch/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Crawlbot/Nutch'; # https://nutch.apache.org/ elseif (preg_match('/Dalvik/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Dalvik'; # elseif (preg_match('/DataForSeoBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'DataForSeoBot'; # https://dataforseo.com/dataforseo-bot elseif (preg_match('/deepnoc/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Deepnoc'; # https://deepnoc.com/bot elseif (preg_match('/DomainStatsBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'DomainStatsBot';# https://domainstats.com/pages/our-bot elseif (preg_match('/dotbot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'DotBot'; # http://www.opensiteexplorer.org/dotbot elseif (preg_match('/DuckDuckGo-Favicons-Bot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'DuckDuckGo-Favicons-Bot'; # http://duckduckgo.com elseif (preg_match('/exabot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Exalead'; elseif (preg_match('/Expanse/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Expanse'; # scaninfo@expanseinc.com elseif (preg_match('/facebookexternalhit/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Facebook'; # http://www.facebook.com/externalhit_uatext.php elseif (preg_match('/fast/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Fast/Alltheweb'; elseif (preg_match('/gigabot/i', $_SERVER['HTTP_USER_AGENT']) // http://www.gigablast.com/spider.html || preg_match('/GigablastOpenSource/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Gigablast'; // https://github.com/gigablast/open-source-search-engine elseif (preg_match('/googlebot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Google'; // # http://www.google.com/bot.html elseif (preg_match('/James BOT/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'CognitiveSEO'; # http://cognitiveseo.com/bot.html elseif (preg_match('/libwww-perl/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Libwww-perl'; # libwww-perl elseif (preg_match('/linkdexbot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Linkdex'; // # http://www.linkdex.com/bots/ elseif (preg_match('/Mediapartners-Google/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Google'; # https://support.google.com/webmasters/answer/1061943?hl=en elseif (preg_match('/AdsBot-Google/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Google'; // 1.10.0 elseif (preg_match('/grub-client/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Grub'; elseif (preg_match('/libcurl/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'cURL'; elseif (preg_match('/slurp@inktomi.com/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Inktomi'; elseif (preg_match('/Keybot Translation-Search-Machine/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Keybot Translation-Search-Machine'; elseif (preg_match('/ltx71/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'ltx71'; # http://ltx71.com/ elseif (preg_match('/Mail\.RU_Bot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'mail.ru'; // 1.10.0 # http://go.mail.ru/help/robots elseif (preg_match('/meanpathbot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'meanpath'; // 1.10.0 elseif (preg_match('/MJ12bot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Majestic'; // 1.10.0 # http://www.majestic12.co.uk/bot.php elseif (preg_match('/MojeekBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'MojeekBot'; // 1.10.0 # https://www.mojeek.com/bot.html elseif (preg_match('/msnbot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'MSN'; elseif (preg_match('/NerdyBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Nerdy data'; // 1.10.0 elseif (preg_match('/NetcraftSurveyAgent/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Netcraft'; # info@netcraft.com elseif (preg_match('/Netcraft Web Server Survey/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Netcraft'; elseif (preg_match('/NetpeakCheckerBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'NetpeakCheckerBot'; # https://netpeaksoftware.com/checker elseif (preg_match('/NetSystemsResearch/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'NetSystemsResearch'; # https://netsystemsresearch.com elseif (preg_match('/Neevabot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Neevabot'; # https://neeva.com/neevabot elseif (preg_match('/Nimo Software/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Nimo Software HTTP Retriever'; # elseif (preg_match('/NLNZ_IAHarvester/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'NLNZ_IAHarvester';# https://natlib.govt.nz/publishers-and-authors/web-harvesting/domain-harvest elseif (preg_match('/petalbot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Petalbot'; # https://petalsearch.com/ elseif (preg_match('/PHP-Curl-Class/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'PHP-Curl-Class'; # https://github.com/php-curl-class/php-curl-class elseif (preg_match('/Pinterest/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Pinterest'; // # http://www.pinterest.com elseif (preg_match('/python-requests/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Python-requests'; // # python-requests elseif (preg_match('/Qwantify/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Qwantify';# https://www.qwant.com/ elseif (preg_match('/scooter/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Altavista'; elseif (preg_match('/SISTRIX/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'SISTRIX'; // 1.10.0 # http://crawler.007ac9.net/ elseif (preg_match('/Crawler/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'SISTRIX'; // 1.10.0 # http://crawler.007ac9.net/ elseif (preg_match('/SemrushBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'SemrushBot'; # http://www.semrush.com/bot.html elseif (preg_match('/SeznamBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'SeznamBot'; # http://napoveda.seznam.cz/en/seznambot-intro/ elseif (preg_match('/SiteExplorer/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Site Explorer'; # http://siteexplorer.info/ elseif (preg_match('/snapchat/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Snapchat URL Preview Service'; # https://developers.snap.com/robots elseif (preg_match('/SpiceworksAgentShell/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Spiceworks Agent Shell'; # https://community.spiceworks.com/support/inventory-online/docs/deploy-agent elseif (preg_match('/SurdotlyBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'SurdotlyBot'; # http://sur.ly/bot.html elseif (preg_match('/synapse/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Synapse'; // 1.10.0 elseif (preg_match('/Twisted PageGetter/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Twisted PageGetter'; // 1.10.0 # https://twistedmatrix.com/trac/ elseif (preg_match('/unirest-java/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'unirest-java'; // # unirest-java elseif (preg_match('/WebTarantula/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'WebTarantula'; // # http://webtarantula.com/ elseif (preg_match('/wget/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'wget'; #https://www.gnu.org/software/wget/ elseif (preg_match('/yahoo! slurp/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Yahoo!'; //http://help.yahoo.com/help/us/ysearch/slurp elseif (preg_match('/XoviBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Xovi'; // 1.10.0 # http://www.xovibot.net/ elseif (preg_match('/YandexBot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Yandex'; // 1.10.0 # http://yandex.com/bots elseif (preg_match('/YottaaMonitor/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'Yottaa'; // 1.10.0 # http://www.yottaa.com/blog/bid/223629/Google-Analytics-How-to-Segment-and-Filter-Robot-Traffic elseif (preg_match('/zyborg/i', $_SERVER['HTTP_USER_AGENT']) || preg_match('/zealbot/i', $_SERVER['HTTP_USER_AGENT'])) $tc_bot = 'WiseNut!'; // not a bot, so find the browser, https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent elseif (preg_match('/arachne/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Arachne GPL'; elseif (preg_match('/vivaldi/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Vivaldi'; elseif (preg_match('/blazer/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Blazer'; elseif (preg_match('/brave/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Brave'; elseif (preg_match('/opera/i', $_SERVER['HTTP_USER_AGENT']) || preg_match('/OPR/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Opera'; // 1.10.0 # must be before Chrome below elseif (preg_match('/webtv/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'WebTV'; elseif (preg_match('/camino/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Camino'; elseif (preg_match('/MAXTHON/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'MAXTHON'; // 1.10.0 # must be before msie below # http://www.maxthon.com/ elseif (preg_match('/netpositive/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'NetPositive'; elseif (preg_match('/internet explorer/i', $_SERVER['HTTP_USER_AGENT']) || preg_match('/msie/i', $_SERVER['HTTP_USER_AGENT']) || preg_match('/IEMobile/i', $_SERVER['HTTP_USER_AGENT']) || preg_match('/mspie/i', $_SERVER['HTTP_USER_AGENT']) || preg_match('/trident/i', $_SERVER['HTTP_USER_AGENT']) ) $tc_browser = 'MS Internet Explorer'; // 1.10.0 # add trident elseif (preg_match('/avant browser/i', $_SERVER['HTTP_USER_AGENT']) || preg_match('/advanced browser/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Avant Browser'; elseif (preg_match('/galeon/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Galeon'; elseif (preg_match('/konqueror/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Konqueror'; elseif (preg_match('/icab/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'iCab'; elseif (preg_match('/Nmap Scripting Engine/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Nmap'; // 1.10.0 # http://nmap.org/book/nse.html elseif (preg_match('/omniweb/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'OmniWeb'; elseif (preg_match('/phoenix/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Phoenix'; elseif (preg_match('/firebird/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Firebird'; elseif (preg_match('/seamonkey/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Seamonkey'; # must be before Firefox elseif (preg_match('/firefox/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Firefox'; elseif (preg_match('/netscape/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Netscape'; // 1.10.0 # must be before Mozilla below elseif (preg_match('/minimo/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Minimo'; elseif (preg_match('/mozilla/i', $_SERVER['HTTP_USER_AGENT']) && preg_match('/rv:[0-9].[0-9][a-b]/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Mozilla'; // 1.10.0 fix regex elseif (preg_match('/mozilla/i', $_SERVER['HTTP_USER_AGENT']) && preg_match('/rv:[0-9].[0-9]/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Mozilla'; // 1.10.0 fix regex elseif (preg_match('/YaBrowser/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Yandex browser'; // 1.10.0 # http://help.yandex.ru/yabrowser/?lang=en elseif (preg_match('/libwww/i', $_SERVER['HTTP_USER_AGENT'])) { if (preg_match('/amaya/i', $_SERVER['HTTP_USER_AGENT'])) { $tc_browser = 'Amaya'; } else { $tc_browser = 'Text browser'; } } elseif (preg_match('/edge/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Edge'; // must be before Safari elseif (preg_match('/chromium/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Chromium'; // must be before Chrome elseif (preg_match('/chrome/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Chrome'; // must be before Safari elseif (preg_match('/safari/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Safari'; // must be after Chrome above elseif (preg_match('/elinks/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'ELinks'; elseif (preg_match('/offbyone/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Off By One'; elseif (preg_match('/playstation portable/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'PlayStation Portable'; elseif (preg_match('/links/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Links'; elseif (preg_match('/ibrowse/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'iBrowse'; elseif (preg_match('/w3m/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'w3m'; elseif (preg_match('/aweb/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'AWeb'; elseif (preg_match('/voyager/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Voyager'; elseif (preg_match('/oregano/i', $_SERVER['HTTP_USER_AGENT'])) $tc_browser = 'Oregano'; else { $tc_browser = 'Unknown'; tcmsg ('Browser', $_SERVER['HTTP_USER_AGENT'] . ' unknown'); if ($TotalCounterEnableLog >= 1) { $fwritestatus = fwrite($logfilehandle, $logfiletime . 'Browser: UA:"' . $_SERVER['HTTP_USER_AGENT'] . "\"\n"); if ($fwritestatus === false) { tcmsg ('fwrite failed', $logfile, error_get_last()); } } } // end find web bot or browser // decide if we are counting this visit $tc_count_visit = (empty ($tc_bot) // don't count bots || ($TotalCounterCountBots == 1)); // count bots (all visits) if ($tc_count_visit) { // 1.10.0 # don't count bots by default // find operating system if (empty($_SERVER['HTTP_USER_AGENT'])) { } // can't find it if its empty elseif (preg_match('/android/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Android'; // 1.10.0 # must be before linux below elseif (preg_match('/linux/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Linux'; elseif (preg_match('/irix/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'IRIX'; elseif (preg_match('/hp-ux/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'HP-Unix'; elseif (preg_match('/os2/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'OS/2'; elseif (preg_match('/beos/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'BeOS'; elseif (preg_match('/sunos/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'SunOS'; elseif (preg_match('/palm/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'PalmOS'; elseif (preg_match('/cygwin/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Cygwin'; elseif (preg_match('/amiga/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Amiga'; elseif (preg_match('/unix/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Unix'; elseif (preg_match('/qnx/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'QNX'; elseif (preg_match('/Windows Phone/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Windows Phone'; // 1.10.0 # must be before Windows below elseif (preg_match('/windows/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Windows'; // 1.10.0 win to windows elseif (preg_match('/iphone os/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'iPhone'; // 1.10.0 # must be before Mac OS below elseif (preg_match('/mac os/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Mac'; // 1.10.0 mac to mac os elseif (preg_match('/cros/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Chrome OS'; elseif (preg_match('/symbian/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Symbian'; elseif (preg_match('/risc/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'RISC'; elseif (preg_match('/dreamcast/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'Dreamcast'; elseif (preg_match('/freebsd/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'FreeBSD'; elseif (preg_match('/dos/i', $_SERVER['HTTP_USER_AGENT'])) $tc_os = 'dos'; elseif (empty ($tc_bot)) { # skip OS if it is a bot and OS not identified // 1.10.0 $tc_os = 'Unknown'; tcmsg ('OpSystem', $_SERVER['HTTP_USER_AGENT'] . ' unknown'); if ($TotalCounterEnableLog >= 1) { $fwritestatus = fwrite($logfilehandle, $logfiletime . 'OpSystem: RH:"' . $_SERVER['REMOTE_HOST'] . ' UA:"' . $_SERVER['HTTP_USER_AGENT'] . "\"\n"); if ($fwritestatus === false) { tcmsg ('fwrite failed', $logfile, error_get_last()); } } }; // end preg_match }; // end find OS if ($tc_count_visit) { // 1.10.0 # don't count bots by default // find referrer domain $matches = []; $referer = ''; $tc_referer = 'Unknown'; if (!empty ($_SERVER['HTTP_REFERER'])) { # remove the schema, see https://regex101.com/r/epmzHv/2 if (1 == preg_match("/^(?:https?:\/\/)?([^\/:\r\n]+)/", $_SERVER['HTTP_REFERER'], $matches)) { $referer = $matches[1]; } } if (!empty($referer)) { $tc_referer = $referer; } if ($tc_referer == 'Unknown') { if (!empty ($tc_bot)) { # skip referer if it is a bot and referer not identified // 1.10.0 unset ($tc_referer); }; // end !empty $tc_bot if ($TotalCounterEnableLog >= 1 and !empty($_SERVER['HTTP_REFERER'])) { tcmsg ('Referer unknown', $_SERVER['HTTP_REFERER'] . ' UA:"' . $_SERVER['HTTP_USER_AGENT'] . '"'); $fwritestatus = fwrite($logfilehandle, $logfiletime . 'Referer: "' . $_SERVER['HTTP_REFERER'] . '", UA:"' . $_SERVER['HTTP_USER_AGENT'] . '" ^' . $referer . '^ [' . implode (', ', $matches) . '] ' . "\n"); if ($fwritestatus === false) { tcmsg ('fwrite failed', $logfile, error_get_last()); } } }; // end find referrer } if ($tc_count_visit) { // 1.10.0 # don't count bots by default // find location $dbgloc = ''; # de-facto standard header for identifying the originating IP address of a client connecting to a web server through an HTTP proxy or a load balancer if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $dbgloc .= 'XFF'; if (false !== strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',')) { $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $thehost = trim($ips[0]); # see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For } else { $thehost = $_SERVER['HTTP_X_FORWARDED_FOR']; } } elseif (!empty($_SERVER['HTTP_FORWARDED'])) { $dbgloc = 'Fw'; $posn = strpos($_SERVER['HTTP_FORWARDED'], 'for='); if (false !== $posn) { $ips = explode(';', substr($_SERVER['HTTP_FORWARDED'], $posn + 4)); #for=192.0.2.60;proto=http $ips = explode(',', $ips[0]); # 192.0.2.43, for=198.51.100.17 $thehost = trim($ips[0]); } else { $thehost = $_SERVER['HTTP_FORWARDED']; } } elseif (false !== strpos($_SERVER['REMOTE_HOST'], ',')) { $dbgloc = 'RH+'; # empty($_SERVER['HTTP_X_FORWARDED_FOR']) and empty($_SERVER['HTTP_FORWARDED']) $ips = explode(',', $_SERVER['REMOTE_HOST']); $thehost = trim($ips[0]); } else { $dbgloc = 'RH'; $thehost = $_SERVER['REMOTE_HOST']; } // match any character not digits or period backwards from end of string if (1 == preg_match("/[^\.0-9]+$/", $thehost, $matches)) { $loc = $matches[0]; } $tc_location = 'Unknown'; while (true) { if (!empty($loc)) { $dbgloc .= '='; $tc_location = $loc; break; } if ($TotalCounterEnableLookup == 1) { $hostbyaddr = gethostbyaddr($_SERVER['REMOTE_ADDR']); $dbgloc .= 'L^' . $hostbyaddr . '^'; if (false === $hostbyaddr) { $tc_location = 'Unknown'; } elseif (false === preg_match("/[^\.0-9]+$/", $hostbyaddr, $matches)) { // match any character not digits or period (IP address?) $tc_location = 'Unknown'; } else { $gloc = $matches[0]; if (!empty($gloc)) { $tc_location = $gloc; break; } } } if ($TotalCounterEnableGeoIP == 1) { $dbgloc .= 'G'; include ('geoip/geoip.inc'); # return the two letter country code corresponding to a hostname or an IP address $gi = geoip_open($geoIpFile, GEOIP_STANDARD); # https://www.php.net/manual/en/function.geoip-country-code-by-name.php $gccba = geoip_country_code_by_addr($gi, $_SERVER['REMOTE_ADDR']); geoip_close($gi); if (!false === $gccba) { $tc_location = $gccba; break; } } # https://regex101.com/r/ONcmD7/1 if (1 == preg_match("/(?:10\.[0-9]{1,3}|172\.(?:1[6-9]|2[0-9]|3[0-1])|192\.168)(?:\.[0-2]?[0-9]{1,2}){2}/", $thehost, $matches)) { $dbgloc .= 'P'; # match for private IP address https://en.wikipedia.org/wiki/Private_network $tc_location = 'Private IP (' . stristr ($matches [0], '.', true) . ')'; break; } $dbgloc .= '.'; break; } # end while true if ($tc_location == 'Unknown') { if (!empty ($tc_bot)) { # skip location if it is a bot and location not identified // 1.10.0 unset ($tc_location); }; // end !empty $tc_bot if ($TotalCounterEnableLog >= 1) { $logmsg = 'Location: '; if (!empty ($_SERVER['HTTP_X_FORWARDED_FOR'])) $logmsg .= 'XFF:"' . $_SERVER['HTTP_X_FORWARDED_FOR'] . '" '; if (!empty ($_SERVER['HTTP_FORWARDED'])) $logmsg .= 'Fw:"' . $_SERVER['HTTP_FORWARDED'] . '" '; if (!empty ($_SERVER['HTTP_FORWARDED-HOST'])) $logmsg .= 'FH:"' . $_SERVER['HTTP_FORWARDED-HOST'] . '" '; $fwritestatus = fwrite($logfilehandle, $logfiletime . $logmsg . 'RH:"' . $_SERVER['REMOTE_HOST'] . '", RA:"' . $_SERVER['REMOTE_ADDR'] . '", UA:"' . $_SERVER['HTTP_USER_AGENT'] . ' (' . $thehost . ') ' . $dbgloc . "\n"); if ($fwritestatus === false) { tcmsg ('fwrite failed', $logfile, error_get_last()); } } }; //end = Unknown $tc_location = strtolower($tc_location); $tc_location = str_ireplace (['unknown', 'private ip'], ['Unknown', 'Private IP'], $tc_location); }; // end count visits }; // end if action = browse //------------------------------------------------------------------------------------ $oldumask = umask(0); //mkdir($lockfile, 0777); # touch($lockfile); # fixperms($lockfile); if ($TotalCounterEnableDownload == 1) { $downloadfile = $TotalCounterDownloadManager; if (file_exists($downloadfile)) { $TotalCounterDownloadsFileContents = file_get_contents($downloadfile); if (FALSE === $TotalCounterDownloadsFileContents) tcmsg ('get_file_contents failed', $downloadfile, error_get_last()); $TotalCounterDownloads = unserialize($TotalCounterDownloadsFileContents); if (FALSE === TotalCounterDownloads) tcmsg ('unserialize failed', $downloadfile, error_get_last()); } } if (file_exists($statfile)) { $TotalCounterFileContents = file_get_contents($statfile); if (FALSE === $TotalCounterFileContents) { tcmsg ('file_get_contents failed', $statfile, error_get_last()); } $TotalCounter = unserialize($TotalCounterFileContents); if (FALSE === $TotalCounter) { tcmsg ('unserialize failed', $statfile, error_get_last()); } } else { touch($statfile); # create the stat file $TotalCounter['Total'] = 0; $TotalCounter['Pages'][$tc_pagename] = 0; } if (($action == 'browse') && (!empty($tc_pagename))) { if( dblock($statfile) ) { $TotalCounterFileContents = file_get_contents($statfile); if (FALSE === $TotalCounterFileContents) tcmsg ('file_get_contents failed', $statfile, error_get_last()); $TotalCounter = unserialize($TotalCounterFileContents); if (FALSE === $TotalCounter) tcmsg ('unserialize failed', $statfile, error_get_last()); /* // code intended only for developers to clean up entries in the stats file // use at your own risk if ($totalcounter_debugon) { if (!empty ($TotalCounterBrowsersUnset)) { if (isset($TotalCounter['Browsers'][$TotalCounterBrowsersUnset])) { unset ($TotalCounter['Browsers'][$TotalCounterBrowsersUnset]); } } # Browsers if (!empty ($TotalCounterOSesUnset)) { if (isset($TotalCounter['OSes'][$TotalCounterOSesUnset])) { unset ($TotalCounter['OSes'][$TotalCounterOSesUnset]); } } # OSes if (!empty ($TotalCounterLocationsUnset)) { if (isset($TotalCounter['Locations'][$TotalCounterLocationsUnset])) { unset ($TotalCounter['Locations'][$TotalCounterLocationsUnset]); } } # Locations if (!empty ($TotalCounterBotsUnset)) { if (isset($TotalCounter['Bots'][$TotalCounterBotsUnset])) { unset ($TotalCounter['Bots'][$TotalCounterBotsUnset]); } } # Bots if (!empty ($TotalCounterReferersUnset)) { if (isset($TotalCounter['Referers'][$TotalCounterReferersUnset])) { unset ($TotalCounter['Referers'][$TotalCounterReferersUnset]); } } # Referers } # $totalcounter_debugon // end clean up code */ $TotalCount = ++ $TotalCounter['Total']; $blacklisted = false; if (@in_array($tc_user, $TotalCounterBlacklist['Users'])) $blacklisted = true; if (!$blacklisted && !@ in_array($tc_user, $TotalCounterBlacklist['Users'])) { if (is_array($TotalCounterBlacklist['Users'])) foreach ($TotalCounterBlacklist['Users'] as $value) if (substr($value, 0, 1) == '/' && preg_match($value, $tc_user) > 0) $blacklisted = true; if (isset ($tc_user)) // 1.10.0 isset $TotalCounter['Users'][$tc_user]++; } if (!$blacklisted && !@ in_array($tc_pagename, $TotalCounterBlacklist['Pages'])) { if (is_array($TotalCounterBlacklist['Pages'])) foreach ($TotalCounterBlacklist['Pages'] as $value) if (substr($value, 0, 1) == '/') if (preg_match($value, $tc_pagename) > 0) $blacklisted = true; if (!$blacklisted) { $PageCount = ++ $TotalCounter['Pages'][$tc_pagename]; ## handles the daily counter if ($TotalCounter['PagesTodayDay'][$tc_pagename] == date("%y%m%d")) $PageCountToday = ++ $TotalCounter['PagesTodayCounter'][$tc_pagename]; else { $TotalCounter['PagesTodayDay'][$tc_pagename] = date("%y%m%d"); $TotalCounter['PagesTodayCounter'][$tc_pagename] = 1; } } else { $PageCount = 0; // blacklisted } } if (!$blacklisted && defined('MULTILANGUAGE')) if (isset ($userlang2)) $TotalCounter['Languages'][$userlang2]++; if (!$blacklisted && !empty ($tc_browser) && !@ in_array($tc_browser, $TotalCounterBlacklist['Browsers'])) { $TotalCounter['Browsers'][$tc_browser]++; } if (!$blacklisted && !empty ($tc_bot) && !@ in_array($tc_bot, $TotalCounterBlacklist['Bots'])) { $TotalCounter['Bots'][$tc_bot]++; } if (!$blacklisted && isset ($tc_os) && !@ in_array($tc_os, $TotalCounterBlacklist['OSes'])) { // 1.10.0 isset $TotalCounter['OSes'][$tc_os]++; } if (!$blacklisted && !@ in_array($tc_referer, $TotalCounterBlacklist['Referers'])) { if (is_array($TotalCounterBlacklist['Referers'])) foreach ($TotalCounterBlacklist['Referers'] as $value) if (substr($value, 0, 1) == '/') if (preg_match($value, $tc_referer) > 0) $blacklisted = true; if (isset ($tc_referer) && !$blacklisted) // 1.10.0 isset $TotalCounter['Referers'][$tc_referer]++; } if (!$blacklisted && isset ($tc_location) && !@ in_array($tc_location, $TotalCounterBlacklist['Locations'])) { // 1.10.0 isset $TotalCounter['Locations'][$tc_location]++; } if (!$blacklisted && defined('MULTILANGUAGE')) if (!@ in_array($tc_location, $TotalCounterBlacklist['Languages'])) $TotalCounter['Languages'][$userlang2]++; ## by MateuszCzaplinski ## last day, last week, ... - collect data if (!$blacklisted && empty ($tc_bot)) { // don't count if bot $TCnow = time(); foreach ($TotalCounterTimeBins as $n=>$a) TCbins($n, $a['max'], $a['atom']); $TotalCounter['LastTimestamp'] = $TCnow; } dbexport_unlock($statfile, serialize($TotalCounter), 'w'); } else { // could not acquire a lockfile // check if the lockfile isn't a stale one, try to delete it if so dblock_remove_stale($statfile); } } else { $TotalCount = $TotalCounter['Total']; $PageCount = $TotalCounter['Pages'][$tc_pagename]; ## by Schlaefer (==?) $TotalCounter['PagesTodayDay'][$tc_pagename] = date("%y%m%d") ? $PageCountToday = $TotalCounter['PagesTodayCounter'][$tc_pagename] : $PageCountToday = 1; } //rmdir($lockfile); # unlink($lockfile); # umask($oldumask); //add the {$PageCount} and {$TotalCount} markup $FmtPV['$PageCount'] = "'" . $PageCount . "'"; // return count for current page # 1.10.0 FmtPV $FmtPV['$TotalCount'] = "'" . number_format ((float) $TotalCount) . "'"; // return total count for wiki # 1.10.0 FmtPV ## by Schlaefer ## adds vars for the input form $FmtPV['$TotalCounterMaxItems'] = "'" . ($_REQUEST['TotalCounterMaxItems'] ? $_REQUEST['TotalCounterMaxItems'] : $TotalCounterMaxItems) . "'"; // 1.10.0 FmtPV //add the {$PageViews} page variable (this appears to duplicate $PageCount above) $FmtPV['$PageViews'] = '$GLOBALS["TotalCounter"]["Pages"][$pagename]'; ## by Schlaefer ## add the {$PagesTodayCounter} page variable $FmtPV['$PageCountToday'] = '$GLOBALS["TotalCounter"]["PagesTodayCounter"][$pagename]'; return; # finished TotalCounter processing //===================================================================================================================== function HandleTotalCounter(string $pagename, string $auth = 'read') { global $Action, $TotalCounter, $TotalCounterMaxItems, $TotalCounterBarColor, $TotalCounterShowNumbers; global $TotalCount, $TotalCounterDownloads, $TotalCounterTimeBins, $TotalCounterBinsFmt, $TotalCounterEnableUsers; global $PageStartFmt, $PageEndFmt, $MessagesFmt, $totalcounter_debugon; //$page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT); $page = \RetrieveAuthPage($pagename, $auth); # PmWiki function if (!$page) \Abort("?you are not permitted to perform this action"); # PmWiki function # $all_locations = SetAllLocations (); # top level domains $Action = 'TotalCounter statistics'; ## by Schlaefer ## sets the max items if provided by the form if ($_REQUEST['TotalCounterMaxItems']) $TotalCounterMaxItems = $_REQUEST['TotalCounterMaxItems']; $html = '

Total Counter $[statistics]

' . "\n"; //------------------------------------------------------------------------------------------------------------ // PAGES $html .= graphhead ('$[Page views]', true); @ arsort($TotalCounter['Pages']); // sort high to low $tar = @ array_slice($TotalCounter['Pages'], 0, $TotalCounterMaxItems); $tot = $TotalCount; $max = @ current($tar); $i = 0; if (is_array($tar) && $tot) // by Florian Xaver foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, true, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); ## by Schlaefer //------------------------------------------------------------------------------------------------------------ ## PAGES daily $html .= graphhead ('$[Page views] $[today]', true); $tar = array (); foreach ($TotalCounter['PagesTodayCounter'] as $pn => $cnt) { if ($TotalCounter['PagesTodayDay'][$pn] === date("%y%m%d")) $tar[$pn] = $cnt; } @ arsort($tar); $tot = @ array_sum($tar); $tar = @ array_slice($tar, 0, $TotalCounterMaxItems); $max = @ current($tar); $i = 0; if (is_array($tar)) foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, true, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); //------------------------------------------------------------------------------------------------------------ // USERS # TotalCounterEnableUsers if ($TotalCounterEnableUsers == 1) { $html .= graphhead ('$[Users]', true); @ arsort($TotalCounter['Users']); $tar = @ array_slice($TotalCounter['Users'], 0, $TotalCounterMaxItems); $max = @ current($tar); $tot = @ array_sum($tar); $i = 0; if (is_array($tar)) foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); } //------------------------------------------------------------------------------------------------------------ // LANGUAGES if (defined('MULTILANGUAGE')) { $html .= graphhead ('$[Languages]', true); @ arsort($TotalCounter['Languages']); $tar = @ array_slice($TotalCounter['Languages'], 0, $TotalCounterMaxItems); $max = @ current($tar); $tot = @ array_sum($tar); $i = 0; if (is_array($tar)) foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, false, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); } //------------------------------------------------------------------------------------------------------------ // BROWSERS $html .= graphhead ('$[Browsers]', true); @ arsort($TotalCounter['Browsers']); $tar = @ array_slice($TotalCounter['Browsers'], 0, $TotalCounterMaxItems); $max = @ current($tar); $tot = @ array_sum($tar); $i = 0; if (is_array($tar)) foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, false, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); //------------------------------------------------------------------------------------------------------------ // OPERATING SYSTEMS $html .= graphhead ('$[Operating systems]', true); @ arsort($TotalCounter['OSes']); $tar = @ array_slice($TotalCounter['OSes'], 0, $TotalCounterMaxItems); $max = @ current($tar); $tot = @ array_sum($tar); $i = 0; if (is_array($tar)) foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, false, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); //------------------------------------------------------------------------------------------------------------ // REFERERS $html .= graphhead ('$[Referers]', true); @ arsort($TotalCounter['Referers']); $tar = @ array_slice($TotalCounter['Referers'], 0, $TotalCounterMaxItems); $max = @ current($tar); $tot = @ array_sum($tar); $i = 0; if (is_array($tar)) foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, false, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); //------------------------------------------------------------------------------------------------------------ // LOCATIONS $html .= graphhead ('$[Locations]', true); @ arsort($TotalCounter['Locations']); $tar = @ array_slice($TotalCounter['Locations'], 0, $TotalCounterMaxItems); $max = @ current($tar); $tot = @ array_sum($tar); $i = 0; if (is_array($tar)) foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, false, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); //------------------------------------------------------------------------------------------------------------ // WEB BOTS $html .= graphhead ('$[Web bots]', true); @ arsort($TotalCounter['Bots']); $tar = @ array_slice($TotalCounter['Bots'], 0, $TotalCounterMaxItems); $max = @ current($tar); $tot = @ array_sum($tar); $i = 0; if (is_array($tar)) foreach ($tar as $pn => $cnt) { $html .= graphline ($pn, false, $cnt, $tot, $max, ++ $i); } $html .= graphhead ('', false); //------------------------------------------------------------------------------------------------------------ // Downloads if ($TotalCounterEnableDownload == 1) { $html .= graphhead ('$[File Downloads]', true); @ arsort($TotalCounterDownloads); $max = count($TotalCounterDownloads); $tot = @ array_sum($TotalCounterDownloads); $i = 0; if (is_array($TotalCounterDownloads)) { for ($row = 0; $row < $max; $row++) { $tablerow = each($TotalCounterDownloads); $value = $tablerow['value']; $html .= '' . ($TotalCounterShowNumbers ? TD1 . ++ $i . '.' : '') . '' . $tablerow['key'] . '' . '' . ' ' . $value . '' . '' . "\n"; } } $html .= graphhead ('', false); } //------------------------------------------------------------------------------------------------------------ // Time statistics ## by MateuszCzaplinski foreach( $TotalCounterTimeBins as $n=>$a ) { $name = $a['name']; // 1.10.0 $fmt = $a['fmt']; $html .= BR . '
' . "

$[$name]

\n" . "\n"; // name 1.10.0 \SDVA($TotalCounterBinsFmt,array( 'number_format("$count")', // number_format 1.10.0 '"
"', 'date("G",$now-$atom*($maxnr-1-$nr))' )); // 1.10.0 from talk page if( is_string($fmt) ) { $tmp = $fmt; $fmt = $TotalCounterBinsFmt; $fmt[2] = $tmp; } if( is_array($fmt) ) { $rows = array(); ## Variables used in 'fmt' $maxcount = @max( $TotalCounter[$n] ); $direction = 'height'; $maxnr = $a['max']; $atom = $a['atom']; $now = time(); for( $nr=0; $nr<$maxnr; $nr++ ) { $count = $TotalCounter[$n][$nr]; // 1.10.0 moved out of loop if (($n!=='LastYears') or ($n=='LastYears' and $count > 0)) { ## skip years with zero count // 1.10.0 for( $j=0; $j". (string)eval("global \$TotalCounterMonthsShort; return ({$fmt[$j]});"). "\n"; } } } } $html .= ''.implode(''."\n".'',$rows).'
' . "\n"; // 1.10.0 } //------------------------------------------------------------------------------------------------------------ if ($totalcounter_debugon) { $html .= '

Messages

' . $MessagesFmt [TOTALCOUNTERNAME]; } $html .= '

TotalCounter ' . TOTALCOUNTERV . '

'; \PrintFmt($pagename, array ( # PmWiki function & $PageStartFmt, $html, & $PageEndFmt )); if ($TotalCounterEnableLog != 0) { $fclosestatus = fclose($logfilehandle); if ($fclosestatus === false) { tcmsg ('fclose failed', '"' . $logfile, error_get_last()); if ($totalcounter_debugon) Exit ($MessagesFmt [TOTALCOUNTERNAME]); } } } # HandleTotalCounter // ## by MateuszCzaplinski ## Manages an array of counters, each for a specified time interval. ## In $TotalCounter[$name] array there are $max counters. Each counter ## is for time interval of $atom length. ## Note: if $atom is a number, it is a length of interval measured ## in seconds. If $atom is a string, it means date($atom) is executed ## and the result is the index of an interval. ## NOTE: See TODO below function TCbins(string $name, int $max, $atom) { global $TotalCounter, $TCnow; $last = $TotalCounter['LastTimestamp']; if( $TCnow < $last ) return; // some error? if( !$last ) $TotalCounter[$name] = array_fill(0,$max,0); if( is_string($atom) ) { $diff = (int)date($atom,$TCnow) - (int)date($atom,$last); if( $diff < 0 ) $diff += $max; # TODO: handle time delta > $max # Until fixed, if the site has no visitor for about a # year, statistics will get falsified (empty years will compress) } else $diff = (int)($TCnow/$atom) - (int)($last/$atom); if( $diff < 0 ) return; if( $diff > 0 ) { $a = @array_slice($TotalCounter[$name], $diff, max(0,$max-$diff)); if(!$a) $a = array(); $a = array_pad($a, $max, 0); $TotalCounter[$name] = $a; } $TotalCounter[$name][$max-1]++; // put our visit in last bin } # end TCbins // generate graph head and tail function graphhead (string $headline='', bool $heading):string { global $TotalCounterShowNumbers; if ($heading) { $retval = BR . '

' . $headline . '

' . "\n"; $retval .= '' . "\n"; $retval .= '' . '' . '' . "\n"; $retval .= '' . "\n"; } else { $retval .= '
' . $headline . ' $[Percent]$[Count]
' . "\n"; } return $retval; } # end graphhead // generate graph line function graphline (string $pname, bool $bpage, int $pcnt, int $ptotal, int $pmax, int $linenr) :string { global $TotalCounterShowNumbers; $retval = '' . "\n"; if ($TotalCounterShowNumbers) { $retval .= '' . $linenr . '.'; } $retval .= ''; if ($bpage) { $retval .= "$pname "; } else { $retval .= $pname; } $retval .= "\n"; $retval .= '' . Round(100 * $pcnt / $ptotal) . "%\n"; $retval .= '
'; $retval .= ' ' . number_format ($pcnt) . ''; return $retval . '' . "\n"; } # end graphline // https://www.exakat.io/en/prevent-multiple-php-scripts-at-the-same-time/ // https://stackoverflow.com/questions/6967553/php-flock-alternative // Modified (breaks and returns 0 on failure, // or returns 1 on success) by Mateusz Czaplinski, 22.01.2008 function aquirelock(string $wp) { //Check if lock doesn't exist or our target is unwritable if(file_exists("$wp.l") || !is_writable($wp)) return FALSE; //create the lock - hide warnings and pass empty if already created from racing return @ fopen("$wp.l", 'x'); } function dblock(string $wp):bool { global $TotalCounterEnableChmods; //Check for lockfile handle - if empty , another process raced the lock so report a failure $ftw = aquirelock($wp); if( !$ftw ) return FALSE; if($TotalCounterEnableChmods) chmod($wp, 0444); //set the target file to read-only fwrite($ftw, 'lock'); //write the lockfile with 4bytes if($TotalCounterEnableChmods) chmod("$wp.l", 0444); //set the lockfile to read only (OPTIONAL) fclose($ftw); //close our lockfile clearstatcache(); //Clear the stat cache return TRUE; } // Note: don't call it if 'dblock()' returned 0 ! function dbexport_unlock(string $wp, $data, string $meth) { global $TotalCounterEnableChmods; if($TotalCounterEnableChmods) chmod($wp, 0666); //Set the target file to read+write //Write the passed string to the target file then close fwrite($ftw = fopen($wp, $meth), $data); fclose($ftw); //Validate the written data using a string comparison $check = file_get_contents($wp); if ($check != $data) echo "Data Mismatch - Locking FAILED!". BR; chmod("$wp.l", 0666); //Set the lockfile to read+write (OPTIONAL) unlink("$wp.l"); //Release the lockfile by removing it } function dblock_remove_stale(string $wp) { $t=filemtime("$wp.l"); // 75 minutes - to make absolutely sure we're not tricked by Daylight // Savings on Windows - see https://www.php.net/manual/en/function.stat.php#58404 if( $t+(75*60) < time()) @unlink("$wp.l"); } // Record message to PmWiki for display by (:message:) directive function tcmsg(string $smsgprefix, string $smsgtxt, array $LastError = []) { global $MessagesFmt; $MessagesFmt [TOTALCOUNTERNAME] .= '' . $smsgprefix . ': ' . htmlspecialchars($smsgtxt); if (!empty ($LastError)) $MessagesFmt [TOTALCOUNTERNAME] .= ' ' . TOTALCOUNTERNAME . ' {' . implode (', ', $LastError) . '}'; $MessagesFmt [TOTALCOUNTERNAME] .= BR; } // Define top level domains function SetAllLocations ():array { return array ( 'localhost' => 'localhost', 'Unknown' => 'Unknown', # original top level domains 'com' => 'Commercial', 'net' => 'Networks', 'org' => 'Organizations', 'int' => 'International organizations', 'edu' => 'US higher Education', 'gov' => 'US Government', 'mil' => 'US Dept of Defense', # selected ICANN TLDs 'academy' => 'Academy', 'aero' => 'Aviation', 'biz' => 'Business organizations', 'church' => 'Churches', 'city' => 'City', 'club' => 'Clubs', 'community' => 'Community', 'coop' => 'Co-operative organizations', 'education' => 'Education insitiutes', 'info' => 'Information', 'international' => 'International entities', 'mobi' => 'mobile devices', 'museum' => 'Museums', 'name' => 'Personal', 'place' => 'Place', 'travel' => 'Travelling', 'universite' => 'University', 'wiki' => 'Wikis', # selected geographic TLDs 'africa' => 'Africa', 'asia' => 'Asia', 'berlin' => 'Berlin', 'brussels' => 'Brussels', 'kiwi' => 'Kiwi', 'london' => 'London', 'paris' => 'Paris', 'quebec' => 'Quebec', 'scot' => 'Scotland', # country code top level https://icannwiki.org/Country_code_top-level_domain # updates from https://isotc.iso.org/livelink/livelink?func=ll&objId=16944257&objAction=browse&viewType=1 'ac' => 'Ascension Island', 'ad' => 'Andorra', 'ae' => 'United Arab Emirates', 'af' => 'Afghanistan', 'ag' => 'Antigua & Barbuda', 'ai' => 'Anguilla', 'al' => 'Albania', 'am' => 'Armenia', 'an' => 'Netherlands Antilles', 'ao' => 'Angola', 'aq' => 'Antarctica', 'ar' => 'Argentina', 'as' => 'American Samoa', 'at' => 'Austria', 'au' => 'Australia', 'aw' => 'Aruba', 'ax' => 'Åland', // 1.10.0 'az' => 'Azerbaijan', 'ba' => 'Bosnia & Herzegovina', 'bb' => 'Barbados', 'bd' => 'Bangladesh', 'be' => 'Belgium', 'bf' => 'Burkina Faso', 'bg' => 'Bulgaria', 'bh' => 'Bahrain', 'bi' => 'Burundi', 'bj' => 'Benin', 'bm' => 'Bermuda', 'bn' => 'Brunei Darussalam', 'bo' => 'Bolivia', 'br' => 'Brazil', 'bs' => 'Bahamas', 'bt' => 'Bhutan', 'bv' => 'Bouvet Island', 'bw' => 'Botswana', 'by' => 'Belarus', 'bz' => 'Belize', 'ca' => 'Canada', 'cc' => 'Cocos (Keeling) Islands', 'cd' => 'Democratic republic of Congo', 'cf' => 'Central African Republic', 'cg' => 'Congo', 'ch' => 'Switzerland', 'ci' => 'Ivory Coast', 'ck' => 'Cook Islands', 'cl' => 'Chile', 'cm' => 'Cameroon', 'cn' => 'China', 'co' => 'Colombia', 'cr' => 'Costa Rica', 'cs' => 'Czechoslovakia/Sebia & Montenegro', // deleted 'cu' => 'Cuba', 'cv' => 'Cape Verde', 'cw' => 'Curaçao', // 1.10.0 'cx' => 'Christmas Island', 'cy' => 'Cyprus', 'cz' => 'Czech Republic', 'de' => 'Germany', 'dj' => 'Djibouti', 'dk' => 'Denmark', 'dm' => 'Dominica', 'do' => 'Dominican Republic', 'dz' => 'Algeria', 'ec' => 'Ecuador', 'ee' => 'Estonia', 'eg' => 'Egypt', 'eh' => 'Western Sahara', 'er' => 'Eritrea', 'es' => 'Spain', 'et' => 'Ethiopia', 'eu' => 'European Union', 'fi' => 'Finland', 'fj' => 'Fiji', 'fk' => 'Falkland Islands', 'fm' => 'Micronesia', 'fo' => 'Faroe Islands', 'fr' => 'France', 'ga' => 'Gabon', 'gb' => 'United Kingdom', 'gd' => 'Grenada', 'ge' => 'Georgia', 'gf' => 'French Guiana', 'gg' => 'Guernsey', 'gh' => 'Ghana', 'gi' => 'Gibraltar', 'gl' => 'Greenland', 'gm' => 'Gambia', 'gn' => 'Guinea', 'gp' => 'Guadeloupe', 'gq' => 'Equatorial Guinea', 'gr' => 'Greece', 'gs' => 'South Georgia & South Sandwich Islands', 'gt' => 'Guatemala', 'gu' => 'Guam', 'gw' => 'Guinea-Bissau', 'gy' => 'Guyana', 'hk' => 'Hong Kong', 'hm' => 'Heard & McDonald Islands', 'hn' => 'Honduras', 'hr' => 'Croatia', 'ht' => 'Haiti', 'hu' => 'Hungary', 'id' => 'Indonesia', 'ie' => 'Ireland', 'il' => 'Israel', 'im' => 'Isle of Man', 'in' => 'India', 'io' => 'British Indian Ocean Territory', 'iq' => 'Iraq', 'ir' => 'Iran', 'is' => 'Iceland', 'it' => 'Italy', 'je' => 'Jersey', 'jm' => 'Jamaica', 'jo' => 'Jordan', 'jp' => 'Japan', 'ke' => 'Kenya', 'kg' => 'Kyrgyzstan', 'kh' => 'Cambodia', 'ki' => 'Kiribati', 'km' => 'Comoros', 'kn' => 'Saint Kitts & Nevis', 'kp' => 'North Korea', // 1.10.0 'kr' => 'South Korea', 'kw' => 'Kuwait', 'ky' => 'Cayman Islands', 'kz' => 'Kazakhstan', 'la' => 'Laos', 'lb' => 'Lebanon', 'lc' => 'Saint Lucia', 'li' => 'Liechtenstein', 'lk' => 'Sri Lanka', 'lr' => 'Liberia', 'ls' => 'Lesotho', 'lt' => 'Lithuania', 'lu' => 'Luxembourg', 'lv' => 'Latvia', 'ly' => 'Libyan Arab Jamahiriya', 'ma' => 'Morocco', 'mc' => 'Monaco', 'md' => 'Moldova', 'me' => 'Montenegro', // 1.10.0 'mg' => 'Madagascar', 'mh' => 'Marshall Islands', 'mk' => 'North Macedonia', 'ml' => 'Mali', 'mm' => 'Myanmar', 'mn' => 'Mongolia', 'mo' => 'Macau', 'mp' => 'Northern Mariana Islands', 'mq' => 'Martinique', 'mr' => 'Mauritania', 'ms' => 'Montserrat', 'mt' => 'Malta', 'mu' => 'Mauritius', 'mv' => 'Maldives', 'mw' => 'Malawi', 'mx' => 'Mexico', 'my' => 'Malaysia', 'mz' => 'Mozambique', 'na' => 'Namibia', 'nc' => 'New Caledonia', 'ne' => 'Niger', 'nf' => 'Norfolk Island', 'ng' => 'Nigeria', 'ni' => 'Nicaragua', 'nl' => 'The Netherlands', 'no' => 'Norway', 'np' => 'Nepal', 'nr' => 'Nauru', 'nu' => 'Niue', 'nz' => 'New Zealand', 'om' => 'Oman', 'pa' => 'Panama', 'pe' => 'Peru', 'pf' => 'French Polynesia', 'pg' => 'Papua New Guinea', 'ph' => 'Philippines', 'pk' => 'Pakistan', 'pl' => 'Poland', 'pm' => 'St. Pierre & Miquelon', 'pn' => 'Pitcairn', 'pr' => 'Puerto Rico', 'ps' => 'Palestine', 'pt' => 'Portugal', 'pw' => 'Palau', 'py' => 'Paraguay', 'qa' => 'Qatar', 're' => 'Réunion', 'ro' => 'Romania', 'rs' => 'Serbia', // 1.10.0 'ru' => 'Russia', 'rw' => 'Rwanda', 'sa' => 'Saudi Arabia', 'sb' => 'Solomon Islands', 'sc' => 'Seychelles', 'sd' => 'Sudan', 'se' => 'Sweden', 'sg' => 'Singapore', 'sh' => 'St. Helena', 'si' => 'Slovenia', 'sj' => 'Svalbard & Jan Mayen Islands', 'sk' => 'Slovakia', 'sl' => 'Sierra Leone', 'sm' => 'San Marino', 'sn' => 'Senegal', 'so' => 'Somalia', 'sr' => 'Surinam', 'st' => 'Sao Tome & Principe', 'su' => 'USSR', 'sv' => 'El Salvador', 'sy' => 'Syrian Arab Republic', 'sz' => 'Swaziland', 'tc' => 'The Turks & Caicos Islands', 'td' => 'Chad', 'tf' => 'French Southern Territories', 'tg' => 'Togo', 'th' => 'Thailand', 'tj' => 'Tajikistan', 'tk' => 'Tokelau', 'tl' => 'Timor-Leste', 'tm' => 'Turkmenistan', 'tn' => 'Tunisia', 'to' => 'Tonga', 'tp' => 'East Timor', 'tr' => 'Turkey', 'tt' => 'Trinidad & Tobago', 'tv' => 'Tuvalu', 'tw' => 'Taiwan', 'tz' => 'Tanzania', 'ua' => 'Ukraine', 'ug' => 'Uganda', 'uk' => 'United Kingdom', 'um' => 'United States Minor Outlying Islands', 'us' => 'United States', 'uy' => 'Uruguay', 'uz' => 'Uzbekistan', 'va' => 'Vatican City', 'vc' => 'Saint Vincent & the Grenadines', 've' => 'Venezuela', 'vg' => 'British Virgin Islands', 'vi' => 'US Virgin Islands', 'vn' => 'Vietnam', 'vu' => 'Vanuatu', 'wf' => 'Wallis & Futuna Islands', 'ws' => 'Samoa', 'ye' => 'Yemen', 'yt' => 'Mayotte', 'yu' => 'Yugoslavia', 'za' => 'South Africa', 'zm' => 'Zambia', 'zr' => 'Zaire', // deprecated 'zw' => 'Zimbabwe', ); } ?>