Subversion Repositories Applications.papyrus

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
439 ddelon 1
<?php
2
/* encoding: iso-8859-1
3
wakka.php
4
Copyright (c) 2002, Hendrik Mans <hendrik@mans.de>
5
Copyright  2003 Carlo Zottmann
6
Copyright 2002, 2003 David DELON
7
Copyright 2002, 2003, 2004 Charles NÉPOTE
8
Copyright 2002, 2003 Patrick PAUL
9
Copyright 2003 Éric DELORD
10
Copyright 2003 Éric FELDSTEIN
11
Copyright 2004 Jean-Christophe ANDRÉ
12
All rights reserved.
13
Redistribution and use in source and binary forms, with or without
14
modification, are permitted provided that the following conditions
15
are met:
16
1. Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
18
2. Redistributions in binary form must reproduce the above copyright
19
notice, this list of conditions and the following disclaimer in the
20
documentation and/or other materials provided with the distribution.
21
3. The name of the author may not be used to endorse or promote products
22
derived from this software without specific prior written permission.
23
 
24
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
*/
35
 
36
/*
37
    Yes, most of the formatting used in this file is HORRIBLY BAD STYLE. However,
38
    most of the action happens outside of this file, and I really wanted the code
39
    to look as small as what it does. Basically. Oh, I just suck. :)
40
*/
41
 
42
 
43
 
44
// do not change this line, you fool. In fact, don't change anything! Ever!
45
define("WAKKA_VERSION", "0.1.1");
46
define("WIKINI_VERSION", "0.4.3");
47
// start the compute time
48
list($g_usec, $g_sec) = explode(" ",microtime());
49
define ("t_start", (float)$g_usec + (float)$g_sec);
50
$t_SQL=0;
51
 
52
 
53
 
54
class Wiki
55
{
56
	var $dblink;
57
	var $page;
58
	var $tag;
59
	var $parameter = array();
60
	var $queryLog = array();
61
	var $interWiki = array();
62
	var $VERSION;
63
	var $CookiePath = '/';
64
 
65
 
66
	// constructor
67
	function Wiki($config)
68
	{
69
		$this->config = $config;
70
		// some host do not allow mysql_pconnect
71
		$this->dblink = @mysql_connect (
72
			$this->config["mysql_host"],
73
			$this->config["mysql_user"],
74
			$this->config["mysql_password"]);
75
		if ($this->dblink)
76
		{
77
			if (!@mysql_select_db($this->config["mysql_database"], $this->dblink))
78
			{
79
				@mysql_close($this->dblink);
80
				$this->dblink = false;
81
			}
82
		}
83
		$this->VERSION = WAKKA_VERSION;
84
 
85
		//determine le chemin pour le cookie
86
		$a = parse_url($this->GetConfigValue('base_url'));
87
		$this->CookiePath = dirname($a['path']);
88
		if ($this->CookiePath != '/') $this->CookiePath .= '/';
89
	}
90
 
91
 
92
 
93
	// DATABASE
94
	function Query($query)
95
	{
96
		if($this->GetConfigValue("debug")) $start = $this->GetMicroTime();
97
		if (!$result = mysql_query($query, $this->dblink))
98
		{
99
			ob_end_clean();
100
			die("Query failed: ".$query." (".mysql_error().")");
101
		}
102
		if($this->GetConfigValue("debug"))
103
		{
104
			$time = $this->GetMicroTime() - $start;
105
			$this->queryLog[] = array(
106
				"query"		=> $query,
107
				"time"		=> $time);
108
		}
109
		return $result;
110
	}
111
	function LoadSingle($query) { if ($data = $this->LoadAll($query)) return $data[0]; }
112
	function LoadAll($query)
113
	{
114
	$data=array();
115
	if ($r = $this->Query($query))
116
		{
117
			while ($row = mysql_fetch_assoc($r)) $data[] = $row;
118
			mysql_free_result($r);
119
		}
120
		return $data;
121
	}
122
 
123
 
124
 
125
	// MISC
126
	function GetMicroTime() { list($usec, $sec) = explode(" ",microtime()); return ((float)$usec + (float)$sec); }
127
	function IncludeBuffered($filename, $notfoundText = "", $vars = "", $path = "")
128
	{
129
		if ($path) $dirs = explode(":", $path);
130
		else $dirs = array("");
131
 
132
		foreach($dirs as $dir)
133
		{
134
			if ($dir) $dir .= "/";
135
			$fullfilename = $dir.$filename;
136
			if (file_exists($fullfilename))
137
			{
138
				if (is_array($vars)) extract($vars);
139
 
140
				ob_start();
141
				include($fullfilename);
142
				$output = ob_get_contents();
143
				ob_end_clean();
144
				return $output;
145
			}
146
		}
147
		if ($notfoundText) return $notfoundText;
148
		else return false;
149
	}
150
 
151
 
152
 
153
	// VARIABLES
154
	function GetPageTag() { return $this->tag; }
155
	function GetPageTime() { return $this->page["time"]; }
156
	function GetMethod() { return $this->method; }
157
	function GetConfigValue($name) { return $this->config[$name]; }
158
	function GetWakkaName() { return $this->GetConfigValue("wakka_name"); }
159
	function GetWakkaVersion() { return $this->VERSION; }
160
	function GetWikiNiVersion() { return WIKINI_VERSION; }
161
 
162
 
163
 
164
	// PAGES
165
	function LoadPage($tag, $time = "", $cache = 1) {
166
		// retrieve from cache
167
		if (!$time && $cache && ($cachedPage = $this->GetCachedPage($tag))) { $page = $cachedPage;}
168
		// load page
169
		if (!isset($page)) $page = $this->LoadSingle("select * from ".$this->config["table_prefix"]."pages where tag = '".mysql_escape_string($tag)."' ".($time ? "and time = '".mysql_escape_string($time)."'" : "and latest = 'Y'")." limit 1");
170
		// cache result
171
		if (!$time) $this->CachePage($page);
172
		return $page;
173
	}
174
	function GetCachedPage($tag) {return (isset($this->pageCache[$tag]) ? $this->pageCache[$tag] : ''); }
175
	function CachePage($page) { $this->pageCache[$page["tag"]] = $page; }
176
	function SetPage($page) { $this->page = $page; if ($this->page["tag"]) $this->tag = $this->page["tag"]; }
177
	function LoadPageById($id) { return $this->LoadSingle("select * from ".$this->config["table_prefix"]."pages where id = '".mysql_escape_string($id)."' limit 1"); }
178
	function LoadRevisions($page) { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where tag = '".mysql_escape_string($page)."' order by time desc"); }
179
	function LoadPagesLinkingTo($tag) { return $this->LoadAll("select from_tag as tag from ".$this->config["table_prefix"]."links where to_tag = '".mysql_escape_string($tag)."' order by tag"); }
180
	function LoadRecentlyChanged($limit=50) {
181
		$limit= (int) $limit;
182
		if ($pages = $this->LoadAll("select tag, time, user, owner from ".$this->config["table_prefix"]."pages where latest = 'Y' and comment_on = '' order by time desc limit $limit"))
183
		{
184
			foreach ($pages as $page)
185
			{
186
				$this->CachePage($page);
187
			}
188
			return $pages;
189
		}
190
	}
191
	function LoadAllPages() { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where latest = 'Y' order by tag"); }
192
	function FullTextSearch($phrase) { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where latest = 'Y' and match(tag, body) against('".mysql_escape_string($phrase)."')"); }
193
	function LoadWantedPages() { return $this->LoadAll("select distinct ".$this->config["table_prefix"]."links.to_tag as tag,count(".$this->config["table_prefix"]."links.from_tag) as count from ".$this->config["table_prefix"]."links left join ".$this->config["table_prefix"]."pages on ".$this->config["table_prefix"]."links.to_tag = ".$this->config["table_prefix"]."pages.tag where ".$this->config["table_prefix"]."pages.tag is NULL group by tag order by count desc"); }
194
	function LoadOrphanedPages() { return $this->LoadAll("select distinct tag from ".$this->config["table_prefix"]."pages left join ".$this->config["table_prefix"]."links on ".$this->config["table_prefix"]."pages.tag = ".$this->config["table_prefix"]."links.to_tag where ".$this->config["table_prefix"]."links.to_tag is NULL and ".$this->config["table_prefix"]."pages.comment_on = '' order by tag"); }
195
	function IsOrphanedPage($tag) { return $this->LoadAll("select distinct tag from ".$this->config["table_prefix"]."pages left join ".$this->config["table_prefix"]."links on ".$this->config["table_prefix"]."pages.tag = ".$this->config["table_prefix"]."links.to_tag where ".$this->config["table_prefix"]."links.to_tag is NULL and ".$this->config["table_prefix"]."pages.comment_on ='' and tag='".mysql_escape_string($tag)."'"); }
196
	function DeleteOrphanedPage($tag) {
197
		$this->Query("delete from ".$this->config["table_prefix"]."pages where tag='".mysql_escape_string($tag)."' ");
198
		$this->Query("delete from ".$this->config["table_prefix"]."links where from_tag='".mysql_escape_string($tag)."' ");
199
		$this->Query("delete from ".$this->config["table_prefix"]."acls where page_tag='".mysql_escape_string($tag)."' ");
200
		$this->Query("delete from ".$this->config["table_prefix"]."referrers where page_tag='".mysql_escape_string($tag)."' ");
201
	}
202
	function SavePage($tag, $body, $comment_on = "") {
203
		// get current user
204
		$user = $this->GetUserName();
205
 
206
		//die($tag);
207
 
208
		// TODO: check write privilege
209
		if ($this->HasAccess("write", $tag))
210
		{
211
			// is page new?
212
			if (!$oldPage = $this->LoadPage($tag))
213
			{
214
				// create default write acl. store empty write ACL for comments.
215
				$this->SaveAcl($tag, "write", ($comment_on ? "" : $this->GetConfigValue("default_write_acl")));
216
 
217
				// create default read acl
218
				$this->SaveAcl($tag, "read", $this->GetConfigValue("default_read_acl"));
219
 
220
				// create default comment acl.
221
				$this->SaveAcl($tag, "comment", $this->GetConfigValue("default_comment_acl"));
222
 
223
				// current user is owner; if user is logged in! otherwise, no owner.
224
				if ($this->GetUser()) $owner = $user;
225
			}
226
			else
227
			{
228
				// aha! page isn't new. keep owner!
229
				$owner = $oldPage["owner"];
230
			}
231
 
232
 
233
			// set all other revisions to old
234
			$this->Query("update ".$this->config["table_prefix"]."pages set latest = 'N' where tag = '".mysql_Escape_string($tag)."'");
235
 
236
			// add new revision
237
			$this->Query("insert into ".$this->config["table_prefix"]."pages set ".
238
				"tag = '".mysql_escape_string($tag)."', ".
239
				($comment_on ? "comment_on = '".mysql_escape_string($comment_on)."', " : "").
240
				"time = now(), ".
241
				"owner = '".mysql_escape_string($owner)."', ".
242
				"user = '".mysql_escape_string($user)."', ".
243
				"latest = 'Y', ".
244
				"body = '".mysql_escape_string(chop($body))."'");
245
		}
246
	}
247
	function PurgePages() {
248
		if ($days = $this->GetConfigValue("pages_purge_time")) {
249
			// Selection of pages which can be deleted
250
			$pages = $this->LoadAll("select distinct tag, time from ".$this->config["table_prefix"]."pages where time < date_sub(now(), interval '".mysql_escape_string($days)."' day) and latest = 'N' order by time asc");
251
			foreach ($pages as $page) {
252
				// Deletion if there are more than 2 versions avalaible (TODO : parameter ?)
253
				$tags=$this->LoadAll("select distinct tag from ".$this->config["table_prefix"]."pages where tag = '".mysql_escape_string($page[tag])."' group by tag having count(*) > 2 order by tag");
254
				foreach ($tags as $tag) {
255
					$this->Query("delete from ".$this->config["table_prefix"]."pages where time = '".mysql_escape_string($page[time])."' and tag = '".mysql_escape_string($tag[tag])."'");
256
				}
257
			}
258
		}
259
	}
260
 
261
 
262
 
263
	// COOKIES
264
	function SetSessionCookie($name, $value) { SetCookie($name, $value, 0, $this->CookiePath); $_COOKIE[$name] = $value; }
265
	function SetPersistentCookie($name, $value, $remember = 0) { SetCookie($name, $value, time() + ($remember ? 90*24*60*60 : 60 * 60), $this->CookiePath); $_COOKIE[$name] = $value; }
266
	function DeleteCookie($name) { SetCookie($name, "", 1, $this->CookiePath); $_COOKIE[$name] = ""; }
267
	function GetCookie($name) { return $_COOKIE[$name]; }
268
 
269
 
270
 
271
	// HTTP/REQUEST/LINK RELATED
272
	function SetMessage($message) { $_SESSION["message"] = $message; }
273
	function GetMessage()
274
	{
275
		if (isset($_SESSION["message"])) $message = $_SESSION["message"];
276
		else $message = "";
277
		$_SESSION["message"] = "";
278
		return $message;
279
	}
280
	function Redirect($url)
281
	{
282
		header("Location: $url");
283
		exit;
284
	}
285
	// returns just PageName[/method].
286
	function MiniHref($method = "", $tag = "")
287
	{
288
		if (!$tag = trim($tag)) $tag = $this->tag;
289
		return $tag.($method ? "/".$method : "");
290
	}
291
	// returns the full url to a page/method.
292
	function Href($method = "", $tag = "", $params = "")
293
	{
294
		$href = $this->config["base_url"].$this->MiniHref($method, $tag);
295
		if ($params)
296
		{
297
			$href .= ($this->config["rewrite_mode"] ? "?" : "&amp;").$params;
298
		}
299
		return $href;
300
	}
301
	function Link($tag, $method = "", $text = "", $track = 1) {
302
		$tag=htmlspecialchars($tag); //avoid xss
303
		$text=htmlspecialchars($text); //paranoiac again
304
		if (!$text) $text = $tag;
305
 
306
		// is this an interwiki link?
307
		if (preg_match("/^([A-Z][A-Z,a-z]+)[:]([A-Z,a-z,0-9]*)$/s", $tag, $matches))
308
		{
309
			$tag = $this->GetInterWikiUrl($matches[1], $matches[2]);
310
			return "<a href=\"$tag\">$text (interwiki)</a>";
311
		}
312
		// is this a full link? ie, does it contain non alpha-numeric characters?
313
		// Note : [:alnum:] is equivalent [0-9A-Za-z]
314
		//        [^[:alnum:]] means : some caracters other than [0-9A-Za-z]
315
		// For example : "www.adress.com", "mailto:adress@domain.com", "http://www.adress.com"
316
		else if (preg_match("/[^[:alnum:]]/", $tag))
317
		{
318
			// check for email addresses
319
			if (preg_match("/^.+\@.+$/", $tag))
320
			{
321
				$tag = "mailto:".$tag;
322
			}
323
			// check for protocol-less URLs
324
			else if (!preg_match("/:\/\//", $tag))
325
			{
326
				$tag = "http://".$tag;	//Very important for xss (avoid javascript:() hacking)
327
			}
328
			// is this an inline image (text!=tag and url ends png,gif,jpeg)
329
			if ($text!=$tag and preg_match("/.(gif|jpeg|png|jpg)$/i",$tag))
330
			{
331
				return "<img src=\"$tag\" alt=\"$text\" />";
332
			}
333
			else
334
			{
335
				return "<a href=\"$tag\">$text</a>";
336
			}
337
		}
338
		else
339
		{
340
			// it's a Wiki link!
341
			if (isset($_SESSION["linktracking"]) && $track) $this->TrackLinkTo($tag);
342
			return ($this->LoadPage($tag) ? "<a href=\"".$this->href($method, $tag)."\">".$text."</a>" : "<span class=\"missingpage\">".$text."</span><a href=\"".$this->href("edit", $tag)."\">?</a>");
343
		}
344
	}
345
	function ComposeLinkToPage($tag, $method = "", $text = "", $track = 1) {
346
		if (!$text) $text = $tag;
347
		$text = htmlentities($text);
348
		if (isset($_SESSION["linktracking"]) && $track)
349
			$this->TrackLinkTo($tag);
350
		return '<a href="'.$this->href($method, $tag).'">'.$text.'</a>';
351
	}
352
	// function PregPageLink($matches) { return $this->Link($matches[1]); }
353
	function IsWikiName($text) { return preg_match("/^[A-Z][a-z]+[A-Z,0-9][A-Z,a-z,0-9]*$/", $text); }
354
	function TrackLinkTo($tag) { $_SESSION["linktable"][] = $tag; }
355
	function GetLinkTable() { return $_SESSION["linktable"]; }
356
	function ClearLinkTable() { $_SESSION["linktable"] = array(); }
357
	function StartLinkTracking() { $_SESSION["linktracking"] = 1; }
358
	function StopLinkTracking() { $_SESSION["linktracking"] = 0; }
359
	function WriteLinkTable() {
360
		// delete old link table
361
		$this->Query("delete from ".$this->config["table_prefix"]."links where from_tag = '".mysql_escape_string($this->GetPageTag())."'");
362
		if ($linktable = $this->GetLinkTable())
363
		{
364
			$from_tag = mysql_escape_string($this->GetPageTag());
365
			foreach ($linktable as $to_tag)
366
			{
367
				$lower_to_tag = strtolower($to_tag);
368
				if (!$written[$lower_to_tag])
369
				{
370
					$this->Query("insert into ".$this->config["table_prefix"]."links set from_tag = '".$from_tag."', to_tag = '".mysql_escape_string($to_tag)."'");
371
					$written[$lower_to_tag] = 1;
372
				}
373
			}
374
		}
375
	}
376
	function Header() { return $this->Action($this->GetConfigValue("header_action"), 1); }
377
	function Footer() { return $this->Action($this->GetConfigValue("footer_action"), 1); }
378
 
379
 
380
 
381
	// FORMS
382
	function FormOpen($method = "", $tag = "", $formMethod = "post") {
383
		$result = "<form action=\"".$this->href($method, $tag)."\" method=\"".$formMethod."\">\n";
384
		if (!$this->config["rewrite_mode"]) $result .= "<input type=\"hidden\" name=\"wiki\" value=\"".$this->MiniHref($method, $tag)."\" />\n";
385
		return $result;
386
	}
387
	function FormClose() {
388
		return "</form>\n";
389
	}
390
 
391
 
392
 
393
	// INTERWIKI STUFF
394
	function ReadInterWikiConfig() {
395
		if ($lines = file("interwiki.conf"))
396
		{
397
			foreach ($lines as $line)
398
			{
399
				if ($line = trim($line))
400
				{
401
					list($wikiName, $wikiUrl) = explode(" ", trim($line));
402
					$this->AddInterWiki($wikiName, $wikiUrl);
403
				}
404
			}
405
		}
406
	}
407
	function AddInterWiki($name, $url) {
408
		$this->interWiki[$name] = $url;
409
	}
410
	function GetInterWikiUrl($name, $tag) {
411
		if (isset($this->interWiki[$name]))
412
		{
413
			return $this->interWiki[$name].$tag;
414
		} else {
415
		return 'http://'.$tag; //avoid xss by putting http:// in front of JavaScript:()
416
		}
417
	}
418
 
419
 
420
 
421
	// REFERRERS
422
	function LogReferrer($tag = "", $referrer = "") {
423
		// fill values
424
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
425
		if (!$referrer = trim($referrer) AND isset($_SERVER["HTTP_REFERER"])) $referrer = $_SERVER["HTTP_REFERER"];
426
 
427
		// check if it's coming from another site
428
		if ($referrer && !preg_match("/^".preg_quote($this->GetConfigValue("base_url"), "/")."/", $referrer))
429
		{
430
			$this->Query("insert into ".$this->config["table_prefix"]."referrers set ".
431
				"page_tag = '".mysql_escape_string($tag)."', ".
432
				"referrer = '".mysql_escape_string($referrer)."', ".
433
				"time = now()");
434
		}
435
	}
436
	function LoadReferrers($tag = "") {
437
		return $this->LoadAll("select referrer, count(referrer) as num from ".$this->config["table_prefix"]."referrers ".($tag = trim($tag) ? "where page_tag = '".mysql_escape_string($tag)."'" : "")." group by referrer order by num desc");
438
	}
439
	function PurgeReferrers() {
440
		if ($days = $this->GetConfigValue("referrers_purge_time")) {
441
			$this->Query("delete from ".$this->config["table_prefix"]."referrers where time < date_sub(now(), interval '".mysql_escape_string($days)."' day)");
442
		}
443
	}
444
 
445
 
446
 
447
	// PLUGINS
448
	function Action($action, $forceLinkTracking = 0)
449
	{
450
		$action = trim($action); $vars=array();
451
		// stupid attributes check
452
		if ((stristr($action, "=\"")) || (stristr($action, "/")))
453
		{
454
			// extract $action and $vars_temp ("raw" attributes)
455
			preg_match("/^([A-Za-z0-9]*)\/?(.*)$/", $action, $matches);
456
			list(, $action, $vars_temp) = $matches;
457
			// match all attributes (key and value)
458
			$this->parameter[$vars_temp]=$vars_temp;
459
			preg_match_all("/([A-Za-z0-9]*)=\"(.*)\"/U", $vars_temp, $matches);
460
 
461
		// prepare an array for extract() to work with (in $this->IncludeBuffered())
462
		if (is_array($matches))
463
			{
464
				for ($a = 0; $a < count($matches[1]); $a++)
465
				{
466
					$vars[$matches[1][$a]] = $matches[2][$a];
467
					$this->parameter[$matches[1][$a]]=$matches[2][$a];
468
				}
469
			}
470
		}
471
		if (!$forceLinkTracking) $this->StopLinkTracking();
472
		$result = $this->IncludeBuffered(strtolower($action).".php", "<i>Action inconnue \"$action\"</i>", $vars, $this->config["action_path"]);
473
		$this->StartLinkTracking();
474
		if (isset($parameter)) unset($this->parameter[$parameter]);
475
		unset($this->parameter);
476
		return $result;
477
	}
478
	function Method($method) {
479
		if (!$handler = $this->page["handler"]) $handler = "page";
480
		$methodLocation = $handler."/".$method.".php";
481
		return $this->IncludeBuffered($methodLocation, "<i>M&eacute;thode inconnue \"$methodLocation\"</i>", "", $this->config["handler_path"]);
482
	}
483
	function Format($text, $formatter = "wakka") {
484
		return $this->IncludeBuffered("formatters/".$formatter.".php", "<i>Impossible de trouver le formateur \"$formatter\"</i>", compact("text"));
485
	}
486
 
487
 
488
 
489
	// USERS
490
	function LoadUser($name, $password = 0) { return $this->LoadSingle("select * from ".$this->config["table_prefix"]."users where name = '".mysql_escape_string($name)."' ".($password === 0 ? "" : "and password = '".mysql_escape_string($password)."'")." limit 1"); }
491
	function LoadUsers() { return $this->LoadAll("select * from ".$this->config["table_prefix"]."users order by name"); }
492
	function GetUserName() { if ($user = $this->GetUser()) $name = $user["name"]; else if (!$name = gethostbyaddr($_SERVER["REMOTE_ADDR"])) $name = $_SERVER["REMOTE_ADDR"]; return $name; }
493
	function UserName() { /* deprecated! */ return $this->GetUserName(); }
494
	function GetUser() { return (isset($_SESSION["user"]) ? $_SESSION["user"] : '');}
495
	function SetUser($user, $remember=0) { $_SESSION["user"] = $user; $this->SetPersistentCookie("name", $user["name"], $remember); $this->SetPersistentCookie("password", $user["password"], $remember); $this->SetPersistentCookie("remember", $remember, $remember); }
496
	function LogoutUser() { $_SESSION["user"] = ""; $this->DeleteCookie("name"); $this->DeleteCookie("password"); }
497
	function UserWantsComments() { if (!$user = $this->GetUser()) return false; return ($user["show_comments"] == "Y"); }
498
	function GetParameter($parameter, $default = '') { return (isset($this->parameter[$parameter]) ? $this->parameter[$parameter] : $default); }
499
 
500
 
501
 
502
	// COMMENTS
503
	function LoadComments($tag) { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where comment_on = '".mysql_escape_string($tag)."' and latest = 'Y' order by time"); }
504
	function LoadRecentComments() { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where comment_on != '' and latest = 'Y' order by time desc"); }
505
	function LoadRecentlyCommented($limit = 50) {
506
		// NOTE: this is really stupid. Maybe my SQL-Fu is too weak, but apparently there is no easier way to simply select
507
		//       all comment pages sorted by their first revision's (!) time. ugh!
508
 
509
		// load ids of the first revisions of latest comments. err, huh?
510
		$pages=array();
511
		$comments=array();
512
		if ($ids = $this->LoadAll("select min(id) as id from ".$this->config["table_prefix"]."pages where comment_on != '' group by tag order by id desc"))
513
		{
514
			// load complete comments
515
			$num=0;
516
			foreach ($ids as $id)
517
			{
518
				$comment = $this->LoadSingle("select * from ".$this->config["table_prefix"]."pages where id = '".$id["id"]."' limit 1");
519
				if (!isset($comments[$comment["comment_on"]]) && $num < $limit)
520
				{
521
					$comments[$comment["comment_on"]] = $comment;
522
					$num++;
523
				}
524
			}
525
 
526
			// now load pages
527
			if ($comments)
528
			{
529
				// now using these ids, load the actual pages
530
				foreach ($comments as $comment)
531
				{
532
					$page = $this->LoadPage($comment["comment_on"]);
533
					$page["comment_user"] = $comment["user"];
534
					$page["comment_time"] = $comment["time"];
535
					$page["comment_tag"] = $comment["tag"];
536
					$pages[] = $page;
537
				}
538
			}
539
		}
540
		// load tags of pages
541
		//return $this->LoadAll("select comment_on as tag, max(time) as time, tag as comment_tag, user from ".$this->config["table_prefix"]."pages where comment_on != '' group by comment_on order by time desc");
542
		return $pages;
543
	}
544
 
545
 
546
 
547
	// ACCESS CONTROL
548
	// returns true if logged in user is owner of current page, or page specified in $tag
549
	function UserIsOwner($tag = "") {
550
		// check if user is logged in
551
		if (!$this->GetUser()) return false;
552
 
553
		// set default tag
554
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
555
 
556
		// check if user is owner
557
		if ($this->GetPageOwner($tag) == $this->GetUserName()) return true;
558
	}
559
	function GetPageOwner($tag = "", $time = "") { if (!$tag = trim($tag)) $tag = $this->GetPageTag(); if ($page = $this->LoadPage($tag, $time)) return $page["owner"]; }
560
	function SetPageOwner($tag, $user) {
561
		// check if user exists
562
		if (!$this->LoadUser($user)) return;
563
 
564
		// updated latest revision with new owner
565
		$this->Query("update ".$this->config["table_prefix"]."pages set owner = '".mysql_escape_string($user)."' where tag = '".mysql_escape_string($tag)."' and latest = 'Y' limit 1");
566
	}
567
	function LoadAcl($tag, $privilege, $useDefaults = 1) {
568
		if ((!$acl = $this->LoadSingle("select * from ".$this->config["table_prefix"]."acls where page_tag = '".mysql_escape_string($tag)."' and privilege = '".mysql_escape_string($privilege)."' limit 1")) && $useDefaults)
569
		{
570
			$acl = array("page_tag" => $tag, "privilege" => $privilege, "list" => $this->GetConfigValue("default_".$privilege."_acl"));
571
		}
572
		return $acl;
573
	}
574
	function SaveAcl($tag, $privilege, $list) {
575
		if ($this->LoadAcl($tag, $privilege, 0)) $this->Query("update ".$this->config["table_prefix"]."acls set list = '".mysql_escape_string(trim(str_replace("\r", "", $list)))."' where page_tag = '".mysql_escape_string($tag)."' and privilege = '".mysql_escape_string($privilege)."' limit 1");
576
		else $this->Query("insert into ".$this->config["table_prefix"]."acls set list = '".mysql_escape_string(trim(str_replace("\r", "", $list)))."', page_tag = '".mysql_escape_string($tag)."', privilege = '".mysql_escape_string($privilege)."'");
577
	}
578
	// returns true if $user (defaults to current user) has access to $privilege on $page_tag (defaults to current page)
579
	function HasAccess($privilege, $tag = "", $user = "") {
580
		// set defaults
581
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
582
		if (!$user = $this->GetUserName());
583
 
584
		// load acl
585
		$acl = $this->LoadAcl($tag, $privilege);
586
 
587
		// if current user is owner, return true. owner can do anything!
588
		if ($this->UserIsOwner($tag)) return true;
589
 
590
		// fine fine... now go through acl
591
		foreach (explode("\n", $acl["list"]) as $line)
592
		{
593
			$line = trim($line);
594
 
595
			// check for inversion character "!"
596
			if (preg_match("/^[!](.*)$/", $line, $matches))
597
			{
598
				$negate = 1;
599
				$line = $matches[1];
600
			}
601
			else
602
			{
603
				$negate = 0;
604
			}
605
 
606
			// if there's still anything left... lines with just a "!" don't count!
607
			if ($line)
608
			{
609
				switch ($line[0])
610
				{
611
				// comments
612
				case "#":
613
					break;
614
				// everyone
615
				case "*":
616
					return !$negate;
617
				// aha! a user entry.
618
				case "+":
619
					if (!$this->LoadUser($user))
620
					{
621
						return $negate;
622
					}
623
					else
624
					{
625
						return !$negate;
626
					}
627
				default:
628
					if ($line == $user)
629
					{
630
						return !$negate;
631
					}
632
				}
633
			}
634
		}
635
 
636
		// tough luck.
637
		return false;
638
	}
639
 
640
 
641
 
642
	// MAINTENANCE
643
	function Maintenance() {
644
		// purge referrers
645
		$this->PurgeReferrers();
646
		// purge old page revisions
647
		$this->PurgePages();
648
	}
649
 
650
 
651
 
652
	// THE BIG EVIL NASTY ONE!
653
	function Run($tag, $method = "") {
654
		if(!($this->GetMicroTime()%3)) $this->Maintenance();
655
 
656
		$this->ReadInterWikiConfig();
657
 
658
		// do our stuff!
659
		if (!$this->method = trim($method)) $this->method = "show";
660
		if (!$this->tag = trim($tag)) $this->Redirect($this->href("", $this->config["root_page"]));
661
		if ((!$this->GetUser() && isset($_COOKIE["name"])) && ($user = $this->LoadUser($_COOKIE["name"], $_COOKIE["password"]))) $this->SetUser($user, $_COOKIE["remember"]);
662
		$this->SetPage($this->LoadPage($tag, (isset($_REQUEST["time"]) ? $_REQUEST["time"] :'')));
663
		$this->LogReferrer();
664
 
665
      //correction pour un support plus facile de nouveaux handlers
666
      print($this->Method($this->method));
667
	}
668
}
669
 
670
 
671
 
672
// stupid version check
673
if (!isset($_REQUEST)) die('$_REQUEST[] not found. Wakka requires PHP 4.1.0 or higher!');
674
 
675
// workaround for the amazingly annoying magic quotes.
676
function magicQuotesSuck(&$a)
677
{
678
	if (is_array($a))
679
	{
680
		foreach ($a as $k => $v)
681
		{
682
			if (is_array($v))
683
				magicQuotesSuck($a[$k]);
684
			else
685
				$a[$k] = stripslashes($v);
686
		}
687
	}
688
}
689
set_magic_quotes_runtime(0);
690
if (get_magic_quotes_gpc())
691
{
692
	magicQuotesSuck($_POST);
693
	magicQuotesSuck($_GET);
694
	magicQuotesSuck($_COOKIE);
695
}
696
 
697
 
698
// default configuration values
699
$wakkaConfig= array();
700
$wakkaDefaultConfig = array(
701
	'wakka_version'		=> '',
702
	'wikini_version'	=> '',
703
	'debug'			=> 'no',
704
	"mysql_host"		=> "localhost",
705
	"mysql_database"		=> "wikini",
706
	"mysql_user"		=> "wikini",
707
	"mysql_password"		=> '',
708
	"table_prefix"		=> "wikini_",
709
	"root_page"			=> "PagePrincipale",
710
	"wakka_name"		=> "MonSiteWikiNi",
711
	"base_url"			=> "http://".$_SERVER["SERVER_NAME"].($_SERVER["SERVER_PORT"] != 80 ? ":".$_SERVER["SERVER_PORT"] : "").$_SERVER["REQUEST_URI"].(preg_match("/".preg_quote("wakka.php")."$/", $_SERVER["REQUEST_URI"]) ? "?wiki=" : ""),
712
	"rewrite_mode"		=> (preg_match("/".preg_quote("wakka.php")."$/", $_SERVER["REQUEST_URI"]) ? "0" : "1"),
713
	'meta_keywords'		=> '',
714
	'meta_description'	=> '',
715
	"action_path"		=> "actions",
716
	"handler_path"		=> "handlers",
717
	"header_action"		=> "header",
718
	"footer_action"		=> "footer",
719
	"navigation_links"		=> "DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur",
720
	"referrers_purge_time"	=> 24,
721
	"pages_purge_time"	=> 90,
722
	"default_write_acl"	=> "*",
723
	"default_read_acl"	=> "*",
724
	"default_comment_acl"	=> "*",
725
	"preview_before_save"	=> "0");
726
 
727
// load config
728
if (!$configfile = GetEnv("WAKKA_CONFIG")) $configfile = "wakka.config.php";
729
if (file_exists($configfile)) include($configfile);
730
$wakkaConfigLocation = $configfile;
731
$wakkaConfig = array_merge($wakkaDefaultConfig, $wakkaConfig);
732
 
733
// check for locking
734
if (file_exists("locked")) {
735
	// read password from lockfile
736
	$lines = file("locked");
737
	$lockpw = trim($lines[0]);
738
 
739
	// is authentification given?
740
	if (isset($_SERVER["PHP_AUTH_USER"])) {
741
		if (!(($_SERVER["PHP_AUTH_USER"] == "admin") && ($_SERVER["PHP_AUTH_PW"] == $lockpw))) {
742
			$ask = 1;
743
		}
744
	} else {
745
		$ask = 1;
746
	}
747
 
748
	if ($ask) {
749
		header("WWW-Authenticate: Basic realm=\"".$wakkaConfig["wakka_name"]." Install/Upgrade Interface\"");
750
		header("HTTP/1.0 401 Unauthorized");
751
		echo "Ce site est en cours de mise &agrave; jour. Veuillez essayer plus tard." ;
752
		exit;
753
	}
754
}
755
 
756
 
757
// compare versions, start installer if necessary
758
if ($wakkaConfig["wakka_version"] && (!$wakkaConfig["wikini_version"])) { $wakkaConfig["wikini_version"]=$wakkaConfig["wakka_version"]; }
759
if (($wakkaConfig["wakka_version"] != WAKKA_VERSION) || ($wakkaConfig["wikini_version"] != WIKINI_VERSION)) {
760
	// start installer
761
	if (!isset($_REQUEST["installAction"]) OR !$installAction = trim($_REQUEST["installAction"])) $installAction = "default";
762
	include("setup/header.php");
763
	if (file_exists("setup/".$installAction.".php")) include("setup/".$installAction.".php"); else echo "<i>Invalid action</i>" ;
764
	include("setup/footer.php");
765
	exit;
766
}
767
 
768
 
769
// configuration du cookie de session
770
//determine le chemin pour le cookie
771
$a = parse_url($wakkaConfig['base_url']);
772
$CookiePath = dirname($a['path']);
773
if ($CookiePath != '/') $CookiePath .= '/';
774
$a = session_get_cookie_params();
775
session_set_cookie_params($a['lifetime'],$CookiePath);
776
unset($a);
777
unset($CookiePath);
778
 
779
// start session
780
session_start();
781
 
782
// fetch wakka location
783
if (!isset($_REQUEST["wiki"])) $_REQUEST["wiki"] = '';
784
 
785
$wiki = $_REQUEST["wiki"];
786
 
787
// remove leading slash
788
$wiki = preg_replace("/^\//", "", $wiki);
789
 
790
// split into page/method
791
if (preg_match("#^(.+?)/([A-Za-z0-9_]*)$#", $wiki, $matches)) list(, $page, $method) = $matches;
792
else if (preg_match("#^(.*)$#", $wiki, $matches)) list(, $page) = $matches;
793
 
794
// create wiki object
795
$wiki = new Wiki($wakkaConfig);
796
// check for database access
797
if (!$wiki->dblink)
798
{
799
	echo "<p>Pour des raisons ind&eacute;pendantes de notre volont&eacute;, le contenu de ce Wiki est temporairement inaccessible. Veuillez r&eacute;essayer ult&eacute;rieurement, merci de votre compr&eacute;hension.</p>";
800
	exit;
801
}
802
 
803
function compress_output($output)
804
{
805
	return gzencode($output);
806
}
807
 
808
// Check if the browser supports gzip encoding, HTTP_ACCEPT_ENCODING
809
if (strstr ($HTTP_SERVER_VARS['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') )
810
{
811
	// Start output buffering, and register compress_output() (see
812
	// below)
813
	ob_start ("compress_output");
814
 
815
	// Tell the browser the content is compressed with gzip
816
	header ("Content-Encoding: gzip");
817
}
818
 
819
 
820
// go!
821
if (!isset($method)) $method='';
822
 
823
// Security (quick hack)  : Check method syntax
824
if (!(preg_match('#^[A-Za-z0-9_]*$#',$method))) {
825
	$method='';
826
}
827
 
828
$wiki->Run($page, $method);
829
?>