2025-08-20 16:34:20 +03:00
< ? php
use dokuwiki\Extension\EventHandler ;
use dokuwiki\Extension\Event ;
2025-09-10 14:44:08 +02:00
use dokuwiki\Logger ;
2025-08-20 16:34:20 +03:00
/**
2025-09-01 16:25:25 +02:00
* Action Component for the Bot Monitoring Plugin
2025-08-20 16:34:20 +03:00
*
* @ license GPL 3 ( http :// www . gnu . org / licenses / gpl . html )
* @ author Sascha Leib < sascha . leib ( at ) kolmio . com >
*/
2025-09-01 16:25:25 +02:00
class action_plugin_botmon extends DokuWiki_Action_Plugin {
2025-08-20 16:34:20 +03:00
/**
2025-08-20 22:58:42 +03:00
* Registers a callback functions
*
* @ param EventHandler $controller DokuWiki ' s event controller object
* @ return void
*/
public function register ( EventHandler $controller ) {
$controller -> register_hook ( 'TPL_METAHEADER_OUTPUT' , 'BEFORE' , $this , 'insertHeader' );
}
2025-09-12 15:38:28 +02:00
/* session information */
2025-09-12 17:50:05 +02:00
private $sessionId = null ;
private $sessionType = '' ;
2025-09-12 15:38:28 +02:00
2025-08-20 22:58:42 +03:00
/**
* Inserts tracking code to the page header
*
* @ param Event $event event object by reference
* @ return void
*/
2025-08-20 16:34:20 +03:00
public function insertHeader ( Event $event , $param ) {
global $INFO ;
2025-09-12 15:38:28 +02:00
// populate the session id and type:
$this -> getSessionInfo ();
2025-08-20 16:34:20 +03:00
// is there a user logged in?
2025-08-20 22:58:42 +03:00
$username = ( ! empty ( $INFO [ 'userinfo' ]) && ! empty ( $INFO [ 'userinfo' ][ 'name' ])
2025-09-04 09:44:01 +02:00
? $INFO [ 'userinfo' ][ 'name' ] : '' );
2025-08-20 16:34:20 +03:00
// build the tracker code:
2025-09-12 15:38:28 +02:00
$code = NL . DOKU_TAB . " document._botmon = { 't0': Date.now(), 'session': ' " . json_encode ( $this -> sessionId ) . " '}; " . NL ;
2025-08-20 22:58:42 +03:00
if ( $username ) {
2025-09-01 16:25:25 +02:00
$code .= DOKU_TAB . 'document._botmon.user = "' . $username . '";' . NL ;
2025-08-20 16:34:20 +03:00
}
$code .= DOKU_TAB . " addEventListener('load',function() { " . NL ;
$code .= DOKU_TAB . DOKU_TAB . " const e=document.createElement('script'); " . NL ;
2025-08-20 22:58:42 +03:00
$code .= DOKU_TAB . DOKU_TAB . " e.async=true;e.defer=true; " . NL ;
2025-09-01 16:25:25 +02:00
$code .= DOKU_TAB . DOKU_TAB . " e.src=' " . DOKU_BASE . " lib/plugins/botmon/client.js'; " . NL ;
2025-08-20 22:58:42 +03:00
$code .= DOKU_TAB . DOKU_TAB . " document.getElementsByTagName('head')[0].appendChild(e); " . NL ;
2025-09-05 16:22:39 +02:00
$code .= DOKU_TAB . " }); " . NL . DOKU_TAB ;
2025-08-20 16:34:20 +03:00
2025-08-20 22:58:42 +03:00
$event -> data [ 'script' ][] = [
2025-08-20 16:34:20 +03:00
'_data' => $code
];
2025-08-20 22:58:42 +03:00
2025-09-01 10:15:36 +02:00
/* Write out server-side info to a server log: */
2025-09-06 20:01:03 +02:00
$this -> writeServerLog ( $username );
}
/**
* Writes data to the server log .
*
* @ return void
*/
private function writeServerLog ( $username ) {
global $conf ;
global $INFO ;
2025-08-29 23:18:51 +03:00
2025-09-05 09:15:08 +02:00
// clean the page ID
$pageId = preg_replace ( '/[\x00-\x1F]/' , " \ u { FFFD} " , $INFO [ 'id' ] ? ? '' );
2025-09-10 14:44:08 +02:00
// collect GeoIP information (if available):
2025-09-12 15:38:28 +02:00
$geoIp = ( $this -> sessionId == 'localhost' ? 'local' : 'ZZ' ); /* User-defined code for unknown country */
2025-09-10 14:44:08 +02:00
try {
if ( extension_loaded ( 'geoip' ) && geoip_db_avail ( GEOIP_COUNTRY_EDITION )) {
$geoIp = geoip_country_code_by_name ( $_SERVER [ 'REMOTE_ADDR' ]);
} else {
Logger :: debug ( 'BotMon Plugin: GeoIP module not available' );
}
} catch ( Exception $e ) {
Logger :: error ( 'BotMon Plugin: GeoIP Error' , $e -> getMessage ());
}
2025-09-06 20:01:03 +02:00
// create the log array:
2025-08-20 22:58:42 +03:00
$logArr = Array (
2025-08-26 21:37:19 +03:00
$_SERVER [ 'REMOTE_ADDR' ] ? ? '' , /* remote IP */
2025-09-05 09:15:08 +02:00
$pageId , /* page ID */
2025-09-12 15:38:28 +02:00
$this -> sessionId , /* Session ID */
$this -> sessionType , /* session ID type */
2025-08-20 22:58:42 +03:00
$username ,
2025-08-30 13:01:50 +03:00
$_SERVER [ 'HTTP_USER_AGENT' ] ? ? '' , /* User agent */
2025-09-06 20:01:03 +02:00
$_SERVER [ 'HTTP_REFERER' ] ? ? '' , /* HTTP Referrer */
substr ( $conf [ 'lang' ], 0 , 2 ), /* page language */
2025-09-10 14:44:08 +02:00
implode ( ',' , array_unique ( array_map ( function ( $it ) { return substr ( $it , 0 , 2 ); }, explode ( ',' , trim ( $_SERVER [ 'HTTP_ACCEPT_LANGUAGE' ], " \t ;,* " ))))), /* accepted client languages */
$geoIp /* GeoIP country code */
2025-08-20 22:58:42 +03:00
);
//* create the log line */
2025-09-01 10:15:36 +02:00
$filename = __DIR__ . '/logs/' . gmdate ( 'Y-m-d' ) . '.srv.txt' ; /* use GMT date for filename */
2025-08-20 22:58:42 +03:00
$logline = gmdate ( 'Y-m-d H:i:s' ); /* use GMT time for log entries */
foreach ( $logArr as $tab ) {
$logline .= " \t " . $tab ;
};
/* write the log line to the file */
$logfile = fopen ( $filename , 'a' );
if ( ! $logfile ) die ();
if ( fwrite ( $logfile , $logline . " \n " ) === false ) {
fclose ( $logfile );
die ();
}
/* Done */
fclose ( $logfile );
}
2025-09-12 15:38:28 +02:00
private function getSessionInfo () {
// what is the session identifier?
if ( isset ( $_SESSION )) {
$sesKeys = array_keys ( $_SESSION ); /* DokuWiki Session ID preferred */
foreach ( $sesKeys as $key ) {
if ( substr ( $key , 0 , 2 ) == 'DW' ) {
$this -> sessionId = $key ;
$this -> sessionType = 'dw' ;
return ;
}
}
}
2025-09-12 17:50:05 +02:00
if ( ! $this -> sessionId ) { /* no DokuWiki Session ID, try PHP session ID */
2025-09-12 15:38:28 +02:00
$this -> sessionId = session_id ();
$this -> sessionType = 'php' ;
}
2025-09-12 17:50:05 +02:00
if ( ! $this -> sessionId ) { /* no PHP session ID, try IP address */
2025-09-12 15:38:28 +02:00
$this -> sessionId = $_SERVER [ 'REMOTE_ADDR' ] ? ? '' ;
$this -> sessionType = 'ip' ;
}
2025-09-12 17:50:05 +02:00
if ( ! $this -> sessionId ) { /* if everything else fails, just us a random ID */
2025-09-12 15:38:28 +02:00
$this -> sessionId = rand ( 1000000 , 9999999 );
$this -> sessionType = 'rand' ;
}
}
2025-08-20 16:34:20 +03:00
}