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