Commit | Line | Data |
---|---|---|
ccb397e5 FB |
1 | <?php |
2 | /*************************************************************************** | |
2ab75571 | 3 | * Copyright (C) 2003-2010 Polytechnique.org * |
ccb397e5 FB |
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 | ||
ec537891 | 39 | private $content = null; |
ccb397e5 FB |
40 | private $perms = null; |
41 | ||
42 | /** Build a new page from a PmWiki page name (ie NameSpace.Page). | |
43 | */ | |
44 | public function __construct($n) | |
45 | { | |
46 | if (!is_utf8($n)) { | |
47 | $n = utf8_encode($n); | |
48 | } | |
49 | $this->name = $n; | |
50 | $this->path = str_replace('.', '/', $n); | |
51 | } | |
52 | ||
53 | /** Return the filename. | |
54 | */ | |
55 | public function filename() | |
56 | { | |
57 | return self::workDir() . '/' . $this->name; | |
58 | } | |
59 | ||
60 | /** Return the filename for the cache file. | |
61 | */ | |
62 | public function cacheFilename() | |
63 | { | |
64 | return self::workDir() . '/cache_' . $this->name . '.tpl'; | |
65 | } | |
66 | ||
6cc34b50 FB |
67 | /** Remove the cache for the current page. |
68 | */ | |
69 | public function removePageCache() | |
70 | { | |
71 | @unlink($this->cacheFilename()); | |
72 | global $globals; | |
73 | $page = glob($globals->spoolroot . '/spool/templates_c/*cache_' . $this->name . '.tpl.php'); | |
74 | if (count($page) > 0) { | |
75 | @unlink($page[0]); | |
76 | } | |
77 | } | |
78 | ||
ec537891 | 79 | /** Fetch the content of the wiki page. |
ccb397e5 | 80 | */ |
ec537891 | 81 | private function fetchContent() |
ccb397e5 | 82 | { |
ec537891 | 83 | if (!is_null($this->content)) { |
ccb397e5 FB |
84 | return; |
85 | } | |
86 | $file = $this->filename(); | |
ec537891 | 87 | if (!is_file($file)) { |
ccb397e5 FB |
88 | return; |
89 | } | |
90 | $lines = explode("\n", file_get_contents($file)); | |
ec537891 | 91 | $this->content = array(); |
ccb397e5 FB |
92 | foreach ($lines as $line) { |
93 | @list($k, $v) = explode('=', $line, 2); | |
ec537891 FB |
94 | $this->content[$k] = $v; |
95 | } | |
96 | } | |
97 | ||
98 | /** Save the content of the wiki page based on the | |
99 | * fetched content. | |
100 | */ | |
101 | private function saveContent() | |
102 | { | |
103 | if (is_null($this->content)) { | |
104 | return false; | |
105 | } | |
106 | $lines = array(); | |
107 | foreach ($this->content as $k => $v) { | |
108 | $lines[] = "$k=$v"; | |
109 | } | |
110 | return file_put_contents($this->filename(), implode("\n", $lines)) !== false; | |
111 | } | |
112 | ||
113 | /** Get a field from the wiki content. | |
114 | */ | |
115 | public function getField($name) | |
116 | { | |
117 | $this->fetchContent(); | |
118 | return @$this->content[$name]; | |
119 | } | |
120 | ||
121 | /** Fetch the permissions. | |
122 | */ | |
123 | private function fetchPerms() | |
124 | { | |
125 | if (!is_null($this->perms)) { | |
126 | return; | |
127 | } | |
128 | $this->fetchContent(); | |
129 | if (isset($this->content['platal_perms'])) { | |
130 | $this->perms = explode(':', $this->content['platal_perms']); | |
131 | } else { | |
132 | $this->perms = self::$defaulPerms; | |
ccb397e5 | 133 | } |
ccb397e5 FB |
134 | } |
135 | ||
136 | /** Return read perms. | |
137 | */ | |
138 | public function readPerms() | |
139 | { | |
140 | if (is_null($this->perms)) { | |
141 | $this->fetchPerms(); | |
142 | } | |
143 | return $this->perms[0]; | |
144 | } | |
145 | ||
146 | /** Check if the user can read the page. | |
147 | */ | |
148 | public function canRead() | |
149 | { | |
150 | return self::havePerms($this->readPerms()); | |
151 | } | |
152 | ||
153 | /** Return write perms. | |
154 | */ | |
155 | public function writePerms() | |
156 | { | |
157 | if (is_null($this->perms)) { | |
158 | $this->fetchPerms(); | |
159 | } | |
160 | return $this->perms[1]; | |
161 | } | |
162 | ||
163 | /** Check if the user can write the page. | |
164 | */ | |
165 | public function canWrite() | |
166 | { | |
167 | return self::havePerms($this->writePerms()); | |
168 | } | |
169 | ||
170 | /** Set the permission level for the page. | |
171 | */ | |
172 | public function setPerms($read, $write) | |
173 | { | |
ec537891 FB |
174 | $this->fetchContent(); |
175 | if (is_null($this->content)) { | |
ccb397e5 FB |
176 | return false; |
177 | } | |
ec537891 | 178 | $this->content['platal_perms'] = $read . ':' . $write; |
ccb397e5 | 179 | $this->perms = array($read, $write); |
ec537891 | 180 | return $this->saveContent(); |
ccb397e5 FB |
181 | } |
182 | ||
183 | ||
184 | /** Check permission for RSS feed. | |
185 | */ | |
186 | public function prepareFeed() | |
187 | { | |
188 | if ($this->canRead()) { | |
189 | return; | |
190 | } | |
191 | $uid = Platal::session()->tokenAuth(Get::v('user'), Get::v('hash')); | |
192 | if ($this->canRead()) { | |
193 | return; | |
194 | } | |
195 | exit; | |
196 | } | |
197 | ||
198 | /** Apply the read permissions for the current page. | |
199 | */ | |
200 | public function applyReadPerms() | |
201 | { | |
202 | if ($this->canRead()) { | |
203 | return; | |
204 | } | |
205 | $this->applyPerms($this->readPerms()); | |
206 | } | |
207 | ||
208 | /** Apply the write permissions for the current page. | |
209 | */ | |
210 | public function applyWritePerms() | |
211 | { | |
212 | if ($this->canWrite()) { | |
213 | return; | |
214 | } | |
215 | $this->applyPerms($this->writePerms()); | |
216 | } | |
217 | ||
218 | /** Build the cache for the page. | |
219 | */ | |
220 | public function buildCache() | |
221 | { | |
222 | global $globals; | |
223 | if (is_file($this->cacheFilename())) { | |
224 | return; | |
225 | } | |
226 | system('wget --no-check-certificate ' . escapeshellarg($globals->baseurl . '/' . $this->path) . ' -O /dev/null'); | |
227 | } | |
228 | ||
229 | /** Remove the page. | |
230 | */ | |
231 | public function delete() | |
232 | { | |
233 | $file = $this->filename(); | |
234 | $cache = $this->cacheFilename(); | |
235 | if (is_file($cache)) { | |
236 | unlink($cache); | |
237 | } | |
238 | if (!is_file($file)) { | |
239 | return false; | |
240 | } | |
241 | unlink($file); | |
242 | return true; | |
243 | } | |
244 | ||
245 | /** Return the wiki storage dir. | |
246 | */ | |
247 | public static function workDir() | |
248 | { | |
249 | global $globals; | |
250 | return $globals->spoolroot . '/spool/wiki.d'; | |
251 | } | |
252 | ||
253 | /** Clear wiki cache. | |
254 | */ | |
255 | public static function clearCache() | |
256 | { | |
257 | system('rm -f ' . self::workDir() . '/cache_*'); | |
258 | } | |
259 | ||
260 | ||
261 | /** Search links in the a page | |
262 | */ | |
263 | private static function findLinks($line, $groupname) | |
264 | { | |
265 | $links = array(); | |
266 | if (preg_match_all('@\[\[([^~][^\]\|\?#]*)((\?|#)[^\]\|]+)?(\\|[^\]]+)?\]\]@', $line, $matches, PREG_OFFSET_CAPTURE)) { | |
267 | foreach ($matches[1] as $j => $link) if (!preg_match('@http://@', $link[0])) { | |
268 | $mylink = str_replace('/','.',trim($link[0])); | |
269 | $sup = trim(substr($matches[2][$j][0],1)); | |
270 | $alt = trim(substr($matches[4][$j][0],1)); | |
271 | $newlink = str_replace(' ','',ucwords($mylink)); | |
272 | if (strpos($newlink,'.') === false) { | |
273 | $newlink = $groupname.'.'.$newlink; | |
274 | } | |
275 | if (!$alt && $mylink != $newlink) { | |
276 | $alt = trim($link[0]); | |
277 | } | |
278 | $links[] = array( | |
279 | 'pos' => $matches[0][$j][1], | |
280 | 'size' => strlen($matches[0][$j][0]), | |
281 | 'href' => $newlink, | |
282 | 'sup' => $sup, | |
283 | 'alt' => $alt, | |
284 | 'group' => substr($mylink, 0, strpos($mylink, '.'))); | |
285 | } | |
286 | } | |
287 | return $links; | |
288 | } | |
289 | ||
290 | public function rename($newname, $changeLinks = true) | |
291 | { | |
292 | $newpage = new PlWikiPage(str_replace('/', '.', $newname)); | |
ec537891 FB |
293 | $cache = $this->cacheFilename(); |
294 | if (is_file($cache)) { | |
295 | unlink($cache); | |
296 | } | |
ccb397e5 FB |
297 | |
298 | list($groupname, ) = explode('.', $this->name); | |
299 | list($newgroupname, ) = explode('.', $newpage->name); | |
300 | ||
301 | $file = $this->filename(); | |
302 | $newfile = $newpage->filename(); | |
303 | if (!is_file($file)) { | |
304 | // old page doesn't exist | |
305 | return false; | |
306 | } | |
307 | if (!rename($file, $newfile)) { | |
308 | // impossible to renama page | |
309 | return false; | |
310 | } | |
311 | ||
312 | if (!$changeLinks) { | |
313 | $this->name = $newpage->name; | |
314 | $this->path = $newpage->path; | |
315 | return true; | |
316 | } | |
317 | ||
318 | $changedLinks = 0; | |
319 | // change name inside this folder and ingroup links if changing group | |
320 | $lines = explode("\n", file_get_contents($newfile)); | |
321 | $changed = false; | |
322 | foreach ($lines as $i => $line) { | |
323 | list($k, $v) = explode('=', $line, 2); | |
324 | if ($k == 'name' && $v == $pagename_dots) { | |
325 | $lines[$i] = 'name=' . $newpage->name; | |
326 | $changed = true; | |
327 | } else if ($groupname != $newgroupname) { | |
328 | $links = self::findLinks($line, $groupname); | |
329 | $newline = ''; | |
330 | $last = 0; | |
331 | foreach ($links as $link) { | |
332 | if ($link['group'] == $groupname) { | |
333 | $newline .= substr($line, $last, $link['pos']); | |
334 | $newline .= '[['.$link['href'].$link['sup'].($link['alt']?(' |'.$link['alt']):'').']]'; | |
335 | $last = $link['pos']+$link['size']; | |
336 | $changedLinks++; | |
337 | } | |
338 | } | |
339 | if ($last != 0) { | |
340 | $newline .= substr($line, $last); | |
341 | $lines[$i] = $newline; | |
342 | $changed = true; | |
343 | } | |
344 | } | |
345 | } | |
346 | file_put_contents($newfile, join("\n", $lines)); | |
347 | ||
348 | // change wiki links in all wiki pages | |
349 | $endname = substr($pagename_dots, strpos($this->name, '.') + 1); | |
350 | $pages = array(); | |
351 | exec('grep ' . $endname . ' ' . self::workDir() . '/* -sc', $pages); | |
352 | foreach($pages as $line) { | |
353 | if (preg_match('%/([^/:]+):([0-9]+)$%', $line, $vals) && $vals[2] > 0) { | |
354 | $inpage = $vals[1]; | |
355 | $lines = explode("\n", file_get_contents(self::workDir().'/'.$inpage)); | |
356 | $changed = false; | |
357 | // find all wiki links in page and change if linked to this page | |
358 | foreach ($lines as $i => $line) { | |
359 | $links = self::findLinks($line, substr($inpage, 0, strpos($inpage, '.'))); | |
360 | $newline = ''; | |
361 | $last = 0; | |
362 | foreach ($links as $link) { | |
363 | if ($link['href'] == $pagename_dots) { | |
364 | $newline .= substr($line, $last, $link['pos']); | |
365 | $newline .= '[[' . $newname_dots . $link['sup'] . ($link['alt'] ? (' |' . $link['alt']) : '') . ']]'; | |
366 | $last = $link['pos'] + $link['size']; | |
367 | $changedLinks++; | |
368 | } | |
369 | } | |
370 | if ($last != 0) { | |
371 | $newline .= substr($line, $last); | |
372 | $lines[$i] = $newline; | |
373 | $changed = true; | |
374 | } | |
375 | } | |
376 | if ($changed) { | |
377 | file_put_contents(self::workDir() . '/' . $inpage, join("\n", $lines)); | |
378 | } | |
379 | } | |
380 | } | |
381 | if ($changedLinks > 0) { | |
382 | return $changedLinks; | |
383 | } | |
384 | $this->name = $newpage->name; | |
385 | $this->path = $newpage->path; | |
386 | return true; | |
387 | } | |
388 | ||
389 | /** Return the authentication level translation table. | |
390 | */ | |
391 | public static function permOptions() | |
392 | { | |
393 | return array('public' => 'Public', | |
394 | 'logged' => 'Connecté', | |
395 | 'mdp' => 'Authentifié', | |
396 | 'admin' => 'Admin'); | |
397 | } | |
398 | ||
399 | /** Check permissions. | |
400 | */ | |
401 | public static function havePerms($perm) | |
402 | { | |
403 | switch ($perm) { | |
404 | case 'public': | |
405 | return true; | |
406 | case 'logged': | |
ccb397e5 | 407 | return S::logged(); |
f1c8bb75 FB |
408 | case 'mdp': |
409 | return S::identified(); | |
ccb397e5 | 410 | case 'admin': |
f1c8bb75 | 411 | return S::admin(); |
ccb397e5 FB |
412 | default: |
413 | return false; | |
414 | } | |
415 | } | |
416 | ||
417 | /** Apply permissions. | |
418 | */ | |
419 | public static function applyPerms($perm) | |
420 | { | |
421 | switch ($perm) { | |
422 | case 'public': | |
423 | return; | |
424 | case 'logged': | |
4f67da27 FB |
425 | $ok = Platal::session()->start(AUTH_PUBLIC + 1); |
426 | break; | |
ccb397e5 | 427 | default: |
4f67da27 FB |
428 | $ok = Platal::session()->start(Platal::session()->sureLevel()); |
429 | break; | |
430 | } | |
431 | if (!$ok) { | |
432 | global $platal; | |
433 | $page =& Platal::page(); | |
434 | $platal->force_login($page); | |
ccb397e5 FB |
435 | } |
436 | } | |
437 | ||
438 | /** Return the current page. | |
439 | */ | |
440 | public static function currentPage() | |
441 | { | |
442 | if (!Get::v('n')) { | |
443 | return null; | |
444 | } | |
445 | ||
446 | $words = explode('/', trim(Get::v('n'), '/')); | |
447 | if (count($words) == 2) { | |
448 | return new PlWikiPage(join('.', $words)); | |
449 | } | |
450 | ||
451 | // We are on NameSpace.Page, redirect to NameSpace/Page | |
452 | array_unshift($words, $words[0]); | |
453 | $b = array_pop($words); | |
454 | $a = array_pop($words); | |
455 | ||
456 | pl_redirect($a . '/' . $b); | |
457 | } | |
ec537891 FB |
458 | |
459 | /** List wiki pages. | |
460 | */ | |
461 | public static function listPages() | |
462 | { | |
463 | $wiki_pages = array(); | |
464 | $dir = PlWikiPage::workDir(); | |
465 | if (is_dir($dir)) { | |
466 | if ($dh = opendir($dir)) { | |
467 | while (($file = readdir($dh)) !== false) { | |
468 | if ($file{0} >= 'A' && $file{0} <= 'Z') { | |
469 | $wp = new PlWikiPage($file); | |
470 | $wiki_pages[$file] = array('read' => $wp->readPerms(), | |
471 | 'edit' => $wp->writePerms(), | |
472 | 'cached' => is_file($wp->cacheFilename())); | |
473 | } | |
474 | } | |
475 | closedir($dh); | |
476 | } | |
477 | } | |
478 | return $wiki_pages; | |
479 | } | |
ccb397e5 FB |
480 | } |
481 | ||
482 | // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: | |
483 | ?> |