1<?php
2/**
3 * directions plug-in - Nuno Flores
4 * based on logstats plug-in by J.-F. Lalande (jf@lalande.nom.fr)
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Nuno Flores (nuno.flores@gmail.com)
8 */
9
10if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
12require_once(DOKU_PLUGIN.'action.php');
13
14/**
15 * All DokuWiki plugins to extend the parser/rendering mechanism
16 * need to inherit from this class
17 */
18class action_plugin_directions extends DokuWiki_Action_Plugin {
19
20    /**
21     * return some info
22     */
23    function getInfo(){
24        return array(
25            'author' => 'Nuno Flores',
26            'email'  => 'nuno.flores@gmail.com',
27            'date'   => '2011-03-01',
28            'name'   => 'directions plugin (logger component)',
29            'desc'   => 'Logs when a user navigates from one wikipage to another.',
30            'url'    => 'http://www.dokuwiki.org/plugin:directions',
31        );
32    }
33
34
35    /*
36    * Log.
37    *
38	* @author J.-F. Lalande (jf@lalande.nom.fr)
39	*/
40    function dir_tpl_logfile(){
41	    global $ID;
42	    $this->dir_logPageAccess(cleanID($ID));
43    }
44
45    /**
46    * Checks the existance of the log file.
47    *
48	* @author J.-F. Lalande (jf@lalande.nom.fr)
49	* adapted by Nuno Flores (nuno.flores@gmail.com)
50    */
51    function dir_init_log_file($file){
52	global $conf;
53
54	if(!@file_exists($file)){
55	    $fh = @fopen($file,'a');
56	    if($fh){
57		fclose($fh);
58		if($conf['fperm'])
59		chmod($file, $conf['fperm']);
60	    }else{
61		nice_die("directions plugin error: Unable to create
62		$file ; The directory where access.log will be
63		created must be writtable by the apache daemon.
64		if you think that it's possibly a bug,
65		please report it !");
66	    }
67	}
68	return $file;
69    }
70
71    /*
72    * Init the paths for hits.log
73    *
74	* @author J.-F. Lalande (jf@lalande.nom.fr)
75	* adapted by Nuno Flores (nuno.flores@gmail.com)
76	*/
77    function dir_init_log_path(){
78	    global $conf;
79	    $logstats_accessconf = $this->getConf('hitslog');
80
81
82	    if($logstats_accessconf == "")
83	    {
84		    nice_die('Error in directions plugin (logger component): the configuration
85		    variable $conf[\'plugin\'][\'directions\'][\'hitslog\'] is
86		    not set or the default value cannot be read.');
87	    }
88	    $tmp_accesslogname = DOKU_INC . $logstats_accessconf;
89	    $tmp_accesslogname = init_path($tmp_accesslogname);
90	    if($tmp_accesslogname == "")
91	    {
92		$this->dir_init_log_file(DOKU_INC .  $logstats_accessconf);
93
94	    }
95	}
96
97
98    /*
99    * Register its handlers with the dokuwiki's event controller
100	*
101	* @author J.-F. Lalande (jf@lalande.nom.fr)
102	* adapted by Nuno Flores (nuno.flores@gmail.com)
103    */
104    function register(&$controller) {
105            $controller->register_hook('ACTION_HEADERS_SEND', 'BEFORE',  $this, 'dir_tpl_logfile');
106	    $this->dir_init_log_path();
107    }
108
109/**
110 * beautify a wiki page id for the log
111 *
112 * The wiki page id will be transformed to a filename like string
113 * utf8 codes will be encoded.
114 *
115 * @param  $id  wiki page id
116 *
117 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
118 */
119function dir_prepareID($path){
120    $path = cleanID($path);
121    $path = str_replace(':','/',$path);
122    $path = utf8_encodeFN($path);
123    return $path;
124}
125
126/**
127 * checks if a file exists and returns an appropriate web
128 * server status
129 *
130 * @param  $file  complete filepath to check
131 *
132 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
133 */
134function dir_getStatus($file){
135    if(@file_exists($file)){
136      $size = @filesize($file);
137      return "200 $size";
138    }else
139      return "404 0";
140}
141
142/**
143 * logs access to a wiki page
144 *
145 * @param  $id  page id of the wiki page including namespace
146 *
147 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
148 */
149function dir_logPageAccess($id){
150    global $ACT;
151
152    if ($ACT == 'show'){
153      $page = $this->dir_prepareID($id);
154
155      $crumbs = breadcrumbs();          // get last visited pages
156      $crumbs = array_keys($crumbs);   // get raw page IDs
157      array_pop($crumbs);             // skip current page
158      $referer = array_pop($crumbs); // get current page's predecessor
159      $referer = ($referer) ? $this->dir_prepareID($referer) : '';
160
161      $this->dir_logAccess($page,$this->dir_getStatus(wikiFN($id)),$referer);
162    }
163}
164
165/**
166 * creates a log file entry and writes it to the log
167 *
168 * This function writes access information of the current page to a log
169 * file. It uses the combined log file format that is also used by the
170 * apache web server. A whole bunch of available log analysers could be
171 * used to visualize the log.
172 *
173 * @param  $page     page name that was called
174 * @param  $status   HTTP status code followed by the file size
175 * @param  $referer  predecessor of $page (which page link to $page)
176 *                   Is this field empty, the functions tries to get
177 *                   the referer from the web server (HTTP_REFERER)
178 *
179 * @author Matthias Grimm <matthias.grimm@users.sourceforge.net>
180 *
181 * combined log file format:
182 *     <host> <rfc931> <user> [<timestamp>] "<request>" <error> <filesize>
183 *               "<referer>" "<agent>"\n
184 *
185 * <host>      IP of the client host (we don't do reverse host lookups)
186 * <rfc931>    remote user identification or '-' if not available
187 * <user>      user id or '-' if not available
188 * <timestamp> time in format [01/Dec/2005:22:19:12 +0200]
189 * <request>   Requested protocol, for eg. GET or POST, requested page
190 *             and protocol
191 * <error>     error code from server, for eg. 200 (OK) or 404 (file
192 *             not found)
193 * <filesize>  size of the wiki page (only the bare text)
194 * <referer>   page that called this one. We don't have this information
195 *             and filled the dokuwiki script name in.
196 * <agent>     identifying information that the client browser reports
197 *             about itself
198 */
199function dir_logAccess($page,$status,$referer=''){
200    global $conf;
201
202    if ($this->getConf('hitslog') != ""){
203	$host      = $_SERVER['REMOTE_ADDR'];
204	$user      = isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : "-";
205	$timestamp = date("[d/M/Y:H:i:s O]");
206	$method    = isset($_SERVER['REQUEST_METHOD'])  ? $_SERVER['REQUEST_METHOD']  : "";
207	$protocol  = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : "";
208	$agent     = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
209
210	// We have to check if this agent is not banned
211	if ($this->getConf('banned_agents') != "")
212	{
213	    $tmp_array_agents_banned = explode(',', $this->getConf('banned_agents'));
214	    foreach ($tmp_array_agents_banned as $agents_banned)
215	    {
216		if (stristr($agent, $agents_banned) !== false)
217		{
218		return 0; // exit the function, nothing have to be written
219		}
220	    }
221	}
222
223	// We have to check if this IP is not banned
224	if ($this->getConf('banned_ip') != "")
225	{
226	    $tmp_array_ip_banned = explode(',', $this->getConf('banned_ip'));
227	    foreach ($tmp_array_ip_banned as $ip_banned)
228	    {
229		//echo $ip_banned . "=" . $host;
230		if (strcmp($host, $ip_banned) == 0)
231		{
232		    //echo "Banned: " . $host . "!!!";
233		    return 0; // exit the function, nothing have to be written
234		}
235	    }
236	}
237
238	// Banned some users
239	if ($this->getConf('banned_users') != "")
240	{
241	    $tmp_array_users_banned = explode(',', $this->getConf('banned_users'));
242	    foreach ($tmp_array_users_banned as $users_banned)
243	    {
244		//echo $users_banned . "=" . $host;
245		if (strcmp($user, $users_banned) == 0)
246		{
247		    //echo "Banned: " . $host . "!!!";
248		    return 0; // exit the function, nothing have to be written
249		}
250	    }
251	}
252
253	// Analyzing referer
254	//echo "referrer:" . $referer . "/";
255	if ($referer == ""){
256	    //echo "referrer: " . $_SERVER['HTTP_REFERER'];
257	    if(isset($_SERVER['HTTP_REFERER'])){
258		$cnt = preg_match('/\?id=((\w+\:*)+)/i',$_SERVER['HTTP_REFERER'], $match);
259		if($cnt == 1)
260		{
261		    $referer = $this->dir_prepareID($match[1]);
262		}
263		else
264		{
265		    $referer = $_SERVER['HTTP_REFERER'];
266		}
267	    }
268	}
269	// NUNO FLORES: Taken out...
270	//$logline = "$host - $user $timestamp \"$method $page $protocol\" $status \"$referer\" \"$agent\"\n";
271	//io_saveFile(DOKU_INC . $this->getConf('accesslog'), $logline, true);
272
273	// NUNO FLORES: Put in...
274	$hit = "$user>$referer>$page\n";
275	io_saveFile(DOKU_INC . $this->getConf('hitslog'), $hit, true);
276
277    }
278}
279
280
281} // End of class
282
283