1<?php 2 3use dokuwiki\Extension\EventHandler; 4use dokuwiki\Extension\Event; 5use dokuwiki\Logger; 6 7/** 8 * Action Component for the Bot Monitoring Plugin 9 * 10 * @license GPL 3 (http://www.gnu.org/licenses/gpl.html) 11 * @author Sascha Leib <sascha.leib(at)kolmio.com> 12 */ 13 14class action_plugin_botmon extends DokuWiki_Action_Plugin { 15 16 /** 17 * Registers a callback functions 18 * 19 * @param EventHandler $controller DokuWiki's event controller object 20 * @return void 21 */ 22 public function register(EventHandler $controller) { 23 $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'insertHeader'); 24 } 25 26 /** 27 * Inserts tracking code to the page header 28 * 29 * @param Event $event event object by reference 30 * @return void 31 */ 32 public function insertHeader(Event $event, $param) { 33 34 global $INFO; 35 36 // is there a user logged in? 37 $username = ( !empty($INFO['userinfo']) && !empty($INFO['userinfo']['name']) 38 ? $INFO['userinfo']['name'] : ''); 39 40 // build the tracker code: 41 $code = NL . DOKU_TAB . "document._botmon = {'t0': Date.now()};" . NL; 42 if ($username) { 43 $code .= DOKU_TAB . 'document._botmon.user = "' . $username . '";'. NL; 44 } 45 $code .= DOKU_TAB . "addEventListener('load',function(){" . NL; 46 47 $code .= DOKU_TAB . DOKU_TAB . "const e=document.createElement('script');" . NL; 48 $code .= DOKU_TAB . DOKU_TAB . "e.async=true;e.defer=true;" . NL; 49 $code .= DOKU_TAB . DOKU_TAB . "e.src='".DOKU_BASE."lib/plugins/botmon/client.js';" . NL; 50 $code .= DOKU_TAB . DOKU_TAB . "document.getElementsByTagName('head')[0].appendChild(e);" . NL; 51 $code .= DOKU_TAB . "});" . NL . DOKU_TAB; 52 53 $event->data['script'][] = [ 54 '_data' => $code 55 ]; 56 57 /* Write out server-side info to a server log: */ 58 $this->writeServerLog($username); 59 } 60 61 /** 62 * Writes data to the server log. 63 * 64 * @return void 65 */ 66 private function writeServerLog($username) { 67 68 global $conf; 69 global $INFO; 70 71 // what is the session identifier? 72 $sessionId = $_COOKIE['DokuWiki'] ?? ''; 73 $sessionType = 'dw'; 74 if ($sessionId == '') { 75 $sessionId = $_SERVER['REMOTE_ADDR'] ?? ''; 76 if ($sessionId == '127.0.0.1' || $sessionId == '::1') { 77 $sessionId = 'localhost'; 78 } 79 $sessionType = 'ip'; 80 } 81 82 // clean the page ID 83 $pageId = preg_replace('/[\x00-\x1F]/', "\u{FFFD}", $INFO['id'] ?? ''); 84 85 // collect GeoIP information (if available): 86 $geoIp = 'XX'; /* User-defined code for unknown country */ 87 try { 88 if (extension_loaded('geoip') && geoip_db_avail(GEOIP_COUNTRY_EDITION)) { 89 $geoIp = geoip_country_code_by_name($_SERVER['REMOTE_ADDR']); 90 } else { 91 Logger::debug('BotMon Plugin: GeoIP module not available'); 92 } 93 } catch (Exception $e) { 94 Logger::error('BotMon Plugin: GeoIP Error', $e->getMessage()); 95 } 96 97 // create the log array: 98 $logArr = Array( 99 $_SERVER['REMOTE_ADDR'] ?? '', /* remote IP */ 100 $pageId, /* page ID */ 101 $sessionId, /* Session ID */ 102 $sessionType, /* session ID type */ 103 $username, 104 $_SERVER['HTTP_USER_AGENT'] ?? '', /* User agent */ 105 $_SERVER['HTTP_REFERER'] ?? '', /* HTTP Referrer */ 106 substr($conf['lang'],0,2), /* page language */ 107 implode(',', array_unique(array_map( function($it) { return substr($it,0,2); }, explode(',',trim($_SERVER['HTTP_ACCEPT_LANGUAGE'], " \t;,*"))))), /* accepted client languages */ 108 $geoIp /* GeoIP country code */ 109 ); 110 111 //* create the log line */ 112 $filename = __DIR__ .'/logs/' . gmdate('Y-m-d') . '.srv.txt'; /* use GMT date for filename */ 113 $logline = gmdate('Y-m-d H:i:s'); /* use GMT time for log entries */ 114 foreach ($logArr as $tab) { 115 $logline .= "\t" . $tab; 116 }; 117 118 /* write the log line to the file */ 119 $logfile = fopen($filename, 'a'); 120 if (!$logfile) die(); 121 if (fwrite($logfile, $logline . "\n") === false) { 122 fclose($logfile); 123 die(); 124 } 125 126 /* Done */ 127 fclose($logfile); 128 } 129}