Subversion Repositories Applications.wikini

Rev

Rev 43 | Rev 54 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 43 Rev 45
Line 1... Line -...
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
	/* Debut de la modif ACeditor */
-
 
384
	// ACEditor: id=\"ACEditor\" name=\"ACEditor\" ci-dessous le if a été ajouté (initialement, seule la ligne du else existait)
-
 
385
	// si l'url se termine par edit (expression régulière edit$), on est en mode édition et dans ce cas on donne les id et name au formulaire
-
 
386
	// Sinon surtout pas car ça marche plus dans la mesure ou plusieurs formulaires auraient ces ID et name et dans ce cas
-
 
387
	// il semble que le dernier soit considéré, c'est à dire pas le bon :o(
-
 
388
 
-
 
389
		if (ereg('edit$', $this->href($method, $tag))) {
-
 
390
			$result = "<form id=\"ACEditor\" name=\"ACEditor\" action=\"".$this->href($method, $tag)."\" method=\"".$formMethod."\">\n";
-
 
391
		} else {
-
 
392
		$result = "<form action=\"".$this->href($method, $tag)."\" method=\"".$formMethod."\">\n";
-
 
393
		}
-
 
394
 
-
 
395
/* fin de la modif ACeditor */
-
 
396
		if (!$this->config["rewrite_mode"]) $result .= "<input type=\"hidden\" name=\"wiki\" value=\"".$this->MiniHref($method, $tag)."\" />\n";
-
 
397
		return $result;
-
 
398
	}
-
 
399
	function FormClose() {
-
 
400
		return "</form>\n";
-
 
401
	}
-
 
402
 
-
 
403
 
-
 
404
 
-
 
405
	// INTERWIKI STUFF
-
 
406
	function ReadInterWikiConfig() {
-
 
407
		if ($lines = file("interwiki.conf"))
-
 
408
		{
-
 
409
			foreach ($lines as $line)
-
 
410
			{
-
 
411
				if ($line = trim($line))
-
 
412
				{
-
 
413
					list($wikiName, $wikiUrl) = explode(" ", trim($line));
-
 
414
					$this->AddInterWiki($wikiName, $wikiUrl);
-
 
415
				}
-
 
416
			}
-
 
417
		}
-
 
418
	}
-
 
419
	function AddInterWiki($name, $url) {
-
 
420
		$this->interWiki[$name] = $url;
-
 
421
	}
-
 
422
	function GetInterWikiUrl($name, $tag) {
-
 
423
		if (isset($this->interWiki[$name]))
-
 
424
		{
-
 
425
			return $this->interWiki[$name].$tag;
-
 
426
		} else {
-
 
427
		return 'http://'.$tag; //avoid xss by putting http:// in front of JavaScript:()
-
 
428
		}
-
 
429
	}
-
 
430
 
-
 
431
 
-
 
432
 
-
 
433
	// REFERRERS
-
 
434
	function LogReferrer($tag = "", $referrer = "") {
-
 
435
		// fill values
-
 
436
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
-
 
437
		if (!$referrer = trim($referrer) AND isset($_SERVER["HTTP_REFERER"])) $referrer = $_SERVER["HTTP_REFERER"];
-
 
438
		
-
 
439
		// check if it's coming from another site
-
 
440
		if ($referrer && !preg_match("/^".preg_quote($this->GetConfigValue("base_url"), "/")."/", $referrer))
-
 
441
		{
-
 
442
			$this->Query("insert into ".$this->config["table_prefix"]."referrers set ".
-
 
443
				"page_tag = '".mysql_escape_string($tag)."', ".
-
 
444
				"referrer = '".mysql_escape_string($referrer)."', ".
-
 
445
				"time = now()");
-
 
446
		}
-
 
447
	}
-
 
448
	function LoadReferrers($tag = "") {
-
 
449
		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");
-
 
450
	}
-
 
451
	function PurgeReferrers() {
-
 
452
		if ($days = $this->GetConfigValue("referrers_purge_time")) {
-
 
453
			$this->Query("delete from ".$this->config["table_prefix"]."referrers where time < date_sub(now(), interval '".mysql_escape_string($days)."' day)");
-
 
454
		}
-
 
455
	}
-
 
456
 
-
 
457
 
-
 
458
 
-
 
459
	// PLUGINS
-
 
460
	function Action($action, $forceLinkTracking = 0)
-
 
461
	{
-
 
462
		$action = trim($action); $vars=array();
-
 
463
		// stupid attributes check
-
 
464
		if ((stristr($action, "=\"")) || (stristr($action, "/")))
-
 
465
		{
-
 
466
			// extract $action and $vars_temp ("raw" attributes)
-
 
467
			preg_match("/^([A-Za-z0-9]*)\/?(.*)$/", $action, $matches);
-
 
468
			list(, $action, $vars_temp) = $matches;
-
 
469
			// match all attributes (key and value)
-
 
470
			$this->parameter[$vars_temp]=$vars_temp;
-
 
471
			preg_match_all("/([A-Za-z0-9]*)=\"(.*)\"/U", $vars_temp, $matches);
-
 
472
 
-
 
473
		// prepare an array for extract() to work with (in $this->IncludeBuffered())
-
 
474
		if (is_array($matches))
-
 
475
			{
-
 
476
				for ($a = 0; $a < count($matches[1]); $a++)
-
 
477
				{
-
 
478
					$vars[$matches[1][$a]] = $matches[2][$a];
-
 
479
					$this->parameter[$matches[1][$a]]=$matches[2][$a];
-
 
480
				}
-
 
481
			}
-
 
482
		}
-
 
483
		if (!$forceLinkTracking) $this->StopLinkTracking();
-
 
484
		$result = $this->IncludeBuffered(strtolower($action).".php", "<i>Action inconnue \"$action\"</i>", $vars, $this->config["action_path"]);
-
 
485
		$this->StartLinkTracking();
-
 
486
		if (isset($parameter)) unset($this->parameter[$parameter]);
-
 
487
		unset($this->parameter);
-
 
488
		return $result;
-
 
489
	}
-
 
490
	function Method($method) {
-
 
491
		if (!$handler = $this->page["handler"]) $handler = "page";
-
 
492
		$methodLocation = $handler."/".$method.".php";
-
 
493
		return $this->IncludeBuffered($methodLocation, "<i>M&eacute;thode inconnue \"$methodLocation\"</i>", "", $this->config["handler_path"]);
-
 
494
	}
-
 
495
	function Format($text, $formatter = "wakka") {
-
 
496
		return $this->IncludeBuffered("formatters/".$formatter.".php", "<i>Impossible de trouver le formateur \"$formatter\"</i>", compact("text")); 
-
 
497
	}
-
 
498
 
-
 
499
 
-
 
500
 
-
 
501
	// USERS
-
 
502
	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"); }
-
 
503
	function LoadUsers() { return $this->LoadAll("select * from ".$this->config["table_prefix"]."users order by name"); }
-
 
504
	function GetUserName() { if ($user = $this->GetUser()) $name = $user["name"]; else if (!$name = gethostbyaddr($_SERVER["REMOTE_ADDR"])) $name = $_SERVER["REMOTE_ADDR"]; return $name; }
-
 
505
	function UserName() { /* deprecated! */ return $this->GetUserName(); }
-
 
506
	function GetUser() { return (isset($_SESSION["user"]) ? $_SESSION["user"] : '');}
-
 
507
	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); }
-
 
508
	function LogoutUser() { $_SESSION["user"] = ""; $this->DeleteCookie("name"); $this->DeleteCookie("password"); }
-
 
509
	function UserWantsComments() { if (!$user = $this->GetUser()) return false; return ($user["show_comments"] == "Y"); }
-
 
510
	function GetParameter($parameter, $default = '') { return (isset($this->parameter[$parameter]) ? $this->parameter[$parameter] : $default); }
-
 
511
 
-
 
512
 
-
 
513
	
-
 
514
	// COMMENTS
-
 
515
	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"); }
-
 
516
	function LoadRecentComments() { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where comment_on != '' and latest = 'Y' order by time desc"); }
-
 
517
	function LoadRecentlyCommented($limit = 50) {
-
 
518
		// NOTE: this is really stupid. Maybe my SQL-Fu is too weak, but apparently there is no easier way to simply select
-
 
519
		//       all comment pages sorted by their first revision's (!) time. ugh!
-
 
520
		
-
 
521
		// load ids of the first revisions of latest comments. err, huh?
-
 
522
		$pages=array();
-
 
523
		$comments=array();
-
 
524
		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"))
-
 
525
		{
-
 
526
			// load complete comments
-
 
527
			foreach ($ids as $id)
-
 
528
			{
-
 
529
				$comment = $this->LoadSingle("select * from ".$this->config["table_prefix"]."pages where id = '".$id["id"]."' limit 1");
-
 
530
				$num=0;
-
 
531
				if (!isset($comments[$comment["comment_on"]])) $comments[$comment["comment_on"]]='';
-
 
532
				if (!$comments[$comment["comment_on"]] && $num < $limit)
-
 
533
				{
-
 
534
					$comments[$comment["comment_on"]] = $comment;
-
 
535
					$num++;
-
 
536
				}
-
 
537
			}
-
 
538
		
-
 
539
			// now load pages
-
 
540
			if ($comments)
-
 
541
			{
-
 
542
				// now using these ids, load the actual pages
-
 
543
				foreach ($comments as $comment)
-
 
544
				{
-
 
545
					$page = $this->LoadPage($comment["comment_on"]);
-
 
546
					$page["comment_user"] = $comment["user"];
-
 
547
					$page["comment_time"] = $comment["time"];
-
 
548
					$page["comment_tag"] = $comment["tag"];
-
 
549
					$pages[] = $page;
-
 
550
				}
-
 
551
			}
-
 
552
		}
-
 
553
		// load tags of pages 
-
 
554
		//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");
-
 
555
		return $pages;
-
 
556
	}
-
 
557
 
-
 
558
 
-
 
559
 
-
 
560
	// ACCESS CONTROL
-
 
561
	// returns true if logged in user is owner of current page, or page specified in $tag
-
 
562
	function UserIsOwner($tag = "") {
-
 
563
		// check if user is logged in
-
 
564
		if (!$this->GetUser()) return false;
-
 
565
 
-
 
566
		// set default tag
-
 
567
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
-
 
568
		
-
 
569
		// check if user is owner
-
 
570
		if ($this->GetPageOwner($tag) == $this->GetUserName()) return true;
-
 
571
	}
-
 
572
	function GetPageOwner($tag = "", $time = "") { if (!$tag = trim($tag)) $tag = $this->GetPageTag(); if ($page = $this->LoadPage($tag, $time)) return $page["owner"]; }
-
 
573
	function SetPageOwner($tag, $user) {
-
 
574
		// check if user exists
-
 
575
		if (!$this->LoadUser($user)) return;
-
 
576
		
-
 
577
		// updated latest revision with new owner
-
 
578
		$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");
-
 
579
	}
-
 
580
	function LoadAcl($tag, $privilege, $useDefaults = 1) {
-
 
581
		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)
-
 
582
		{
-
 
583
			$acl = array("page_tag" => $tag, "privilege" => $privilege, "list" => $this->GetConfigValue("default_".$privilege."_acl"));
-
 
584
		}
-
 
585
		return $acl;
-
 
586
	}
-
 
587
	function SaveAcl($tag, $privilege, $list) {
-
 
588
		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");
-
 
589
		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)."'");
-
 
590
	}
-
 
591
	// returns true if $user (defaults to current user) has access to $privilege on $page_tag (defaults to current page)
-
 
592
	function HasAccess($privilege, $tag = "", $user = "") {
-
 
593
		// set defaults
-
 
594
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
-
 
595
		if (!$user = $this->GetUserName());
-
 
596
		
-
 
597
		// load acl
-
 
598
		$acl = $this->LoadAcl($tag, $privilege);
-
 
599
		
-
 
600
		// if current user is owner, return true. owner can do anything!
-
 
601
		if ($this->UserIsOwner($tag)) return true;
-
 
602
		
-
 
603
		// fine fine... now go through acl
-
 
604
		foreach (explode("\n", $acl["list"]) as $line)
-
 
605
		{
-
 
606
			$line = trim($line);
-
 
607
 
-
 
608
			// check for inversion character "!"
-
 
609
			if (preg_match("/^[!](.*)$/", $line, $matches))
-
 
610
			{
-
 
611
				$negate = 1;
-
 
612
				$line = $matches[1];
-
 
613
			}
-
 
614
			else
-
 
615
			{
-
 
616
				$negate = 0;
-
 
617
			}
-
 
618
 
-
 
619
			// if there's still anything left... lines with just a "!" don't count!
-
 
620
			if ($line)
-
 
621
			{
-
 
622
				switch ($line[0])
-
 
623
				{
-
 
624
				// comments
-
 
625
				case "#":
-
 
626
					break;
-
 
627
				// everyone
-
 
628
				case "*":
-
 
629
					return !$negate;
-
 
630
				// aha! a user entry.
-
 
631
				case "+":
-
 
632
					if (!$this->LoadUser($user)) 
-
 
633
					{
-
 
634
						return $negate;
-
 
635
					}
-
 
636
					else
-
 
637
					{
-
 
638
						return !$negate;
-
 
639
					}
-
 
640
				default:
-
 
641
					if ($line == $user)
-
 
642
					{
-
 
643
						return !$negate;
-
 
644
					}
-
 
645
				}
-
 
646
			}
-
 
647
		}
-
 
648
		
-
 
649
		// tough luck.
-
 
650
		return false;
-
 
651
	}
-
 
652
 
-
 
653
 
-
 
654
 
-
 
655
	// MAINTENANCE
-
 
656
	function Maintenance() {
-
 
657
		// purge referrers
-
 
658
		$this->PurgeReferrers();
-
 
659
		// purge old page revisions
-
 
660
		$this->PurgePages();
-
 
661
	}
-
 
662
 
-
 
663
 
-
 
664
 
-
 
665
	// THE BIG EVIL NASTY ONE!
-
 
666
	function Run($tag, $method = "") {
-
 
667
		if(!($this->GetMicroTime()%3)) $this->Maintenance(); 
-
 
668
 
-
 
669
		$this->ReadInterWikiConfig();
-
 
670
 
-
 
671
		// do our stuff!
-
 
672
		if (!$this->method = trim($method)) $this->method = "show";
-
 
673
		if (!$this->tag = trim($tag)) $this->Redirect($this->href("", $this->config["root_page"]));
-
 
674
		if ((!$this->GetUser() && isset($_COOKIE["name"])) && ($user = $this->LoadUser($_COOKIE["name"], $_COOKIE["password"]))) $this->SetUser($user, $_COOKIE["remember"]);
-
 
675
		$this->SetPage($this->LoadPage($tag, (isset($_REQUEST["time"]) ? $_REQUEST["time"] :'')));
-
 
676
		$this->LogReferrer();
-
 
677
 
-
 
678
      //correction pour un support plus facile de nouveaux handlers
-
 
679
      print($this->Method($this->method));
-
 
680
	}
-
 
681
}
-
 
682
 
-
 
683
 
-
 
684
 
-
 
685
// stupid version check
-
 
686
if (!isset($_REQUEST)) die('$_REQUEST[] not found. Wakka requires PHP 4.1.0 or higher!');
-
 
687
 
-
 
688
// workaround for the amazingly annoying magic quotes.
-
 
689
function magicQuotesSuck(&$a)
-
 
690
{
-
 
691
	if (is_array($a))
-
 
692
	{
-
 
693
		foreach ($a as $k => $v)
-
 
694
		{
-
 
695
			if (is_array($v))
-
 
696
				magicQuotesSuck($a[$k]);
-
 
697
			else
-
 
698
				$a[$k] = stripslashes($v);
-
 
699
		}
-
 
700
	}
-
 
701
}
-
 
702
set_magic_quotes_runtime(0);
-
 
703
if (get_magic_quotes_gpc())
-
 
704
{
-
 
705
	magicQuotesSuck($_POST);
-
 
706
	magicQuotesSuck($_GET);
-
 
707
	magicQuotesSuck($_COOKIE);
-
 
708
}
-
 
709
 
-
 
710
 
-
 
711
// default configuration values
-
 
712
$wakkaConfig= array();
-
 
713
$wakkaDefaultConfig = array(
-
 
714
	'wakka_version'		=> '',
-
 
715
	'wikini_version'	=> '',
-
 
716
	'debug'			=> 'no',
-
 
717
	"mysql_host"		=> "localhost",
-
 
718
	"mysql_database"		=> "wikini",
-
 
719
	"mysql_user"		=> "wikini",
-
 
720
	"mysql_password"		=> '',
-
 
721
	"table_prefix"		=> "wikini_",
-
 
722
	"root_page"			=> "PagePrincipale",
-
 
723
	"wakka_name"		=> "MonSiteWikiNi",
-
 
724
	"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=" : ""),
-
 
725
	"rewrite_mode"		=> (preg_match("/".preg_quote("wakka.php")."$/", $_SERVER["REQUEST_URI"]) ? "0" : "1"),
-
 
726
	'meta_keywords'		=> '',
-
 
727
	'meta_description'	=> '',
-
 
728
	"action_path"		=> "actions",
-
 
729
	"handler_path"		=> "handlers",
-
 
730
	"header_action"		=> "header",
-
 
731
	"footer_action"		=> "footer",
-
 
732
	"navigation_links"		=> "DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur",
-
 
733
	"referrers_purge_time"	=> 24,
-
 
734
	"pages_purge_time"	=> 90,
-
 
735
	"default_write_acl"	=> "*",
-
 
736
	"default_read_acl"	=> "*",
-
 
737
	"default_comment_acl"	=> "*",
-
 
738
	"menu_page"	 	=> "PageMenu",
-
 
739
	"preview_before_save"	=> "0");
-
 
740
 
-
 
741
// load config
-
 
742
if (!$configfile = GetEnv("WAKKA_CONFIG")) $configfile = "wakka.config.php";
-
 
743
if (file_exists($configfile)) include($configfile);
-
 
744
$wakkaConfigLocation = $configfile;
-
 
745
$wakkaConfig = array_merge($wakkaDefaultConfig, $wakkaConfig);
-
 
746
 
-
 
747
// check for locking
-
 
748
if (file_exists("locked")) {
-
 
749
	// read password from lockfile
-
 
750
	$lines = file("locked");
-
 
751
	$lockpw = trim($lines[0]);
-
 
752
	
-
 
753
	// is authentification given?
-
 
754
	if (isset($_SERVER["PHP_AUTH_USER"])) {
-
 
755
		if (!(($_SERVER["PHP_AUTH_USER"] == "admin") && ($_SERVER["PHP_AUTH_PW"] == $lockpw))) {
-
 
756
			$ask = 1;
-
 
757
		}
-
 
758
	} else {
-
 
759
		$ask = 1;
-
 
760
	}
-
 
761
	
-
 
762
	if ($ask) {
-
 
763
		header("WWW-Authenticate: Basic realm=\"".$wakkaConfig["wakka_name"]." Install/Upgrade Interface\"");
-
 
764
		header("HTTP/1.0 401 Unauthorized");
-
 
765
		echo "Ce site est en cours de mise &agrave; jour. Veuillez essayer plus tard." ;
-
 
766
		exit;
-
 
767
	}
-
 
768
}
-
 
769
 
-
 
770
 
-
 
771
// compare versions, start installer if necessary
-
 
772
if ($wakkaConfig["wakka_version"] && (!$wakkaConfig["wikini_version"])) { $wakkaConfig["wikini_version"]=$wakkaConfig["wakka_version"]; }
-
 
773
if (($wakkaConfig["wakka_version"] != WAKKA_VERSION) || ($wakkaConfig["wikini_version"] != WIKINI_VERSION)) {
-
 
774
	// start installer
-
 
775
	if (!isset($_REQUEST["installAction"]) OR !$installAction = trim($_REQUEST["installAction"])) $installAction = "default";
-
 
776
	include("setup/header.php");
-
 
777
	if (file_exists("setup/".$installAction.".php")) include("setup/".$installAction.".php"); else echo "<i>Invalid action</i>" ;
-
 
778
	include("setup/footer.php");
-
 
779
	exit;
-
 
780
}
-
 
781
 
-
 
782
 
-
 
783
// configuration du cookie de session
-
 
784
//determine le chemin pour le cookie
-
 
785
$a = parse_url($wakkaConfig['base_url']);
-
 
786
$CookiePath = dirname($a['path']);
-
 
787
if ($CookiePath != '/') $CookiePath .= '/';
-
 
788
$a = session_get_cookie_params();
-
 
789
session_set_cookie_params($a['lifetime'],$CookiePath);
-
 
790
unset($a);
-
 
791
unset($CookiePath);
-
 
792
 
-
 
793
// start session
-
 
794
session_start();
-
 
795
 
-
 
796
// fetch wakka location
-
 
797
if (!isset($_REQUEST["wiki"])) $_REQUEST["wiki"] = '';
-
 
798
 
-
 
799
$wiki = $_REQUEST["wiki"];
-
 
800
 
-
 
801
// remove leading slash
-
 
802
$wiki = preg_replace("/^\//", "", $wiki);
-
 
803
 
-
 
804
// split into page/method
-
 
805
if (preg_match("#^(.+?)/([A-Za-z0-9_]*)$#", $wiki, $matches)) list(, $page, $method) = $matches;
-
 
806
else if (preg_match("#^(.*)$#", $wiki, $matches)) list(, $page) = $matches;
-
 
807
 
-
 
808
// create wiki object
-
 
809
$wiki = new Wiki($wakkaConfig);
-
 
810
// check for database access
-
 
811
if (!$wiki->dblink)
-
 
812
{
-
 
813
	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>";
-
 
814
	exit;
-
 
815
}
-
 
816
 
-
 
817
function compress_output($output) 
-
 
818
{ 
-
 
819
	return gzencode($output); 
-
 
820
} 
-
 
821
 
-
 
822
// Check if the browser supports gzip encoding, HTTP_ACCEPT_ENCODING 
-
 
823
if (strstr ($HTTP_SERVER_VARS['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') )
-
 
824
{ 
-
 
825
	// Start output buffering, and register compress_output() (see 
-
 
826
	// below) 
-
 
827
//	ob_start ("compress_output"); 
-
 
828
 
-
 
829
	// Tell the browser the content is compressed with gzip 
-
 
830
//	header ("Content-Encoding: gzip"); 
-
 
831
} 
-
 
832
 
-
 
833
 
-
 
834
// go!
-
 
835
if (!isset($method)) $method='';
-
 
836
 
-
 
837
// Security (quick hack)  : Check method syntax
-
 
838
if (!(preg_match('#^[A-Za-z0-9_]*$#',$method))) {
-
 
839
	$method='';
-
 
840
}
-
 
841
 
-
 
842
include('tools/prepend.php');//$wiki->Run($page, $method);
-
 
843
?>
-
 
844
1
<?php
-
 
2
/*
-
 
3
$Id: wakka.php 864 2007-11-28 12:44:52Z nepote $
-
 
4
Copyright (c) 2002, Hendrik Mans <hendrik@mans.de>
-
 
5
Copyright 2003 Carlo Zottmann
-
 
6
Copyright 2002, 2003, 2005 David DELON
-
 
7
Copyright 2002, 2003, 2004, 2006 Charles N?POTE
-
 
8
Copyright 2002, 2003 Patrick PAUL
-
 
9
Copyright 2003 Eric DELORD
-
 
10
Copyright 2003 Eric FELDSTEIN
-
 
11
Copyright 2004-2006 Jean-Christophe ANDR?
-
 
12
Copyright 2005-2006 Didier LOISEAU
-
 
13
All rights reserved.
-
 
14
Redistribution and use in source and binary forms, with or without
-
 
15
modification, are permitted provided that the following conditions
-
 
16
are met:
-
 
17
1. Redistributions of source code must retain the above copyright
-
 
18
notice, this list of conditions and the following disclaimer.
-
 
19
2. Redistributions in binary form must reproduce the above copyright
-
 
20
notice, this list of conditions and the following disclaimer in the
-
 
21
documentation and/or other materials provided with the distribution.
-
 
22
3. The name of the author may not be used to endorse or promote products
-
 
23
derived from this software without specific prior written permission.
-
 
24
 
-
 
25
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-
 
26
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 
27
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 
28
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 
29
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 
30
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 
31
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 
32
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 
33
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 
34
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 
35
 */
-
 
36
 
-
 
37
/*
-
 
38
	Yes, most of the formatting used in this file is HORRIBLY BAD STYLE. However,
-
 
39
	most of the action happens outside of this file, and I really wanted the code
-
 
40
	to look as small as what it does. Basically. Oh, I just suck. :)
-
 
41
 */
-
 
42
 
-
 
43
 
-
 
44
 
-
 
45
// do not change this line, you fool. In fact, don't change anything! Ever!
-
 
46
define("WAKKA_VERSION", "0.1.1");
-
 
47
define("WIKINI_VERSION", "0.5.0");
-
 
48
require 'includes/constants.php';
-
 
49
include 'includes/urlutils.inc.php';
-
 
50
 
-
 
51
// start the compute time
-
 
52
list($g_usec, $g_sec) = explode(" ",microtime());
-
 
53
define ("t_start", (float)$g_usec + (float)$g_sec);
-
 
54
$t_SQL=0;
-
 
55
 
-
 
56
 
-
 
57
 
-
 
58
class Wiki
-
 
59
{
-
 
60
	var $dblink;
-
 
61
	var $page;
-
 
62
	var $tag;
-
 
63
	var $parameter = array();
-
 
64
	var $queryLog = array();
-
 
65
	var $interWiki = array();
-
 
66
	var $VERSION;
-
 
67
	var $CookiePath = '/';
-
 
68
	var $inclusions = array();
-
 
69
	/**
-
 
70
	 * an array containing all the actions that are implemented by an object
-
 
71
	 * @access private
-
 
72
	 */
-
 
73
	var $actionObjects;
-
 
74
 
-
 
75
	// LinkTrackink
-
 
76
	var $isTrackingLinks = false;
-
 
77
	var $linktable = array();
-
 
78
 
-
 
79
	var $pageCache = array();
-
 
80
	var $_groupsCache = array();
-
 
81
	var $_actionsAclsCache = array();
-
 
82
 
-
 
83
	// constructor
-
 
84
	function Wiki($config)
-
 
85
	{
-
 
86
		$this->config = $config;
-
 
87
		// some host do not allow mysql_pconnect
-
 
88
		$this->dblink = @mysql_connect (
-
 
89
			$this->config["mysql_host"],
-
 
90
			$this->config["mysql_user"],
-
 
91
			$this->config["mysql_password"]);
-
 
92
		if ($this->dblink)
-
 
93
		{
-
 
94
			if (!@mysql_select_db($this->config["mysql_database"], $this->dblink))
-
 
95
			{
-
 
96
				@mysql_close($this->dblink);
-
 
97
				$this->dblink = false;
-
 
98
			}
-
 
99
		}
-
 
100
		$this->VERSION = WAKKA_VERSION;
-
 
101
 
-
 
102
		// determine le chemin pour les cookies
-
 
103
		$a = parse_url($this->GetConfigValue('base_url'));
-
 
104
		$this->CookiePath = dirname($a['path']);
-
 
105
		// Fixe la gestion des cookie sous les OS utilisant le \ comme s?parteur de chemin
-
 
106
		$this->CookiePath = str_replace("\\","/",$this->CookiePath);
-
 
107
		// ajoute un '/' terminal sauf si on est ? la racine web
-
 
108
		if ($this->CookiePath != '/') $this->CookiePath .= '/';
-
 
109
	}
-
 
110
 
-
 
111
 
-
 
112
 
-
 
113
	// DATABASE
-
 
114
	function Query($query)
-
 
115
	{
-
 
116
		if($this->GetConfigValue("debug")) $start = $this->GetMicroTime();
-
 
117
		if (!$result = mysql_query($query, $this->dblink))
-
 
118
		{
-
 
119
			ob_end_clean();
-
 
120
			die("Query failed: ".$query." (".mysql_error().")");
-
 
121
		}
-
 
122
		if($this->GetConfigValue("debug"))
-
 
123
		{
-
 
124
			$time = $this->GetMicroTime() - $start;
-
 
125
			$this->queryLog[] = array(
-
 
126
				"query"		=> $query,
-
 
127
				"time"		=> $time);
-
 
128
		}
-
 
129
		return $result;
-
 
130
	}
-
 
131
	function LoadSingle($query) {
-
 
132
		if ($data = $this->LoadAll($query)) return $data[0];
-
 
133
		return null;
-
 
134
	}
-
 
135
	function LoadAll($query)
-
 
136
	{
-
 
137
		$data=array();
-
 
138
		if ($r = $this->Query($query))
-
 
139
		{
-
 
140
			while ($row = mysql_fetch_assoc($r)) $data[] = $row;
-
 
141
			mysql_free_result($r);
-
 
142
		}
-
 
143
		return $data;
-
 
144
	}
-
 
145
 
-
 
146
 
-
 
147
 
-
 
148
	// MISC
-
 
149
	function GetMicroTime()
-
 
150
	{
-
 
151
		list($usec, $sec) = explode(" ",microtime()); return ((float)$usec + (float)$sec);
-
 
152
	}
-
 
153
	function IncludeBuffered($filename, $notfoundText = "", $vars = "", $path = "")
-
 
154
	{
-
 
155
		if ($path) $dirs = explode(":", $path);
-
 
156
		else $dirs = array("");
-
 
157
 
-
 
158
		foreach($dirs as $dir)
-
 
159
		{
-
 
160
			if ($dir) $dir .= "/";
-
 
161
			$fullfilename = $dir.$filename;
-
 
162
			if (file_exists($fullfilename))
-
 
163
			{
-
 
164
				if (is_array($vars)) extract($vars);
-
 
165
 
-
 
166
				ob_start();
-
 
167
				include($fullfilename);
-
 
168
				$output = ob_get_contents();
-
 
169
				ob_end_clean();
-
 
170
				return $output;
-
 
171
			}
-
 
172
		}
-
 
173
		if ($notfoundText) return $notfoundText;
-
 
174
		else return false;
-
 
175
	}
-
 
176
 
-
 
177
 
-
 
178
 
-
 
179
	// VARIABLES
-
 
180
	function GetPageTag() { return $this->tag; }
-
 
181
	function GetPageTime() { return $this->page["time"]; }
-
 
182
	function GetMethod() { return $this->method; }
-
 
183
	function GetConfigValue($name) { return isset($this->config[$name]) ? trim($this->config[$name]) : ''; }
-
 
184
	function GetWakkaName() { return $this->GetConfigValue("wakka_name"); }
-
 
185
	function GetWakkaVersion() { return $this->VERSION; }
-
 
186
	function GetWikiNiVersion() { return WIKINI_VERSION; }
-
 
187
 
-
 
188
	/**
-
 
189
	 * Retrieves all the triples that match some criteria.
-
 
190
	 * This allows to search triples by their approximate resource or property names.
-
 
191
	 * The allowed operators are the sql LIKE and the sql =
-
 
192
	 * @param string $resource The resource of the triples
-
 
193
	 * @param string $property The property of the triple to retrieve or null
-
 
194
	 * @param string $res_op The operator of comparison between the effective resource and $resource (default: 'LIKE')
-
 
195
	 * @param string $prop_op The operator of comparison between the effective property and $property (default: '=')
-
 
196
	 * @return array The list of all the triples that match the asked criteria 
-
 
197
	 */
-
 
198
	function GetMatchingTriples($resource, $property = null, $res_op = 'LIKE', $prop_op = '=')
-
 
199
	{
-
 
200
		static $operators = array('=', 'LIKE'); // we might want to add other operators later
-
 
201
		$res_op = strtoupper($res_op);
-
 
202
		if (!in_array($res_op, $operators)) $res_op = '=';
-
 
203
		$sql = 'SELECT * FROM ' . $this->GetConfigValue('table_prefix') . 'triples '
-
 
204
			. 'WHERE resource ' . $res_op . ' "' . addslashes($resource) . '"';
-
 
205
		if ($property !== null)
-
 
206
		{
-
 
207
			$prop_op = strtoupper($prop_op);
-
 
208
			if (!in_array($prop_op, $operators)) $prop_op = '=';
-
 
209
			$sql .= ' AND property ' . $prop_op . ' "' . addslashes($property) . '"';
-
 
210
		}
-
 
211
		return $this->LoadAll($sql);
-
 
212
	}
-
 
213
 
-
 
214
	/**
-
 
215
	 * Retrieves all the values for a given couple (resource, property)
-
 
216
	 * @param string $resource The resource of the triples
-
 
217
	 * @param string $property The property of the triple to retrieve
-
 
218
	 * @param string $re_prefix The prefix to add to $resource (defaults to THISWIKI_PREFIX)
-
 
219
	 * @param string $prop_prefix The prefix to add to $property (defaults to WIKINI_VOC_PREFIX)
-
 
220
	 * @return array An array of the retrieved values, in the form
-
 
221
	 * array(
-
 
222
	 * 	0 => array(id = 7 , 'value' => $value1),
-
 
223
	 * 	1 => array(id = 34, 'value' => $value2),
-
 
224
	 * 	...
-
 
225
	 * )
-
 
226
	 */
-
 
227
	function GetAllTriplesValues($resource, $property, $re_prefix = THISWIKI_PREFIX, $prop_prefix = WIKINI_VOC_PREFIX)
-
 
228
	{
-
 
229
		$sql = 'SELECT id, value FROM ' . $this->GetConfigValue('table_prefix') . 'triples '
-
 
230
			. 'WHERE resource = "' . addslashes($re_prefix . $resource) . '" '
-
 
231
			. 'AND property = "' . addslashes($prop_prefix . $property) . '" ';
-
 
232
		return $this->LoadAll($sql);
-
 
233
	} 
-
 
234
 
-
 
235
	/**
-
 
236
	 * Retrieves a single value for a given couple (resource, property)
-
 
237
	 * @param string $resource The resource of the triples
-
 
238
	 * @param string $property The property of the triple to retrieve
-
 
239
	 * @param string $re_prefix The prefix to add to $resource (defaults to <tt>THISWIKI_PREFIX</tt>)
-
 
240
	 * @param string $prop_prefix The prefix to add to $property (defaults to <tt>WIKINI_VOC_PREFIX</tt>)
-
 
241
	 * @return string The value corresponding to ($resource, $property) or null if
-
 
242
	 * there is no such couple in the triples table.
-
 
243
	 */
-
 
244
	function GetTripleValue($resource, $property, $re_prefix = THISWIKI_PREFIX, $prop_prefix = WIKINI_VOC_PREFIX)
-
 
245
	{
-
 
246
		$res = $this->GetAllTriplesValues($resource, $property, $re_prefix, $prop_prefix);
-
 
247
		if ($res) return $res[0]['value'];
-
 
248
		return null;
-
 
249
	}
-
 
250
 
-
 
251
	/**
-
 
252
	 * Checks whether a triple exists or not
-
 
253
	 * @param string $resource The resource of the triple to find
-
 
254
	 * @param string $property The property of the triple to find
-
 
255
	 * @param string $value The value of the triple to find
-
 
256
	 * @param string $re_prefix The prefix to add to $resource (defaults to <tt>THISWIKI_PREFIX</tt>)
-
 
257
	 * @param string $prop_prefix The prefix to add to $property (defaults to <tt>WIKINI_VOC_PREFIX</tt>)
-
 
258
	 * @param int The id of the found triple or 0 if there is no such triple. 
-
 
259
	 */
-
 
260
	function TripleExists($resource, $property, $value, $re_prefix = THISWIKI_PREFIX, $prop_prefix = WIKINI_VOC_PREFIX)
-
 
261
	{
-
 
262
		$sql = 'SELECT id FROM ' . $this->GetConfigValue('table_prefix') . 'triples '
-
 
263
			. 'WHERE resource = "' . addslashes($re_prefix . $resource) . '" '
-
 
264
			. 'AND property = "' . addslashes($prop_prefix . $property) . '" '
-
 
265
			. 'AND value = "' . addslashes($value) . '"';
-
 
266
		$res = $this->LoadSingle($sql);
-
 
267
		if (!$res) return 0;
-
 
268
		return $res['id'];
-
 
269
	}
-
 
270
 
-
 
271
	/**
-
 
272
	 * Inserts a new triple ($resource, $property, $value) in the triples' table
-
 
273
	 * @param string $resource The resource of the triple to insert
-
 
274
	 * @param string $property The property of the triple to insert
-
 
275
	 * @param string $value The value of the triple to insert
-
 
276
	 * @param string $re_prefix The prefix to add to $resource (defaults to <tt>THISWIKI_PREFIX</tt>)
-
 
277
	 * @param string $prop_prefix The prefix to add to $property (defaults to <tt>WIKINI_VOC_PREFIX</tt>)
-
 
278
	 * @return int An error code: 0 (success), 1 (failure) or 3 (already exists)
-
 
279
	 */
-
 
280
	function InsertTriple($resource, $property, $value, $re_prefix = THISWIKI_PREFIX, $prop_prefix = WIKINI_VOC_PREFIX)
-
 
281
	{
-
 
282
		if ($this->TripleExists($resource, $property, $value, $re_prefix, $prop_prefix))
-
 
283
		{
-
 
284
			return 3;
-
 
285
		}
-
 
286
		$sql = 'INSERT INTO ' . $this->GetConfigValue('table_prefix') . 'triples (resource, property, value)'
-
 
287
			. 'VALUES ("' . addslashes($re_prefix . $resource) . '", "'
-
 
288
				. addslashes($prop_prefix . $property) . '", "'
-
 
289
				. addslashes($value) . '")';
-
 
290
		return $this->Query($sql) ? 0 : 1;
-
 
291
	}
-
 
292
 
-
 
293
	/**
-
 
294
	 * Updates a triple ($resource, $property, $value) in the triples' table
-
 
295
	 * @param string $resource The resource of the triple to update
-
 
296
	 * @param string $property The property of the triple to update
-
 
297
	 * @param string $oldvalue The old value of the triple to update
-
 
298
	 * @param string $newvalue The new value of the triple to update
-
 
299
	 * @param string $re_prefix The prefix to add to $resource (defaults to <tt>THISWIKI_PREFIX</tt>)
-
 
300
	 * @param string $prop_prefix The prefix to add to $property (defaults to <tt>WIKINI_VOC_PREFIX</tt>)
-
 
301
	 * @return int An error code: 0 (succ?s), 1 (?chec),
-
 
302
	 * 		2 ($resource, $property, $oldvalue does not exist)
-
 
303
	 * 		or 3 ($resource, $property, $newvalue already exists)
-
 
304
	 */
-
 
305
	function UpdateTriple($resource, $property, $oldvalue, $newvalue, $re_prefix = THISWIKI_PREFIX, $prop_prefix = WIKINI_VOC_PREFIX)
-
 
306
	{
-
 
307
		$id = $this->TripleExists($resource, $property, $oldvalue, $re_prefix, $prop_prefix);
-
 
308
		if (!$id) return 2;
-
 
309
		if ($this->TripleExists($resource, $property, $newvalue, $re_prefix, $prop_prefix))
-
 
310
		{
-
 
311
			return 3;
-
 
312
		}
-
 
313
		$sql = 'UPDATE ' . $this->GetConfigValue('table_prefix') . 'triples '
-
 
314
			. 'SET value = "' . addslashes($newvalue) . '" '
-
 
315
			. 'WHERE id = ' . $id;
-
 
316
		return $this->Query($sql) ? 0 : 1;
-
 
317
	}
-
 
318
 
-
 
319
	/**
-
 
320
	 * Deletes a triple ($resource, $property, $value) from the triples' table
-
 
321
	 * @param string $resource The resource of the triple to delete
-
 
322
	 * @param string $property The property of the triple to delete
-
 
323
	 * @param string $value The value of the triple to delete. If set to <tt>null</tt>,
-
 
324
	 * deletes all the triples corresponding to ($resource, $property). (defaults to <tt>null</tt>)
-
 
325
	 * @param string $re_prefix The prefix to add to $resource (defaults to <tt>THISWIKI_PREFIX</tt>)
-
 
326
	 * @param string $prop_prefix The prefix to add to $property (defaults to <tt>WIKINI_VOC_PREFIX</tt>)
-
 
327
	 */
-
 
328
	function DeleteTriple($resource, $property, $value = null, $re_prefix = THISWIKI_PREFIX, $prop_prefix = WIKINI_VOC_PREFIX)
-
 
329
	{
-
 
330
		$sql = 'DELETE FROM ' . $this->GetConfigValue('table_prefix') . 'triples '
-
 
331
			. 'WHERE resource = "' . addslashes($re_prefix . $resource) . '" '
-
 
332
			. 'AND property = "' . addslashes($prop_prefix . $property) . '" ';
-
 
333
		if ($value !== null) $sql .= 'AND value = "' . addslashes($value) . '"';
-
 
334
		$this->Query($sql);
-
 
335
	}
-
 
336
 
-
 
337
	// inclusions
-
 
338
	/**
-
 
339
	 * Enr?gistre une nouvelle inclusion dans la pile d'inclusions.
-
 
340
	 * 
-
 
341
	 * @param string $pageTag Le nom de la page qui va ?tre inclue
-
 
342
	 * @return int Le nombre d'?l?ments dans la pile
-
 
343
	 */
-
 
344
	function RegisterInclusion($pageTag)
-
 
345
	{
-
 
346
		return array_unshift($this->inclusions, strtolower(trim($pageTag)));
-
 
347
	} 
-
 
348
	/**
-
 
349
	 * Retire le dernier ?l?ment de la pile d'inclusions.
-
 
350
	 * 
-
 
351
	 * @return string Le nom de la page dont l'inclusion devrait se terminer.
-
 
352
	 * null s'il n'y a plus d'inclusion dans la pile.
-
 
353
	 */
-
 
354
	function UnregisterLastInclusion()
-
 
355
	{
-
 
356
		return array_shift($this->inclusions);
-
 
357
	} 
-
 
358
	/**
-
 
359
	 * Renvoie le nom de la page en cours d'inclusion.
-
 
360
	 * 
-
 
361
	 * @example // dans le cas d'une action comme l'ActionEcrivezMoi
-
 
362
	 * if($inc = $this->CurrentInclusion() && strtolower($this->GetPageTag()) != $inc)
-
 
363
	 * 	echo 'Cette action ne peut ?tre appel?e depuis une page inclue';
-
 
364
	 * @return string Le nom (tag) de la page (en minuscules)
-
 
365
	 * false si la pile est vide.
-
 
366
	 */
-
 
367
	function GetCurrentInclusion()
-
 
368
	{
-
 
369
		return isset($this->inclusions[0]) ? $this->inclusions[0]: false ;
-
 
370
	} 
-
 
371
	/**
-
 
372
	 * V?rifie si on est ? l'int?rieur d'une inclusion par $pageTag (sans tenir compte de la casse)
-
 
373
	 * 
-
 
374
	 * @param string $pageTag Le nom de la page ? v?rifier
-
 
375
	 * @return bool True si on est ? l'int?rieur d'une inclusion par $pageTag (false sinon)
-
 
376
	 */
-
 
377
	function IsIncludedBy($pageTag)
-
 
378
	{
-
 
379
		return in_array(strtolower($pageTag), $this->inclusions);
-
 
380
	} 
-
 
381
	/**
-
 
382
	 * 
-
 
383
	 * @return array La pile d'inclusions
-
 
384
	 * L'?l?ment 0 sera la derni?re inclusion, l'?l?ment 1 sera son parent et ainsi de suite.
-
 
385
	 */
-
 
386
	function GetAllInclusions()
-
 
387
	{
-
 
388
		return $this->inclusions;
-
 
389
	} 
-
 
390
	/**
-
 
391
	 * Remplace la pile des inclusions par une nouvelle pile (par d?faut une pile vide)
-
 
392
	 * Permet de formatter une page sans tenir compte des inclusions pr?c?dentes.
-
 
393
	 * 
-
 
394
	 * @param array $ La nouvelle pile d'inclusions.
-
 
395
	 * L'?l?ment 0 doit repr?senter la derni?re inclusion, l'?l?ment 1 son parent et ainsi de suite.
-
 
396
	 * @return array L'ancienne pile d'inclusions, avec les noms des pages en minuscules.
-
 
397
	 */
-
 
398
	function SetInclusions($pile = array())
-
 
399
	{
-
 
400
		$temp = $this->inclusions;
-
 
401
		$this->inclusions = $pile;
-
 
402
		return $temp;
-
 
403
	} 
-
 
404
 
-
 
405
	// PAGES
-
 
406
	function LoadPage($tag, $time = "", $cache = 1)
-
 
407
	{
-
 
408
		// retrieve from cache
-
 
409
		if (!$time && $cache && (($cachedPage = $this->GetCachedPage($tag)) !== false))
-
 
410
		{
-
 
411
			$page = $cachedPage;
-
 
412
		}
-
 
413
		else // load page
-
 
414
		{
-
 
415
			$sql = "SELECT * FROM ".$this->config["table_prefix"]."pages"
-
 
416
				. " WHERE tag = '".mysql_real_escape_string($tag)."' AND "
-
 
417
				. ($time ? "time = '".mysql_real_escape_string($time)."'" : "latest = 'Y'") . " LIMIT 1";
-
 
418
			$page = $this->LoadSingle($sql);
-
 
419
			// cache result
-
 
420
			if (!$time) $this->CachePage($page, $tag);
-
 
421
		}
-
 
422
		return $page;
-
 
423
	}
-
 
424
	/**
-
 
425
	 * Retrieves the cached version of a page.
-
 
426
	 *
-
 
427
	 * Notice that this method null or false, use
-
 
428
	 * 	$this->GetCachedPage($tag) === false
-
 
429
	 * to check if a page is not in the cache.
-
 
430
	 * @return mixed The cached version of a page:
-
 
431
	 * 	- the page DB line if the page exists and is in cache
-
 
432
	 * 	- null if the cache knows that the page does not exists
-
 
433
	 * 	- false is the cache does not know the page
-
 
434
	 */
-
 
435
	function GetCachedPage($tag) {return (array_key_exists($tag, $this->pageCache) ? $this->pageCache[$tag] : false); }
-
 
436
	/**
-
 
437
	 * Caches a page's DB line.
-
 
438
	 *
-
 
439
	 * @param array $page The page (full) DB line or null if the page does not exists
-
 
440
	 * @param string $pageTag The tag of the page to cache. Defaults to $page['tag'] but is mendatory when $page === null
-
 
441
	 */
-
 
442
	function CachePage($page, $pageTag = null) {
-
 
443
		if ($pageTag === null)
-
 
444
		{
-
 
445
			$pageTag = $page["tag"];
-
 
446
		}
-
 
447
		$this->pageCache[$pageTag] = $page;
-
 
448
	}
-
 
449
	function SetPage($page) { $this->page = $page; if ($this->page["tag"]) $this->tag = $this->page["tag"]; }
-
 
450
	function LoadPageById($id) { return $this->LoadSingle("select * from ".$this->config["table_prefix"]."pages where id = '".mysql_real_escape_string($id)."' limit 1"); }
-
 
451
	function LoadRevisions($page) { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where tag = '".mysql_real_escape_string($page)."' order by time desc"); }
-
 
452
	function LoadPagesLinkingTo($tag) { return $this->LoadAll("select from_tag as tag from ".$this->config["table_prefix"]."links where to_tag = '".mysql_real_escape_string($tag)."' order by tag"); }
-
 
453
	function LoadRecentlyChanged($limit=50)
-
 
454
	{
-
 
455
		$limit= (int) $limit;
-
 
456
		if ($pages = $this->LoadAll("select id, tag, time, user, owner from ".$this->config["table_prefix"]."pages where latest = 'Y' and comment_on = '' order by time desc limit $limit"))
-
 
457
		{
-
 
458
			foreach ($pages as $page)
-
 
459
			{
-
 
460
				$this->CachePage($page);
-
 
461
			}
-
 
462
			return $pages;
-
 
463
		}
-
 
464
	}
-
 
465
	function LoadAllPages() { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where latest = 'Y' order by tag"); }
-
 
466
	function FullTextSearch($phrase) { return $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where latest = 'Y' and match(tag, body) against('".mysql_real_escape_string($phrase)."')"); }
-
 
467
	function LoadWantedPages() {
-
 
468
		$p = $this->config["table_prefix"];
-
 
469
		$r = "SELECT ${p}links.to_tag AS tag, COUNT(${p}links.from_tag) AS count "
-
 
470
			. "FROM ${p}links LEFT JOIN ${p}pages ON ${p}links.to_tag = ${p}pages.tag "
-
 
471
			. "WHERE ${p}pages.tag IS NULL GROUP BY ${p}links.to_tag ORDER BY count DESC, tag ASC";
-
 
472
		return $this->LoadAll($r);
-
 
473
	}
-
 
474
	function LoadOrphanedPages() { return $this->LoadAll("select distinct tag from ".$this->config["table_prefix"]."pages as p left join ".$this->config["table_prefix"]."links as l on p.tag = l.to_tag where l.to_tag is NULL and p.comment_on = '' and p.latest = 'Y' order by tag"); }
-
 
475
	function IsOrphanedPage($tag) { return $this->LoadAll("select distinct tag from ".$this->config['table_prefix']."pages as p left join ".$this->config['table_prefix']."links as l on p.tag = l.to_tag where l.to_tag is NULL and p.latest = 'Y' and tag = '".mysql_real_escape_string($tag)."'"); }
-
 
476
	function DeleteOrphanedPage($tag) {
-
 
477
		$p = $this->config["table_prefix"];
-
 
478
		$this->Query("DELETE FROM ${p}pages WHERE tag='".mysql_real_escape_string($tag)."' OR comment_on='".mysql_real_escape_string($tag)."'");
-
 
479
		$this->Query("DELETE FROM ${p}links WHERE from_tag='".mysql_real_escape_string($tag)."' ");
-
 
480
		$this->Query("DELETE FROM ${p}acls WHERE page_tag='".mysql_real_escape_string($tag)."' ");
-
 
481
		$this->Query("DELETE FROM ${p}referrers WHERE page_tag='".mysql_real_escape_string($tag)."' ");
-
 
482
	}
-
 
483
 
-
 
484
	/**
-
 
485
	 * SavePage
-
 
486
	 * Sauvegarde un contenu dans une page donn?e
-
 
487
	 *
-
 
488
	 * @param string $body Contenu ? sauvegarder dans la page
-
 
489
	 * @param string $tag Nom de la page
-
 
490
	 * @param string $comment_on Indication si c'est un commentaire
-
 
491
	 * @param boolean $bypass_acls Indication si on bypasse les droits d'?criture
-
 
492
	 * @return int Code d'erreur : 0 (succ?s), 1 (l'utilisateur n'a pas les droits)
-
 
493
	 */	
-
 
494
	function SavePage($tag, $body, $comment_on = "", $bypass_acls = false)
-
 
495
	{
-
 
496
		// get current user
-
 
497
		$user = $this->GetUserName();
-
 
498
 
-
 
499
		// check bypass of rights or write privilege
-
 
500
		$rights = $bypass_acls || ($comment_on ? $this->HasAccess("comment", $comment_on) : $this->HasAccess("write", $tag));
-
 
501
			
-
 
502
		if ($rights)
-
 
503
		{
-
 
504
			// is page new?
-
 
505
			if (!$oldPage = $this->LoadPage($tag))
-
 
506
			{
-
 
507
				// create default write acl. store empty write ACL for comments.
-
 
508
				$this->SaveAcl($tag, "write", ($comment_on ? $user : $this->GetConfigValue("default_write_acl")));
-
 
509
 
-
 
510
				// create default read acl
-
 
511
				$this->SaveAcl($tag, "read", $this->GetConfigValue("default_read_acl"));
-
 
512
 
-
 
513
				// create default comment acl.
-
 
514
				$this->SaveAcl($tag, "comment", ($comment_on ? "" : $this->GetConfigValue("default_comment_acl")));
-
 
515
 
-
 
516
				// current user is owner; if user is logged in! otherwise, no owner.
-
 
517
				if ($this->GetUser()) $owner = $user;
-
 
518
				else $owner = '';
-
 
519
			}
-
 
520
			else
-
 
521
			{
-
 
522
				// aha! page isn't new. keep owner!
-
 
523
				$owner = $oldPage["owner"];
-
 
524
 
-
 
525
				// ...and comment_on, eventualy?
-
 
526
				if ($comment_on == '') $comment_on = $oldPage['comment_on'];
-
 
527
			}
-
 
528
 
-
 
529
 
-
 
530
			// set all other revisions to old
-
 
531
			$this->Query("update ".$this->config["table_prefix"]."pages set latest = 'N' where tag = '".mysql_real_escape_string($tag)."'");
-
 
532
 
-
 
533
			// add new revision
-
 
534
			$this->Query("insert into ".$this->config["table_prefix"]."pages set ".
-
 
535
				"tag = '".mysql_real_escape_string($tag)."', ".
-
 
536
				($comment_on ? "comment_on = '".mysql_real_escape_string($comment_on)."', " : "").
-
 
537
				"time = now(), ".
-
 
538
				"owner = '".mysql_real_escape_string($owner)."', ".
-
 
539
				"user = '".mysql_real_escape_string($user)."', ".
-
 
540
				"latest = 'Y', ".
-
 
541
				"body = '".mysql_real_escape_string(chop($body))."'");
-
 
542
 
-
 
543
			unset($this->pageCache[$tag]);
-
 
544
			return 0;
-
 
545
		}
-
 
546
		else return 1;
-
 
547
	}
-
 
548
 
-
 
549
	
-
 
550
	/**
-
 
551
	 * AppendContentToPage
-
 
552
	 * Ajoute du contenu ? la fin d'une page
-
 
553
	 *
-
 
554
	 * @param string $content Contenu ? ajouter ? la page
-
 
555
	 * @param string $page Nom de la page
-
 
556
	 * @param boolean $bypass_acls Boul?en pour savoir s'il faut bypasser les ACLs
-
 
557
	 * @return int Code d'erreur : 0 (succ?s), 1 (pas de contenu sp?cifi?)
-
 
558
	 */
-
 
559
	function AppendContentToPage($content, $page, $bypass_acls = false)
-
 
560
	{
-
 
561
		// Si un contenu est sp?cifi?
-
 
562
		if (isset($content))
-
 
563
		{
-
 
564
			// -- D?termine quelle est la page :
-
 
565
			//    -- pass?e en param?tre (que se passe-t'il si elle n'existe pas ?)
-
 
566
			//    -- ou la page en cours par d?faut
-
 
567
			$page = isset($page) ? $page : $this->GetPageTag();
-
 
568
 
-
 
569
			// -- Chargement de la page
-
 
570
			$result = $this->LoadPage($page);
-
 
571
			$body = $result['body'];
-
 
572
			// -- Ajout du contenu ? la fin de la page
-
 
573
			$body .= $content;
-
 
574
 
-
 
575
			// -- Sauvegarde de la page
-
 
576
			// TODO : que se passe-t-il si la page est pleine ou si l'utilisateur n'a pas les droits ?
-
 
577
			$this->SavePage($page, $body, "", $bypass_acls);
-
 
578
			
-
 
579
			// now we render it internally so we can write the updated link table.
-
 
580
			$this->ClearLinkTable();
-
 
581
			$this->StartLinkTracking();
-
 
582
			$temp = $this->SetInclusions();
-
 
583
			$this->RegisterInclusion($this->GetPageTag()); // on simule totalement un affichage normal
-
 
584
			$this->Format($body);
-
 
585
			$this->SetInclusions($temp);
-
 
586
			if($user = $this->GetUser())
-
 
587
			{
-
 
588
				$this->TrackLinkTo($user['name']);
-
 
589
			}
-
 
590
			if($owner = $this->GetPageOwner())
-
 
591
			{
-
 
592
				$this->TrackLinkTo($owner);
-
 
593
			}
-
 
594
			$this->StopLinkTracking();
-
 
595
			$this->WriteLinkTable();
-
 
596
			$this->ClearLinkTable();/**/
-
 
597
 
-
 
598
			// Retourne 0 seulement si tout c'est bien pass?
-
 
599
			return 0;
-
 
600
		}
-
 
601
		else return 1;
-
 
602
	}
-
 
603
	
-
 
604
	/**
-
 
605
	 * LogAdministrativeAction($user, $content, $page = "")
-
 
606
	 * 
-
 
607
	 * @param string $user Utilisateur
-
 
608
	 * @param string $content Contenu de l'enregistrement
-
 
609
	 * @param string $page Page de log
-
 
610
	 * 
-
 
611
	 * @return int Code d'erreur : 0 (succ?s), 1 (pas de contenu sp?cifi?)
-
 
612
	 */
-
 
613
	function LogAdministrativeAction($user, $content, $page = "")
-
 
614
	{
-
 
615
		$order   = array("\r\n", "\n", "\r");
-
 
616
		$replace = '\\n';
-
 
617
		$content = str_replace($order, $replace, $content);
-
 
618
		$contentToAppend = "\n" . date("Y-m-d H:i:s") . " . . . . " . $user . " . . . . " . $content . "\n";
-
 
619
		$page = $page ? $page : "LogDesActionsAdministratives" . date("Ymd");
-
 
620
		return $this->AppendContentToPage($contentToAppend, $page, true);
-
 
621
	}
-
 
622
 
-
 
623
	
-
 
624
	/**
-
 
625
	 * Make the purge of page versions that are older than the last version older than 3 "pages_purge_time"
-
 
626
	 * This method permits to allways keep a version that is older than that period.
-
 
627
	 */
-
 
628
	function PurgePages() {
-
 
629
		if ($days = $this->GetConfigValue("pages_purge_time")) { // is purge active ?
-
 
630
			// let's search which pages versions we have to remove
-
 
631
			// this is necessary beacause even MySQL does not handel multi-tables deletes before version 4.0
-
 
632
			$wnPages = $this->GetConfigValue('table_prefix') . 'pages';
-
 
633
			$sql = 'SELECT DISTINCT a.id FROM ' . $wnPages . ' a,' . $wnPages . ' b WHERE a.latest = \'N\' AND a.time < date_sub(now(), INTERVAL \'' . addslashes($days) . '\' DAY) AND a.tag = b.tag AND a.time < b.time AND b.time < date_sub(now(), INTERVAL \'' . addslashes($days) . '\' DAY)';
-
 
634
			$ids = $this->LoadAll($sql);
-
 
635
 
-
 
636
			if (count($ids)) { // there are some versions to remove from DB
-
 
637
				// let's build one big request, that's better...
-
 
638
				$sql = 'DELETE FROM ' . $wnPages . ' WHERE id IN (';
-
 
639
				foreach($ids as $key => $line){
-
 
640
					$sql .= ($key ? ', ':'') . $line['id']; // NB.: id is an int, no need of quotes
-
 
641
				}
-
 
642
				$sql .= ')';
-
 
643
 
-
 
644
				// ... and send it !
-
 
645
				$this->Query($sql);
-
 
646
			}
-
 
647
		}
-
 
648
	}
-
 
649
 
-
 
650
 
-
 
651
 
-
 
652
	// COOKIES
-
 
653
	function SetSessionCookie($name, $value)
-
 
654
	{
-
 
655
		SetCookie($name, $value, 0, $this->CookiePath);
-
 
656
		$_COOKIE[$name] = $value;
-
 
657
	}
-
 
658
	function SetPersistentCookie($name, $value, $remember = 0)
-
 
659
	{
-
 
660
		SetCookie($name, $value, time() + ($remember ? 90*24*60*60 : 60 * 60), $this->CookiePath);
-
 
661
		$_COOKIE[$name] = $value;
-
 
662
	}
-
 
663
	function DeleteCookie($name)
-
 
664
	{
-
 
665
		SetCookie($name, "", 1, $this->CookiePath);
-
 
666
		$_COOKIE[$name] = "";
-
 
667
	}
-
 
668
	function GetCookie($name) { return $_COOKIE[$name]; }
-
 
669
 
-
 
670
 
-
 
671
 
-
 
672
	// HTTP/REQUEST/LINK RELATED
-
 
673
	function SetMessage($message) { $_SESSION["message"] = $message; }
-
 
674
	function GetMessage()
-
 
675
	{
-
 
676
		if (isset($_SESSION["message"])) $message = $_SESSION["message"];
-
 
677
		else $message = "";
-
 
678
		$_SESSION["message"] = "";
-
 
679
		return $message;
-
 
680
	}
-
 
681
	function Redirect($url)
-
 
682
	{
-
 
683
		header("Location: $url");
-
 
684
		exit;
-
 
685
	}
-
 
686
	// returns just PageName[/method].
-
 
687
	function MiniHref($method = "", $tag = "")
-
 
688
	{
-
 
689
		if (!$tag = trim($tag)) $tag = $this->tag;
-
 
690
		return $tag.($method ? "/".$method : "");
-
 
691
	}
-
 
692
	// returns the full url to a page/method.
-
 
693
	function Href($method = "", $tag = "", $params = "", $htmlspchars = true)
-
 
694
	{
-
 
695
		$href = $this->config["base_url"].$this->MiniHref($method, $tag);
-
 
696
		if ($params)
-
 
697
		{
-
 
698
			$href .= ($this->config["rewrite_mode"] ? "?" : ($htmlspchars ? "&amp;" : '&')).$params;
-
 
699
		}
-
 
700
		return $href;
-
 
701
	}
-
 
702
	function Link($tag, $method = "", $text = "", $track = 1)
-
 
703
	{
-
 
704
		$displayText = $text ? $text : $tag;
-
 
705
		// is this an interwiki link?
-
 
706
		if (preg_match('/^' . WN_INTERWIKI_CAPTURE . '$/', $tag, $matches))
-
 
707
		{
-
 
708
			if ($tagInterWiki = $this->GetInterWikiUrl($matches[1], $matches[2])) {
-
 
709
				return '<a href="'.htmlspecialchars($tagInterWiki).'">'
-
 
710
					.htmlspecialchars($displayText).' (interwiki)</a>';
-
 
711
			}
-
 
712
			else return '<a href="'.htmlspecialchars($tag).'">'
-
 
713
				.htmlspecialchars($displayText).' (interwiki inconnu)</a>';
-
 
714
		}
-
 
715
		// is this a full link? ie, does it contain non alpha-numeric characters?
-
 
716
		// Note : [:alnum:] is equivalent [0-9A-Za-z]
-
 
717
		//		  [^[:alnum:]] means : some caracters other than [0-9A-Za-z]
-
 
718
		// For example : "www.adress.com", "mailto:adress@domain.com", "http://www.adress.com"
-
 
719
		else if (preg_match("/[^[:alnum:]]/", $tag))
-
 
720
		{
-
 
721
			// check for various modifications to perform on $tag
-
 
722
			if (preg_match("/^[\w.-]+\@[\w.-]+$/", $tag))
-
 
723
			{ // email addresses
-
 
724
				$tag = 'mailto:'.$tag;
-
 
725
			}
-
 
726
			// Note : in Perl regexp, (?: ... ) is a non-catching cluster
-
 
727
			else if (preg_match('/^[[:alnum:]][[:alnum:].-]*(?:\/|$)/', $tag))
-
 
728
			{ // protocol-less URLs
-
 
729
				$tag = 'http://'.$tag;
-
 
730
			}
-
 
731
			// Finally, block script schemes (see RFC 3986 about
-
 
732
			// schemes) and allow relative link & protocol-full URLs
-
 
733
			else if (preg_match('/^[a-z0-9.+-]*script[a-z0-9.+-]*:/i', $tag)
-
 
734
				|| !(preg_match('/^\.?\.?\//', $tag)
-
 
735
					|| preg_match('/^[a-z0-9.+-]+:\/\//i', $tag)))
-
 
736
			{
-
 
737
				// If does't fit, we can't qualify $tag as an URL.
-
 
738
				// There is a high risk that $tag is just XSS (bad
-
 
739
				// javascript: code) or anything nasty. So we must not
-
 
740
				// produce any link at all.
-
 
741
				return htmlspecialchars($tag.($text ? ' '.$text : ''));
-
 
742
			}
-
 
743
			// Important: Here, we know that $tag is not something bad
-
 
744
			// and that we must produce a link with it
-
 
745
 
-
 
746
			// An inline image? (text!=tag and url ends by png,gif,jpeg)
-
 
747
			if ($text and preg_match("/\.(gif|jpeg|png|jpg)$/i",$tag))
-
 
748
			{
-
 
749
				return '<img src="'.htmlspecialchars($tag)
-
 
750
					.'" alt="'.htmlspecialchars($displayText).'"/>';
-
 
751
			}
-
 
752
			else
-
 
753
			{
-
 
754
				// Even if we know $tag is harmless, we MUST encode it
-
 
755
				// in HTML with htmlspecialchars() before echoing it.
-
 
756
				// This is not about being paranoiac. This is about
-
 
757
				// being compliant to the HTML standard.
-
 
758
				return '<a href="'.htmlspecialchars($tag).'">'
-
 
759
					.htmlspecialchars($displayText).'</a>';
-
 
760
			}
-
 
761
		}
-
 
762
		else
-
 
763
		{
-
 
764
			// it's a Wiki link!
-
 
765
			if (!empty($track)) $this->TrackLinkTo($tag);
-
 
766
			if ($this->LoadPage($tag))
-
 
767
				return '<a href="'.htmlspecialchars($this->href($method, $tag)).'">'
-
 
768
					.htmlspecialchars($displayText).'</a>';
-
 
769
			else
-
 
770
				return '<span class="missingpage">'.htmlspecialchars($displayText)
-
 
771
				.'</span><a href="'.htmlspecialchars($this->href("edit", $tag)).'">?</a>';
-
 
772
		}
-
 
773
	}
-
 
774
	function ComposeLinkToPage($tag, $method = "", $text = "", $track = 1) {
-
 
775
		if (!$text) $text = $tag;
-
 
776
		$text = htmlspecialchars($text);
-
 
777
		if ($track)
-
 
778
			$this->TrackLinkTo($tag);
-
 
779
		return '<a href="'.$this->href($method, $tag).'">'.$text.'</a>';
-
 
780
	}
-
 
781
	function IsWikiName($text) {
-
 
782
		return preg_match('/^' . WN_CAMEL_CASE . '$/', $text);
-
 
783
	}
-
 
784
 
-
 
785
	// LinkTracking management
-
 
786
	/**
-
 
787
	 * Tracks the link to a given page (only if the LinkTracking is activated)
-
 
788
	 * @param string $tag The tag (name) of the page to track a link to.
-
 
789
	 */
-
 
790
	function TrackLinkTo($tag) {
-
 
791
		if ($this->LinkTracking()) $this->linktable[] = $tag;
-
 
792
	}
-
 
793
	/**
-
 
794
	 * @return array The current link tracking table
-
 
795
	 */
-
 
796
	function GetLinkTable() { return $this->linktable; }
-
 
797
	/**
-
 
798
	 * Clears the link tracking table
-
 
799
	 */
-
 
800
	function ClearLinkTable() { $this->linktable = array(); }
-
 
801
	/**
-
 
802
	 * Starts the LinkTracking
-
 
803
	 * @return bool The previous state of the link tracking
-
 
804
	 */
-
 
805
	function StartLinkTracking() {
-
 
806
		return $this->LinkTracking(true);
-
 
807
	}
-
 
808
	/**
-
 
809
	 * Stops the LinkTracking
-
 
810
	 * @return bool The previous state of the link tracking
-
 
811
	 */
-
 
812
	function StopLinkTracking() {
-
 
813
		return $this->LinkTracking(false);
-
 
814
	}
-
 
815
	/**
-
 
816
	 * Sets and/or retrieve the state of the LinkTracking
-
 
817
	 * @param bool $newStatus The new status of the LinkTracking
-
 
818
	 * (defaults to <tt>null</tt> which lets it unchanged)
-
 
819
	 * @return bool The previous state of the link tracking
-
 
820
	 */
-
 
821
	function LinkTracking($newStatus = null)
-
 
822
	{
-
 
823
		$old = $this->isTrackingLinks;
-
 
824
		if ($newStatus !== null) $this->isTrackingLinks = $newStatus;
-
 
825
		return $old;
-
 
826
	}
-
 
827
	function WriteLinkTable() {
-
 
828
		// delete old link table
-
 
829
		$this->Query("delete from ".$this->config["table_prefix"]."links where from_tag = '".mysql_real_escape_string($this->GetPageTag())."'");
-
 
830
		if ($linktable = $this->GetLinkTable())
-
 
831
		{
-
 
832
			$from_tag = mysql_real_escape_string($this->GetPageTag());
-
 
833
			foreach ($linktable as $to_tag)
-
 
834
			{
-
 
835
				$lower_to_tag = strtolower($to_tag);
-
 
836
				if (!isset($written[$lower_to_tag]))
-
 
837
				{
-
 
838
					$this->Query("insert into ".$this->config["table_prefix"]."links set from_tag = '".$from_tag."', to_tag = '".mysql_real_escape_string($to_tag)."'");
-
 
839
					$written[$lower_to_tag] = 1;
-
 
840
				}
-
 
841
			}
-
 
842
		}
-
 
843
	}
-
 
844
 
-
 
845
	function Header() {
-
 
846
		$action = $this->GetConfigValue("header_action");
-
 
847
		if (($actionObj = &$this->GetActionObject($action)) && is_object($actionObj))
-
 
848
		{
-
 
849
			return $actionObj->GenerateHeader();
-
 
850
		}
-
 
851
		return $this->Action($action, 1);
-
 
852
	}
-
 
853
 
-
 
854
	function Footer() {
-
 
855
		$action = $this->GetConfigValue("footer_action");
-
 
856
		if (($actionObj = &$this->GetActionObject($action)) && is_object($actionObj))
-
 
857
		{
-
 
858
			return $actionObj->GenerateFooter();
-
 
859
		}
-
 
860
		return $this->Action($action, 1);
-
 
861
	}
-
 
862
 
-
 
863
	// FORMS
-
 
864
	function FormOpen($method = "", $tag = "", $formMethod = "post") {
-
 
865
		$result = "<form action=\"".$this->href($method, $tag)."\" method=\"".$formMethod."\">\n";
-
 
866
		if (!$this->config["rewrite_mode"]) $result .= "<input type=\"hidden\" name=\"wiki\" value=\"".$this->MiniHref($method, $tag)."\" />\n";
-
 
867
		return $result;
-
 
868
	}
-
 
869
	function FormClose() {
-
 
870
		return "</form>\n";
-
 
871
	}
-
 
872
 
-
 
873
 
-
 
874
 
-
 
875
	// INTERWIKI STUFF
-
 
876
	function ReadInterWikiConfig() {
-
 
877
		if ($lines = file("interwiki.conf"))
-
 
878
		{
-
 
879
			foreach ($lines as $line)
-
 
880
			{
-
 
881
				if ($line = trim($line))
-
 
882
				{
-
 
883
					list($wikiName, $wikiUrl) = explode(" ", trim($line));
-
 
884
					$this->AddInterWiki($wikiName, $wikiUrl);
-
 
885
				}
-
 
886
			}
-
 
887
		}
-
 
888
	}
-
 
889
	function AddInterWiki($name, $url) {
-
 
890
		$this->interWiki[strtolower($name)] = $url;
-
 
891
	}
-
 
892
	function GetInterWikiUrl($name, $tag)
-
 
893
	{
-
 
894
		if (isset($this->interWiki[strtolower($name)])) return $this->interWiki[strtolower($name)].$tag;
-
 
895
		else return FALSE;
-
 
896
	}
-
 
897
 
-
 
898
 
-
 
899
 
-
 
900
	// REFERRERS
-
 
901
	function LogReferrer($tag = "", $referrer = "") {
-
 
902
		// fill values
-
 
903
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
-
 
904
		if (!$referrer = trim($referrer) AND isset($_SERVER["HTTP_REFERER"])) $referrer = $_SERVER["HTTP_REFERER"];
-
 
905
 
-
 
906
		// check if it's coming from another site
-
 
907
		if ($referrer && !preg_match("/^".preg_quote($this->GetConfigValue("base_url"), "/")."/", $referrer))
-
 
908
		{
-
 
909
			// avoid XSS (with urls like "javascript:alert()" and co)
-
 
910
			// by forcing http/https prefix
-
 
911
			// NB.: this does NOT exempt to htmlspecialchars() the collected URIs !
-
 
912
			if (!preg_match('`^https?://`', $referrer)) return;
-
 
913
 
-
 
914
			$this->Query("insert into ".$this->config["table_prefix"]."referrers set ".
-
 
915
				"page_tag = '".mysql_real_escape_string($tag)."', ".
-
 
916
				"referrer = '".mysql_real_escape_string($referrer)."', ".
-
 
917
				"time = now()");
-
 
918
		}
-
 
919
	}
-
 
920
	function LoadReferrers($tag = "") {
-
 
921
		return $this->LoadAll("select referrer, count(referrer) as num from ".$this->config["table_prefix"]."referrers ".($tag = trim($tag) ? "where page_tag = '".mysql_real_escape_string($tag)."'" : "")." group by referrer order by num desc");
-
 
922
	}
-
 
923
	function PurgeReferrers() {
-
 
924
		if ($days = $this->GetConfigValue("referrers_purge_time")) {
-
 
925
			$this->Query("delete from ".$this->config["table_prefix"]."referrers where time < date_sub(now(), interval '".mysql_real_escape_string($days)."' day)");
-
 
926
		}
-
 
927
	}
-
 
928
 
-
 
929
 
-
 
930
 
-
 
931
	// PLUGINS
-
 
932
	/**
-
 
933
	 * Exacutes an "action" module and returns the generated output
-
 
934
	 * @param string $action The name of the action and its eventual parameters,
-
 
935
	 * as it appears in the page between "{{" and "}}"
-
 
936
	 * @param boolean $forceLinkTracking By default, the link tracking will be disabled
-
 
937
	 * during the call of an action. Set this value to <code>true</code> to allow it.
-
 
938
	 * @param array $vars An array of additionnal parameters to give to the action, in the form
-
 
939
	 * array( 'param' => 'value').
-
 
940
	 * This allows you to call Action() internally, setting $action to the name of the action
-
 
941
	 * you want to call and it's parameters in an array, wich is more efficient than
-
 
942
	 * the pattern-matching algorithm used to extract the parameters from $action.
-
 
943
	 * @return The output generated by the action.
-
 
944
	 */
-
 
945
	function Action($action, $forceLinkTracking = 0, $vars = array())
-
 
946
	{
-
 
947
		$cmd = trim($action);
-
 
948
		// extract $action and $vars_temp ("raw" attributes)
-
 
949
		if (!preg_match("/^([a-zA-Z-0-9]+)\/?(.*)$/", $cmd, $matches))
-
 
950
		{
-
 
951
			return '<i>Action invalide &quot;' . htmlspecialchars($cmd) . '&quot;</i>';
-
 
952
		}
-
 
953
		list(, $action, $vars_temp) = $matches;
-
 
954
		$vars[$vars_temp] = $vars_temp; // usefull for {{action/vars_temp}}
-
 
955
 
-
 
956
		// now that we have the action's name, we can check if the user satisfies the ACLs
-
 
957
		if (!$this->CheckModuleACL($action, 'action'))
-
 
958
		{
-
 
959
			return 'Erreur: vous n\'avez pas acc&egrave;s &agrave; l\'action ' . $action . '.';
-
 
960
		}
-
 
961
 
-
 
962
		// match all attributes (key and value)
-
 
963
		// prepare an array for extract() to work with (in $this->IncludeBuffered())
-
 
964
		if (preg_match_all("/([a-zA-Z0-9]*)=\"(.*)\"/U", $vars_temp, $matches))
-
 
965
		{
-
 
966
			for ($a = 0; $a < count($matches[1]); $a++)
-
 
967
			{
-
 
968
				$vars[$matches[1][$a]] = $matches[2][$a];
-
 
969
			}
-
 
970
		}
-
 
971
 
-
 
972
		if (!$forceLinkTracking) $this->StopLinkTracking();
-
 
973
		if ($actionObj = &$this->GetActionObject($action))
-
 
974
		{
-
 
975
			if (is_object($actionObj))
-
 
976
			{
-
 
977
				$result = $actionObj->PerformAction($vars, $cmd);
-
 
978
			}
-
 
979
			else // $actionObj is an error message
-
 
980
			{
-
 
981
				$result = $actionObj;
-
 
982
			}
-
 
983
		}
-
 
984
		else // $actionObj == null (not found, no error message)
-
 
985
		{
-
 
986
			$this->parameter = &$vars;
-
 
987
			$result = $this->IncludeBuffered(strtolower($action).".php", "<i>Action inconnue &quot;$action&quot;</i>", $vars, $this->config["action_path"]);
-
 
988
			unset($this->parameter);
-
 
989
		}
-
 
990
		$this->StartLinkTracking(); // shouldn't we restore the previous status ?
-
 
991
		return $result;
-
 
992
	}
-
 
993
 
-
 
994
	/**
-
 
995
	 * Finds the object corresponding to an action, if it exists.
-
 
996
	 * @param string $name The name of an action (should be alphanumeric)
-
 
997
	 * @return mixed
-
 
998
	 * 	- null if the corresponding file was not found or the corresponding class didn't exist after inclusion
-
 
999
	 *  - an error string if the corresponding file was found but an error append while loading it
-
 
1000
	 *  - the object corresponding to this action if no problem happend
-
 
1001
	 * To check the result, you should use is_object() on it.
-
 
1002
	 * You should always assign the result of this method by referrence
-
 
1003
	 * to avoid copying the object, which is the default beheviour in PHP4.
-
 
1004
	 * @example
-
 
1005
	 * $var = &$wiki->GetActionObject('actionname');
-
 
1006
	 * if (is_object($var))
-
 
1007
	 * {
-
 
1008
	 * 		// normal behaviour
-
 
1009
	 * }
-
 
1010
	 * elseif ($var) // $var is not an object but an error string
-
 
1011
	 * {
-
 
1012
	 * 		// threat error
-
 
1013
	 * }
-
 
1014
	 * else // action was not found
-
 
1015
	 * {
-
 
1016
	 * 		// rescue from inexising action or sth
-
 
1017
	 * } 
-
 
1018
	 */
-
 
1019
	function &GetActionObject($name)
-
 
1020
	{
-
 
1021
		$name = strtolower($name);
-
 
1022
		$actionObj = null; // the generated object
-
 
1023
		if (!preg_match('/^[a-z0-9]+$/', $name)) // paranoiac
-
 
1024
		{
-
 
1025
			return $actionObj;
-
 
1026
		}
-
 
1027
 
-
 
1028
		// already tried to load this object ? (may be null)
-
 
1029
		if (isset($this->actionObjects[$name]))
-
 
1030
		{
-
 
1031
			return $this->actionObjects[$name];
-
 
1032
		}
-
 
1033
 
-
 
1034
		// object not loaded, try to load it
-
 
1035
		$filename = $name . '.class.php';
-
 
1036
		// load parent class for all action objects (only once)
-
 
1037
		require_once 'includes/action.class.php';
-
 
1038
		// include the action file, this should return an empty string
-
 
1039
		$result = $this->IncludeBuffered($filename, null, null, $this->GetConfigValue('action_path'));
-
 
1040
		if ($result) // the result was not an empty string, certainly an error message
-
 
1041
		{
-
 
1042
			$actionObj = $result;
-
 
1043
		}
-
 
1044
		elseif ($result !== false) // the result was empty but the file was found
-
 
1045
		{
-
 
1046
			$class = 'Action' . ucfirst($name);
-
 
1047
			if (class_exists($class))
-
 
1048
			{
-
 
1049
				$actionObj = new $class($this);
-
 
1050
				if (!is_a($actionObj, 'WikiniAction'))
-
 
1051
				{
-
 
1052
					die("Action invalide '$name': classe incorrecte");
-
 
1053
				}
-
 
1054
			}
-
 
1055
		}
-
 
1056
		$this->actionObjects[$name] = &$actionObj;
-
 
1057
		return $actionObj;
-
 
1058
	}
-
 
1059
 
-
 
1060
	/**
-
 
1061
	 * Retrieves the list of existing actions
-
 
1062
	 * @return array An unordered array of all the available actions.
-
 
1063
	 */
-
 
1064
	function GetActionsList()
-
 
1065
	{
-
 
1066
		$action_path = $this->GetConfigValue('action_path');
-
 
1067
		$list = array();
-
 
1068
		if ($dh = opendir($action_path))
-
 
1069
		{
-
 
1070
			while (($file = readdir($dh)) !== false)
-
 
1071
			{
-
 
1072
				if (preg_match('/^([a-zA-Z-0-9]+)(.class)?.php$/', $file, $matches))
-
 
1073
				{
-
 
1074
					$list[] = $matches[1];
-
 
1075
				}
-
 
1076
			}
-
 
1077
		}
-
 
1078
		return $list;
-
 
1079
	}
-
 
1080
 
-
 
1081
	/**
-
 
1082
	 * Retrieves the list of existing handlers
-
 
1083
	 * @return array An unordered array of all the available handlers.
-
 
1084
	 */
-
 
1085
	function GetHandlersList()
-
 
1086
	{
-
 
1087
		$handler_path = $this->GetConfigValue('handler_path') . '/page/';
-
 
1088
		$list = array();
-
 
1089
		if ($dh = opendir($handler_path))
-
 
1090
		{
-
 
1091
			while (($file = readdir($dh)) !== false)
-
 
1092
			{
-
 
1093
				if (preg_match('/^([a-zA-Z-0-9]+)(.class)?.php$/', $file, $matches))
-
 
1094
				{
-
 
1095
					$list[] = $matches[1];
-
 
1096
				}
-
 
1097
			}
-
 
1098
		}
-
 
1099
		return $list;
-
 
1100
	}
-
 
1101
 
-
 
1102
	function Method($method) {
-
 
1103
		if (!$handler = $this->page["handler"]) $handler = "page";
-
 
1104
		$methodLocation = $handler."/".$method.".php";
-
 
1105
		return $this->IncludeBuffered($methodLocation, "<i>M&eacute;thode inconnue \"$methodLocation\"</i>", "", $this->config["handler_path"]);
-
 
1106
	}
-
 
1107
	function Format($text, $formatter = "wakka") {
-
 
1108
		return $this->IncludeBuffered("formatters/".$formatter.".php", "<i>Impossible de trouver le formateur \"$formatter\"</i>", compact("text")); 
-
 
1109
	}
-
 
1110
 
-
 
1111
 
-
 
1112
 
-
 
1113
	// USERS
-
 
1114
	function LoadUser($name, $password = 0) { return $this->LoadSingle("select * from ".$this->config["table_prefix"]."users where name = '".mysql_real_escape_string($name)."' ".($password === 0 ? "" : "and password = '".mysql_real_escape_string($password)."'")." limit 1"); }
-
 
1115
	function LoadUsers() { return $this->LoadAll("select * from ".$this->config["table_prefix"]."users order by name"); }
-
 
1116
	function GetUserName() { if ($user = $this->GetUser()) $name = $user["name"]; else if (!$name = gethostbyaddr($_SERVER["REMOTE_ADDR"])) $name = $_SERVER["REMOTE_ADDR"]; return $name; }
-
 
1117
	function GetUser() { return (isset($_SESSION["user"]) ? $_SESSION["user"] : '');}
-
 
1118
	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); }
-
 
1119
	function LogoutUser() { $_SESSION["user"] = ""; $this->DeleteCookie("name"); $this->DeleteCookie("password"); }
-
 
1120
	function UserWantsComments() { if (!$user = $this->GetUser()) return false; return ($user["show_comments"] == "Y"); }
-
 
1121
	function GetParameter($parameter, $default = '') { return (isset($this->parameter[$parameter]) ? $this->parameter[$parameter] : $default); }
-
 
1122
 
-
 
1123
 
-
 
1124
	// COMMENTS
-
 
1125
	/**
-
 
1126
	 * Charge les commentaires relatifs ? une page.
-
 
1127
	 * 
-
 
1128
	 * @param string $tag Nom de la page. Ex : "PagePrincipale"
-
 
1129
	 * @return array Tableau contenant tous les commentaires et leurs
-
 
1130
	 * propri?t?s correspondantes.
-
 
1131
	 */
-
 
1132
	function LoadComments($tag)
-
 
1133
	{
-
 
1134
		return $this->LoadAll(
-
 
1135
			"select * " .
-
 
1136
			"from ".$this->config["table_prefix"]."pages " .
-
 
1137
			"where comment_on = '".mysql_real_escape_string($tag)."' " .
-
 
1138
			"and latest = 'Y' " .
-
 
1139
			"order by substring(tag, 8) + 0");
-
 
1140
	}
-
 
1141
	/**
-
 
1142
	 * Charge les derniers commentaires de toutes les pages.
-
 
1143
	 * 
-
 
1144
	 * @param int $limit Nombre de commentaires charg?s.
-
 
1145
	 *                   0 par d?faut (ie tous les commentaires).
-
 
1146
	 * @return array Tableau contenant chaque commentaire et ses
-
 
1147
	 *               propri?t?s associ?es.
-
 
1148
	 * @todo Ajouter le param?tre $start pour permettre une pagination
-
 
1149
	 *       des commentaires : ->LoadRecentComments(10, 10)
-
 
1150
	 */
-
 
1151
	function LoadRecentComments($limit = 0)
-
 
1152
	{
-
 
1153
		// The part of the query which limit the number of comments  
-
 
1154
		if(is_numeric($limit) && $limit > 0) $lim = " limit ".$limit;
-
 
1155
		else $lim = "";
-
 
1156
 
-
 
1157
		// Query
-
 
1158
		return $this->LoadAll(
-
 
1159
			"select * " .
-
 
1160
			"from " . $this->config["table_prefix"] . "pages " .
-
 
1161
			"where comment_on != '' " .
-
 
1162
			"and latest = 'Y' " .
-
 
1163
			"order by time desc " .
-
 
1164
			$lim);
-
 
1165
	}
-
 
1166
	function LoadRecentlyCommented($limit = 50)
-
 
1167
	{
-
 
1168
		$pages = array();
-
 
1169
 
-
 
1170
		// NOTE: this is really stupid. Maybe my SQL-Fu is too weak, but apparently there is no easier way to simply select
-
 
1171
		//       all comment pages sorted by their first revision's (!) time. ugh!
-
 
1172
 
-
 
1173
		// load ids of the first revisions of latest comments. err, huh?
-
 
1174
		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"))
-
 
1175
		{
-
 
1176
			// load complete comments
-
 
1177
			$num=0;
-
 
1178
			foreach ($ids as $id)
-
 
1179
			{
-
 
1180
				$comment = $this->LoadSingle("select * from ".$this->config["table_prefix"]."pages where id = '".$id["id"]."' limit 1");
-
 
1181
				if (!isset($comments[$comment["comment_on"]]) && $num < $limit)
-
 
1182
				{
-
 
1183
					$comments[$comment["comment_on"]] = $comment;
-
 
1184
					$num++;
-
 
1185
				}
-
 
1186
			}
-
 
1187
 
-
 
1188
			// now load pages
-
 
1189
			if ($comments)
-
 
1190
			{
-
 
1191
				// now using these ids, load the actual pages
-
 
1192
				foreach ($comments as $comment)
-
 
1193
				{
-
 
1194
					$page = $this->LoadPage($comment["comment_on"]);
-
 
1195
					$page["comment_user"] = $comment["user"];
-
 
1196
					$page["comment_time"] = $comment["time"];
-
 
1197
					$page["comment_tag"] = $comment["tag"];
-
 
1198
					$pages[] = $page;
-
 
1199
				}
-
 
1200
			}
-
 
1201
		}
-
 
1202
		// load tags of pages 
-
 
1203
		//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");
-
 
1204
		return $pages;
-
 
1205
	}
-
 
1206
 
-
 
1207
 
-
 
1208
 
-
 
1209
	// ACCESS CONTROL
-
 
1210
	// returns true if logged in user is owner of current page, or page specified in $tag
-
 
1211
	function UserIsOwner($tag = "") {
-
 
1212
		// check if user is logged in
-
 
1213
		if (!$this->GetUser()) return false;
-
 
1214
 
-
 
1215
		// set default tag
-
 
1216
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
-
 
1217
 
-
 
1218
		// check if user is owner
-
 
1219
		if ($this->GetPageOwner($tag) == $this->GetUserName()) return true;
-
 
1220
	}
-
 
1221
 
-
 
1222
	/**
-
 
1223
	 * @param string $group The name of a group
-
 
1224
	 * @return string the ACL associated with the group $gname
-
 
1225
	 * @see UserIsInGroup to check if a user belongs to some group
-
 
1226
	 */
-
 
1227
	function GetGroupACL($group)
-
 
1228
	{
-
 
1229
		if (array_key_exists($group, $this->_groupsCache))
-
 
1230
		{
-
 
1231
			return $this->_groupsCache[$group];
-
 
1232
		}
-
 
1233
		return $this->_groupsCache[$group] = $this->GetTripleValue($group, WIKINI_VOC_ACLS, GROUP_PREFIX);
-
 
1234
	}
-
 
1235
 
-
 
1236
	/**
-
 
1237
	 * Checks if a new group acl is not defined recursively
-
 
1238
	 * (this method expects that groups that are already defined are not themselves defined recursively...)
-
 
1239
	 * @param string $gname The name of the group
-
 
1240
	 * @param string $acl The new acl for that group
-
 
1241
	 * @return boolean True iff the new acl defines the group recursively
-
 
1242
	 */
-
 
1243
	function MakesGroupRecursive($gname, $acl, $origin = null, $checked = array())
-
 
1244
	{
-
 
1245
		$gname = strtolower($gname);
-
 
1246
		if ($origin === null)
-
 
1247
		{
-
 
1248
			$origin = $gname;
-
 
1249
		}
-
 
1250
		elseif ($gname === $origin)
-
 
1251
		{
-
 
1252
			return true;
-
 
1253
		}
-
 
1254
		foreach (explode("\n", $acl) as $line)
-
 
1255
		{
-
 
1256
			if (!$line) continue;
-
 
1257
			if ($line[0] == '!')
-
 
1258
			{
-
 
1259
				$line = substr($line, 1);
-
 
1260
			}
-
 
1261
			if (!$line) continue;
-
 
1262
			if ($line[0] == '@')
-
 
1263
			{
-
 
1264
				$line = substr($line, 1);
-
 
1265
				if (!in_array($line, $checked))
-
 
1266
				{
-
 
1267
					if ($this->MakesGroupRecursive($line, $this->GetGroupACL($line), $origin, $checked))
-
 
1268
					{
-
 
1269
						return true;
-
 
1270
					}
-
 
1271
				}
-
 
1272
			}
-
 
1273
		}
-
 
1274
		$checked[] = $gname;
-
 
1275
		return false;
-
 
1276
	}
-
 
1277
 
-
 
1278
	/**
-
 
1279
	 * Sets a new ACL to a given group
-
 
1280
	 * @param string $gname The name of a group
-
 
1281
	 * @param string $acl The new ACL to associate with the group $gname
-
 
1282
	 * @return int 0 if successful, a triple error code or a specific error code:
-
 
1283
	 * 	1000 if the new value would define the group recursively
-
 
1284
	 * 	1001 if $gname is not named with alphanumeric chars
-
 
1285
	 * @see GetGroupACL
-
 
1286
	 */
-
 
1287
	function SetGroupACL($gname, $acl)
-
 
1288
	{
-
 
1289
		if (preg_match('/[^A-Za-z0-9]/', $gname))
-
 
1290
		{
-
 
1291
			return 1001;
-
 
1292
		}
-
 
1293
		$old = $this->GetGroupACL($gname);
-
 
1294
		if ($this->MakesGroupRecursive($gname, $acl))
-
 
1295
		{
-
 
1296
			return 1000;
-
 
1297
		}
-
 
1298
		$this->_groupsCache[$gname] = $acl;
-
 
1299
		if ($old === null)
-
 
1300
		{
-
 
1301
			return $this->InsertTriple($gname, WIKINI_VOC_ACLS, $acl, GROUP_PREFIX);
-
 
1302
		}
-
 
1303
		elseif ($old === $acl)
-
 
1304
		{
-
 
1305
			return 0; // nothing has changed
-
 
1306
		}
-
 
1307
		else
-
 
1308
		{
-
 
1309
			return $this->UpdateTriple($gname, WIKINI_VOC_ACLS, $old, $acl, GROUP_PREFIX);
-
 
1310
		}
-
 
1311
	}
-
 
1312
	/**
-
 
1313
	 * @return array The list of all group names
-
 
1314
	 */
-
 
1315
	function GetGroupsList()
-
 
1316
	{
-
 
1317
		$res = $this->GetMatchingTriples(GROUP_PREFIX . '%', WIKINI_VOC_ACLS_URI);
-
 
1318
		$prefix_len = strlen(GROUP_PREFIX);
-
 
1319
		$list = array();
-
 
1320
		foreach ($res as $line)
-
 
1321
		{
-
 
1322
			$list[] = substr($line['resource'], $prefix_len);
-
 
1323
		}
-
 
1324
		return $list;
-
 
1325
	}
-
 
1326
 
-
 
1327
	/**
-
 
1328
	 * @param string $group The name of a group
-
 
1329
	 * @return boolean true iff the user is in the given $group 
-
 
1330
	 */
-
 
1331
	function UserIsInGroup($group, $user = null, $admincheck = true)
-
 
1332
	{
-
 
1333
		return $this->CheckACL($this->GetGroupACL($group), $user, $admincheck);
-
 
1334
	}
-
 
1335
 
-
 
1336
	/**
-
 
1337
	 * Checks if a given user is andministrator
-
 
1338
	 * @param string $user The name of the user (defaults to the current user if not given)
-
 
1339
	 * @return boolean true iff the user is an administrator
-
 
1340
	 */
-
 
1341
	function UserIsAdmin($user = null)
-
 
1342
	{
-
 
1343
		return $this->UserIsInGroup(ADMIN_GROUP, $user, false);
-
 
1344
	}
-
 
1345
 
-
 
1346
	function GetPageOwner($tag = "", $time = "") { if (!$tag = trim($tag)) $tag = $this->GetPageTag(); if ($page = $this->LoadPage($tag, $time)) return $page["owner"]; }
-
 
1347
	function SetPageOwner($tag, $user) {
-
 
1348
		// check if user exists
-
 
1349
		if (!$this->LoadUser($user)) return;
-
 
1350
 
-
 
1351
		// updated latest revision with new owner
-
 
1352
		$this->Query("update ".$this->config["table_prefix"]."pages set owner = '".mysql_real_escape_string($user)."' where tag = '".mysql_real_escape_string($tag)."' and latest = 'Y' limit 1");
-
 
1353
	}
-
 
1354
	function LoadAcl($tag, $privilege, $useDefaults = 1) {
-
 
1355
		if ((!$acl = $this->LoadSingle("select * from ".$this->config["table_prefix"]."acls where page_tag = '".mysql_real_escape_string($tag)."' and privilege = '".mysql_real_escape_string($privilege)."' limit 1")) && $useDefaults)
-
 
1356
		{
-
 
1357
			$acl = array("page_tag" => $tag, "privilege" => $privilege, "list" => $this->GetConfigValue("default_".$privilege."_acl"));
-
 
1358
		}
-
 
1359
		return $acl;
-
 
1360
	}
-
 
1361
	function SaveAcl($tag, $privilege, $list) {
-
 
1362
		if ($this->LoadAcl($tag, $privilege, 0)) $this->Query("update ".$this->config["table_prefix"]."acls set list = '".mysql_real_escape_string(trim(str_replace("\r", "", $list)))."' where page_tag = '".mysql_real_escape_string($tag)."' and privilege = '".mysql_real_escape_string($privilege)."' limit 1");
-
 
1363
		else $this->Query("insert into ".$this->config["table_prefix"]."acls set list = '".mysql_real_escape_string(trim(str_replace("\r", "", $list)))."', page_tag = '".mysql_real_escape_string($tag)."', privilege = '".mysql_real_escape_string($privilege)."'");
-
 
1364
	}
-
 
1365
	// returns true if $user (defaults to current user) has access to $privilege on $page_tag (defaults to current page)
-
 
1366
	function HasAccess($privilege, $tag = "", $user = "") {
-
 
1367
		// set defaults
-
 
1368
		if (!$tag = trim($tag)) $tag = $this->GetPageTag();
-
 
1369
		if (!$user)
-
 
1370
		{
-
 
1371
			// if current user is owner, return true. owner can do anything!
-
 
1372
			if ($this->UserIsOwner($tag)) return true;
-
 
1373
			$user = $this->GetUserName();
-
 
1374
		}
-
 
1375
 
-
 
1376
		// TODO: we might want to check if a given $user (other than the current user)
-
 
1377
		// has access to a given page. If the $user is the owner of that page,
-
 
1378
		// this method might give a wrong result (because we can't check that)
-
 
1379
 
-
 
1380
		// load acl
-
 
1381
		$acl = $this->LoadAcl($tag, $privilege);
-
 
1382
 
-
 
1383
		// fine fine... now go through acl
-
 
1384
		return $this->CheckACL($acl["list"], $user);
-
 
1385
	}
-
 
1386
 
-
 
1387
	/**
-
 
1388
	 * Checks if some $user satisfies the given $acl
-
 
1389
	 * @param string $acl The acl to check, in the same format than for pages ACL's
-
 
1390
	 * @param string $user The name of the user that must satisfy the ACL. By default
-
 
1391
	 * the current remote user.
-
 
1392
	 * @return bool True if the $user satisfies the $acl, false otherwise
-
 
1393
	 */
-
 
1394
	function CheckACL($acl, $user = null, $admincheck = true)
-
 
1395
	{
-
 
1396
		if (!$user)
-
 
1397
		{
-
 
1398
			$user = $this->GetUserName();
-
 
1399
		}
-
 
1400
 
-
 
1401
		if ($admincheck && $this->UserIsAdmin($user))
-
 
1402
		{
-
 
1403
			return true;
-
 
1404
		}
-
 
1405
 
-
 
1406
 
-
 
1407
		foreach (explode("\n", $acl) as $line)
-
 
1408
		{
-
 
1409
			$line = trim($line);
-
 
1410
 
-
 
1411
			// check for inversion character "!"
-
 
1412
			if (preg_match("/^[!](.*)$/", $line, $matches))
-
 
1413
			{
-
 
1414
				$negate = 1;
-
 
1415
				$line = $matches[1];
-
 
1416
			}
-
 
1417
			else
-
 
1418
			{
-
 
1419
				$negate = 0;
-
 
1420
			}
-
 
1421
 
-
 
1422
			// if there's still anything left... lines with just a "!" don't count!
-
 
1423
			if ($line)
-
 
1424
			{
-
 
1425
				switch ($line[0])
-
 
1426
				{
-
 
1427
				case "#": // comments
-
 
1428
					break;
-
 
1429
				case "*": // everyone
-
 
1430
					return !$negate;
-
 
1431
				case "+": // registered users
-
 
1432
					if (!$this->LoadUser($user)) 
-
 
1433
					{
-
 
1434
						return $negate;
-
 
1435
					}
-
 
1436
					else
-
 
1437
					{
-
 
1438
						return !$negate;
-
 
1439
					}
-
 
1440
				case '@': // groups
-
 
1441
					$gname = substr($line, 1);
-
 
1442
					// paranoiac: avoid line = '@'
-
 
1443
					if ($gname && $this->UserIsInGroup($gname, $user, false /* we have allready checked if user was an admin */))
-
 
1444
					{
-
 
1445
						return !$negate;
-
 
1446
					}
-
 
1447
					break;
-
 
1448
				default: // simple user entry
-
 
1449
					if ($line == $user)
-
 
1450
					{
-
 
1451
						return !$negate;
-
 
1452
					}
-
 
1453
				}
-
 
1454
			}
-
 
1455
		}
-
 
1456
 
-
 
1457
		// tough luck.
-
 
1458
		return false;
-
 
1459
	}
-
 
1460
 
-
 
1461
	/**
-
 
1462
	 * Loads the module ACL for a certain module
-
 
1463
	 * @param string $module The name of the module
-
 
1464
	 * @param string $module_type The type of module: 'action' or 'handler'
-
 
1465
	 * @return mixed The ACL for the given module or <tt>null</tt> if no such
-
 
1466
	 * ACL was found (which should probably be interpreted as '*'). 
-
 
1467
	 */
-
 
1468
	function GetModuleACL($module, $module_type)
-
 
1469
	{
-
 
1470
		$module = strtolower($module);
-
 
1471
		switch ($module_type)
-
 
1472
		{
-
 
1473
		case 'action':
-
 
1474
			if (array_key_exists($module, $this->_actionsAclsCache))
-
 
1475
			{
-
 
1476
				$acl = $this->_actionsAclsCache[$module];
-
 
1477
				break;
-
 
1478
			}
-
 
1479
			$this->_actionsAclsCache[$module] = $acl = $this->GetTripleValue($module, WIKINI_VOC_ACLS, WIKINI_VOC_ACTIONS_PREFIX);
-
 
1480
			if ($acl === null)
-
 
1481
			{
-
 
1482
				$action = &$this->GetActionObject($module);
-
 
1483
				if (is_object($action))
-
 
1484
				{
-
 
1485
					return $this->_actionsAclsCache[$module] = $action->GetDefaultACL();
-
 
1486
				}
-
 
1487
			}
-
 
1488
			break;
-
 
1489
		case 'handler':
-
 
1490
			$acl = $this->GetTripleValue($module, WIKINI_VOC_ACLS, WIKINI_VOC_HANDLERS_PREFIX);
-
 
1491
			break;
-
 
1492
		default:
-
 
1493
			return null; // TODO error msg ?
-
 
1494
		}
-
 
1495
		return $acl === null ? '*' : $acl;
-
 
1496
	}
-
 
1497
 
-
 
1498
	/**
-
 
1499
	 * Sets the $acl for a given $module
-
 
1500
	 * @param string $module The name of the module
-
 
1501
	 * @param string $module_type The type of module ('action' or 'handler')
-
 
1502
	 * @param string $acl The new ACL for that module
-
 
1503
	 * @return 0 on success, > 0 on error (see InsertTriple and UpdateTriple)
-
 
1504
	 */
-
 
1505
	function SetModuleACL($module, $module_type, $acl)
-
 
1506
	{
-
 
1507
		$module = strtolower($module);
-
 
1508
		$voc_prefix = $module_type == 'action' ? WIKINI_VOC_ACTIONS_PREFIX : WIKINI_VOC_HANDLERS_PREFIX;
-
 
1509
		$old = $this->GetTripleValue($module, WIKINI_VOC_ACLS, $voc_prefix);
-
 
1510
		if ($module_type == 'action')
-
 
1511
		{
-
 
1512
			$this->_actionsAclsCache[$module] = $acl;
-
 
1513
		}
-
 
1514
		if ($old === null)
-
 
1515
		{
-
 
1516
			return $this->InsertTriple($module, WIKINI_VOC_ACLS, $acl, $voc_prefix);
-
 
1517
		}
-
 
1518
		elseif ($old === $acl)
-
 
1519
		{
-
 
1520
			return 0; // nothing has changed
-
 
1521
		}
-
 
1522
		else
-
 
1523
		{
-
 
1524
			return $this->UpdateTriple($module, WIKINI_VOC_ACLS, $old, $acl, $voc_prefix);
-
 
1525
		}
-
 
1526
	}
-
 
1527
 
-
 
1528
	/**
-
 
1529
	 * Checks if a $user satisfies the ACL to access a certain $module
-
 
1530
	 * @param string $module The name of the module to access
-
 
1531
	 * @param string $module_type The type of the module ('action' or 'handler')
-
 
1532
	 * @param string $user The name of the user. By default
-
 
1533
	 * the current remote user.
-
 
1534
	 * @return bool True if the $user has access to the given $module, false otherwise.
-
 
1535
	 */
-
 
1536
	function CheckModuleACL($module, $module_type, $user = null)
-
 
1537
	{
-
 
1538
		$acl = $this->GetModuleACL($module, $module_type);
-
 
1539
		if ($acl === null) return true; // undefined ACL means everybody has access
-
 
1540
		return $this->CheckACL($acl, $user);
-
 
1541
	}
-
 
1542
 
-
 
1543
 
-
 
1544
	// MAINTENANCE
-
 
1545
	function Maintenance() {
-
 
1546
		// purge referrers
-
 
1547
		$this->PurgeReferrers();
-
 
1548
		// purge old page revisions
-
 
1549
		$this->PurgePages();
-
 
1550
	}
-
 
1551
 
-
 
1552
 
-
 
1553
 
-
 
1554
	// THE BIG EVIL NASTY ONE!
-
 
1555
	function Run($tag, $method = "") {
-
 
1556
		if(!($this->GetMicroTime()%9)) $this->Maintenance(); 
-
 
1557
 
-
 
1558
		$this->ReadInterWikiConfig();
-
 
1559
 
-
 
1560
		// do our stuff!
-
 
1561
		if (!$this->method = trim($method)) $this->method = "show";
-
 
1562
		if (!$this->tag = trim($tag)) $this->Redirect($this->href("", $this->config["root_page"]));
-
 
1563
		if ((!$this->GetUser() && isset($_COOKIE["name"])) && ($user = $this->LoadUser($_COOKIE["name"], $_COOKIE["password"]))) $this->SetUser($user, $_COOKIE["remember"]);
-
 
1564
		$this->SetPage($this->LoadPage($tag, (isset($_REQUEST["time"]) ? $_REQUEST["time"] :'')));
-
 
1565
		$this->LogReferrer();
-
 
1566
 
-
 
1567
		//correction pour un support plus facile de nouveaux handlers
-
 
1568
		if ($this->CheckModuleACL($this->method, 'handler'))
-
 
1569
		{
-
 
1570
			echo $this->Method($this->method);
-
 
1571
		}
-
 
1572
		else
-
 
1573
		{
-
 
1574
			echo 'Vous ne pouvez pas acc&eacute;der &agrave; cette page par le handler sp&eacute;cifi&eacute;.';
-
 
1575
		}
-
 
1576
 
-
 
1577
		// action redirect: aucune redirection n'a eu lieu, effacer la liste des redirections pr?c?dentes
-
 
1578
		if(!empty($_SESSION['redirects'])) session_unregister('redirects');
-
 
1579
	}
-
 
1580
}
-
 
1581
 
-
 
1582
 
-
 
1583
 
-
 
1584
// stupid version check
-
 
1585
if (!isset($_REQUEST)) die('$_REQUEST[] not found. Wakka requires PHP 4.1.0 or higher!');
-
 
1586
 
-
 
1587
// workaround for the amazingly annoying magic quotes.
-
 
1588
function magicQuotesSuck(&$a)
-
 
1589
{
-
 
1590
	if (is_array($a))
-
 
1591
	{
-
 
1592
		foreach ($a as $k => $v)
-
 
1593
		{
-
 
1594
			if (is_array($v))
-
 
1595
				magicQuotesSuck($a[$k]);
-
 
1596
			else
-
 
1597
				$a[$k] = stripslashes($v);
-
 
1598
		}
-
 
1599
	}
-
 
1600
}
-
 
1601
 
-
 
1602
if (get_magic_quotes_runtime())
-
 
1603
{
-
 
1604
    // Deactivate
-
 
1605
    set_magic_quotes_runtime(false);
-
 
1606
}
-
 
1607
 
-
 
1608
if (get_magic_quotes_gpc())
-
 
1609
{
-
 
1610
	magicQuotesSuck($_POST);
-
 
1611
	magicQuotesSuck($_GET);
-
 
1612
	magicQuotesSuck($_COOKIE);
-
 
1613
}
-
 
1614
 
-
 
1615
 
-
 
1616
// default configuration values
-
 
1617
$wakkaConfig= array();
-
 
1618
$_rewrite_mode = detectRewriteMode();
-
 
1619
$wakkaDefaultConfig = array(
-
 
1620
	'wakka_version'		=> '',
-
 
1621
	'wikini_version'	=> '',
-
 
1622
	'debug'				=> 'no',
-
 
1623
	"mysql_host"		=> "localhost",
-
 
1624
	"mysql_database"	=> "wikini",
-
 
1625
	"mysql_user"		=> "wikini",
-
 
1626
	"mysql_password"	=> '',
-
 
1627
	"table_prefix"		=> "wikini_",
-
 
1628
	"root_page"			=> "PagePrincipale",
-
 
1629
	"wakka_name"		=> "MonSiteWikiNi",
-
 
1630
	"base_url"			=> computeBaseURL($_rewrite_mode),
-
 
1631
	"rewrite_mode"		=> $_rewrite_mode,
-
 
1632
	'meta_keywords'		=> '',
-
 
1633
	'meta_description'	=> '',
-
 
1634
	"action_path"		=> "actions",
-
 
1635
	"handler_path"		=> "handlers",
-
 
1636
	"header_action"		=> "header",
-
 
1637
	"footer_action"		=> "footer",
-
 
1638
	"navigation_links"		=> "DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur",
-
 
1639
	"referrers_purge_time"	=> 24,
-
 
1640
	"pages_purge_time"	=> 90,
-
 
1641
	"default_write_acl"	=> "*",
-
 
1642
	"default_read_acl"	=> "*",
-
 
1643
	"default_comment_acl"	=> "*",
-
 
1644
	"preview_before_save"	=> 0,
-
 
1645
	'allow_raw_html'	=> false);
-
 
1646
unset($_rewrite_mode);
-
 
1647
 
-
 
1648
// load config
-
 
1649
if (!$configfile = GetEnv("WAKKA_CONFIG")) $configfile = "wakka.config.php";
-
 
1650
if (file_exists($configfile)) include($configfile);
-
 
1651
$wakkaConfigLocation = $configfile;
-
 
1652
$wakkaConfig = array_merge($wakkaDefaultConfig, $wakkaConfig);
-
 
1653
 
-
 
1654
// check for locking
-
 
1655
if (file_exists("locked")) {
-
 
1656
	// read password from lockfile
-
 
1657
	$lines = file("locked");
-
 
1658
	$lockpw = trim($lines[0]);
-
 
1659
 
-
 
1660
	// is authentification given?
-
 
1661
	if (isset($_SERVER["PHP_AUTH_USER"])) {
-
 
1662
		if (!(($_SERVER["PHP_AUTH_USER"] == "admin") && ($_SERVER["PHP_AUTH_PW"] == $lockpw))) {
-
 
1663
			$ask = 1;
-
 
1664
		}
-
 
1665
	} else {
-
 
1666
		$ask = 1;
-
 
1667
	}
-
 
1668
 
-
 
1669
	if ($ask) {
-
 
1670
		header("WWW-Authenticate: Basic realm=\"".$wakkaConfig["wakka_name"]." Install/Upgrade Interface\"");
-
 
1671
		header("HTTP/1.0 401 Unauthorized");
-
 
1672
		echo "Ce site est en cours de mise &agrave; jour. Veuillez essayer plus tard." ;
-
 
1673
		exit;
-
 
1674
	}
-
 
1675
}
-
 
1676
 
-
 
1677
 
-
 
1678
// compare versions, start installer if necessary
-
 
1679
if ($wakkaConfig["wakka_version"] && (!$wakkaConfig["wikini_version"])) { $wakkaConfig["wikini_version"]=$wakkaConfig["wakka_version"]; }
-
 
1680
if (($wakkaConfig["wakka_version"] != WAKKA_VERSION) || ($wakkaConfig["wikini_version"] != WIKINI_VERSION)) {
-
 
1681
	// start installer
-
 
1682
	if (!isset($_REQUEST["installAction"]) OR !$installAction = trim($_REQUEST["installAction"])) $installAction = "default";
-
 
1683
	include("setup/header.php");
-
 
1684
	if (file_exists("setup/".$installAction.".php")) include("setup/".$installAction.".php"); else echo "<i>Invalid action</i>" ;
-
 
1685
	include("setup/footer.php");
-
 
1686
	exit;
-
 
1687
}
-
 
1688
 
-
 
1689
// Check if the server is configured to automatically compress the output
-
 
1690
if (!ini_get('zlib.output_compression') && !ini_get('zlib.output_handler'))
-
 
1691
{ 
-
 
1692
	// Check if we can use ob_gzhandler (requires the zlib extension)
-
 
1693
	if (function_exists('ob_gzhandler'))
-
 
1694
	{
-
 
1695
		// let ob_gzhandler do the dirty job
-
 
1696
		// NB.: this must be done BEFORE session_start() when session.use_trans_sid is on
-
 
1697
		ob_start('ob_gzhandler');
-
 
1698
	}
-
 
1699
	// else lets do the dirty job by ourselves...
-
 
1700
	elseif (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode'))
-
 
1701
	{
-
 
1702
		ob_start ('gzencode');
-
 
1703
		// Tell the browser the content is compressed with gzip 
-
 
1704
		header ("Content-Encoding: gzip"); 
-
 
1705
	}
-
 
1706
}
-
 
1707
 
-
 
1708
// configuration du cookie de session
-
 
1709
// determine le chemin pour les cookies
-
 
1710
$a = parse_url($wakkaConfig['base_url']);
-
 
1711
$CookiePath = dirname($a['path']);
-
 
1712
// Fixe la gestion des cookie sous les OS utilisant le \ comme s?parteur de chemin
-
 
1713
$CookiePath = str_replace("\\","/",$CookiePath);
-
 
1714
// ajoute un '/' terminal sauf si on est ? la racine web
-
 
1715
if ($CookiePath != '/') $CookiePath .= '/';
-
 
1716
$a = session_get_cookie_params();
-
 
1717
session_set_cookie_params($a['lifetime'],$CookiePath);
-
 
1718
unset($a);
-
 
1719
unset($CookiePath);
-
 
1720
 
-
 
1721
// start session
-
 
1722
session_start();
-
 
1723
 
-
 
1724
// fetch wakka location
-
 
1725
if (empty($_REQUEST['wiki']))
-
 
1726
{
-
 
1727
	// redirect to the root page
-
 
1728
	header('Location: ' . $wakkaConfig['base_url'] . $wakkaConfig['root_page']);
-
 
1729
	exit;
-
 
1730
}
-
 
1731
$wiki = $_REQUEST['wiki'];
-
 
1732
 
-
 
1733
// remove leading slash
-
 
1734
$wiki = preg_replace("/^\//", "", $wiki);
-
 
1735
 
-
 
1736
// split into page/method, checking wiki name & method name (XSS proof)
-
 
1737
if (preg_match('`^' . WN_TAG_HANDLER_CAPTURE . '$`', $wiki, $matches))
-
 
1738
{
-
 
1739
	list(, $page, $method) = $matches;
-
 
1740
}
-
 
1741
elseif (preg_match('`^' . WN_PAGE_TAG . '$`', $wiki))
-
 
1742
{
-
 
1743
	$page = $wiki;
-
 
1744
}
-
 
1745
else
-
 
1746
{
-
 
1747
	echo "<p>Le nom de la page est incorrect.</p>";
-
 
1748
	exit;
-
 
1749
}
-
 
1750
 
-
 
1751
// create wiki object
-
 
1752
$wiki = new Wiki($wakkaConfig);
-
 
1753
// check for database access
-
 
1754
if (!$wiki->dblink)
-
 
1755
{
-
 
1756
	echo	"<p>Pour des raisons ind&eacute;pendantes de notre volont&eacute;, ".
-
 
1757
		"le contenu de ce Wiki est temporairement inaccessible. Veuillez ".
-
 
1758
		"r&eacute;essayer ult&eacute;rieurement, merci de votre ".
-
 
1759
		"compr&eacute;hension.</p>";
-
 
1760
	// Log error (useful to find the buggy server in a load balancing platform)
-
 
1761
	trigger_error("WikiNi : DB connection failed");
-
 
1762
	exit;
-
 
1763
}
-
 
1764
 
-
 
1765
 
-
 
1766
// go!
-
 
1767
if (!isset($method)) $method='';
-
 
1768
 
-
 
1769
 
-
 
1770
// Security (quick hack)  : Check method syntax
-
 
1771
if (!(preg_match('#^[A-Za-z0-9_]*$#',$method))) {
-
 
1772
	$method='';
-
 
1773
}
-
 
1774
include('tools/prepend.php');//$wiki->Run($page, $method);
-
 
1775
?>
-
 
1776