1<?php 2 3use dokuwiki\Extension\ActionPlugin; 4use dokuwiki\Extension\Event; 5use dokuwiki\Extension\EventHandler; 6 7/** 8 * 9 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 10 * @author Andreas Gohr <gohr@cosmocode.de> 11 */ 12class action_plugin_statistics extends ActionPlugin 13{ 14 /** 15 * register the eventhandlers and initialize some options 16 */ 17 public function register(EventHandler $controller) 18 { 19 global $JSINFO; 20 global $ACT; 21 $JSINFO['act'] = $ACT; 22 23 $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'initSession', []); 24 // FIXME new save event might be better: 25 $controller->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'logedits', []); 26 $controller->register_hook('SEARCH_QUERY_FULLPAGE', 'AFTER', $this, 'logsearch', []); 27 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'loglogins', []); 28 $controller->register_hook('AUTH_USER_CHANGE', 'AFTER', $this, 'logregistration', []); 29 $controller->register_hook('FETCH_MEDIA_STATUS', 'BEFORE', $this, 'logmedia', []); 30 $controller->register_hook('INDEXER_TASKS_RUN', 'AFTER', $this, 'loghistory', []); 31 } 32 33 /** 34 * This ensures we have a session for the statistics plugin 35 * 36 * We reset this when the user agent changes or the session is too old 37 * (15 minutes). 38 */ 39 public function initSession() 40 { 41 global $INPUT; 42 43 // load session data 44 if (isset($_SESSION[DOKU_COOKIE]['statistics'])) { 45 $session = $_SESSION[DOKU_COOKIE]['statistics']; 46 } else { 47 $session = []; 48 } 49 // reset if session is too old 50 if (time() - ($session['time'] ?? 0) > 60 * 15) { 51 $session = []; 52 } 53 // reset if user agent changed 54 if ($INPUT->server->str('HTTP_USER_AGENT') != ($session['user_agent'] ?? '')) { 55 $session = []; 56 } 57 58 // update session data 59 $session['time'] = time(); 60 $session['user_agent'] = $INPUT->server->str('HTTP_USER_AGENT'); 61 $session['uid'] = get_doku_pref('plgstats', bin2hex(random_bytes(16))); 62 if (!isset($session['id'])) { 63 // generate a new session id if not set 64 $session['id'] = bin2hex(random_bytes(16)); 65 } 66 67 // store session and cookie data 68 $_SESSION[DOKU_COOKIE]['statistics'] = $session; 69 set_doku_pref('plgstats', $session['uid']); 70 } 71 72 /** 73 * @fixme call this in the webbug call 74 */ 75 public function putpixel() 76 { 77 global $ID, $INPUT; 78 $url = DOKU_BASE . 'lib/plugins/statistics/log.php?p=' . rawurlencode($ID) . 79 '&r=' . rawurlencode($INPUT->server->str('HTTP_REFERER')) . '&rnd=' . time(); 80 81 echo '<noscript><img alt="" src="' . $url . '" width="1" height="1" /></noscript>'; 82 } 83 84 /** 85 * Log page edits actions 86 */ 87 public function logedits(Event $event, $param) 88 { 89 if ($event->data[3]) return; // no revision 90 91 if (file_exists($event->data[0][0])) { 92 if ($event->data[0][1] == '') { 93 $type = 'D'; 94 } else { 95 $type = 'E'; 96 } 97 } else { 98 $type = 'C'; 99 } 100 /** @var helper_plugin_statistics $hlp */ 101 $hlp = plugin_load('helper', 'statistics'); 102 $hlp->getLogger()->logEdit($event->data[1] . ':' . $event->data[2], $type); 103 } 104 105 /** 106 * Log internal search 107 */ 108 public function logsearch(Event $event, $param) 109 { 110 /** @var helper_plugin_statistics $hlp */ 111 $hlp = plugin_load('helper', 'statistics'); 112 $hlp->getLogger()->logSearch($event->data['query'], $event->data['highlight']); 113 } 114 115 /** 116 * Log login/logouts 117 */ 118 public function loglogins(Event $event, $param) 119 { 120 global $INPUT; 121 122 $type = ''; 123 $act = $this->actClean($event->data); 124 $user = $INPUT->server->str('REMOTE_USER'); 125 if ($act == 'logout') { 126 // logout 127 $type = 'o'; 128 } elseif ($INPUT->server->str('REMOTE_USER') && $act == 'login') { 129 if ($INPUT->str('r')) { 130 // permanent login 131 $type = 'p'; 132 } else { 133 // normal login 134 $type = 'l'; 135 } 136 } elseif ($INPUT->str('u') && !$INPUT->str('http_credentials') && !$INPUT->server->str('REMOTE_USER')) { 137 // failed attempt 138 $user = $INPUT->str('u'); 139 $type = 'f'; 140 } 141 if (!$type) return; 142 143 /** @var helper_plugin_statistics $hlp */ 144 $hlp = plugin_load('helper', 'statistics'); 145 $hlp->getLogger()->logLogin($type, $user); 146 } 147 148 /** 149 * Log user creations 150 */ 151 public function logregistration(Event $event, $param) 152 { 153 if ($event->data['type'] == 'create') { 154 /** @var helper_plugin_statistics $hlp */ 155 $hlp = plugin_load('helper', 'statistics'); 156 $hlp->getLogger()->logLogin('C', $event->data['params'][0]); 157 } 158 } 159 160 /** 161 * Log media access 162 */ 163 public function logmedia(Event $event, $param) 164 { 165 if ($event->data['status'] < 200) return; 166 if ($event->data['status'] >= 400) return; 167 if (preg_match('/^\w+:\/\//', $event->data['media'])) return; 168 169 // no size for redirect/not modified 170 if ($event->data['status'] >= 300) { 171 $size = 0; 172 } else { 173 $size = @filesize($event->data['file']); 174 } 175 176 /** @var helper_plugin_statistics $hlp */ 177 $hlp = plugin_load('helper', 'statistics'); 178 $hlp->getLogger()->logMedia( 179 $event->data['media'], 180 $event->data['mime'], 181 !$event->data['download'], 182 $size 183 ); 184 } 185 186 /** 187 * Log the daily page and media counts for the history 188 */ 189 public function loghistory(Event $event, $param) 190 { 191 echo 'Plugin Statistics: started' . DOKU_LF; 192 193 /** @var helper_plugin_statistics $hlp */ 194 $hlp = plugin_load('helper', 'statistics'); 195 $db = $hlp->getDB(); 196 197 // check if a history was gathered already today 198 $result = $db->queryAll( 199 "SELECT info FROM history WHERE date(dt) = date('now')" 200 ); 201 202 $page_ran = false; 203 $media_ran = false; 204 foreach ($result as $row) { 205 if ($row['info'] == 'page_count') $page_ran = true; 206 if ($row['info'] == 'media_count') $media_ran = true; 207 } 208 209 if ($page_ran && $media_ran) { 210 echo 'Plugin Statistics: nothing to do - finished' . DOKU_LF; 211 return; 212 } 213 214 $event->stopPropagation(); 215 $event->preventDefault(); 216 217 if ($page_ran) { 218 echo 'Plugin Statistics: logging media' . DOKU_LF; 219 $hlp->getLogger()->logHistoryMedia(); 220 } else { 221 echo 'Plugin Statistics: logging pages' . DOKU_LF; 222 $hlp->getLogger()->logHistoryPages(); 223 } 224 echo 'Plugin Statistics: finished' . DOKU_LF; 225 } 226 227 /** 228 * Pre-Sanitize the action command 229 * 230 * Similar to act_clean in action.php but simplified and without 231 * error messages 232 */ 233 protected function actClean($act) 234 { 235 // check if the action was given as array key 236 if (is_array($act)) { 237 [$act] = array_keys($act); 238 } 239 240 //remove all bad chars 241 $act = strtolower($act); 242 $act = preg_replace('/[^a-z_]+/', '', $act); 243 244 return $act; 245 } 246} 247