1<?php 2/** 3 * Access Counter and Popularity Plugin -- Access Counter 4 * 5 * Original source of this plugin is PukiWiki. 6 * 7 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8 * @author HokkaidoPerson <dosankomali@yahoo.co.jp> 9 */ 10 11// Original Licenses of this plugin: 12// 13// PukiWiki - Yet another WikiWikiWeb clone 14// $Id: counter.inc.php,v 1.19 2007/02/04 11:14:44 henoheno Exp $ 15// Copyright (C) 16// 2002-2005, 2007 PukiWiki Developers Team 17// 2002 Y.MASUI GPL2 http://masui.net/pukiwiki/ masui@masui.net 18// License: GPL2 19// 20// Counter plugin (per page) 21 22// must be run within Dokuwiki 23if(!defined('DOKU_INC')) die(); 24 25class syntax_plugin_accscounter_counter extends DokuWiki_Syntax_Plugin { 26 27 function getType(){ 28 return 'substition'; 29 } 30 31 function getSort(){ 32 return 200; 33 } 34 35 36 // Internal function 37 // Return a summary 38 function plugin_counter_get_count($page) 39 { 40 global $ACT; 41 global $USERINFO; 42 global $conf; 43 static $counters = array(); 44 static $default; 45 46 $achelper = plugin_load('helper','accscounter'); 47 $clientIP = clientIP(true); 48 49 if (! isset($default)) 50 $default = array( 51 'total' => 0, 52 'date' => date('Y/m/d'), 53 'today' => 0, 54 'yesterday' => 0, 55 'ip' => ''); 56 57 if (page_exists($page) == FALSE) return $default; 58 if (isset($counters[$page])) return $counters[$page]; 59 60 // Set default 61 $counters[$page] = $default; 62 $modify = FALSE; 63 64 // Load and handle the exclusion list (IPs and remote hosts) 65 $exlist = str_replace(array("\r\n", "\r", "\n"), "\n", $this->getConf('exclusionList')); 66 $exlist = preg_quote($exlist, '/'); 67 $exlist = str_replace('\*', '[0-9A-Za-z.-]+', $exlist); 68 $exlist = str_replace('\?', '[0-9A-Za-z.-]', $exlist); 69 $exlist = str_replace('~', '[0-9]+', $exlist); 70 $exlist = str_replace('\!', '[0-9]', $exlist); 71 $exlist = explode("\n", $exlist); 72 73 $remotehost = gethostbyaddr($clientIP); 74 $excluded = FALSE; 75 foreach ($exlist as $checking) { 76 $prefix = '/^' . $checking . '$/'; 77 if (preg_match($prefix, $clientIP)) $excluded = TRUE; 78 if (preg_match($prefix, $remotehost)) $excluded = TRUE; 79 } 80 81 // Check about the country 82 $countries = explode(',', $this->getConf('cntrExclusion')); 83 $countries = array_map('trim', $countries); 84 $countries = array_unique($countries); 85 $countries = array_filter($countries); 86 87 $countriesin = explode(',', $this->getConf('cntrInclusion')); 88 $countriesin = array_map('trim', $countriesin); 89 $countriesin = array_unique($countriesin); 90 $countriesin = array_filter($countriesin); 91 92 // Get a country code related to the user 93 // Ingredients to generate a DNS address 94 $ingr = explode(".", $clientIP); 95 // Compose a "cc.wariate.jp" DNS address 96 $dnsaddr = $ingr[3] . "." . $ingr[2] . "." . $ingr[1] . "." . $ingr[0] . ".cc.wariate.jp"; 97 98 // Investigate now 99 $dnsdatas = dns_get_record($dnsaddr, DNS_TXT); 100 if ($dnsdatas !== FALSE) $hiscountry = $dnsdatas[0]["txt"]; else $hiscountry = FALSE; 101 102 // Check now 103 if ($hiscountry !== FALSE) { 104 $hiscountry = utf8_strtolower($hiscountry); 105 foreach ($countries as $checking) { 106 $checkinglower = utf8_strtolower($checking); 107 if ($checkinglower == $hiscountry) $excluded = TRUE; 108 } 109 if ($this->getConf('cntrInclusion') != '') { 110 $included = FALSE; 111 foreach ($countriesin as $checking) { 112 $checkinglower = utf8_strtolower($checking); 113 if ($checkinglower == $hiscountry) $included = TRUE; 114 } 115 if ($included != TRUE) $excluded = TRUE; 116 } 117 } 118 119 // Check about IPs reverse lookup 120 if ($this->getConf('reverseLookupFailed') == '1' && $remotehost == $clientIP) { 121 $rexlist = str_replace(array("\r\n", "\r", "\n"), "\n", $this->getConf('reverseLookupException')); 122 $rexlist = preg_quote($rexlist, '/'); 123 $rexlist = str_replace('\*', '[0-9]+', $rexlist); 124 $rexlist = str_replace('\?', '[0-9]', $rexlist); 125 $rexlist = explode("\n", $rexlist); 126 127 $cntrexlist = explode(',', $this->getConf('reverseLookupCntrException')); 128 $cntrexlist = array_map('trim', $cntrexlist); 129 $cntrexlist = array_unique($cntrexlist); 130 $cntrexlist = array_filter($cntrexlist); 131 132 133 $excluded = TRUE; 134 foreach ($rexlist as $checking) { 135 $prefix = '/^' . $checking . '$/'; 136 if (preg_match($prefix, $clientIP)) $excluded = FALSE; 137 } 138 139 if ($hiscountry !== FALSE) { 140 foreach ($cntrexlist as $checking) { 141 $checkinglower = utf8_strtolower($checking); 142 if ($checkinglower == $hiscountry) $excluded = FALSE; 143 } 144 } 145 146 } 147 148 // Exclude managers and superusers? 149 if ($this->getConf('excludeMgAndSp') == 'mg' && auth_ismanager()) $excluded = TRUE; 150 if ($this->getConf('excludeMgAndSp') == 'sp' && auth_isadmin()) $excluded = TRUE; 151 152 // Check about a list of users and user groups 153 if(auth_isMember($this->getConf('usrExclusion'), $_SERVER['REMOTE_USER'], (array) $USERINFO['grps'])) $excluded = TRUE; 154 155 // Check if the user is a spammer 156 $ishespam = FALSE; 157 $sfspluginok = FALSE; 158 if (! plugin_isdisabled('stopforumspam2')) { 159 if ($helper = plugin_load('helper','stopforumspam2')) { 160 $sfspluginok = TRUE; 161 if ($helper->quickipcheck(null, $this->getConf('sfsExFreq'), $this->getConf('sfsExConf'))) { 162 $ishespam = TRUE; 163 $excluded = TRUE; 164 } 165 } 166 } 167 168 169 // Open 170 $file = $achelper->counterFN($page, '.number'); 171 if (file_exists($file)) { 172 $fp = io_readFile($file); 173 if ($fp === FALSE) return $this->getLang('err1') . basename($file); 174 $fp = explode("\n", $fp); 175 } else $fp = array(); 176 177 // Read 178 if ($fp[0]) $counters[$page]['total'] = $fp[0]; 179 if ($fp[1]) $counters[$page]['date'] = $fp[1]; 180 if ($fp[2]) $counters[$page]['today'] = $fp[2]; 181 if ($fp[3]) $counters[$page]['yesterday'] = $fp[3]; 182 if ($fp[4]) $counters[$page]['ip'] = $fp[4]; 183 184 // Anothoer day? 185 if ($counters[$page]['date'] != $default['date']) { 186 $modify = TRUE; 187 $is_yesterday = ($counters[$page]['date'] == date('Y/m/d', CURRENT - 24 * 60 * 60)); 188 $counters[$page]['ip'] = $clientIP; 189 $counters[$page]['date'] = $default['date']; 190 $counters[$page]['yesterday'] = $is_yesterday ? $counters[$page]['today'] : 0; 191 // Excluded? 192 if ($excluded == FALSE) { 193 $counters[$page]['today'] = 1; 194 $counters[$page]['total']++; 195 196 // Save the log? 197 switch ($this->getConf('saveLog')) { 198 case 'pdate' : 199 $filepageid = str_replace(':','/',$page); 200 $logfiledir = $conf['cachedir'] . '/accscounterlog/' . utf8_encodeFN($filepageid) . '/'; 201 if (!file_exists($logfiledir)) mkdir($logfiledir, 0777, true); 202 $logfilename = $logfiledir . utf8_strtolower(date('M-d-Y')) . '.txt'; 203 if ($loghandle = fopen($logfilename, 'a')) { 204 $logcontent = $clientIP ."(" . date('H:i:s M d, Y') . ")\n"; 205 fwrite($loghandle, $logcontent); 206 fclose($loghandle); 207 } 208 break; 209 210 case 'ppage' : 211 $filepageid = str_replace(':','/',$page); 212 $logfiledir = $conf['cachedir'] . '/accscounterlog/' . utf8_encodeFN($filepageid) . '/'; 213 if (!file_exists($logfiledir)) mkdir($logfiledir, 0777, true); 214 $logfilename = $logfiledir . 'wholeperiod.txt'; 215 if ($loghandle = fopen($logfilename, 'a')) { 216 $logcontent = $clientIP ."(" . date('H:i:s M d, Y') . ")\n"; 217 fwrite($loghandle, $logcontent); 218 fclose($loghandle); 219 } 220 break; 221 } 222 if (file_exists($achelper->counterFN($page, '.ip'))) { 223 $ipdata = @file($achelper->counterFN($page, '.ip')); 224 if ($ipdata != FALSE) { 225 $inthelog = FALSE; 226 $newcontents = array(); 227 foreach ($ipdata as $dataline) { 228 $element = explode('|', $dataline); 229 $element[0] = trim($element[0]); 230 $element[1] = trim($element[1]); 231 if ($clientIP == $element[0]) { 232 $inthelog = TRUE; 233 $element[1]++; 234 } 235 $newcontents[] = $element[0] . '|' . $element[1]; 236 } 237 if (!$inthelog) $newcontents[] = $clientIP . '|1'; 238 $writing = ''; 239 foreach ($newcontents as $part) { 240 $writing .= $part . "\n"; 241 } 242 io_saveFile($achelper->counterFN($page, '.ip'), $writing); 243 } 244 } else io_saveFile($achelper->counterFN($page, '.ip'), $clientIP . "|1\n"); 245 } else { 246 $counters[$page]['today'] = 0; 247 } 248 } else if ($counters[$page]['ip'] != $clientIP) { 249 // Not the same host 250 if ($excluded == FALSE) { 251 $modify = TRUE; 252 $counters[$page]['ip'] = $clientIP; 253 $counters[$page]['today']++; 254 $counters[$page]['total']++; 255 256 // Save the log? 257 switch ($this->getConf('saveLog')) { 258 case 'pdate' : 259 $filepageid = str_replace(':','/',$page); 260 $logfiledir = $conf['cachedir'] . '/accscounterlog/' . utf8_encodeFN($filepageid) . '/'; 261 if (!file_exists($logfiledir)) mkdir($logfiledir, 0777, true); 262 $logfilename = $logfiledir . utf8_strtolower(date('M-d-Y')) . '.txt'; 263 if ($loghandle = fopen($logfilename, 'a')) { 264 $logcontent = $clientIP ."(" . date('H:i:s M d, Y') . ")\n"; 265 fwrite($loghandle, $logcontent); 266 fclose($loghandle); 267 } 268 break; 269 270 case 'ppage' : 271 $filepageid = str_replace(':','/',$page); 272 $logfiledir = $conf['cachedir'] . '/accscounterlog/' . utf8_encodeFN($filepageid) . '/'; 273 if (!file_exists($logfiledir)) mkdir($logfiledir, 0777, true); 274 $logfilename = $logfiledir . 'wholeperiod.txt'; 275 if ($loghandle = fopen($logfilename, 'a')) { 276 $logcontent = $clientIP ."(" . date('H:i:s M d, Y') . ")\n"; 277 fwrite($loghandle, $logcontent); 278 fclose($loghandle); 279 } 280 break; 281 } 282 if (file_exists($achelper->counterFN($page, '.ip'))) { 283 $ipdata = @file($achelper->counterFN($page, '.ip')); 284 if ($ipdata != FALSE) { 285 $inthelog = FALSE; 286 $newcontents = array(); 287 foreach ($ipdata as $dataline) { 288 $element = explode('|', $dataline); 289 $element[0] = trim($element[0]); 290 $element[1] = trim($element[1]); 291 if ($clientIP == $element[0]) { 292 $inthelog = TRUE; 293 $element[1]++; 294 } 295 $newcontents[] = $element[0] . '|' . $element[1]; 296 } 297 if (!$inthelog) $newcontents[] = $clientIP . '|1'; 298 $writing = ''; 299 foreach ($newcontents as $part) { 300 $writing .= $part . "\n"; 301 } 302 io_saveFile($achelper->counterFN($page, '.ip'), $writing); 303 } 304 } else io_saveFile($achelper->counterFN($page, '.ip'), $clientIP . "|1\n"); 305 } 306 } 307 308 // Modify 309 if ($ACT == '' or $ACT == 'show') $showing = TRUE; 310 311 if ($modify && $showing == TRUE) { 312 $savedata = ''; 313 foreach (array_keys($default) as $key) 314 $savedata .= $counters[$page][$key] . "\n"; 315 io_saveFile($file, $savedata); 316 } 317 318 return $counters[$page]; 319 } 320 321 322 //Syntax: {{counter|total(default), today, or yesterday|texts following the number (when it is 0 or 1)|texts following the number (when it is 2 or more)}} 323 //The texts following the number are not required (If entered just {{counter|today or yesterday or total}} or {{counter}}, this will return only the number) 324 325 function connectTo($mode) { 326 $this->Lexer->addSpecialPattern('\{\{counter[^}]*\}\}',$mode,'plugin_accscounter_counter'); 327 } 328 329 330 function handle($match, $state, $pos, Doku_Handler $handler){ 331 332 return explode('|', substr($match, strlen('{{counter|'), -2)); 333 334 } 335 336 function render($mode, Doku_Renderer $renderer, $data) { 337 global $INFO; 338 339 // Get the time zone from conf (if null, it will use the default setting on your server) 340 if ($this->getConf('timezone') != '') date_default_timezone_set($this->getConf('timezone')); 341 342 // Get current time (local) 343 define('CURRENT', time()); 344 345 346 // Main process 347 348 switch ($data[0]) { 349 case '' : 350 case 'total': $arg = 'total'; 351 break; 352 case 'today': $arg = 'today'; 353 break; 354 case 'yesterday': $arg = 'yesterday'; 355 break; 356 default: 357 $renderer->doc .= htmlspecialchars($this->getLang('err2')); 358 return; 359 } 360 361 $counter = $this->plugin_counter_get_count($INFO['id']); 362 if (gettype($counter) == "string") { 363 $renderer->doc .= $counter; 364 } else if ($counter[$arg] <= 1) { 365 $renderer->doc .= htmlspecialchars($counter[$arg]) .htmlspecialchars($data[1]); 366 } else { 367 $renderer->doc .= htmlspecialchars($counter[$arg]) .htmlspecialchars($data[2]); 368 } 369 370 } 371 372} 373