Migrate wiki.inc.php as a core class PlWikiPage.
[platal.git] / classes / plwikipage.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2008 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
22 /** This namespace groups all the methods relative to the integration
23 * of PmWiki into plat/al.
24 *
25 * pagename: A page name is NameSpace.Page and must be acceed trough
26 * NameSpace/Page.
27 */
28 class PlWikiPage
29 {
30 static private $permLevels = array('public' => 'Public',
31 'logged' => 'Connecté',
32 'mdp' => 'Authentifié',
33 'admin' => 'Admin');
34 static private $defaulPerms = array('logged', 'admin');
35
36 public $name;
37 public $path;
38
39 private $perms = null;
40
41 /** Build a new page from a PmWiki page name (ie NameSpace.Page).
42 */
43 public function __construct($n)
44 {
45 if (!is_utf8($n)) {
46 $n = utf8_encode($n);
47 }
48 $this->name = $n;
49 $this->path = str_replace('.', '/', $n);
50 }
51
52 /** Return the filename.
53 */
54 public function filename()
55 {
56 return self::workDir() . '/' . $this->name;
57 }
58
59 /** Return the filename for the cache file.
60 */
61 public function cacheFilename()
62 {
63 return self::workDir() . '/cache_' . $this->name . '.tpl';
64 }
65
66 /** Fetch the permissions.
67 */
68 private function fetchPerms()
69 {
70 if (!is_null($this->perms)) {
71 return;
72 }
73 $file = $this->filename();
74 if (!file_exists($file)) {
75 $this->perms = self::$defaulPerms;
76 return;
77 }
78 $lines = explode("\n", file_get_contents($file));
79 foreach ($lines as $line) {
80 @list($k, $v) = explode('=', $line, 2);
81 if ($k == 'platal_perms') {
82 $this->perms = explode(':', $v);
83 return;
84 }
85 }
86 $this->perms = self::$defaulPerms;
87 }
88
89 /** Return read perms.
90 */
91 public function readPerms()
92 {
93 if (is_null($this->perms)) {
94 $this->fetchPerms();
95 }
96 return $this->perms[0];
97 }
98
99 /** Check if the user can read the page.
100 */
101 public function canRead()
102 {
103 return self::havePerms($this->readPerms());
104 }
105
106 /** Return write perms.
107 */
108 public function writePerms()
109 {
110 if (is_null($this->perms)) {
111 $this->fetchPerms();
112 }
113 return $this->perms[1];
114 }
115
116 /** Check if the user can write the page.
117 */
118 public function canWrite()
119 {
120 return self::havePerms($this->writePerms());
121 }
122
123 /** Set the permission level for the page.
124 */
125 public function setPerms($read, $write)
126 {
127 $file = $this->filename();
128 if (!file_exists($file)) {
129 return false;
130 }
131
132 $p = $read . ':' . $write;
133 $lines = explode("\n", file_get_contents($file));
134 foreach ($lines as $i => $line) {
135 list($k, $v) = explode('=', $line, 2);
136 if ($k == 'platal_perms') {
137 unset($lines[$i]);
138 break;
139 }
140 }
141 array_splice($lines, 1, 0, array('platal_perms=' . $p));
142 file_put_contents($file, join("\n", $lines));
143 $this->perms = array($read, $write);
144 return true;
145 }
146
147
148 /** Check permission for RSS feed.
149 */
150 public function prepareFeed()
151 {
152 if ($this->canRead()) {
153 return;
154 }
155 $uid = Platal::session()->tokenAuth(Get::v('user'), Get::v('hash'));
156 if ($this->canRead()) {
157 return;
158 }
159 exit;
160 }
161
162 /** Apply the read permissions for the current page.
163 */
164 public function applyReadPerms()
165 {
166 if ($this->canRead()) {
167 return;
168 }
169 $this->applyPerms($this->readPerms());
170 }
171
172 /** Apply the write permissions for the current page.
173 */
174 public function applyWritePerms()
175 {
176 if ($this->canWrite()) {
177 return;
178 }
179 $this->applyPerms($this->writePerms());
180 }
181
182 /** Build the cache for the page.
183 */
184 public function buildCache()
185 {
186 global $globals;
187 if (is_file($this->cacheFilename())) {
188 return;
189 }
190 system('wget --no-check-certificate ' . escapeshellarg($globals->baseurl . '/' . $this->path) . ' -O /dev/null');
191 }
192
193 /** Remove the page.
194 */
195 public function delete()
196 {
197 $file = $this->filename();
198 $cache = $this->cacheFilename();
199 if (is_file($cache)) {
200 unlink($cache);
201 }
202 if (!is_file($file)) {
203 return false;
204 }
205 unlink($file);
206 return true;
207 }
208
209 /** Return the wiki storage dir.
210 */
211 public static function workDir()
212 {
213 global $globals;
214 return $globals->spoolroot . '/spool/wiki.d';
215 }
216
217 /** Clear wiki cache.
218 */
219 public static function clearCache()
220 {
221 system('rm -f ' . self::workDir() . '/cache_*');
222 }
223
224
225 /** Search links in the a page
226 */
227 private static function findLinks($line, $groupname)
228 {
229 $links = array();
230 if (preg_match_all('@\[\[([^~][^\]\|\?#]*)((\?|#)[^\]\|]+)?(\\|[^\]]+)?\]\]@', $line, $matches, PREG_OFFSET_CAPTURE)) {
231 foreach ($matches[1] as $j => $link) if (!preg_match('@http://@', $link[0])) {
232 $mylink = str_replace('/','.',trim($link[0]));
233 $sup = trim(substr($matches[2][$j][0],1));
234 $alt = trim(substr($matches[4][$j][0],1));
235 $newlink = str_replace(' ','',ucwords($mylink));
236 if (strpos($newlink,'.') === false) {
237 $newlink = $groupname.'.'.$newlink;
238 }
239 if (!$alt && $mylink != $newlink) {
240 $alt = trim($link[0]);
241 }
242 $links[] = array(
243 'pos' => $matches[0][$j][1],
244 'size' => strlen($matches[0][$j][0]),
245 'href' => $newlink,
246 'sup' => $sup,
247 'alt' => $alt,
248 'group' => substr($mylink, 0, strpos($mylink, '.')));
249 }
250 }
251 return $links;
252 }
253
254 public function rename($newname, $changeLinks = true)
255 {
256 $newpage = new PlWikiPage(str_replace('/', '.', $newname));
257
258 list($groupname, ) = explode('.', $this->name);
259 list($newgroupname, ) = explode('.', $newpage->name);
260
261 $file = $this->filename();
262 $newfile = $newpage->filename();
263 if (!is_file($file)) {
264 // old page doesn't exist
265 return false;
266 }
267 if (!rename($file, $newfile)) {
268 // impossible to renama page
269 return false;
270 }
271
272 if (!$changeLinks) {
273 $this->name = $newpage->name;
274 $this->path = $newpage->path;
275 return true;
276 }
277
278 $changedLinks = 0;
279 // change name inside this folder and ingroup links if changing group
280 $lines = explode("\n", file_get_contents($newfile));
281 $changed = false;
282 foreach ($lines as $i => $line) {
283 list($k, $v) = explode('=', $line, 2);
284 if ($k == 'name' && $v == $pagename_dots) {
285 $lines[$i] = 'name=' . $newpage->name;
286 $changed = true;
287 } else if ($groupname != $newgroupname) {
288 $links = self::findLinks($line, $groupname);
289 $newline = '';
290 $last = 0;
291 foreach ($links as $link) {
292 if ($link['group'] == $groupname) {
293 $newline .= substr($line, $last, $link['pos']);
294 $newline .= '[['.$link['href'].$link['sup'].($link['alt']?(' |'.$link['alt']):'').']]';
295 $last = $link['pos']+$link['size'];
296 $changedLinks++;
297 }
298 }
299 if ($last != 0) {
300 $newline .= substr($line, $last);
301 $lines[$i] = $newline;
302 $changed = true;
303 }
304 }
305 }
306 file_put_contents($newfile, join("\n", $lines));
307
308 // change wiki links in all wiki pages
309 $endname = substr($pagename_dots, strpos($this->name, '.') + 1);
310 $pages = array();
311 exec('grep ' . $endname . ' ' . self::workDir() . '/* -sc', $pages);
312 foreach($pages as $line) {
313 if (preg_match('%/([^/:]+):([0-9]+)$%', $line, $vals) && $vals[2] > 0) {
314 $inpage = $vals[1];
315 $lines = explode("\n", file_get_contents(self::workDir().'/'.$inpage));
316 $changed = false;
317 // find all wiki links in page and change if linked to this page
318 foreach ($lines as $i => $line) {
319 $links = self::findLinks($line, substr($inpage, 0, strpos($inpage, '.')));
320 $newline = '';
321 $last = 0;
322 foreach ($links as $link) {
323 if ($link['href'] == $pagename_dots) {
324 $newline .= substr($line, $last, $link['pos']);
325 $newline .= '[[' . $newname_dots . $link['sup'] . ($link['alt'] ? (' |' . $link['alt']) : '') . ']]';
326 $last = $link['pos'] + $link['size'];
327 $changedLinks++;
328 }
329 }
330 if ($last != 0) {
331 $newline .= substr($line, $last);
332 $lines[$i] = $newline;
333 $changed = true;
334 }
335 }
336 if ($changed) {
337 file_put_contents(self::workDir() . '/' . $inpage, join("\n", $lines));
338 }
339 }
340 }
341 if ($changedLinks > 0) {
342 return $changedLinks;
343 }
344 $this->name = $newpage->name;
345 $this->path = $newpage->path;
346 return true;
347 }
348
349 /** Return the authentication level translation table.
350 */
351 public static function permOptions()
352 {
353 return array('public' => 'Public',
354 'logged' => 'Connecté',
355 'mdp' => 'Authentifié',
356 'admin' => 'Admin');
357 }
358
359 /** Check permissions.
360 */
361 public static function havePerms($perm)
362 {
363 switch ($perm) {
364 case 'public':
365 return true;
366 case 'logged':
367 case 'mdp':
368 return S::logged();
369 case 'admin':
370 return S::has_perms();
371 default:
372 return false;
373 }
374 }
375
376 /** Apply permissions.
377 */
378 public static function applyPerms($perm)
379 {
380 switch ($perm) {
381 case 'public':
382 return;
383 case 'logged':
384 Platal::session()->start(AUTH_PUBLIC + 1);
385 return;
386 default:
387 Platal::session()->start(Platal::session()->sureLevel());
388 return;
389 }
390 }
391
392 /** Return the current page.
393 */
394 public static function currentPage()
395 {
396 if (!Get::v('n')) {
397 return null;
398 }
399
400 $words = explode('/', trim(Get::v('n'), '/'));
401 if (count($words) == 2) {
402 return new PlWikiPage(join('.', $words));
403 }
404
405 // We are on NameSpace.Page, redirect to NameSpace/Page
406 array_unshift($words, $words[0]);
407 $b = array_pop($words);
408 $a = array_pop($words);
409
410 pl_redirect($a . '/' . $b);
411 }
412 }
413
414 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
415 ?>