*/ if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); if(!defined('QUICK_STATS')) define ('QUICK_STATS',DOKU_PLUGIN . 'quickstats/'); require_once DOKU_PLUGIN.'action.php'; require_once QUICK_STATS . 'scripts/php-inet6_1.0.2/valid_v6.php'; require_once QUICK_STATS .'GEOIP/vendor/autoload.php'; use GeoIp2\Database\Reader; /* for backward compatiblity */ if(!function_exists('utf8_strtolower')) { require_once(DOKU_INC.'inc/common.php'); require_once(DOKU_INC.'inc/utf8.php'); } /* error_reporting(E_ALL); ini_set('display_errors','1'); */ class action_plugin_quickstats extends DokuWiki_Action_Plugin { private $page_file; private $ip_file; private $misc_data_file; private $pages; private $ips; private $misc_data; private $page_totals_file; private $is_edit_user=false; private $year_month; private $totals; private $SEP = '/'; private $show_date; private $ua_file; private $helper; private $ipaddr; private $qs_file; private $dw_tokens; // query string names to omit from stats private $page_users_file; private $ipv6 = false; private $id; private $geocity2 = true; private $db_check; function __construct() { global $ID,$INPUT; $this->id = $INPUT->str('id'); $ip = $_SERVER['REMOTE_ADDR']; //$ip = "2001:982:acd6:1:4899:d135:226b:2e79"; //$ip = "2602:304:cec0:9b00:e96b:9c78:eb14:9fb"; // $ip = "76.24.190.253"; if($this->is_excluded($ip, true)){ exit("403: Not Available"); } $ipv6 = isValidIPv6($ip); if($ipv6) { $this->ipaddr = $ipv6; $this->ipv6 = $ipv6; } else $this->ipaddr = $ip; $today = getdate(); $ns_prefix = "quickstats:"; $ns = $ns_prefix . $today['mon'] . '_' . $today['year'] . ':'; $this->page_file = metaFN($ns . 'pages' , '.ser'); $this->ua_file = metaFN($ns . 'ua' , '.ser'); $this->ip_file = metaFN($ns . 'ip' , '.ser'); $this->misc_data_file = metaFN($ns . 'misc_data' , '.ser'); $this->qs_file = metaFN($ns . 'qs_data' , '.ser'); $this->page_users_file = metaFN($ns . 'page_users' , '.ser'); $this->page_totals_file = metaFN($ns_prefix . 'page_totals' , '.ser'); $this ->db_check = metaFN($ns_prefix . 'db_warning' , '.txt'); if(!file_exists($this ->db_check)) { io_saveFile($this ->db_check,0); } $this->year_month = $today['mon'] . '_' .$today['year']; if( preg_match('/WINNT/i', PHP_OS) ) { $this->SEP='\\'; } $this->show_date=$this->getConf('show_date'); $this->dw_tokens=array('do', 'sectok', 'page', 's[]','id','rev','idx'); $conf_tokens = $this->getConf('xcl_name_val'); if(!empty($conf_tokens)) { $conf_tokens = explode(',',$conf_tokens); if(!empty($conf_tokens)) { $this->dw_tokens = array_merge($this->dw_tokens,$conf_tokens); } } $this->helper = $this->loadHelper('quickstats', true); } function test_geocity2() { global $INFO; $test = false; $err = ""; if($this->getConf('by_pass_mmdb')) { $this->geocity2 = false; return; } try { $reader = new Reader(QUICK_STATS .'GEOIP/vendor/GeoLite2-City/GeoLite2-City.mmdb'); if($test) { $record = $reader->city('138.201.137.132'); msg($record->country->isoCode); // 'DE' msg($record->country->name); // 'Germany' $ip ="2001:982:acd6:1:4899:d135:226b:2e79"; $record = $reader->city($ip); msg($record->country->isoCode); // 'NL' msg($record->country->name); // 'Netherlands' } } catch (Exception $e) { $this->geocity2 = false; $err = $e->getMessage(); $checked = io_readFile($this ->db_check,false); if($checked <= 6){ io_saveFile($this ->db_check,($checked+1)); $err .= $this->getLang('missing_mmdb_warning'); } } // if($this->getConf('hide_db_warning'))return; if($INFO['isadmin'] && $err) msg($err,2); } /** * Register its handlers with the DokuWiki's event controller */ function register(Doku_Event_Handler $controller) { $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'set_cookies'); $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'search_queries'); $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this,'_ajax_handler'); $controller->register_hook('DOKUWIKI_DONE', 'BEFORE', $this, '_add__data'); $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'load_js'); } function isQSfile() { global $ID; if(!$this->helper->is_inConfList($ID) ) { return $this->helper->is_inCache($ID) ; } return true; } function load_js(&$event, $param) { global $ACT, $ID; if($ACT != 'show' && $ACT != 'preview') return; // don't load the sortable script unless it's potentially needed if(!$this->isQSfile()) return; $event->data["script"][] = array ( "type" => "text/javascript", "src" => DOKU_BASE."lib/plugins/quickstats/scripts/sorttable-cmpr.js", "_data" => "", ); } function set_cookies(&$event, $param) { global $ACT; global $ID, $JSINFO; global $conf; $this->test_geocity2(); if(!empty($ACT) && !is_array($ACT) ) { $JSINFO['act'] = $ACT; } else $JSINFO['act'] = ""; $ajax =$this->getConf('ajax'); $JSINFO['ajax'] = $this->getConf('ajax') ? 'ajax' : 'event'; $sidebar_ns = $this->getConf('hide_sidebar'); if(!empty($sidebar_ns)) { $quick_ns =getNS($ID); $sidebar_ns = trim($sidebar_ns,':'); if($quick_ns == trim($sidebar_ns,':')) $conf['sidebar'] = ""; } if(is_array($ACT) || $ACT=='edit') { $expire = time()+3600; setcookie('Quick_Stats','abc', $expire, '/'); $this->is_edit_user=true; return; } if(isset($_COOKIE['Quick_Stats'])) { setcookie("Quick_Stats", 'abc', time()-7200, '/'); $this->is_edit_user=true; } } function search_queries(&$event, $param) { global $ACT; if(is_array($ACT) || $this->is_edit_user) return; if($ACT !='show' && $ACT != 'search') return; //login,admin,profile, revisions,logout if(empty($_SERVER['QUERY_STRING']) || $this->is_excluded($this->ipaddr)) return; $queries = unserialize(io_readFile($this->qs_file,false)); if(!$queries) $queries = array('words'=>array(), 'ns'=>array(), 'extern'=>array() ); $elems = explode('&',html_entity_decode($_SERVER['QUERY_STRING'])) ; $data_found = false; if($elems && count($elems)>1) { $words = array(); $temp = array(); foreach ($elems as $el) { if(isset($el) && $el) { list($name,$value) = explode('=',$el); $temp[$name]=$value; } } if(isset($temp['do']) && $temp['do'] == 'search') { $data_found = true; if(function_exists ('idx_get_indexer')) { $ar = ft_queryParser(idx_get_indexer(), urldecode($temp['id'])); } else $ar = ft_queryParser(urldecode($temp['id'])); if(!empty($ar['phrases']) && !empty($ar['not'])) { $words = array_diff($ar['words'],$ar['not']); } else { $words = $ar['words']; } if(!empty($words)) { foreach($words as $word) { $this->set_queries($queries,$word,'words'); } } if(!empty($ar['ns'])) { foreach($ar['ns'] as $ns) { $this->set_queries($queries,$ns,'ns'); } } } else { foreach($this->dw_tokens as $t) { if(isset($temp[$t])) { unset($temp[$t]); } } if(count($temp)) { $keys = array_keys($temp); foreach($keys as $k) { if(preg_match('/rev\d*\[\d*\]/', $k)) { unset($temp[$k]); } } if(count($temp)) $data_found = true; } foreach($temp as $name=>$val) { $this->set_queries($queries['extern'],urldecode($name),'name'); if(!$val) $val = '_empty_'; $this->set_queries($queries['extern'],urldecode($val),'val'); $this->set_named_values($queries['extern']['name'][urldecode($name)],urldecode($val)); } } if($data_found) { io_saveFile($this->qs_file,serialize($queries)); } } } function set_named_values(&$queries,$val="_empty_") { if(!isset($queries['values'])) { $queries['values'] = array(); } if(!isset($queries['values'][$this->ipaddr])) { $queries['values'][$this->ipaddr] = array(); } if(!in_array($val, $queries['values'][$this->ipaddr])) { $queries['values'][$this->ipaddr][] = $val; } } function set_queries(&$queries,$word,$which) { if(!isset($queries[$which][$word])) { $queries[$which][$word]['count'] = 1; } else { $queries[$which][$word]['count'] += 1; } if(!isset($queries[$which][$word][$this->ipaddr])) { $queries[$which][$word][$this->ipaddr] = 1; } else $queries[$which][$word][$this->ipaddr] += 1; } function msg_dbg($what,$prefix="",$type="1") { if(is_array($what)) { $what = print_r($what,true); } msg("
$prefix $what",$type); } function load_data() { $this->pages = unserialize(io_readFile($this->page_file,false)); if(!$this->pages) $this->pages = array(); $this->ips = unserialize(io_readFile($this->ip_file,false)); if(!$this->ips) $this->ips = array(); $this->totals = unserialize(io_readFile($this->page_totals_file,false)); if(!$this->totals) $this->totals = array(); } function save_data() { io_saveFile($this->ip_file,serialize($this->ips)); io_saveFile($this->page_file,serialize($this->pages)); $this->totals[$this->year_month] = $this->pages['site_total'] ; io_saveFile($this->page_totals_file,serialize($this->totals)); } function is_excluded($ip,$abort=false) { if(!$abort) { $xcl = $this->getConf('excludes'); } else $xcl = $this->getConf('aborts'); $xcl=str_replace("\040", '',$xcl); if(!$xcl) return false; $xcludes=explode(',',$xcl); $regex = '#'. implode('|',$xcludes) . '#'; if(preg_match($regex,$ip)){ return true; } return false; } function _ajax_handler(Doku_Event $event,$param) { if ($event->data != 'quickstats') return; global $INPUT,$ACT,$ID, $INFO; $ip = $_SERVER['REMOTE_ADDR']; $event->stopPropagation(); $event->preventDefault(); if(!$this->getConf('ajax')) return; $qs = $INPUT->str('qs'); $do = $INPUT->str('do'); if(strpos($qs,'edit') !== false || $do == 'edit') { $act = 'edit'; } else $act = $INPUT->str('act'); $ACT = $act; $ID = $INPUT->str('id') ; if(isset($_COOKIE['Quick_Stats'])) $this->is_edit_user = 'edit_user'; $param = 'ajax'; $this->add_data($event, $param); } function _add__data($event, $param) { if($this->getConf('ajax')) return; $this->add_data($event, 'event'); } /** * adds new data to stats files * * @author Myron Turner