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('&nbsp;&nbsp;<button class="button" onclick="toggle_panel(' . "'quick__stats'" . ');">' . $this->getLang("btn_queries") . '</button>');
189      ptln('&nbsp;&nbsp;<button class="button" id="qs_query_info_button"  onclick="qs_open_info(' . "'qs_query_intro'" . ');">' . $this->getLang("btn_qinfo") . '</button>');
190      ptln('&nbsp;&nbsp;<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('&nbsp;&nbsp;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>&nbsp;</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">&nbsp;' . $this->getLang('label_qs_pages') .' &nbsp;</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>&nbsp;<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>&nbsp;' . $this->getLang('label_ip') . ':&nbsp;<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>&nbsp;<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>&nbsp;' . $this->getLang('label_page') . ':&nbsp;<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">&nbsp;' . $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">&nbsp;</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('&nbsp;IP <input type="radio" value="ip" name="qs_priority" id="qs_priority_ip">');
281      ptln('&nbsp;' . $this->getLang('country') .'<input type="radio" value="country" name="qs_priority" id="qs_priority_country">');
282      ptln('&nbsp;' . $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">&nbsp;</td>');
287      ptln('<td class="padded">&nbsp;' . $this->getLang('year')  . '&nbsp;<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" >&nbsp;' . $this->getLang('label_no_secondary') . ':&nbsp;<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('&nbsp;<input  type="reset" class="button" value="' . $this->getLang('btn_reset') . '">');
295      ptln('&nbsp;&nbsp;&nbsp;&nbsp;<span class="status">[ <b>' . $this->getLang('label_uniq_ip')  . '</b>&nbsp;&nbsp;' . $this->getLang('label_total') . ': ' .  $this->uniqIPTotal . '&nbsp;&nbsp;' . $this->getLang('label_current_month') . ': ' . $this->uniqIPCurrent .' ]');
296      ptln('&nbsp;&nbsp;&nbsp;[ <b>' . $this->getLang('label_page_access') . '</b>&nbsp;&nbsp;' . $this->getLang('label_total') . ': ' . $this->page_accessesTotal. '&nbsp;&nbsp;' . $this->getLang('label_current_month') . ': ' . $this->page_accessesCurrent.  ' ]</span>');
297      ptln('</p></form></p></div>');
298
299      ptln('<p>&nbsp;</p><div id="extended_data"></div>');
300      ptln('</div>');
301      ptln('<p>&nbsp;</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'>&nbsp;<input type='checkbox' name='del[$key]' value='$id' onclick='uncheck(\"$key\");' $checked>&nbsp;</td><td $bg_color id='$key'>&nbsp;$id&nbsp;</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'> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " . 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> &nbsp;". $this->getLang('click_to_view') . "&nbsp;" . 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> &nbsp; <b>" . $this->getLang('sel_country') ."</b> &nbsp;" . 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> &nbsp; <b>" . $this->getLang('sel_user_agent') ."</b> &nbsp;" . NL);
358        foreach($this->user_agents as $ua) {
359             ptln("<option value='$ua'> $ua" . NL);
360        }
361     }
362    }
363
364}
365