1<?php 2/** 3 * 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Myron Turner <turnermm02@shaw.ca> 7 */ 8 9 if(!defined('DOKU_INC')) die(); 10 require_once(DOKU_PLUGIN.'admin.php'); 11/** 12 * All DokuWiki plugins to extend the admin function 13 * need to inherit from this class 14 */ 15 16class admin_plugin_quickstats extends DokuWiki_Admin_Plugin { 17 18 private $output = ''; 19 private $helper; 20 private $cache; 21 private $deletions; 22 private $to_confirm; 23 private $cc_arrays; 24 private $countries; 25 private $user_agents; 26 private $meta_path; 27 private $page_totals; 28 private $uniqIPTotal; 29 private $uniqIPCurrent; 30 private $page_accessesTotal=0; 31 private $page_accessesCurrent=0; 32 private $script_max_time = 0; 33 function __construct() { 34 35 $this->helper = $this->loadHelper('quickstats', true); 36 $this->cache = $this->helper->getCache(); 37 $this->cc_arrays = $this->helper->get_cc_arrays(); 38 $this->meta_path = $this->helper->metaFilePath(true) ; 39 $this->page_totals = unserialize(io_readFile($this->meta_path . 'page_totals.ser')); 40 if(!$this->page_totals) $this->page_totals = array(); 41 if(!empty($this->page_totals)) { 42 foreach($this->page_totals as $ttl) { 43 $this->page_accessesTotal+=$ttl; 44 $this->page_accessesCurrent=$ttl; 45 } 46 $this->misc_data_setup(); 47 $this->uniq_ip(); 48 } 49 //$this->script_max_time = ini_get('max_execution_time'); 50 $this->script_max_time = $this->getConf('max_exec_time') ? $this->getConf('max_exec_time') : 60; 51 } 52 53 /* 54 * Create a list of countries accessed during last 6 months, for countries Select 55 */ 56 function misc_data_setup() { 57 58 $this->countries = array(); 59 $country_codes = array(); 60 $this->user_agents = array(); 61 62 $data_dirs = array_reverse(array_keys($this->page_totals)); 63 if(count($data_dirs) > 6) { 64 $data_dirs = array_slice($data_dirs,0,6); 65 } 66 67 $ns_prefix = "quickstats:"; 68 foreach($data_dirs as $dir) { 69 $ns = $ns_prefix . $dir . ':'; 70 $misc_data_file = metaFN($ns . 'misc_data' , '.ser'); 71 $misc_data = unserialize(io_readFile($misc_data_file,false)); 72 if(!empty($misc_data)) { 73 if(!empty($misc_data['country'])) { 74 $country_codes = array_merge ($country_codes, array_keys($misc_data['country'])); 75 } 76 if(!empty($misc_data['browser'])) { 77 $this->user_agents = array_merge ($this->user_agents, array_keys($misc_data['browser'])); 78 // $this->user_agents = array_merge ($this->user_agents, array_keys($misc_data['version'])); 79 } 80 } 81 } 82 foreach($country_codes as $cc) { 83 if($cc) { 84 $this->countries[$cc]=$this->cc_arrays->get_country_name($cc) ; 85 } 86 } 87 asort($this->countries); 88 $this->user_agents = array_unique($this->user_agents); 89 natcasesort($this->user_agents); 90 91 92 } 93 94 function uniq_ip() { 95 $dirs = array_keys($this->page_totals); 96 $current_dir = array_pop($dirs); 97 $ns_prefix = "quickstats:"; 98 $uniq_data_file = metaFN($ns_prefix . 'uniq_ip' , '.ser'); 99 100 if(file_exists($uniq_data_file) && !$this->getConf('rebuild_uip')) { 101 $uniq_data = unserialize(io_readFile($uniq_data_file,false)); 102 } 103 else if(count($dirs) > 0) { 104 $uniq_data = array(); 105 foreach($dirs as $dir) { 106 $ns = $ns_prefix . $dir . ':'; 107 $ip_file = metaFN($ns . 'ip' , '.ser'); 108 $ip_data = unserialize(io_readFile($ip_file,false)); 109 if(empty($ip_data)) { 110 $ip_data = array(); 111 } 112 else { 113 unset($ip_data['uniq']); 114 } 115 $ip_data = array_keys($ip_data); 116 $uniq_data = array_merge ($uniq_data , $ip_data); 117 } 118 unset($uniq_data['uniq']); 119 unset($uniq_data['last']); 120 $uniq_data = array_unique($uniq_data); 121 $uniq_data['uniq'] = count($uniq_data); 122 $uniq_data['last'] = $dir; 123 io_saveFile($uniq_data_file,serialize($uniq_data)); 124 } 125 else { 126 $uniq_data = array(); 127 } 128 129 $ns = $ns_prefix . $current_dir . ':'; 130 $ip_file = metaFN($ns . 'ip' , '.ser'); 131 $ip_data = unserialize(io_readFile($ip_file,false)); 132 $this->uniqIPCurrent=$ip_data['uniq']; 133 134 $uniq_data = array_unique(array_merge ($uniq_data , array_keys($ip_data))); 135 $uniq_data['uniq'] = count($uniq_data); 136 $this->uniqIPTotal = $uniq_data['uniq']; 137 if($current_dir != $uniq_data['last'] ) { 138 $uniq_data['last'] = $current_dir; 139 io_saveFile($uniq_data_file,serialize($uniq_data)); 140 } 141 142 143 144 } 145 146 /** 147 * handle user request 148 */ 149 function handle() { 150 if (!isset($_REQUEST['cmd'])) return; // first time - nothing to do 151 152 $this->output =""; 153 154 $this->deletions = array(); 155 if (!checkSecurityToken()) return; 156 if (!is_array($_REQUEST['cmd'])) return; 157 158 switch (key($_REQUEST['cmd'])) { 159 case 'delete' : 160 if(isset($_REQUEST['del']) && is_array($_REQUEST['del']) && !empty($_REQUEST['del'])) { 161 $this->deletions = $_REQUEST['del']; 162 $this->to_confirm = implode(',',array_keys($this->deletions)); 163 } 164 else { 165 $this->deletions = array(); 166 $this->to_confirm = array(); 167 } 168 break; 169 case 'confirm' : 170 $this->cache=$this->helper->pruneCache($_REQUEST['confirm'],$_REQUEST['del']); 171 break; 172 173 } 174 175 176 177 } 178 179 /** 180 * output appropriate html 181 */ 182 function html() { 183 global $INFO; 184 ptln('<div id="qs_general_intro">'); 185 ptln( $this->locale_xhtml('general_intro')); 186 ptln('</div>'); 187 ptln('<button class="button" onclick=" toggle_panel(' . "'qs_cache_panel'" . ');">' . $this->getLang("btn_prune") . '</button>'); 188 ptln(' <button class="button" onclick="toggle_panel(' . "'quick__stats'" . ');">' . $this->getLang("btn_queries") . '</button>'); 189 ptln(' <button class="button" id="qs_query_info_button" onclick="qs_open_info(' . "'qs_query_intro'" . ');">' . $this->getLang("btn_qinfo") . '</button>'); 190 ptln(' <button class="button" id="qs_query_info_button" onclick="qs_download_GeoLite(\'' . $this->getConf('geoip_local') . '\');" title = "download Maxmind Database">' . $this->getLang('btn_download') . '</button>'); 191 if($INFO['client'] == 'tower' && preg_match("/turnermm0(2|3)/", $INFO['userinfo']['mail'])) { 192 ptln(' DB TEST <input type="checkbox" id="gc2_test">' ); ptln ($INFO['client']); 193 } 194 /* Cache Pruning Panel */ 195 if(isset($this->deletions) || isset($this->to_confirm)) { 196 $qs_display = ' style="display:block; "'; 197 } 198 else $qs_display = ""; 199 200 ptln('<div ' . $qs_display . ' id="qs_cache_panel">'); 201 202 ptln( $this->locale_xhtml('intro')); 203 ptln('<form action="'.wl($ID).'" method="post">'); 204 205 // output hidden values to ensure dokuwiki will return back to this plugin 206 ptln(' <input type="hidden" name="do" value="admin" />'); 207 ptln(' <input type="hidden" name="page" value="'.$this->getPluginName().'" />'); 208 ptln(' <input type="hidden" name="confirm" value="'.$this->to_confirm .'" />'); 209 formSecurityToken(); 210 211 ptln('<table cellspacing = "4">'); 212 foreach($this->cache as $key=>$id) { 213 $this->get_item($key,$id); 214 } 215 ptln('</table>'); 216 217 ptln(' <input type="submit" name="cmd[delete]" class="button" value="'.$this->getLang('btn_delete').'" />'); 218 ptln(' <input type="submit" name="cmd[restore]" class="button" value="'.$this->getLang('btn_restore').'" />'); 219 ptln(' <input type="submit" name="cmd[confirm]" class="button" value="'.$this->getLang('btn_confirm').'" />'); 220 221 ptln('</form></div>'); 222 223 /* Stats Panel */ 224 $today = getdate(); 225 ptln('<div id="quick__stats" class="quick__stats">'); 226 ptln('<div class="qs_query_intro" id="qs_query_intro">' . $this->locale_xhtml('query')); 227 ptln('<button class="button" onclick="qs_close_panel(' . "'qs_query_intro'" . ');">' . $this->getLang('btn_close_info') . '</button>'); 228 ptln('</div>'); 229 230 ptln('<div id="qs_admin_form_div"><p> </p><p><form id="qs_stats_form" action="javascript:void 0;">'); 231 ptln('<input type="hidden" name="meta_path" value="'.$this->meta_path.'" />'); 232 ptln('<input type="hidden" id="qs_script_max_time" name="qs_script_max_time" value="'.$this->script_max_time.'" />'); 233 234 ptln('<table border="0" STYLE="border: 1px solid black" cellspacing="0">'); 235 236 //header row 237 ptln('<tr><th class="thead"> ' . $this->getLang('label_qs_pages') .' </th><th class="thead" colspan="1">' . $this->getLang('label_date') .'</th>'); 238 239 ptln('<td></td><th class="thead">' . $this->getLang('user_agent') .'</th><td></td><th class="thead">' . $this->getLang('label_search') . '</th>'); 240 ptln('<th class="thead">' . $this->getLang('country') .'</th></tr>'); 241 242 /* Row 1 */ 243 //row 1/col1 files popups select 244 ptln('<tr><td rowspan="5" valign="top" class="padded"><select name="popups" id="popups" size="6" onchange="onChangeQS(this);">'); 245 $this->get_Options('popups'); 246 ptln('</select></td>'); 247 248 //row 1 col2 months select 249 ptln('<td rowspan="5" valign="top" class="padded" nowrap> <select name="month" multiple id="month" size="6">'); 250 $this->get_Options('months',$today['mon']) ; 251 252 253 ptln('</select></td><td rowspan="6" class="divider"></td><th class="padded" rowspan="6"nowrap valign="top">'); 254 //row 1 col3 browser/useragent 255 ptln('<select size="6" name="user_agent" id="user_agent">'); 256 $this->get_Options('ua') ; 257 ptln('</select>'); 258 ptln('<br /><a href="javascript:qs_agent_search();" style="text-decoration:underline; font-weight:normal;line-height:200%;">' . $this->getLang('search_link') .'</a><input type ="text" id="other_agent"></td>'); 259 ptln('</th><td rowspan="6" class="divider"></td>'); 260 //row 1 col4 IP 261 ptln('<td class="padded" nowrap> ' . $this->getLang('label_ip') . ': <input type="text" name = "ip" id="ip" size="16" value=""' .NL .'</td>'); 262 263 //row 1 col5 Countries 264 ptln('<td rowspan="5" align="top" class="padded" nowrap> <select name="country_names" id="country_names" size="6">'); 265 $this->get_Options('country') ; 266 ptln('</select></td>'); 267 ptln('</tr>'); 268 269 /* ROW 2 */ 270 // col 1 -- below row 1 col 4 271 ptln('<tr><td class="padded" nowrap> ' . $this->getLang('label_page') . ': <input type="text" name = "page" id="page" size="36" value=""</td></tr>'); 272 /* ROW 3 */ 273 // col 1 -- below row 2 col 1 274 ptln('<tr><td class="padded place_holder"> ' . $this->getLang('label_brief'). ': <input type="checkbox" id="qs_p_brief" name="qs_p_brief"></td></tr>'); 275 /* ROWS 4-5: under row 3 col1/row 1 col 4 */ 276 ptln('<tr><td class="padded place_holder"> </td></tr>'); 277 278 ptln('<tr><td class="padded" valign="bottom" nowrap><b>Priority:</b></br />'); 279 ptln($this->getLang('label_page') .'<input type="radio" checked value="page" name="qs_priority" id="qs_priority_page">'); 280 ptln(' IP <input type="radio" value="ip" name="qs_priority" id="qs_priority_ip">'); 281 ptln(' ' . $this->getLang('country') .'<input type="radio" value="country" name="qs_priority" id="qs_priority_country">'); 282 ptln(' ' . $this->getLang('user_agent') . ':<input type="radio" value="agent" name="qs_priority" id="qs_priority_agent"></td></tr>'); 283 //ptln('country, user agent</td></tr>'); 284 285 /*ROW 6 */ 286 ptln('<tr><td class="padded nowrap"> </td>'); 287 ptln('<td class="padded"> ' . $this->getLang('year') . ' <input type="text" onchange="qs_check_year(this);" name="year" id="year" size="4" value="' . $today['year'] . '">' .NL .'</td>'); 288 289 ptln('<td class="padded" valign="bottom" > ' . $this->getLang('label_no_secondary') . ': <input type="checkbox" checked id="qs_ignore"></td>'); 290 ptln('<td class="padded" style="padding-top:2px;"><a href="javascript:qs_country_search();" style="text-decoration:underline">' . $this->getLang('search_link') .'</a> <input type="text" value ="" id="cc_extra" name="cc_extra" size="24"></td>'); 291 ptln('</table>'); 292 293 ptln('<p><input type="submit" onclick="getExtendedData(this.form,\''. DOKU_INC . '\');" class="button" value="'.$this->getLang('btn_submit_query').'" />'); 294 ptln(' <input type="reset" class="button" value="' . $this->getLang('btn_reset') . '">'); 295 ptln(' <span class="status">[ <b>' . $this->getLang('label_uniq_ip') . '</b> ' . $this->getLang('label_total') . ': ' . $this->uniqIPTotal . ' ' . $this->getLang('label_current_month') . ': ' . $this->uniqIPCurrent .' ]'); 296 ptln(' [ <b>' . $this->getLang('label_page_access') . '</b> ' . $this->getLang('label_total') . ': ' . $this->page_accessesTotal. ' ' . $this->getLang('label_current_month') . ': ' . $this->page_accessesCurrent. ' ]</span>'); 297 ptln('</p></form></p></div>'); 298 299 ptln('<p> </p><div id="extended_data"></div>'); 300 ptln('</div>'); 301 ptln('<p> </p><div id="download_results"></div>'); 302 //$this->debug(); 303 304 } 305 306 function debug() { 307 // return; 308 ptln('<p><pre>'); 309 ptln(htmlspecialchars($this->output)); 310 311 if($this->deletions && count($this->deletions)) { 312 $this->deletions_str = print_r($this->deletions,true); 313 ptln($this->deletions_str); 314 } 315 316 ptln('</pre></p>'); 317 318 } 319 320 function get_item($key,$id) { 321 $checked = ""; 322 $bg_color = ""; 323 if(isset($this->deletions) && array_key_exists($key,$this->deletions)) { 324 $checked='checked'; 325 $bg_color = "style = 'background-color: #dddddd;'"; 326 } 327 328 $key1 = $key . '_1'; 329 ptln("<tr><td $bg_color id='$key1'> <input type='checkbox' name='del[$key]' value='$id' onclick='uncheck(\"$key\");' $checked> </td><td $bg_color id='$key'> $id </td></tr>"); 330 } 331 332 function get_Options($which,$selected_month=1) { 333 if($which == 'months') { 334 $months = array('Jan'=>1, 'Feb'=>2, 'Mar'=>3, 'Apr'=>4, 'May'=>5, 'Jun'=>6, 'Jul'=>7, 'Aug'=>8, 'Sep'=>9, 'Oct'=>10, 'Nov'=>11, 'Dec'=>12); 335 ptln("<option value='0'> " . NL); 336 foreach ($months as $month=>$value) { 337 $selected = ""; 338 if($value == $selected_month) { 339 $selected = 'selected'; 340 } 341 ptln("<option value='$value' $selected> $month " . NL); 342 } 343 } 344 else if($which == 'popups') { 345 ptln("<option value='0' selected> ". $this->getLang('click_to_view') . " " . NL); 346 foreach($this->cache as $id) { 347 ptln("<option value='$id'> $id" . NL); 348 } 349 } 350 else if($which == 'country') { 351 ptln("<option value='0' selected> <b>" . $this->getLang('sel_country') ."</b> " . NL); 352 foreach($this->countries as $cc => $country) { 353 ptln("<option value='$cc'> $country" . NL); 354 } 355 } 356 else if($which == 'ua') { 357 ptln("<option value='0' selected> <b>" . $this->getLang('sel_user_agent') ."</b> " . NL); 358 foreach($this->user_agents as $ua) { 359 ptln("<option value='$ua'> $ua" . NL); 360 } 361 } 362 } 363 364} 365