This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * gwikiPage.php - class to access wiki page data |
||
4 | * |
||
5 | * This file is part of gwiki - geekwright wiki |
||
6 | */ |
||
7 | |||
8 | // defined('XOOPS_ROOT_PATH') || exit('XOOPS root path not defined'); |
||
9 | |||
10 | define('_WIKI_CAMELCASE_REGEX', '(([A-Z]{1,}[a-z\x80-\xff0-9\:]+){2,}\d*)'); |
||
11 | define('_WIKI_KEYWORD_REGEX', '([A-Za-z\x80-\xff0-9.\:-]{1,})'); |
||
12 | |||
13 | /** |
||
14 | * gwikiPage.php - class to access wiki page data |
||
15 | * |
||
16 | * |
||
17 | * @category Class |
||
18 | * @package Gwiki |
||
19 | * @author Richard Griffith <[email protected]> |
||
20 | * @copyright 2013-2015 geekwright, LLC. All rights reserved. |
||
21 | * @license gwiki/docs/license.txt GNU General Public License (GPL) |
||
22 | */ |
||
23 | class GwikiPage |
||
24 | { |
||
25 | //------------------------------------------------------------ |
||
26 | // Properties - public, protected, and private |
||
27 | //------------------------------------------------------------ |
||
28 | |||
29 | protected $currentid; |
||
30 | protected $currentkeyword; |
||
31 | public $gwiki_id; |
||
32 | public $keyword; |
||
33 | public $display_keyword; |
||
34 | public $title; |
||
35 | public $body; |
||
36 | public $parent_page; |
||
37 | public $page_set_home; |
||
38 | public $page_set_order; |
||
39 | public $meta_description; |
||
40 | public $meta_keywords; |
||
41 | public $lastmodified; |
||
42 | public $uid; |
||
43 | public $admin_lock; |
||
44 | public $active; |
||
45 | public $search_body; |
||
46 | public $toc_cache; |
||
47 | public $show_in_index; |
||
48 | public $gwiki_version; |
||
49 | |||
50 | public $page_id; // an integer id for the keyword |
||
51 | public $wikiHomePage; // the home page |
||
52 | public $currentprefix; // Prefix of current keyword, if any |
||
53 | public $currentprefixid; // id of current Prefix |
||
54 | public $currenttemplateid; // template for current Prefix (0=use default) |
||
55 | public $attachments; |
||
56 | |||
57 | public $renderedPage; |
||
58 | |||
59 | private $numberOfRecentItems = 10; |
||
60 | // $wikiLinkURL is a sprintf format string, with keyword as only arg. Better link establised in __construct() |
||
61 | private $wikiLinkURL = 'index.php?page=%s'; |
||
62 | public $dateFormat; |
||
63 | public $defaultThumbSize; |
||
64 | private $tocIdPrefix = 'toc'; |
||
65 | private $tocAnchorFmt = '#%s'; |
||
66 | private $imageLib = array(); |
||
67 | private $useCamelCase; |
||
68 | private $autoNameFormat; |
||
69 | |||
70 | private $module_id; |
||
71 | |||
72 | private $wikiDir; // dirname of the gwiki module |
||
73 | private $gwikiVersion = 1; // wiki syntax version for future backward compatibility |
||
74 | |||
75 | private $highlightArg; |
||
76 | |||
77 | private $noWikiQueue = array(); // hold no wiki content during rendering |
||
78 | private $noWikiIndex = 0; |
||
79 | |||
80 | private $tocQueue = array(); // track headers for toc |
||
81 | private $tocIndex = 0; |
||
82 | |||
83 | private $refQueue = array(); // track reference |
||
84 | private $refIndex = 0; |
||
85 | private $refShown = false; |
||
86 | |||
87 | private $wikiPageLinks = array(); // link in current page |
||
88 | |||
89 | // Out Of Bounds data - not cleared with resetPage |
||
90 | private $pageIndexPrefix = ''; // current prefix for the pageindex |
||
91 | |||
92 | //------------------------------------------------------------ |
||
93 | // Methods |
||
94 | //------------------------------------------------------------ |
||
95 | |||
96 | /** |
||
97 | * class constructor |
||
98 | */ |
||
99 | public function __construct() |
||
100 | { |
||
101 | $this->resetPage(); |
||
102 | $dir = basename(dirname(__DIR__)); |
||
103 | $this->wikiDir = $dir; |
||
104 | |||
105 | $moduleHelper = Xmf\Module\Helper::getHelper($dir); |
||
106 | |||
107 | $this->wikiLinkURL = $moduleHelper->getConfig('wikilink_template'); |
||
108 | $this->wikiHomePage = $moduleHelper->getConfig('wiki_home_page'); |
||
109 | $this->dateFormat = $moduleHelper->getConfig('date_format'); |
||
110 | $this->imageLib = explode(',', $moduleHelper->getConfig('imagelib_pages')); |
||
111 | $this->useCamelCase = $moduleHelper->getConfig('allow_camelcase'); |
||
112 | $this->defaultThumbSize = $moduleHelper->getConfig('default_thumb_size'); |
||
113 | $this->autoNameFormat = $moduleHelper->getConfig('auto_name_format'); |
||
114 | $this->module_id = $moduleHelper->getModule()->getVar('mid'); |
||
115 | |||
116 | if (!defined('_MI_GWIKI_WIKIHOME')) { |
||
117 | $this->loadLanguage('modinfo', $dir); |
||
118 | } |
||
119 | if (!defined('_MD_GWIKI_PAGE_PERM_EDIT_ANY_NUM')) { |
||
120 | $this->loadLanguage('main', $dir); |
||
121 | } |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * load language resources |
||
126 | * |
||
127 | * @param string $name language file name (main, modinfo, etc.) |
||
128 | * @param string $domain domain/module |
||
129 | * @param null $language language |
||
130 | * |
||
131 | * @return void |
||
132 | */ |
||
133 | View Code Duplication | private function loadLanguage($name, $domain = '', $language = null) |
|
134 | { |
||
135 | global $xoopsConfig; |
||
136 | if (!@include_once XOOPS_ROOT_PATH . "/modules/{$domain}/language/" . $xoopsConfig['language'] . "/{$name}.php") { |
||
137 | include_once XOOPS_ROOT_PATH . "/modules/{$domain}/language/english/{$name}.php"; |
||
138 | } |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Reset all page properties |
||
143 | * |
||
144 | * @return void |
||
145 | */ |
||
146 | protected function resetPage() |
||
147 | { |
||
148 | $this->gwiki_id = null; |
||
149 | $this->keyword = ''; |
||
150 | $this->display_keyword = ''; |
||
151 | $this->title = ''; |
||
152 | $this->body = ''; |
||
153 | $this->parent_page = ''; |
||
154 | $this->page_set_home = ''; |
||
155 | $this->page_set_order = ''; |
||
156 | $this->meta_description = ''; |
||
157 | $this->meta_keywords = ''; |
||
158 | $this->lastmodified = 0; |
||
159 | $this->uid = 0; |
||
160 | $this->admin_lock = 0; |
||
161 | $this->active = 0; |
||
162 | $this->search_body = ''; |
||
163 | $this->toc_cache = ''; |
||
164 | $this->show_in_index = 1; |
||
165 | $this->gwiki_version = $this->gwikiVersion; |
||
166 | |||
167 | $this->page_id = 0; |
||
168 | $this->created = 0; |
||
169 | $this->renderedPage = ''; |
||
170 | $this->currentprefix = ''; |
||
171 | $this->currentprefixid = ''; |
||
172 | $this->currenttemplateid = 0; |
||
173 | $this->attachments = array(); |
||
174 | $this->tocQueue = array(); |
||
175 | $this->tocIndex = 0; |
||
176 | $this->refQueue = array(); |
||
177 | $this->refIndex = 0; |
||
178 | $this->refShown = false; |
||
179 | $this->wikiPageLinks = array(); |
||
180 | } |
||
181 | |||
182 | /** |
||
183 | * escape a string to be "safe" for use in database |
||
184 | * |
||
185 | * @param string $value string to be escaped |
||
186 | * |
||
187 | * @return string |
||
188 | */ |
||
189 | public function escapeForDB($value) |
||
190 | { |
||
191 | global $xoopsDB; |
||
192 | |||
193 | return $value = $xoopsDB->escape($value); |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * set the count for recent item list |
||
198 | * |
||
199 | * @param int $count item count |
||
200 | * |
||
201 | * @return void |
||
202 | */ |
||
203 | public function setRecentCount($count) |
||
204 | { |
||
205 | $count = (int)$count; |
||
206 | if ($count > 1 && $count < 1000) { |
||
207 | $this->numberOfRecentItems = $count; |
||
208 | } |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * Set the URL pattern for wiki links |
||
213 | * |
||
214 | * @param string $url sprintf pattern for URL. Will get page name as parameter. |
||
215 | * |
||
216 | * @return void |
||
217 | */ |
||
218 | public function setWikiLinkURL($url) |
||
219 | { |
||
220 | $this->wikiLinkURL = $url; |
||
221 | } |
||
222 | |||
223 | /** |
||
224 | * Get the URL pattern for wiki links |
||
225 | * |
||
226 | * @return string |
||
227 | */ |
||
228 | public function getWikiLinkURL() |
||
229 | { |
||
230 | return $this->wikiLinkURL; |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * git the wiki directory (dirname) |
||
235 | * |
||
236 | * @return string |
||
237 | */ |
||
238 | public function getWikiDir() |
||
239 | { |
||
240 | return $this->wikiDir; |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * get max upload size from ini |
||
245 | * |
||
246 | * @return int|string |
||
247 | */ |
||
248 | public function getMaxUploadSize() |
||
249 | { |
||
250 | $val = trim(ini_get('upload_max_filesize')); |
||
251 | $last = strtolower($val[strlen($val) - 1]); |
||
252 | switch ($last) { |
||
253 | // The 'G' modifier is available since PHP 5.1.0 |
||
254 | case 'g': |
||
255 | $val *= 1024; |
||
256 | // no break |
||
257 | case 'm': |
||
258 | $val *= 1024; |
||
259 | // no break |
||
260 | case 'k': |
||
261 | $val *= 1024; |
||
262 | // no break |
||
263 | } |
||
264 | |||
265 | return $val; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * set format for TOC links |
||
270 | * |
||
271 | * @param string $prefix prefix |
||
272 | * @param string $linkformat anchor |
||
273 | * |
||
274 | * @return void |
||
275 | */ |
||
276 | public function setTocFormat($prefix, $linkformat) |
||
277 | { |
||
278 | $this->tocIdPrefix = $prefix; |
||
279 | $this->tocAnchorFmt = $linkformat; |
||
280 | } |
||
281 | |||
282 | /** |
||
283 | * Make sure that keyword obeys formatting rules or switch to illegal name |
||
284 | * |
||
285 | * @param mixed $keyword - wiki page name |
||
286 | * |
||
287 | * @return string |
||
288 | */ |
||
289 | public function makeKeyword($keyword) |
||
290 | { |
||
291 | if (!preg_match('#^' . _WIKI_KEYWORD_REGEX . '$#', $keyword)) { |
||
292 | $keyword = _MI_GWIKI_WIKI404; |
||
293 | } else { // check for undefined prefix |
||
294 | $prefix = $this->getPrefix($keyword); |
||
295 | if ($prefix && !$prefix['defined']) { |
||
296 | $keyword = _MI_GWIKI_WIKI404; |
||
297 | } |
||
298 | } |
||
299 | |||
300 | return $keyword; |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * add namespace prefix to a wiki word |
||
305 | * |
||
306 | * @param int $nsid namespace (prefix) id |
||
307 | * @param string $page keyword |
||
308 | * |
||
309 | * @return bool|string |
||
310 | */ |
||
311 | public function makeKeywordFromPrefix($nsid, $page) |
||
312 | { |
||
313 | if ($nsid >= 0) { |
||
314 | $pfx = $this->getPrefixFromId($nsid); |
||
315 | if (empty($page)) { |
||
316 | if ($pfx['prefix_auto_name']) { |
||
317 | $page = date($this->autoNameFormat); |
||
318 | } else { |
||
319 | $page = $pfx['prefix_home']; |
||
320 | } |
||
321 | } |
||
322 | $page = $pfx['prefix'] . ':' . $page; |
||
323 | } |
||
324 | |||
325 | return $page; |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Capture out of bounds data traveling with keyword. Such data is sent |
||
330 | * in keyword(oob) construct. This function processes any oob data and |
||
331 | * returns a clean keyword. |
||
332 | * oob data is used this way to pass page specific data in any url |
||
333 | * |
||
334 | * Only call this if you will NOT be calling normalizeKeyword or the |
||
335 | * OOB data will be lost. |
||
336 | * |
||
337 | * @param mixed $keyword - wiki page name possibily containing OOB data |
||
338 | * |
||
339 | * @return string - keyword with no OOB data |
||
340 | */ |
||
341 | public function getOOBFromKeyword($keyword) |
||
342 | { |
||
343 | $oob = null; |
||
344 | if (substr($keyword, -1) === ')') { |
||
345 | $lparen = strpos($keyword, '('); |
||
346 | if ($lparen !== false) { |
||
347 | $inparen = substr($keyword, $lparen); |
||
348 | $inparen = substr($inparen, 1, -2); |
||
349 | $keyword = substr($keyword, 0, $lparen); |
||
350 | $oob = $inparen; |
||
351 | } |
||
352 | } |
||
353 | // currently this is the only use |
||
354 | $this->pageIndexPrefix = strtolower($oob); |
||
355 | |||
356 | return $keyword; |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * If page exists, fix case of page name to that specified in database |
||
361 | * |
||
362 | * @param string $keyword - wiki page name |
||
363 | * |
||
364 | * @return string normalized keyword |
||
365 | */ |
||
366 | public function normalizeKeyword($keyword) |
||
367 | { |
||
368 | global $xoopsDB; |
||
369 | |||
370 | $keyword = $this->getOOBFromKeyword($keyword); |
||
371 | $keyword = $this->escapeForDB($keyword); |
||
372 | $sql = 'SELECT keyword FROM ' . $xoopsDB->prefix('gwiki_pages') . " WHERE keyword='{$keyword}' AND active=1 "; |
||
373 | $result = $xoopsDB->query($sql); |
||
374 | if ($content = $xoopsDB->fetchArray($result)) { |
||
375 | $keyword = $content['keyword']; |
||
376 | } else { |
||
377 | $keyword = $this->makeKeyword($keyword); |
||
378 | } |
||
379 | |||
380 | return $keyword; |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * Get the gwiki_id of the active page for the keyword |
||
385 | * |
||
386 | * @param mixed $keyword - wiki page name |
||
387 | * |
||
388 | * @return int - id of page |
||
389 | */ |
||
390 | public function getCurrentId($keyword) |
||
391 | { |
||
392 | global $xoopsDB; |
||
393 | |||
394 | $sql = 'SELECT gwiki_id FROM ' . $xoopsDB->prefix('gwiki_pages'); |
||
395 | $sql .= " WHERE keyword='{$keyword}' AND active = 1 ORDER BY gwiki_id DESC LIMIT 1"; |
||
396 | $result = $xoopsDB->query($sql); |
||
397 | list($id) = $xoopsDB->fetchRow($result); |
||
398 | |||
399 | return (int)$id; |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * Add current page as a new revision |
||
404 | * |
||
405 | * @param bool $leave_inactive true to save page as inactive |
||
406 | * |
||
407 | * @return mixed |
||
408 | */ |
||
409 | public function addRevision($leave_inactive = false) |
||
410 | { |
||
411 | global $xoopsDB; |
||
412 | |||
413 | $page = $this->escapeForDB($this->keyword); |
||
414 | if (empty($this->display_keyword)) { |
||
415 | $this->display_keyword = $page; |
||
416 | } |
||
417 | $this->tocQueue = array(); |
||
418 | $this->tocIndex = 0; |
||
419 | $this->refQueue = array(); |
||
420 | $this->refIndex = 0; |
||
421 | $this->wikiPageLinks = array(); |
||
422 | |||
423 | // eliminate things we don't want in search page because they |
||
424 | // are misleading and/or change outside of the page itself |
||
425 | $search[] = "#{(PageIndex|RecentChanges)([^\"<\n]+?)?}#si"; |
||
426 | $replace[] = ''; |
||
427 | $search[] = "#\{toc\}#i"; |
||
428 | $replace[] = ''; |
||
429 | $search[] = "#\{pagesettoc\}#i"; |
||
430 | $replace[] = ''; |
||
431 | $tempbody = preg_replace($search, $replace, $this->body) . "\n\n"; |
||
432 | |||
433 | $this->search_body = strip_tags($this->renderPage($tempbody)); |
||
434 | $this->toc_cache = serialize($this->tocQueue); |
||
435 | $this->gwiki_version = $this->gwikiVersion; // new revisions always for current engine |
||
436 | |||
437 | // if we are adding to a page set, auto increment the order if none specified |
||
438 | if (!empty($this->page_set_home) && $this->page_set_order === '') { |
||
439 | $this->page_set_order = $this->getNextPageSetOrder($this->page_set_home); |
||
440 | } |
||
441 | |||
442 | // this will usually fail (duplicate) |
||
443 | $sql = 'INSERT INTO ' . $xoopsDB->prefix('gwiki_pageids') . " (keyword, created) VALUES('{$page}', UNIX_TIMESTAMP())"; |
||
444 | $result = $xoopsDB->query($sql); |
||
445 | if ($result) { |
||
446 | $page_id = $xoopsDB->getInsertId(); |
||
447 | $this->page_id = $page_id; |
||
448 | } |
||
449 | if ($leave_inactive) { |
||
450 | // allow a save that is not activated (for conflict management, and maybe more) |
||
451 | $this->active = 0; |
||
452 | $sql = 'INSERT INTO ' . $xoopsDB->prefix('gwiki_pages'); |
||
453 | $sql .= ' (keyword, display_keyword, title, body, parent_page, page_set_home, page_set_order'; |
||
454 | $sql .= ', meta_description, meta_keywords'; |
||
455 | $sql .= ', lastmodified, uid, admin_lock, active, search_body, toc_cache, show_in_index, gwiki_version)'; |
||
456 | $sql .= ' VALUES ('; |
||
457 | $sql .= '\'' . $page . '\' ,'; |
||
458 | $sql .= '\'' . $this->escapeForDB($this->display_keyword) . '\' ,'; |
||
459 | $sql .= '\'' . $this->escapeForDB($this->title) . '\' ,'; |
||
460 | $sql .= '\'' . $this->escapeForDB($this->body) . '\' ,'; |
||
461 | $sql .= '\'' . $this->escapeForDB($this->parent_page) . '\' ,'; |
||
462 | $sql .= '\'' . $this->escapeForDB($this->page_set_home) . '\' ,'; |
||
463 | $sql .= '\'' . $this->escapeForDB($this->page_set_order) . '\' ,'; |
||
464 | $sql .= '\'' . $this->escapeForDB($this->meta_description) . '\' ,'; |
||
465 | $sql .= '\'' . $this->escapeForDB($this->meta_keywords) . '\' ,'; |
||
466 | $sql .= 'UNIX_TIMESTAMP() ,'; |
||
467 | $sql .= '\'' . $this->escapeForDB($this->uid) . '\' ,'; |
||
468 | $sql .= '\'' . $this->escapeForDB($this->admin_lock) . '\' ,'; |
||
469 | $sql .= '\'' . $this->escapeForDB($this->active) . '\' ,'; |
||
470 | $sql .= '\'' . $this->escapeForDB($this->search_body) . '\' ,'; |
||
471 | $sql .= '\'' . $this->escapeForDB($this->toc_cache) . '\' ,'; |
||
472 | $sql .= '\'' . $this->escapeForDB($this->show_in_index) . '\' ,'; |
||
0 ignored issues
–
show
|
|||
473 | $sql .= '\'' . $this->escapeForDB($this->gwiki_version) . '\' )'; |
||
474 | $result = $xoopsDB->query($sql); |
||
475 | if ($result) { |
||
476 | $result = $xoopsDB->getInsertId(); |
||
477 | $this->gwiki_id = $result; |
||
478 | } |
||
479 | } else { |
||
480 | $sql = 'UPDATE ' . $xoopsDB->prefix('gwiki_pages') . " SET active = 0 WHERE keyword='{$page}' and active = 1 "; |
||
481 | $result = $xoopsDB->query($sql); |
||
482 | if ($result) { |
||
483 | $previous_rows = $xoopsDB->getAffectedRows(); |
||
484 | $this->active = 1; |
||
485 | $sql = 'INSERT INTO ' . $xoopsDB->prefix('gwiki_pages'); |
||
486 | $sql .= ' (keyword, display_keyword, title, body, parent_page, page_set_home, page_set_order'; |
||
487 | $sql .= ', meta_description, meta_keywords, lastmodified'; |
||
488 | $sql .= ', uid, admin_lock, active, search_body, toc_cache, show_in_index, gwiki_version)'; |
||
489 | $sql .= ' VALUES ('; |
||
490 | $sql .= '\'' . $page . '\' ,'; |
||
491 | $sql .= '\'' . $this->escapeForDB($this->display_keyword) . '\' ,'; |
||
492 | $sql .= '\'' . $this->escapeForDB($this->title) . '\' ,'; |
||
493 | $sql .= '\'' . $this->escapeForDB($this->body) . '\' ,'; |
||
494 | $sql .= '\'' . $this->escapeForDB($this->parent_page) . '\' ,'; |
||
495 | $sql .= '\'' . $this->escapeForDB($this->page_set_home) . '\' ,'; |
||
496 | $sql .= '\'' . $this->escapeForDB($this->page_set_order) . '\' ,'; |
||
497 | $sql .= '\'' . $this->escapeForDB($this->meta_description) . '\' ,'; |
||
498 | $sql .= '\'' . $this->escapeForDB($this->meta_keywords) . '\' ,'; |
||
499 | $sql .= 'UNIX_TIMESTAMP() ,'; |
||
500 | $sql .= '\'' . $this->escapeForDB($this->uid) . '\' ,'; |
||
501 | $sql .= '\'' . $this->escapeForDB($this->admin_lock) . '\' ,'; |
||
502 | $sql .= '\'' . $this->escapeForDB($this->active) . '\' ,'; |
||
503 | $sql .= '\'' . $this->escapeForDB($this->search_body) . '\' ,'; |
||
504 | $sql .= '\'' . $this->escapeForDB($this->toc_cache) . '\' ,'; |
||
505 | $sql .= '\'' . $this->escapeForDB($this->show_in_index) . '\' ,'; |
||
0 ignored issues
–
show
$this->show_in_index is of type integer|boolean , but the function expects a string .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
506 | $sql .= '\'' . $this->escapeForDB($this->gwiki_version) . '\' )'; |
||
507 | $result = $xoopsDB->query($sql); |
||
508 | if ($result) { |
||
509 | $result = $xoopsDB->getInsertId(); |
||
510 | $this->gwiki_id = $result; |
||
511 | |||
512 | $this->updatePageLinks(); |
||
513 | |||
514 | $notificationHandler = xoops_getHandler('notification'); |
||
515 | $tags['PAGE_NAME'] = $page; |
||
516 | $tags['PAGE_TITLE'] = $this->title; |
||
517 | if (empty($tags['PAGE_TITLE'])) { |
||
518 | $tags['PAGE_TITLE'] = $this->display_keyword; |
||
519 | } |
||
520 | if (empty($tags['PAGE_TITLE'])) { |
||
521 | $tags['PAGE_TITLE'] = $page; |
||
522 | } |
||
523 | $tags['PAGE_LINK'] = sprintf($this->wikiLinkURL, $page); |
||
524 | $tags['NAMESPACE'] = $this->currentprefix; |
||
525 | |||
526 | if ($previous_rows < 1) { |
||
527 | // only for new |
||
528 | $notificationHandler->triggerEvent('global', 0, 'new_page', $tags, array(), $this->module_id); |
||
529 | if ($this->currentprefixid) { // have namespace |
||
530 | $notificationHandler->triggerEvent('namespace', $this->currentprefixid, 'new_ns_page', $tags, array(), $this->module_id); |
||
531 | } |
||
532 | } |
||
533 | // for all cases (new is also an update) |
||
534 | $notificationHandler->triggerEvent('page', $this->page_id, 'page_watch', $tags, array(), $this->module_id); |
||
535 | $notificationHandler->triggerEvent('global', 0, 'upd_page', $tags, array(), $this->module_id); |
||
536 | if ($this->currentprefixid) { // have namespace |
||
537 | $notificationHandler->triggerEvent('namespace', $this->currentprefixid, 'upd_ns_page', $tags, array(), $this->module_id); |
||
538 | } |
||
539 | } |
||
540 | } |
||
541 | } |
||
542 | |||
543 | return $result; |
||
544 | } |
||
545 | |||
546 | /** |
||
547 | * update gwiki_pagelinks table - expects $page to be current |
||
548 | * |
||
549 | * @param bool $render do a fresh page render before updating |
||
550 | * |
||
551 | * @return void |
||
552 | */ |
||
553 | private function updatePageLinks($render = false) |
||
554 | { |
||
555 | global $xoopsDB; |
||
556 | |||
557 | if ($render) { |
||
558 | // eliminate things we don't want in search page because they |
||
559 | // are misleading and/or change outside of the page itself |
||
560 | $search[] = "#{(PageIndex|RecentChanges)([^\"<\n]+?)?}#si"; |
||
561 | $replace[] = ''; |
||
562 | $search[] = "#\{toc\}#i"; |
||
563 | $replace[] = ''; |
||
564 | $search[] = "#\{pagesettoc\}#i"; |
||
565 | $replace[] = ''; |
||
566 | $tempbody = preg_replace($search, $replace, $this->body) . "\n\n"; |
||
567 | |||
568 | $this->renderPage($tempbody); |
||
569 | } |
||
570 | $page = $this->escapeForDB($this->keyword); |
||
571 | |||
572 | $sql = 'DELETE FROM ' . $xoopsDB->prefix('gwiki_pagelinks'); |
||
573 | $sql .= ' WHERE from_keyword = \'' . $page . '\''; |
||
574 | $result = $xoopsDB->query($sql); |
||
575 | |||
576 | if (!empty($this->wikiPageLinks)) { |
||
577 | $sql = 'INSERT INTO ' . $xoopsDB->prefix('gwiki_pagelinks') . ' (from_keyword, to_keyword) VALUES '; |
||
578 | $values = ''; |
||
579 | foreach ($this->wikiPageLinks as $i => $v) { |
||
580 | if (!empty($values)) { |
||
581 | $values .= ', '; |
||
582 | } |
||
583 | $values .= '(\'' . $page . '\', \'' . $this->escapeForDB($i) . '\')'; |
||
584 | } |
||
585 | $sql .= $values; |
||
586 | $result = $xoopsDB->query($sql); |
||
587 | } |
||
588 | |||
589 | return; |
||
590 | } |
||
591 | |||
592 | /** |
||
593 | * get the next higher unused page_set_order for a given page_set_home |
||
594 | * |
||
595 | * @param string $page_set_home keyword of page set home |
||
596 | * |
||
597 | * @return int |
||
598 | */ |
||
599 | View Code Duplication | private function getNextPageSetOrder($page_set_home) |
|
600 | { |
||
601 | global $xoopsDB; |
||
602 | |||
603 | $page_set_order = 1; |
||
604 | |||
605 | $keyword = $this->escapeForDB($page_set_home); |
||
606 | |||
607 | $sql = 'SELECT MAX(page_set_order) FROM ' . $xoopsDB->prefix('gwiki_pages') . " WHERE active = 1 and page_set_home = '{$keyword}' "; |
||
608 | $result = $xoopsDB->query($sql); |
||
609 | if ($result) { |
||
610 | $myrow = $xoopsDB->fetchRow($result); |
||
611 | $page_set_order = $myrow[0] + 1; |
||
612 | } |
||
613 | |||
614 | return $page_set_order; |
||
615 | } |
||
616 | |||
617 | /** |
||
618 | * Check if the current user may edit the current page |
||
619 | * Since the class can be used outside the module where permissions are assigned, we have to work at this a bit |
||
620 | * |
||
621 | * @return boolean mayEdit |
||
622 | */ |
||
623 | public function checkEdit() |
||
624 | { |
||
625 | global $xoopsUser, $xoopsDB; |
||
626 | |||
627 | $mayEdit = false; |
||
628 | $keyword = $this->keyword; |
||
629 | |||
630 | $module_id = $this->module_id; |
||
631 | $groups = XOOPS_GROUP_ANONYMOUS; |
||
632 | if (is_object($xoopsUser)) { |
||
633 | $groups = $xoopsUser->getGroups(); |
||
634 | } |
||
635 | |||
636 | $gpermHandler = xoops_getHandler('groupperm'); |
||
637 | |||
638 | $edit_any = $gpermHandler->checkRight('wiki_authority', _MD_GWIKI_PAGE_PERM_EDIT_ANY_NUM, $groups, $module_id); |
||
639 | $edit_pfx = $gpermHandler->checkRight('wiki_authority', _MD_GWIKI_PAGE_PERM_EDIT_PFX_NUM, $groups, $module_id); |
||
640 | $create_any = $gpermHandler->checkRight('wiki_authority', _MD_GWIKI_PAGE_PERM_CREATE_ANY_NUM, $groups, $module_id); |
||
641 | $create_pfx = $gpermHandler->checkRight('wiki_authority', _MD_GWIKI_PAGE_PERM_CREATE_PFX_NUM, $groups, $module_id); |
||
642 | |||
643 | // check for namespace prefix |
||
644 | $prefix = $this->getPrefix($keyword); |
||
645 | if ($prefix) { |
||
646 | if ($prefix['defined']) { |
||
647 | View Code Duplication | if (is_array($groups)) { |
|
648 | $groupwhere = ' IN (' . implode(', ', $groups) . ') '; |
||
649 | } else { |
||
650 | $groupwhere = " = '" . $groups . "'"; |
||
651 | } |
||
652 | $sql = 'SELECT group_prefix_id FROM ' . $xoopsDB->prefix('gwiki_group_prefix') . ' WHERE prefix_id = \'' . $prefix['prefix_id'] . '\' AND group_id ' . $groupwhere; |
||
653 | $result = $xoopsDB->query($sql); |
||
654 | $rows = $xoopsDB->getRowsNum($result); |
||
655 | $xoopsDB->freeRecordSet($result); |
||
656 | if ($rows) { // prefix is assigned to one or more of user's groups |
||
657 | if (($edit_pfx || $create_pfx) && $this->gwiki_id) { |
||
658 | $mayEdit = true; |
||
659 | } |
||
660 | if ($create_pfx && !$this->gwiki_id) { |
||
661 | $mayEdit = true; |
||
662 | } |
||
663 | } |
||
664 | if (($edit_any || $create_any) && $this->gwiki_id) { |
||
665 | $mayEdit = true; |
||
666 | } |
||
667 | if ($create_any && !$this->gwiki_id) { |
||
668 | $mayEdit = true; |
||
669 | } |
||
670 | } else { // allow edit, but no create if prefix is undefined |
||
671 | if ($edit_any && $this->gwiki_id) { |
||
672 | $mayEdit = true; |
||
673 | } |
||
674 | } |
||
675 | } else { |
||
676 | if (($edit_any || $create_any) && $this->gwiki_id) { |
||
677 | $mayEdit = true; |
||
678 | } |
||
679 | if ($create_any && !$this->gwiki_id) { |
||
680 | $mayEdit = true; |
||
681 | } |
||
682 | } |
||
683 | |||
684 | return $mayEdit; |
||
685 | } |
||
686 | |||
687 | /** |
||
688 | * get user name based on id |
||
689 | * |
||
690 | * @param int $uid user id |
||
691 | * |
||
692 | * @return string |
||
693 | */ |
||
694 | View Code Duplication | public function getUserName($uid) |
|
695 | { |
||
696 | global $xoopsConfig; |
||
697 | |||
698 | $uid = (int)$uid; |
||
699 | |||
700 | if ($uid > 0) { |
||
701 | $memberHandler = xoops_getHandler('member'); |
||
702 | $user = $memberHandler->getUser($uid); |
||
703 | if (is_object($user)) { |
||
704 | return "<a href=\"" . XOOPS_URL . "/userinfo.php?uid=$uid\">" . htmlspecialchars($user->getVar('uname'), ENT_QUOTES) . '</a>'; |
||
705 | } |
||
706 | } |
||
707 | |||
708 | return $xoopsConfig['anonymous']; |
||
709 | } |
||
710 | |||
711 | /** |
||
712 | * get array of prefixes user can edit |
||
713 | * |
||
714 | * @param boolean $createonly true to show only prefixes with create permission |
||
715 | * |
||
716 | * @return string[]|false |
||
717 | */ |
||
718 | public function getUserNamespaces($createonly = false) |
||
719 | { |
||
720 | global $xoopsUser, $xoopsDB; |
||
721 | |||
722 | $module_id = $this->module_id; |
||
723 | |||
724 | $groups = XOOPS_GROUP_ANONYMOUS; |
||
725 | if (is_object($xoopsUser)) { |
||
726 | $groups = $xoopsUser->getGroups(); |
||
727 | } |
||
728 | |||
729 | $gpermHandler = xoops_getHandler('groupperm'); |
||
730 | |||
731 | $edit_any = $gpermHandler->checkRight('wiki_authority', _MD_GWIKI_PAGE_PERM_EDIT_ANY_NUM, $groups, $module_id); |
||
732 | $edit_pfx = $gpermHandler->checkRight('wiki_authority', _MD_GWIKI_PAGE_PERM_EDIT_PFX_NUM, $groups, $module_id); |
||
733 | $create_any = $gpermHandler->checkRight('wiki_authority', _MD_GWIKI_PAGE_PERM_CREATE_ANY_NUM, $groups, $module_id); |
||
734 | $create_pfx = $gpermHandler->checkRight('wiki_authority', _MD_GWIKI_PAGE_PERM_CREATE_PFX_NUM, $groups, $module_id); |
||
735 | |||
736 | View Code Duplication | if (is_array($groups)) { |
|
737 | $groupwhere = ' IN (' . implode(', ', $groups) . ') '; |
||
738 | } else { |
||
739 | $groupwhere = " = '" . $groups . "'"; |
||
740 | } |
||
741 | |||
742 | $sql = 'SELECT distinct p.prefix_id, prefix FROM '; |
||
743 | $sql .= $xoopsDB->prefix('gwiki_prefix') . ' p, '; |
||
744 | $sql .= $xoopsDB->prefix('gwiki_group_prefix') . ' g '; |
||
745 | $sql .= ' WHERE group_id ' . $groupwhere; |
||
746 | $sql .= ' AND p.prefix_id = g.prefix_id'; |
||
747 | $sql .= ' ORDER BY prefix '; |
||
748 | $prefixes = array(); |
||
749 | $result = $xoopsDB->query($sql); |
||
750 | if ($create_any) { |
||
751 | $prefixes[] = array('prefix_id' => -1, 'prefix' => ' '); |
||
752 | } |
||
753 | while ($myrow = $xoopsDB->fetchArray($result)) { |
||
754 | $prefixes[] = $myrow; |
||
755 | } |
||
756 | |||
757 | // make sure we have some edit/create permission. We need full keyword to be certain, so let edit sort it out. |
||
758 | $mayEdit = ($edit_any || $create_any || $edit_pfx || $create_pfx); |
||
759 | if ($createonly) { |
||
760 | $mayEdit = ($create_any || $create_pfx); |
||
761 | } |
||
762 | if ($mayEdit) { |
||
763 | return $prefixes; |
||
764 | } |
||
765 | |||
766 | return false; |
||
767 | } |
||
768 | |||
769 | /** |
||
770 | * Get keyword for an id |
||
771 | * |
||
772 | * @param int $page_id id |
||
773 | * |
||
774 | * @return string|null wiki keyword (page) |
||
775 | */ |
||
776 | public function getKeywordById($page_id) |
||
777 | { |
||
778 | global $xoopsDB; |
||
779 | |||
780 | $keyword = null; |
||
781 | |||
782 | $sql = 'SELECT keyword FROM ' . $xoopsDB->prefix('gwiki_pageids') . " WHERE page_id = '{$page_id}' "; |
||
783 | $result = $xoopsDB->query($sql); |
||
784 | if ($result) { |
||
785 | $myrow = $xoopsDB->fetchRow($result); |
||
786 | $keyword = $myrow[0]; |
||
787 | } |
||
788 | |||
789 | return $keyword; |
||
790 | } |
||
791 | |||
792 | /** |
||
793 | * lookup id for a keyword |
||
794 | * |
||
795 | * @param string $keyword keyword |
||
796 | * |
||
797 | * @return int |
||
798 | */ |
||
799 | View Code Duplication | public function getPageId($keyword) |
|
800 | { |
||
801 | global $xoopsDB; |
||
802 | |||
803 | $page_id = 0; |
||
804 | |||
805 | $keyword = $this->escapeForDB($keyword); |
||
806 | |||
807 | $sql = 'SELECT page_id FROM ' . $xoopsDB->prefix('gwiki_pageids') . " WHERE keyword = '{$keyword}' "; |
||
808 | $result = $xoopsDB->query($sql); |
||
809 | if ($result) { |
||
810 | $myrow = $xoopsDB->fetchRow($result); |
||
811 | $page_id = $myrow[0]; |
||
812 | } |
||
813 | |||
814 | return $page_id; |
||
815 | } |
||
816 | |||
817 | /** |
||
818 | * record a page hit for a keyword |
||
819 | * |
||
820 | * @param string $keyword keyword |
||
821 | * |
||
822 | * @return int count of rows updated |
||
823 | */ |
||
824 | public function registerHit($keyword) |
||
825 | { |
||
826 | global $xoopsDB; |
||
827 | |||
828 | $keyword = $this->escapeForDB($keyword); |
||
829 | |||
830 | $sql = 'UPDATE ' . $xoopsDB->prefix('gwiki_pageids') . " SET hit_count = hit_count + 1 WHERE keyword = '{$keyword}' "; |
||
831 | $result = $xoopsDB->queryF($sql); |
||
832 | |||
833 | // nothing to do if it fails |
||
834 | return $xoopsDB->getAffectedRows(); |
||
835 | } |
||
836 | |||
837 | /** |
||
838 | * set a specific revison as active for a keyword |
||
839 | * |
||
840 | * @param string $keyword wiki keyword |
||
841 | * @param int $id id of revision to activate |
||
842 | * |
||
843 | * @return mixed |
||
844 | */ |
||
845 | public function setRevision($keyword, $id) |
||
846 | { |
||
847 | global $xoopsDB; |
||
848 | |||
849 | $keyword = $this->escapeForDB($keyword); |
||
850 | $id = (int)$id; |
||
851 | |||
852 | $page = $this->getPage($keyword, $id); |
||
853 | if (!$page) { |
||
854 | return false; |
||
855 | } |
||
856 | |||
857 | $sql = 'UPDATE ' . $xoopsDB->prefix('gwiki_pages') . " SET active = 0 WHERE keyword='{$keyword}' and active = 1 "; |
||
858 | $result = $xoopsDB->query($sql); |
||
859 | |||
860 | $sql = 'UPDATE ' . $xoopsDB->prefix('gwiki_pages') . " SET active = 1 WHERE keyword='{$keyword}' AND gwiki_id='{$id}'"; |
||
861 | $result = $xoopsDB->query($sql); |
||
862 | |||
863 | $this->updatePageLinks(true); |
||
864 | |||
865 | return $result; |
||
866 | } |
||
867 | |||
868 | /** |
||
869 | * load a page with optional revision id |
||
870 | * |
||
871 | * @param string $keyword keyword |
||
872 | * @param int|null $id optional page id |
||
873 | * |
||
874 | * @return bool |
||
875 | */ |
||
876 | public function getPage($keyword, $id = null) |
||
877 | { |
||
878 | global $xoopsDB; |
||
879 | |||
880 | $this->resetPage(); |
||
881 | $this->keyword = $keyword; |
||
882 | $prefix = $this->getPrefix($keyword); |
||
883 | if ($prefix && $prefix['defined']) { |
||
884 | $this->currentprefix = $prefix['prefix']; |
||
885 | $this->currentprefixid = $prefix['prefix_id']; |
||
886 | $this->currenttemplateid = $prefix['prefix_template_id']; |
||
887 | } |
||
888 | |||
889 | $keyword = $this->escapeForDB($keyword); |
||
890 | |||
891 | $this->page_id = $this->getPageId($keyword); |
||
892 | |||
893 | if (empty($id)) { |
||
894 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('gwiki_pages') . ' natural left join ' . $xoopsDB->prefix('gwiki_pageids') . " WHERE keyword='{$keyword}' and active = 1 "; |
||
895 | } else { |
||
896 | $id = (int)$id; |
||
897 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('gwiki_pages') . ' natural left join ' . $xoopsDB->prefix('gwiki_pageids') . " WHERE keyword='{$keyword}' and gwiki_id = {$id} "; |
||
898 | } |
||
899 | $result = $xoopsDB->query($sql); |
||
900 | $page = false; |
||
901 | $rows = $xoopsDB->getRowsNum($result); |
||
902 | if ($rows > 0) { |
||
903 | $page = $xoopsDB->fetchArray($result); |
||
904 | |||
905 | $this->gwiki_id = $page['gwiki_id']; |
||
906 | $this->keyword = $page['keyword']; |
||
907 | $this->display_keyword = $page['display_keyword']; |
||
908 | $this->title = $page['title']; |
||
909 | $this->body = $page['body']; |
||
910 | $this->parent_page = $page['parent_page']; |
||
911 | |||
912 | $this->page_set_home = $page['page_set_home']; |
||
913 | $this->page_set_order = $page['page_set_order']; |
||
914 | |||
915 | $this->meta_description = $page['meta_description']; |
||
916 | $this->meta_keywords = $page['meta_keywords']; |
||
917 | $this->lastmodified = $page['lastmodified']; |
||
918 | $this->uid = $page['uid']; |
||
919 | $this->admin_lock = $page['admin_lock']; |
||
920 | $this->active = $page['active']; |
||
921 | $this->search_body = $page['search_body']; |
||
922 | $this->toc_cache = $page['toc_cache']; |
||
923 | $this->show_in_index = $page['show_in_index']; |
||
924 | |||
925 | $this->gwiki_version = $page['gwiki_version']; |
||
926 | $this->page_id = $page['page_id']; |
||
927 | $this->created = $page['created']; |
||
928 | |||
929 | $page['author'] = $this->getUserName($page['uid']); |
||
930 | $page['revisiontime'] = date($this->dateFormat, $page['lastmodified']); |
||
931 | $page['createdtime'] = date($this->dateFormat, $page['created']); |
||
932 | $page['createdmonth'] = date('M', $page['created']); |
||
933 | $page['createdday'] = date('d', $page['created']); |
||
934 | $page['createdyear'] = date('Y', $page['created']); |
||
935 | |||
936 | $temp = $this->renderPageSetNav($keyword); |
||
937 | if ($temp) { |
||
938 | $page['pageset'] = $temp; |
||
939 | } |
||
940 | } |
||
941 | |||
942 | return $page; |
||
943 | } |
||
944 | |||
945 | /** |
||
946 | * Check for a prefix (namespace) |
||
947 | * |
||
948 | * @param mixed $keyword - wiki page name |
||
949 | * |
||
950 | * @return bool |
||
951 | */ |
||
952 | public function getPrefix($keyword) |
||
953 | { |
||
954 | /* |
||
955 | gwiki_prefix columns |
||
956 | prefix_id |
||
957 | prefix |
||
958 | prefix_home |
||
959 | prefix_template_id |
||
960 | prefix_is_external |
||
961 | prefix_external_url < sprintf template for page in external namespace |
||
962 | */ |
||
963 | global $xoopsDB; |
||
964 | |||
965 | $prefix = false; |
||
966 | $keyword = $this->escapeForDB($keyword); |
||
967 | |||
968 | $pos = strpos($keyword, ':'); |
||
969 | // split namespace and page reference on first colon |
||
970 | if ($pos !== false && $pos > 0) { |
||
971 | $pre = substr($keyword, 0, $pos); |
||
972 | $page = substr($keyword, $pos + 1); |
||
973 | $q_pre = $this->escapeForDB($pre); |
||
974 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('gwiki_prefix') . " WHERE prefix='{$q_pre}' "; |
||
975 | $result = $xoopsDB->query($sql); |
||
976 | $rows = $xoopsDB->getRowsNum($result); |
||
977 | if ($rows > 0) { |
||
978 | $prefix = $xoopsDB->fetchArray($result); |
||
979 | if ($page === '') { |
||
980 | $page = $prefix['prefix_home']; |
||
981 | } // supply home page if empty |
||
982 | $prefix['defined'] = true; |
||
983 | // external namespace |
||
984 | if ($prefix['prefix_is_external']) { |
||
985 | $prefix['actual_page'] = sprintf($prefix['prefix_external_url'], $page); |
||
986 | } else { // local namespace |
||
987 | $prefix['actual_page'] = $prefix['prefix'] . ':' . $page; |
||
988 | } |
||
989 | } else { // we have an undefined prefix |
||
990 | $prefix['defined'] = false; |
||
991 | } |
||
992 | } |
||
993 | |||
994 | return $prefix; |
||
995 | } |
||
996 | |||
997 | /** |
||
998 | * get prefix string for an id |
||
999 | * |
||
1000 | * @param int $pid prefix id |
||
1001 | * |
||
1002 | * @return string namespace prefix, or empty string |
||
1003 | */ |
||
1004 | public function getPrefixFromId($pid) |
||
1005 | { |
||
1006 | global $xoopsDB; |
||
1007 | |||
1008 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('gwiki_prefix') . ' WHERE prefix_id =' . $pid; |
||
1009 | $result = $xoopsDB->query($sql); |
||
1010 | while ($myrow = $xoopsDB->fetchArray($result)) { |
||
1011 | return $myrow; |
||
1012 | } |
||
1013 | |||
1014 | return ''; |
||
1015 | } |
||
1016 | |||
1017 | /** |
||
1018 | * get template for the current page |
||
1019 | * |
||
1020 | * @return string template name |
||
1021 | */ |
||
1022 | public function getTemplateName() |
||
1023 | { |
||
1024 | $template = 'gwiki_view.tpl'; |
||
1025 | if ($this->currenttemplateid) { |
||
1026 | $template = $this->wikiDir . '_prefix_' . $this->currentprefixid . '.tpl'; |
||
1027 | } |
||
1028 | |||
1029 | return $template; |
||
1030 | } |
||
1031 | |||
1032 | /** |
||
1033 | * get attachment info associated with a page |
||
1034 | * |
||
1035 | * @param string $page keyword |
||
1036 | * |
||
1037 | * @return array |
||
1038 | */ |
||
1039 | public function getAttachments($page) |
||
1040 | { |
||
1041 | global $xoopsDB; |
||
1042 | |||
1043 | $this->attachments = array(); |
||
1044 | $q_keyword = $this->escapeForDB($page); |
||
1045 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('gwiki_page_files') . " WHERE keyword='{$q_keyword}' "; |
||
1046 | $result = $xoopsDB->query($sql); |
||
1047 | $rows = $xoopsDB->getRowsNum($result); |
||
1048 | while ($row = $xoopsDB->fetchArray($result)) { |
||
1049 | $row['iconlink'] = XOOPS_URL . '/modules/' . $this->wikiDir . '/assets/icons/48px/' . $row['file_icon'] . '.png'; |
||
1050 | $row['userlink'] = $this->getUserName($row['file_uid']); |
||
1051 | $row['size'] = number_format($row['file_size']); |
||
1052 | $row['date'] = date($this->dateFormat, $row['file_upload_date']); |
||
1053 | $this->attachments[] = $row; |
||
1054 | } |
||
1055 | |||
1056 | return $this->attachments; |
||
1057 | } |
||
1058 | |||
1059 | /** |
||
1060 | * Make a link from a wiki keyword |
||
1061 | * |
||
1062 | * @param mixed $keyword - wiki page name |
||
1063 | * @param mixed $altkey - alternate text for link. If empty, display_keyword will be used. |
||
1064 | * |
||
1065 | * @return string |
||
1066 | */ |
||
1067 | public function wikiLink($keyword, $altkey = null) |
||
1068 | { |
||
1069 | global $xoopsDB; |
||
1070 | |||
1071 | // HACK - get rid of spaces in page |
||
1072 | // WikiCreole site is filled with page references such as [[Creole 1.0 Poll]] which resolve as |
||
1073 | // hrefs like http://wikicreole.org/wiki/Creole1.0Poll |
||
1074 | // |
||
1075 | // will assume this is considered normal wikiish behavior, and try to emulate. |
||
1076 | // Also seems to capitalize each portion, ie 'Ab and Cd' yields 'AbAndCd' - emulate this, too. |
||
1077 | $org_keyword = $keyword; |
||
1078 | if (strpos(trim($keyword), ' ')) { |
||
1079 | $keys = explode(' ', $keyword); |
||
1080 | foreach ($keys as $i => $k) { |
||
1081 | $keys[$i] = ucfirst($k); |
||
1082 | } |
||
1083 | $keyword = implode('', $keys); |
||
1084 | } |
||
1085 | // $keyword=str_replace (' ', '', $keyword); |
||
1086 | |||
1087 | // check for namespace prefix |
||
1088 | $prefix = $this->getPrefix($keyword); |
||
1089 | if ($prefix && $prefix['defined']) { |
||
1090 | $link = $prefix['actual_page']; |
||
1091 | // external namespace |
||
1092 | if ($prefix['prefix_is_external']) { |
||
1093 | $linktext = $org_keyword; |
||
1094 | if ($altkey) { |
||
1095 | $linktext = $altkey; |
||
1096 | } |
||
1097 | $linktext = stripslashes($linktext); |
||
1098 | $ret = '<a href="' . $link . '" target="_blank" title="' . _MD_GWIKI_PAGE_EXT_LINK_TT . '">' . $linktext . '<span class="wikiextlink"> </span></a>'; |
||
1099 | |||
1100 | return $ret; |
||
1101 | } else { // interal namespace |
||
1102 | $keyword = $link; // we may have modified the keyword |
||
1103 | } |
||
1104 | } |
||
1105 | |||
1106 | $sql = 'SELECT keyword, display_keyword, title FROM ' . $xoopsDB->prefix('gwiki_pages') . " WHERE keyword='{$keyword}' and active = 1 "; |
||
1107 | $result = $xoopsDB->query($sql); |
||
1108 | $rows = $xoopsDB->getRowsNum($result); |
||
1109 | if ($rows) { // existing page |
||
1110 | list($keyword, $display_keyword, $title) = $xoopsDB->fetchRow($result); |
||
1111 | $display_keyword = htmlentities($display_keyword, ENT_QUOTES); |
||
1112 | if (empty($display_keyword)) { |
||
1113 | $display_keyword = $org_keyword; |
||
1114 | } |
||
1115 | $keyword = strtolower($keyword); |
||
1116 | $newpage = ''; |
||
1117 | } else { // new page link |
||
1118 | $display_keyword = $org_keyword; |
||
1119 | $newpage = '<span class="wikinewpage"> </span>'; |
||
1120 | $title = sprintf(_MD_GWIKI_PAGE_CREATE_TT, $keyword); |
||
1121 | } |
||
1122 | if (!empty($altkey)) { |
||
1123 | $display_keyword = $altkey; |
||
1124 | } |
||
1125 | $title = htmlspecialchars($title); |
||
1126 | $display_keyword = stripslashes($display_keyword); |
||
1127 | |||
1128 | // track where this page links |
||
1129 | if (isset($this->wikiPageLinks[$keyword])) { |
||
1130 | ++$this->wikiPageLinks[$keyword]; |
||
1131 | } else { |
||
1132 | $this->wikiPageLinks[$keyword] = 1; |
||
1133 | } |
||
1134 | |||
1135 | $url = sprintf($this->wikiLinkURL, $keyword); |
||
1136 | |||
1137 | return sprintf('<a href="%s" title="%s">%s%s</a>', $url, $title, $display_keyword, $newpage); |
||
1138 | } |
||
1139 | |||
1140 | /** |
||
1141 | * callback |
||
1142 | * |
||
1143 | * @param string[] $matches preg_replace_callback matches |
||
1144 | * |
||
1145 | * @return string |
||
1146 | */ |
||
1147 | private function wikiCCLink($matches) |
||
1148 | { |
||
1149 | return $this->wikiLink($matches[1]); |
||
1150 | } |
||
1151 | |||
1152 | /** |
||
1153 | * get tabbed page index |
||
1154 | * |
||
1155 | * @return array |
||
1156 | */ |
||
1157 | private function getIndexTabs() |
||
1158 | { |
||
1159 | global $xoopsDB; |
||
1160 | |||
1161 | $tabs = array(); |
||
1162 | |||
1163 | $sql = 'SELECT SUBSTRING(display_keyword,1,1) as letter, count(*) as count '; |
||
1164 | $sql .= ' FROM ' . $xoopsDB->prefix('gwiki_pages'); |
||
1165 | $sql .= ' WHERE active=1 AND show_in_index=1 '; |
||
1166 | $sql .= ' GROUP BY letter '; |
||
1167 | |||
1168 | $result = $xoopsDB->query($sql); |
||
1169 | |||
1170 | $currentset = false; |
||
1171 | $rows = $xoopsDB->getRowsNum($result); |
||
1172 | if ($rows) { |
||
1173 | while ($row = $xoopsDB->fetchArray($result)) { |
||
1174 | $row['letter'] = strtolower($row['letter']); |
||
1175 | if ($this->pageIndexPrefix === $row['letter']) { |
||
1176 | $row['current'] = true; |
||
1177 | $currentset = true; |
||
1178 | } else { |
||
1179 | $row['current'] = false; |
||
1180 | } |
||
1181 | $tabs[] = $row; |
||
1182 | } |
||
1183 | } |
||
1184 | $xoopsDB->freeRecordSet($result); |
||
1185 | |||
1186 | if (!$currentset) { |
||
1187 | $this->pageIndexPrefix = $tabs[0]['letter']; |
||
1188 | $tabs[0]['current'] = true; |
||
1189 | } |
||
1190 | |||
1191 | return $tabs; |
||
1192 | } |
||
1193 | |||
1194 | /** |
||
1195 | * get a page index |
||
1196 | * |
||
1197 | * @param string|null $prefix if not null, limit index to a prefix |
||
1198 | * |
||
1199 | * @return string rendered index |
||
1200 | * |
||
1201 | */ |
||
1202 | private function pageIndex($prefix = null) |
||
1203 | { |
||
1204 | global $xoopsDB; |
||
1205 | $simplelayout = false; |
||
1206 | $tablayout = false; |
||
1207 | |||
1208 | $body = ''; |
||
1209 | |||
1210 | $pageselect = 'active=1 AND show_in_index=1 '; |
||
1211 | |||
1212 | if (!empty($prefix)) { |
||
1213 | $pageselect .= ' AND keyword LIKE "' . $prefix . '%" '; |
||
1214 | } else { |
||
1215 | $sql = 'SELECT count(*) as count FROM ' . $xoopsDB->prefix('gwiki_pages'); |
||
1216 | $sql .= ' WHERE ' . $pageselect; |
||
1217 | $result = $xoopsDB->query($sql); |
||
1218 | $row = $xoopsDB->fetchArray($result); |
||
1219 | $cnt = $row['count']; |
||
1220 | $xoopsDB->freeRecordSet($result); |
||
1221 | if ($cnt > 500) { |
||
1222 | $tablayout = true; |
||
1223 | $simplelayout = true; // tablayout is already grouped by first character |
||
1224 | $tabs = $this->getIndexTabs(); |
||
1225 | $pageselect .= ' AND display_keyword LIKE "' . $this->pageIndexPrefix . '%" '; |
||
1226 | } |
||
1227 | } |
||
1228 | |||
1229 | $sql = 'SELECT keyword, display_keyword, title'; |
||
1230 | $sql .= ' FROM ' . $xoopsDB->prefix('gwiki_pages'); |
||
1231 | $sql .= ' WHERE ' . $pageselect; |
||
1232 | $sql .= ' ORDER BY display_keyword '; |
||
1233 | // $sql.=' ORDER BY active, show_in_index, display_keyword '; |
||
1234 | |||
1235 | $result = $xoopsDB->query($sql); |
||
1236 | $rowcnt = $xoopsDB->getRowsNum($result); |
||
1237 | |||
1238 | if ($rowcnt < 50) { |
||
1239 | $simplelayout = true; |
||
1240 | } // skip the fancy by letter breakout if this is a small index |
||
1241 | |||
1242 | if ($tablayout) { |
||
1243 | $body .= '<div class="wikiindex"><div class="wikiindextabs"><ul>'; |
||
1244 | |||
1245 | foreach ($tabs as $tab) { |
||
1246 | $class = ''; |
||
1247 | if ($tab['current']) { |
||
1248 | $class = ' id="wikiindextabactive"'; |
||
1249 | } |
||
1250 | $url = sprintf($this->wikiLinkURL, strtolower($this->keyword . '(\\' . $tab['letter'] . ')')); |
||
1251 | $letter = strtoupper($tab['letter']); |
||
1252 | $body .= "\n<li{$class}><a href=\"{$url}\">{$letter}</a></li>"; |
||
1253 | } |
||
1254 | $body .= '</ul></div><div class="wikiindexbody">'; |
||
1255 | } |
||
1256 | |||
1257 | $lastletter = ''; |
||
1258 | if ($simplelayout) { |
||
1259 | $body .= '<ul>'; |
||
1260 | } |
||
1261 | while ($content = $xoopsDB->fetchArray($result)) { |
||
1262 | $display_keyword = $content['display_keyword']; |
||
1263 | if (empty($display_keyword)) { |
||
1264 | $display_keyword = $content['keyword']; |
||
1265 | } |
||
1266 | if (!$simplelayout) { |
||
1267 | if (function_exists('mb_substr')) { |
||
1268 | $testletter = mb_strtoupper(mb_substr($display_keyword, 0, 1, 'UTF-8'), 'UTF-8'); |
||
1269 | } else { |
||
1270 | $testletter = strtoupper(substr($display_keyword, 0, 1)); |
||
1271 | } |
||
1272 | if ($lastletter === '') { |
||
1273 | $lastletter = $testletter; |
||
1274 | $body .= "<h3>{$lastletter}</h3><ul>"; |
||
1275 | } |
||
1276 | if ($lastletter !== $testletter) { |
||
1277 | $lastletter = $testletter; |
||
1278 | $body .= "</ul><h3>{$lastletter}</h3><ul>"; |
||
1279 | } |
||
1280 | } |
||
1281 | $title = htmlspecialchars($content['title']); |
||
1282 | $display_keyword = htmlspecialchars($display_keyword); |
||
1283 | $url = sprintf($this->wikiLinkURL, strtolower($content['keyword'])); |
||
1284 | $link = sprintf('<a href="%s" title="%s">%s%s</a>', $url, $title, $display_keyword, ''); |
||
1285 | $body .= '<li>' . $link . ' : ' . $title . '</li>'; |
||
1286 | } |
||
1287 | $xoopsDB->freeRecordSet($result); |
||
1288 | if ($tablayout) { |
||
1289 | $body .= '</ul></div></div>'; |
||
1290 | } elseif ($body != '') { |
||
1291 | $body .= '</ul>'; |
||
1292 | } |
||
1293 | |||
1294 | return $body . "\n\n"; |
||
1295 | } |
||
1296 | |||
1297 | /** |
||
1298 | * get a recently modfied page index |
||
1299 | * |
||
1300 | * @param string|null $prefix if not null, limit index to a prefix |
||
1301 | * |
||
1302 | * @return string rendered index |
||
1303 | * |
||
1304 | */ |
||
1305 | private function recentIndex($prefix = null) |
||
1306 | { |
||
1307 | global $xoopsDB; |
||
1308 | |||
1309 | // only show active pages |
||
1310 | $pageselect = 'active=1 AND show_in_index=1 '; |
||
1311 | if (!empty($prefix)) { |
||
1312 | $pageselect .= ' AND keyword LIKE "' . $prefix . '%" '; |
||
1313 | } |
||
1314 | |||
1315 | $body = ''; |
||
1316 | |||
1317 | $sql = 'SELECT keyword, display_keyword, title, lastmodified'; |
||
1318 | $sql .= ', FROM_UNIXTIME(lastmodified) as fmtlastmodified, uid'; |
||
1319 | $sql .= ' FROM ' . $xoopsDB->prefix('gwiki_pages'); |
||
1320 | $sql .= ' WHERE ' . $pageselect; |
||
1321 | $sql .= ' ORDER BY lastmodified DESC LIMIT ' . $this->numberOfRecentItems; |
||
1322 | |||
1323 | $result = $xoopsDB->query($sql); |
||
1324 | |||
1325 | $lastdate = ''; |
||
1326 | while ($content = $xoopsDB->fetchArray($result)) { |
||
1327 | $testdate = substr($content['fmtlastmodified'], 0, 10); |
||
1328 | if ($lastdate === '') { |
||
1329 | $lastdate = $testdate; |
||
1330 | $body .= "<h3>{$lastdate}</h3><ul>"; |
||
1331 | } |
||
1332 | if ($lastdate !== $testdate) { |
||
1333 | $lastdate = $testdate; |
||
1334 | $body .= "</ul><h3>{$lastdate}</h3><ul>"; |
||
1335 | } |
||
1336 | |||
1337 | $title = htmlspecialchars($content['title']); |
||
1338 | $display_keyword = htmlspecialchars($content['display_keyword']); |
||
1339 | $url = sprintf($this->wikiLinkURL, strtolower($content['keyword'])); |
||
1340 | $link = sprintf('<a href="%s" title="%s">%s%s</a>', $url, $title, $display_keyword, ''); |
||
1341 | $body .= '<li>' . $link . ' : ' . $title . '</li>'; |
||
1342 | } |
||
1343 | $xoopsDB->freeRecordSet($result); |
||
1344 | if ($body !== '') { |
||
1345 | $body .= '</ul>'; |
||
1346 | } |
||
1347 | |||
1348 | return $body . "\n\n"; |
||
1349 | } |
||
1350 | |||
1351 | /** |
||
1352 | * callback render match specified index |
||
1353 | * |
||
1354 | * @param string[] $matches preg_replace_callback matches |
||
1355 | * |
||
1356 | * @return bool|string |
||
1357 | */ |
||
1358 | private function renderIndex($matches) |
||
1359 | { |
||
1360 | $type = $matches[1]; |
||
1361 | $parms = ''; |
||
1362 | if (isset($matches[2])) { |
||
1363 | $parms = trim($matches[2]); |
||
1364 | } |
||
1365 | if (strcasecmp($type, 'RecentChanges') === 0) { |
||
1366 | return $this->recentIndex($parms); |
||
1367 | } |
||
1368 | if (strcasecmp($type, 'PageIndex') === 0) { |
||
1369 | return $this->pageIndex($parms); |
||
1370 | } |
||
1371 | |||
1372 | return false; |
||
1373 | } |
||
1374 | |||
1375 | /** |
||
1376 | * highlight search terms |
||
1377 | * adapted from: http://stack:overflow.com/questions/2591046/highlight-text-except-html-tags |
||
1378 | * |
||
1379 | * @param string[] $capture matches |
||
1380 | * |
||
1381 | * @return string |
||
1382 | */ |
||
1383 | private function mon_rplc_callback($capture) |
||
1384 | { |
||
1385 | $haystack = $capture[1]; |
||
1386 | $p1 = stripos($haystack, $this->highlightArg['needle']); |
||
1387 | $l1 = strlen($this->highlightArg['needle']); |
||
1388 | $ret = ''; |
||
1389 | while ($p1 !== false) { |
||
1390 | $ret .= substr($haystack, 0, $p1) . $this->highlightArg['pre'] . substr($haystack, $p1, $l1) . $this->highlightArg['post']; |
||
1391 | $haystack = substr($haystack, $p1 + $l1); |
||
1392 | $p1 = stripos($haystack, $this->highlightArg['needle']); |
||
1393 | } |
||
1394 | $ret .= $haystack . $capture[2]; |
||
1395 | |||
1396 | return $ret; |
||
1397 | } |
||
1398 | |||
1399 | /** |
||
1400 | * split string aware of html tags |
||
1401 | * |
||
1402 | * @param string $needle string to find |
||
1403 | * @param string $pre string to include before each match |
||
1404 | * @param string $post string to include after each match |
||
1405 | * @param string $txt text to search |
||
1406 | * |
||
1407 | * @return string |
||
1408 | */ |
||
1409 | private function split_on_tag($needle, $pre, $post, $txt) |
||
1410 | { |
||
1411 | $this->highlightArg = compact('needle', 'pre', 'post'); |
||
1412 | |||
1413 | return preg_replace_callback('#((?:(?!<[/a-z]).)*)([^>]*>|$)#si', array($this, 'mon_rplc_callback'), $txt); |
||
1414 | } |
||
1415 | |||
1416 | /** |
||
1417 | * highlight words in page |
||
1418 | * |
||
1419 | * @param string $words space separated words to match |
||
1420 | * |
||
1421 | * @return string rendered page with words highlighted |
||
1422 | */ |
||
1423 | public function highlightWords($words) |
||
1424 | { |
||
1425 | $words = str_replace(' ', ' ', $words); |
||
1426 | $words = explode(' ', $words); |
||
1427 | $body = $this->renderedPage; |
||
1428 | foreach ($words as $word) { |
||
1429 | $body = $this->split_on_tag($word, '<span class="wiki_search_term">', '</span>', $body); |
||
1430 | } |
||
1431 | |||
1432 | return $body; |
||
1433 | } |
||
1434 | |||
1435 | /** |
||
1436 | * Hold content not to be processed for wiki markup, generate a unique tag to locate later |
||
1437 | * |
||
1438 | * @param string $type type of nowiki invocation (block, wcinline or inline) |
||
1439 | * @param string $source content to hold |
||
1440 | * |
||
1441 | * @return string generated tag for held content |
||
1442 | */ |
||
1443 | private function noWikiHold($type, $source) |
||
1444 | { |
||
1445 | ++$this->noWikiIndex; |
||
1446 | switch ($type) { |
||
1447 | case 'block': |
||
1448 | $this->noWikiQueue[$this->noWikiIndex] = "<pre>\n{$source}\n</pre>"; |
||
1449 | break; |
||
1450 | case 'wcinline': |
||
1451 | $this->noWikiQueue[$this->noWikiIndex] = '<span class="wikinoinline">' . $source . '</span>'; |
||
1452 | break; |
||
1453 | case 'inline': |
||
1454 | default: |
||
1455 | $this->noWikiQueue[$this->noWikiIndex] = $source; |
||
1456 | break; |
||
1457 | } |
||
1458 | |||
1459 | $ret = "{PdNlNw:{$this->noWikiIndex}}"; |
||
1460 | |||
1461 | return $ret; |
||
1462 | } |
||
1463 | |||
1464 | /** |
||
1465 | * no wiki block callback |
||
1466 | * |
||
1467 | * @param string[] $matches preg_replace_callback matches |
||
1468 | * |
||
1469 | * @return string |
||
1470 | */ |
||
1471 | private function noWikiHoldBlock($matches) |
||
1472 | { |
||
1473 | return $this->noWikiHold('block', $matches[1]); |
||
1474 | } |
||
1475 | |||
1476 | /** |
||
1477 | * no wiki inline callback |
||
1478 | * |
||
1479 | * @param string[] $matches preg_replace_callback matches |
||
1480 | * |
||
1481 | * @return string |
||
1482 | */ |
||
1483 | private function noWikiHoldInline($matches) |
||
1484 | { |
||
1485 | return $this->noWikiHold('inline', $matches[1]); |
||
1486 | } |
||
1487 | |||
1488 | /** |
||
1489 | * no wiki inline (WikiCreole style) callback |
||
1490 | * |
||
1491 | * @param string[] $matches preg_replace_callback matches |
||
1492 | * |
||
1493 | * @return string |
||
1494 | */ |
||
1495 | private function noWikiHoldWCInline($matches) |
||
1496 | { |
||
1497 | return $this->noWikiHold('wcinline', $matches[1]); |
||
1498 | } |
||
1499 | |||
1500 | /** |
||
1501 | * no wiki for code block callback |
||
1502 | * |
||
1503 | * @param string[] $matches preg_replace_callback matches |
||
1504 | * |
||
1505 | * @return string |
||
1506 | */ |
||
1507 | private function noWikiHoldCode($matches) |
||
1508 | { |
||
1509 | return $matches[1] . $this->noWikiHold('block', $matches[2]) . $matches[3]; |
||
1510 | } |
||
1511 | |||
1512 | /** |
||
1513 | * emit save nowiki content callback |
||
1514 | * |
||
1515 | * @param string[] $matches preg_replace_callback matches |
||
1516 | * |
||
1517 | * @return string |
||
1518 | */ |
||
1519 | private function noWikiEmit($matches) |
||
1520 | { |
||
1521 | $index = $matches[1]; |
||
1522 | |||
1523 | return $this->noWikiQueue[$index]; |
||
1524 | } |
||
1525 | |||
1526 | /** |
||
1527 | * table support callback |
||
1528 | * |
||
1529 | * @param string[] $matches preg_replace_callback matches |
||
1530 | * |
||
1531 | * @return string |
||
1532 | */ |
||
1533 | private function renderTables($matches) |
||
1534 | { |
||
1535 | $source = $matches[0]; |
||
1536 | $rowcnt = 0; |
||
1537 | $table = "<table class=\"wikitable\">\n"; |
||
1538 | $rows = explode("\n", $source); |
||
1539 | foreach ($rows as $i => $row) { |
||
1540 | $row = trim($row); |
||
1541 | if (!empty($row)) { |
||
1542 | if ($row[0] === '|') { |
||
1543 | $row = substr($row, 1); |
||
1544 | } |
||
1545 | if (substr($row, -1) === '|') { |
||
1546 | $row = substr($row, 0, -1); |
||
1547 | } |
||
1548 | $cols = explode('|', $row); |
||
1549 | $table .= '<tr' . (($rowcnt % 2) ? ' class="even"' : ' class="odd"') . '>'; |
||
1550 | ++$rowcnt; |
||
1551 | foreach ($cols as $col) { |
||
1552 | if (empty($col)) { |
||
1553 | $table .= '<td> </td>'; |
||
1554 | View Code Duplication | } elseif ($col[0] === '=') { |
|
1555 | $table .= '<th>' . substr($col, 1) . '</th>'; |
||
1556 | } elseif ($col[0] === '>') { |
||
1557 | $table .= '<td class="right">' . substr($col, 1) . '</td>'; |
||
1558 | View Code Duplication | } elseif ($col[0] === '+') { |
|
1559 | $table .= '<td class="center">' . substr($col, 1) . '</td>'; |
||
1560 | } elseif (substr($col, 0, 4) === '<') { |
||
1561 | $table .= '<td class="left">' . substr($col, 4) . '</td>'; |
||
1562 | } elseif (preg_match('/^\s*[0-9.$+\-]+\s*$/', $col)) { |
||
1563 | $class = 'number'; |
||
1564 | if ((float)preg_replace("/[^-0-9\.]/", '', $col) < 0) { |
||
1565 | $class = 'number negative'; |
||
1566 | } |
||
1567 | $table .= '<td class="' . $class . '">' . trim($col) . '</td>'; |
||
1568 | } else { |
||
1569 | $table .= '<td>' . $col . '</td>'; |
||
1570 | } |
||
1571 | } |
||
1572 | $table .= "</tr>\n"; |
||
1573 | } |
||
1574 | } |
||
1575 | $table .= "</table>\n"; |
||
1576 | |||
1577 | return $table; |
||
1578 | } |
||
1579 | |||
1580 | /** |
||
1581 | * link support callback |
||
1582 | * |
||
1583 | * @param string[] $matches preg_replace_callback matches |
||
1584 | * |
||
1585 | * @return string |
||
1586 | */ |
||
1587 | private function renderLink($matches) |
||
1588 | { |
||
1589 | $source = trim($matches[1]); |
||
1590 | $pos = strpos($source, '|'); |
||
1591 | |||
1592 | if ($pos === false) { // no delimter - whole thing is the link |
||
1593 | $link = $source; |
||
1594 | $linktext = ''; |
||
1595 | // handle the pathological case of a possesive of a person page. |
||
1596 | // Creole test includes "[[Ward Cunningham's]]" which leads to a |
||
1597 | // wiki page WardCunningham. Included in spirit of compatibility. |
||
1598 | if (substr($link, -2) === "'s") { |
||
1599 | $templink = substr($link, 0, -3); // quote is slashed |
||
1600 | // only if a wiki page |
||
1601 | if (preg_match('/^([A-Za-z\x80-\xff0-9.:\- ]){2,}$/', $templink)) { |
||
1602 | $linktext = $link; |
||
1603 | $link = $templink; |
||
1604 | } |
||
1605 | } |
||
1606 | } else { |
||
1607 | $link = trim(substr($source, 0, $pos)); |
||
1608 | $linktext = trim(substr($source, $pos + 1)); |
||
1609 | } |
||
1610 | |||
1611 | if (preg_match('/^([A-Za-z\x80-\xff0-9.:\- ]){2,}$/', $link)) { |
||
1612 | //$link=str_replace (' ', '', $link); |
||
1613 | if (empty($linktext)) { |
||
1614 | $ret = $this->wikiLink($link); |
||
1615 | } else { |
||
1616 | $ret = $this->wikiLink($link, stripslashes($linktext)); |
||
1617 | } |
||
1618 | } else { |
||
1619 | $ext = true; |
||
1620 | if (strncasecmp($link, XOOPS_URL, strlen(XOOPS_URL)) === 0) { |
||
1621 | $ext = false; |
||
1622 | } // matches our site |
||
1623 | View Code Duplication | if (strcasecmp('siteurl:', substr($link, 0, 8)) === 0) { // explicit reference to our site |
|
1624 | $link = XOOPS_URL . substr($link, 8); |
||
1625 | $ext = false; |
||
1626 | } |
||
1627 | if (strpos($link, ':') === false) { |
||
1628 | $ext = false; |
||
1629 | } // no protocol, assume relative url |
||
1630 | if ($linktext === '') { |
||
1631 | $linktext = $link; |
||
1632 | } |
||
1633 | $linktext = stripslashes($linktext); |
||
1634 | // $linktext=$this->noWikiHold('inline',stripslashes($linktext)); |
||
1635 | $ret = "<a href=\"{$link}\" title=\"{$linktext}\">{$linktext}</a>"; |
||
1636 | if ($ext) { |
||
1637 | $ret = '<a href="' . $link . '" target="_blank" title="' . _MD_GWIKI_PAGE_EXT_LINK_TT . '">' . $linktext . '<span class="wikiextlink"> </span></a>'; |
||
1638 | } |
||
1639 | } |
||
1640 | |||
1641 | return $ret; |
||
1642 | } |
||
1643 | |||
1644 | /** |
||
1645 | * header support callback |
||
1646 | * |
||
1647 | * @param string[] $matches preg_replace_callback matches |
||
1648 | * |
||
1649 | * @return string |
||
1650 | */ |
||
1651 | private function renderHeader($matches) |
||
1652 | { |
||
1653 | $source = $matches[3]; |
||
1654 | $level = $matches[2]; |
||
1655 | $level = strlen($level) + 1; |
||
1656 | $this->tocQueue[$this->tocIndex] = array('level' => $level, 'name' => $source); |
||
1657 | $toc = "\n<h" . $level . ' id="' . $this->tocIdPrefix . $this->tocIndex . '" >' . $source . '</h' . $level . ">\n"; |
||
1658 | ++$this->tocIndex; |
||
1659 | |||
1660 | return $toc; |
||
1661 | } |
||
1662 | |||
1663 | /** |
||
1664 | * indent support callback |
||
1665 | * |
||
1666 | * @param string[] $matches preg_replace_callback matches |
||
1667 | * |
||
1668 | * @return string |
||
1669 | */ |
||
1670 | private function renderIndent($matches) |
||
1671 | { |
||
1672 | $source = $matches[2]; |
||
1673 | $level = $matches[1]; |
||
1674 | $level = strlen($level); |
||
1675 | $ret = "\n<div class=\"wikiindent{$level}\">\n{$source}\n</div>"; |
||
1676 | |||
1677 | return $ret; |
||
1678 | } |
||
1679 | |||
1680 | /** |
||
1681 | * table of contents support callback |
||
1682 | * |
||
1683 | * @param string[] $matches preg_replace_callback matches |
||
1684 | * |
||
1685 | * @return string |
||
1686 | */ |
||
1687 | private function renderToc($matches) |
||
1688 | { |
||
1689 | $tocq = $this->tocQueue; |
||
1690 | $toc = ''; |
||
1691 | foreach ($tocq as $i => $v) { |
||
1692 | $toc .= '<li class="wikitoclevel' . $v['level'] . '"><a href="' . sprintf($this->tocAnchorFmt, $this->tocIdPrefix . $i) . '">' . strip_tags($v['name']) . '</a></li>'; |
||
1693 | } |
||
1694 | if (!empty($toc)) { |
||
1695 | $toc = '<div class="wikitoc"><div class="wikitocheader">' . _MD_GWIKI_TOC . '</div><ul class="wikitoclist">' . $toc . '</ul></div>'; |
||
1696 | } |
||
1697 | |||
1698 | return $toc; |
||
1699 | } |
||
1700 | |||
1701 | /** |
||
1702 | * fetch table of contents for a page |
||
1703 | * |
||
1704 | * @param string $page keyword |
||
1705 | * |
||
1706 | * @return array|bool |
||
1707 | */ |
||
1708 | public function fetchPageSetToc(&$page) |
||
1709 | { |
||
1710 | global $xoopsDB; |
||
1711 | $toc = false; |
||
1712 | |||
1713 | $q_page = $this->escapeForDB($page); |
||
1714 | |||
1715 | $sql = 'SELECT gwiki_id, keyword, display_keyword, page_set_home, page_set_order, toc_cache '; |
||
1716 | $sql .= ' FROM ' . $xoopsDB->prefix('gwiki_pages'); |
||
1717 | $sql .= " WHERE active=1 and keyword='{$q_page}' "; |
||
1718 | |||
1719 | $result = $xoopsDB->query($sql); |
||
1720 | |||
1721 | $rows = $xoopsDB->getRowsNum($result); |
||
1722 | if ($rows) { |
||
1723 | $row = $xoopsDB->fetchArray($result); |
||
1724 | if (!empty($row['page_set_home'])) { |
||
1725 | $page = $row['page_set_home']; // this is passed back up to caller! |
||
1726 | $q_page = $this->escapeForDB($row['page_set_home']); |
||
1727 | $xoopsDB->freeRecordSet($result); |
||
1728 | $sql = 'SELECT gwiki_id, keyword, display_keyword, page_set_home, page_set_order, toc_cache '; |
||
1729 | $sql .= ' FROM ' . $xoopsDB->prefix('gwiki_pages'); |
||
1730 | $sql .= " WHERE active=1 and page_set_home='{$q_page}' "; |
||
1731 | $sql .= ' ORDER BY page_set_order, keyword '; |
||
1732 | |||
1733 | $result = $xoopsDB->query($sql); |
||
1734 | while ($row = $xoopsDB->fetchArray($result)) { |
||
1735 | $row['display_keyword'] = strip_tags($row['display_keyword']); |
||
1736 | if (!empty($row['toc_cache'])) { |
||
1737 | $tmp = unserialize($row['toc_cache']); |
||
1738 | foreach ($tmp as $i => $v) { |
||
1739 | $tmp[$i]['name'] = strip_tags($tmp[$i]['name']); |
||
1740 | } |
||
1741 | $row['toc'] = $tmp; |
||
1742 | |||
1743 | $toc[] = $row; |
||
1744 | } |
||
1745 | } |
||
1746 | } |
||
1747 | } |
||
1748 | $xoopsDB->freeRecordSet($result); |
||
1749 | |||
1750 | return $toc; |
||
1751 | } |
||
1752 | |||
1753 | /** |
||
1754 | * page set toc support callback |
||
1755 | * |
||
1756 | * @param string[] $matches preg_replace_callback matches |
||
1757 | * |
||
1758 | * @return string |
||
1759 | */ |
||
1760 | public function renderPageSetTocWrapper($matches) |
||
1761 | { |
||
1762 | return $this->renderPageSetToc($this->keyword, 6); |
||
1763 | } |
||
1764 | |||
1765 | /** |
||
1766 | * render a table of contents |
||
1767 | * |
||
1768 | * @param string $page keyword |
||
1769 | * @param integer $level level limit |
||
1770 | * @param string $tocclass base class for toc. Current level will be appended |
||
1771 | * |
||
1772 | * @return bool|string |
||
1773 | */ |
||
1774 | public function renderPageSetToc(&$page, $level, $tocclass = 'wikitocpage') |
||
1775 | { |
||
1776 | $toc = $this->fetchPageSetToc($page); |
||
1777 | if (!$toc) { |
||
1778 | return false; |
||
1779 | } |
||
1780 | $tocout = ''; |
||
1781 | foreach ($toc as $ti => $tv) { |
||
1782 | //$link=sprintf($this->getWikiLinkURL(),$tv['keyword']); |
||
1783 | foreach ($tv['toc'] as $i => $v) { |
||
1784 | if ((int)$v['level'] <= $level) { |
||
1785 | $tocout .= '<li class="wikitoclevel' . $v['level'] . '"><a href="' . sprintf($this->getWikiLinkURL(), $tv['keyword'] . sprintf($this->tocAnchorFmt, $this->tocIdPrefix . $i)) . '">' |
||
1786 | . $v['name'] . '</a></li>'; |
||
1787 | } |
||
1788 | } |
||
1789 | } |
||
1790 | if (!empty($tocout)) { |
||
1791 | $tocout = '<div class="' . $tocclass . '"><ul class="wikitoclist">' . $tocout . '</ul></div>'; |
||
1792 | } |
||
1793 | |||
1794 | return $tocout; |
||
1795 | } |
||
1796 | |||
1797 | /** |
||
1798 | * render navigation for a page set |
||
1799 | * @param $page |
||
1800 | * |
||
1801 | * @return mixed |
||
1802 | */ |
||
1803 | public function renderPageSetNav($page) |
||
1804 | { |
||
1805 | $sethome = $page; |
||
1806 | $toc = $this->fetchPageSetToc($sethome); // this will set home |
||
1807 | if (!$toc) { |
||
1808 | return false; |
||
1809 | } |
||
1810 | $home = -1; |
||
1811 | $current = -1; |
||
1812 | $prev = -1; |
||
1813 | $next = -1; |
||
1814 | foreach ($toc as $i => $v) { |
||
1815 | if (strcasecmp($toc[$i]['keyword'], $page) === 0) { |
||
1816 | $current = $i; |
||
1817 | } |
||
1818 | if (strcasecmp($toc[$i]['keyword'], $sethome) === 0) { |
||
1819 | $home = $i; |
||
1820 | } |
||
1821 | } |
||
1822 | |||
1823 | if ($current > -1) { |
||
1824 | $prev = $current - 1; |
||
1825 | $next = $current + 1; |
||
1826 | } |
||
1827 | |||
1828 | $first = 0; |
||
1829 | $last = count($toc) - 1; |
||
1830 | |||
1831 | // should these wrap instead? |
||
1832 | if ($next > $last) { |
||
1833 | $next = $last; |
||
1834 | } |
||
1835 | if ($prev < 0) { |
||
1836 | $prev = 0; |
||
1837 | } |
||
1838 | if ($home < 0) { |
||
1839 | $home = 0; |
||
1840 | } |
||
1841 | |||
1842 | $pageset['first'] = array( |
||
1843 | 'link' => sprintf($this->getWikiLinkURL(), $toc[$first]['keyword']), |
||
1844 | 'text' => htmlentities($toc[$first]['display_keyword'], ENT_QUOTES), |
||
1845 | 'desc' => _MD_GWIKI_PAGENAV_FIRST |
||
1846 | ); |
||
1847 | |||
1848 | $pageset['prev'] = array( |
||
1849 | 'link' => sprintf($this->getWikiLinkURL(), $toc[$prev]['keyword']), |
||
1850 | 'text' => htmlentities($toc[$prev]['display_keyword'], ENT_QUOTES), |
||
1851 | 'desc' => _MD_GWIKI_PAGENAV_PREV |
||
1852 | ); |
||
1853 | |||
1854 | $pageset['home'] = array( |
||
1855 | 'link' => sprintf($this->getWikiLinkURL(), $toc[$home]['keyword']), |
||
1856 | 'text' => htmlentities($toc[$home]['display_keyword'], ENT_QUOTES), |
||
1857 | 'desc' => _MD_GWIKI_PAGENAV_TOP |
||
1858 | ); |
||
1859 | |||
1860 | $pageset['next'] = array( |
||
1861 | 'link' => sprintf($this->getWikiLinkURL(), $toc[$next]['keyword']), |
||
1862 | 'text' => htmlentities($toc[$next]['display_keyword'], ENT_QUOTES), |
||
1863 | 'desc' => _MD_GWIKI_PAGENAV_NEXT |
||
1864 | ); |
||
1865 | |||
1866 | $pageset['last'] = array( |
||
1867 | 'link' => sprintf($this->getWikiLinkURL(), $toc[$last]['keyword']), |
||
1868 | 'text' => htmlentities($toc[$last]['display_keyword'], ENT_QUOTES), |
||
1869 | 'desc' => _MD_GWIKI_PAGENAV_LAST |
||
1870 | ); |
||
1871 | |||
1872 | View Code Duplication | if (strcasecmp($toc[$first]['keyword'], $page) === 0) { |
|
1873 | $pageset['first']['link'] = 'javascript:void(0)'; |
||
1874 | } |
||
1875 | View Code Duplication | if (strcasecmp($toc[$prev]['keyword'], $page) === 0) { |
|
1876 | $pageset['prev']['link'] = 'javascript:void(0)'; |
||
1877 | } |
||
1878 | View Code Duplication | if (strcasecmp($toc[$home]['keyword'], $page) === 0) { |
|
1879 | $pageset['home']['link'] = 'javascript:void(0)'; |
||
1880 | } |
||
1881 | View Code Duplication | if (strcasecmp($toc[$next]['keyword'], $page) === 0) { |
|
1882 | $pageset['next']['link'] = 'javascript:void(0)'; |
||
1883 | } |
||
1884 | View Code Duplication | if (strcasecmp($toc[$last]['keyword'], $page) === 0) { |
|
1885 | $pageset['last']['link'] = 'javascript:void(0)'; |
||
1886 | } |
||
1887 | |||
1888 | return $pageset; |
||
1889 | } |
||
1890 | |||
1891 | /** |
||
1892 | * get image libraries for a page |
||
1893 | * |
||
1894 | * @param string $keyword keyword of page |
||
1895 | * |
||
1896 | * @return string[] |
||
1897 | */ |
||
1898 | public function getImageLib($keyword) |
||
1899 | { |
||
1900 | $lib = $this->imageLib; |
||
1901 | array_unshift($lib, $keyword); |
||
1902 | |||
1903 | return array_unique($lib); |
||
1904 | } |
||
1905 | |||
1906 | /** |
||
1907 | * get an image relative to specified page |
||
1908 | * |
||
1909 | * return array includes: |
||
1910 | * image_id |
||
1911 | * keyword |
||
1912 | * image_name |
||
1913 | * image_alt_text |
||
1914 | * image_file |
||
1915 | * |
||
1916 | * @param string $keyword keyword of page |
||
1917 | * @param string $name image name |
||
1918 | * |
||
1919 | * @return array|bool image data or false if invalid or not found |
||
1920 | */ |
||
1921 | public function getPageImage($keyword, $name) |
||
1922 | { |
||
1923 | global $xoopsDB; |
||
1924 | |||
1925 | if (strncasecmp($name, 'http://', 7) === 0 || strncasecmp($name, 'https://', 8) === 0) { |
||
1926 | return false; |
||
1927 | } |
||
1928 | $lib = $this->imageLib; |
||
1929 | array_unshift($lib, $keyword); |
||
1930 | foreach ($lib as $page) { |
||
1931 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('gwiki_page_images') . ' WHERE keyword=\'' . $this->escapeForDB($page) . '\' '; |
||
1932 | $sql .= ' AND image_name=\'' . $this->escapeForDB($name) . '\' '; |
||
1933 | $result = $xoopsDB->query($sql); |
||
1934 | if ($image = $xoopsDB->fetchArray($result)) { |
||
1935 | return $image; |
||
1936 | } |
||
1937 | } |
||
1938 | |||
1939 | return false; |
||
1940 | } |
||
1941 | |||
1942 | /** |
||
1943 | * render image support callback |
||
1944 | * |
||
1945 | * @param string[] $matches preg_replace_callback matches |
||
1946 | * |
||
1947 | * @return string |
||
1948 | */ |
||
1949 | private function renderImage($matches) |
||
1950 | { |
||
1951 | $source = trim($matches[1]); |
||
1952 | $pos = strpos($source, '|'); |
||
1953 | //if($pos===false) $pos=strpos($source,' '); |
||
1954 | if ($pos === false) { // no delimter - whole thing is the image url |
||
1955 | $link = $source; |
||
1956 | $parms = array(); |
||
1957 | } else { |
||
1958 | $link = trim(substr($source, 0, $pos)); |
||
1959 | $parms = explode('|', trim(substr($source, $pos + 1))); |
||
1960 | foreach ($parms as $i => $parm) { |
||
1961 | $parms[$i] = trim($parm); |
||
1962 | } |
||
1963 | } |
||
1964 | View Code Duplication | if (strcasecmp('siteurl:', substr($link, 0, 8)) === 0) { // explicit reference to our site |
|
1965 | $link = XOOPS_URL . substr($link, 8); |
||
1966 | } |
||
1967 | $showthumb = false; |
||
1968 | $showthumblink = false; |
||
1969 | if (strcasecmp('thumb:', substr($link, 0, 6)) === 0) { // explicit request for thumbnail, links to full image |
||
1970 | $revertlink = $link; |
||
1971 | $link = substr($link, 6); |
||
1972 | $showthumblink = true; |
||
1973 | } |
||
1974 | $alttext = empty($parms[0]) ? '' : $parms[0]; |
||
1975 | $align = empty($parms[1]) ? '' : $parms[1]; |
||
1976 | $maxpx = empty($parms[2]) ? '' : (int)$parms[2]; |
||
1977 | |||
1978 | // align must be left, right, center or empty |
||
1979 | $align = ''; |
||
1980 | if (strcasecmp($align, 'left') === 0) { |
||
1981 | $align = 'left'; |
||
1982 | } elseif (strcasecmp($align, 'right') === 0) { |
||
1983 | $align = 'right'; |
||
1984 | } elseif (strcasecmp($align, 'center') === 0) { |
||
1985 | $align = 'center'; |
||
1986 | } |
||
1987 | |||
1988 | $alignparm = ''; |
||
1989 | if ($align === 'left' || $align === 'right' || $align === 'center') { |
||
1990 | $alignparm = ', ' . $align; |
||
1991 | } |
||
1992 | |||
1993 | // look up link in page_images table, if found use that, otherwise just pass on link as is |
||
1994 | $image = $this->getPageImage($this->keyword, $link); |
||
1995 | if ($image) { |
||
1996 | // image array includes: |
||
1997 | // image_id |
||
1998 | // keyword |
||
1999 | // image_name |
||
2000 | // image_alt_text |
||
2001 | // image_file |
||
2002 | // use_to_represent |
||
2003 | $link = XOOPS_URL . '/uploads/' . $this->wikiDir . '/' . $image['image_file']; |
||
2004 | if (empty($alttext)) { |
||
2005 | $alttext = $image['image_alt_text']; |
||
2006 | } |
||
2007 | } else { |
||
2008 | // thumbs don't apply, so put everything back the way it was |
||
2009 | if ($showthumblink) { |
||
2010 | $link = $revertlink; |
||
2011 | $showthumblink = false; |
||
2012 | } |
||
2013 | } |
||
2014 | |||
2015 | $alt = ''; |
||
2016 | // $alttext=htmlspecialchars($alttext); |
||
2017 | if (!empty($alttext)) { |
||
2018 | $alt = " alt=\"{$alttext}\" title=\"{$alttext}\" "; |
||
2019 | } |
||
2020 | |||
2021 | $maxpxstyle = ''; |
||
2022 | if (!empty($maxpx)) { |
||
2023 | $maxpxstyle = " style=\"max-width:{$maxpx}px; max-height:{$maxpx}px; width:auto; height:auto;\" "; |
||
2024 | $showthumb = true; // trigger automatic thumbnail use |
||
2025 | } |
||
2026 | |||
2027 | if ($showthumb) { |
||
2028 | $thumbsize = $this->defaultThumbSize; |
||
2029 | if (!empty($maxpx)) { |
||
2030 | $thumbsize = $maxpx; |
||
2031 | } |
||
2032 | $link = XOOPS_URL . '/modules/' . $this->wikiDir . '/getthumb.php?page=' . $image['keyword'] . '&name=' . urlencode($image['image_name']) . '&size=' . $thumbsize; |
||
2033 | } |
||
2034 | |||
2035 | if ($showthumblink) { |
||
2036 | $ret = ''; |
||
2037 | $thumbsize = $this->defaultThumbSize; |
||
2038 | if (!empty($maxpx)) { |
||
2039 | $thumbsize = $maxpx; |
||
2040 | } |
||
2041 | $thumb = XOOPS_URL . '/modules/' . $this->wikiDir . '/getthumb.php?page=' . $image['keyword'] . '&name=' . urlencode($image['image_name']) . '&size=' . $thumbsize; |
||
2042 | $img = XOOPS_URL . '/uploads/' . $this->wikiDir . '/' . $image['image_file']; |
||
2043 | $ret .= '<a href="' . $img . '" ' . $alt . '><img src="' . $thumb . '"' . $alt . $maxpxstyle . '/></a>'; |
||
2044 | } else { |
||
2045 | $ret = "<img class=\"wikiimage{$alignparm}\" src=\"{$link}\" {$alt}{$maxpxstyle} />"; |
||
2046 | } |
||
2047 | |||
2048 | if ($align === 'center') { |
||
2049 | $ret = '<div style="margin: 0 auto; text-align: center;">' . $ret . '</div>'; |
||
2050 | } |
||
2051 | |||
2052 | return $ret; |
||
2053 | } |
||
2054 | |||
2055 | /** |
||
2056 | * gallery support callback |
||
2057 | * |
||
2058 | * @param string[] $matches preg_replace_callback matches |
||
2059 | * |
||
2060 | * @return string |
||
2061 | */ |
||
2062 | private function renderGallery($matches) |
||
2063 | { |
||
2064 | global $xoopsDB; |
||
2065 | |||
2066 | $source = ''; |
||
2067 | if (isset($matches[1])) { |
||
2068 | $source = $matches[1]; |
||
2069 | } |
||
2070 | $maxpx = (int)trim($source); |
||
2071 | if ($maxpx < 10) { |
||
2072 | $maxpx = $this->defaultThumbSize; |
||
2073 | } |
||
2074 | $page = $this->keyword; |
||
2075 | |||
2076 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('gwiki_page_images') . ' WHERE keyword = \'' . $page . '\' ' . ' ORDER BY image_name '; |
||
2077 | $result = $xoopsDB->query($sql); |
||
2078 | |||
2079 | $dir = $this->wikiDir; |
||
2080 | $body = '<div class="wikigallery"><ul class="wikigalleryimg">'; |
||
2081 | |||
2082 | for ($i = 0, $iMax = $xoopsDB->getRowsNum($result); $i < $iMax; ++$i) { |
||
2083 | $image = $xoopsDB->fetchArray($result); |
||
2084 | $img = XOOPS_URL . '/uploads/' . $dir . '/' . $image['image_file']; |
||
2085 | $thumb = XOOPS_URL . '/modules/' . $dir . '/getthumb.php?page=' . $image['keyword'] . '&name=' . urlencode($image['image_name']) . '&size=' . $maxpx; |
||
2086 | $alt = htmlentities($image['image_alt_text'], ENT_QUOTES); |
||
2087 | $name = htmlentities($image['image_name'], ENT_QUOTES); |
||
2088 | if (empty($alt)) { |
||
2089 | $alt = $name; |
||
2090 | } |
||
2091 | $body .= '<li><a href="' . $img . '" title="' . $name . '"><img src="' . $thumb . '" alt="' . $alt . '" title="' . $alt . '" /></a></li>' . "\n"; |
||
2092 | } |
||
2093 | |||
2094 | $body .= '</ul><br style="clear:both;" /></div>'; |
||
2095 | |||
2096 | return $body; |
||
2097 | } |
||
2098 | |||
2099 | /** |
||
2100 | * list support callback |
||
2101 | * |
||
2102 | * @param string[] $matches preg_replace_callback matches |
||
2103 | * |
||
2104 | * @return string |
||
2105 | */ |
||
2106 | private function renderLists($matches) |
||
2107 | { |
||
2108 | $lines = explode("\n", $matches[0]); |
||
2109 | $last = ''; |
||
2110 | foreach ($lines as $i => $line) { |
||
2111 | $line = ltrim($line); |
||
2112 | if (!empty($line)) { |
||
2113 | $list = ''; |
||
2114 | $p = strpos($line, ' '); |
||
2115 | $current = substr($line, 0, $p); |
||
2116 | $x = 0; |
||
2117 | while (!empty($last[$x]) && !empty($current[$x]) && $last[$x] === $current[$x]) { |
||
2118 | ++$x; |
||
2119 | } |
||
2120 | // $x is where the last and current list prefixes differ |
||
2121 | // close anything from $x to end in last |
||
2122 | $close = strrev(substr($last, $x)); |
||
2123 | $y = 0; |
||
2124 | View Code Duplication | while (!empty($close[$y])) { |
|
2125 | if ($close[$y] === '*') { |
||
2126 | $list .= '</li></ul>'; |
||
2127 | } //.($x>0?'</li>':''); |
||
2128 | if ($close[$y] === '#') { |
||
2129 | $list .= '</li></ol>'; |
||
2130 | } //.($x>0?'</li>':''); |
||
2131 | ++$y; |
||
2132 | } |
||
2133 | // open anything from $x to end in |
||
2134 | $open = substr($current, $x); |
||
2135 | $y = 0; |
||
2136 | View Code Duplication | while (!empty($open[$y])) { |
|
2137 | if ($open[$y] === '*') { |
||
2138 | $list .= '<ul class="wikiulist">'; |
||
2139 | } |
||
2140 | if ($open[$y] === '#') { |
||
2141 | $list .= '<ol class="wikiolist">'; |
||
2142 | } |
||
2143 | ++$y; |
||
2144 | } |
||
2145 | $endli = ($last === $current) ? '</li>' : ''; |
||
2146 | $last = $current; |
||
2147 | $lines[$i] = $list . $endli . "\n<li> " . substr($line, $p + 1); |
||
2148 | } |
||
2149 | } |
||
2150 | |||
2151 | // put list back together |
||
2152 | $list = "\n"; |
||
2153 | foreach ($lines as $line) { |
||
2154 | if (!empty($line)) { |
||
2155 | $list .= $line; |
||
2156 | } |
||
2157 | } |
||
2158 | // close anything left open |
||
2159 | $close = strrev($last); |
||
2160 | $y = 0; |
||
2161 | View Code Duplication | while (!empty($close[$y])) { |
|
2162 | if ($close[$y] === '*') { |
||
2163 | $list .= "</li></ul>\n"; |
||
2164 | } |
||
2165 | if ($close[$y] === '#') { |
||
2166 | $list .= "</li></ol>\n"; |
||
2167 | } |
||
2168 | ++$y; |
||
2169 | } |
||
2170 | |||
2171 | return $list; |
||
2172 | } |
||
2173 | |||
2174 | /** |
||
2175 | * reference support callback |
||
2176 | * |
||
2177 | * @param string[] $matches preg_replace_callback matches |
||
2178 | * |
||
2179 | * @return string |
||
2180 | */ |
||
2181 | private function renderRef($matches) |
||
2182 | { |
||
2183 | $refinfo = $matches[1]; |
||
2184 | $source = $matches[2]; |
||
2185 | $first_ref = false; |
||
2186 | $refs = explode('|', trim($refinfo) . '|||'); |
||
2187 | $rq['id'] = $refs[0]; |
||
2188 | $rq['first'] = $refs[1]; |
||
2189 | $rq['repeat'] = $refs[2]; |
||
2190 | $rq['source'] = $source; |
||
2191 | $refid = (-1); |
||
2192 | if (!empty($rq['id'])) { |
||
2193 | foreach ($this->refQueue as $i => $v) { |
||
2194 | if ($v['id'] === $rq['id']) { |
||
2195 | $refid = $i; |
||
2196 | } |
||
2197 | } |
||
2198 | } |
||
2199 | if ($refid === (-1)) { |
||
2200 | $refid = $this->refIndex; |
||
2201 | $first_ref = true; |
||
2202 | $this->refQueue[$this->refIndex] = $rq; |
||
2203 | ++$this->refIndex; |
||
2204 | } |
||
2205 | $paren_ref = false; |
||
2206 | if (!empty($this->refQueue[$refid]['first'])) { |
||
2207 | $paren_ref = true; |
||
2208 | } |
||
2209 | if ($paren_ref) { |
||
2210 | $ref_text = $this->refQueue[$refid]['first']; |
||
2211 | if (!$first_ref) { |
||
2212 | if (!empty($this->refQueue[$refid]['repeat'])) { |
||
2213 | $ref_text = $this->refQueue[$refid]['repeat']; |
||
2214 | } |
||
2215 | } |
||
2216 | $r = '<span class="wikiparenref"><a href="#ref' . $refid . '">(' . $ref_text . ')</a></span>'; |
||
2217 | } else { |
||
2218 | $r = '<span class="wikinumref"><a href="#ref' . $refid . '">' . ($refid + 1) . '</a></span>'; |
||
2219 | } |
||
2220 | |||
2221 | return $r; |
||
2222 | } |
||
2223 | |||
2224 | /** |
||
2225 | * reference list support callback |
||
2226 | * |
||
2227 | * @param string[] $matches preg_replace_callback matches |
||
2228 | * |
||
2229 | * @return string |
||
2230 | */ |
||
2231 | private function renderRefList($matches) |
||
2232 | { |
||
2233 | $this->refShown = true; |
||
2234 | $r = '<div class="wikicitelist">'; |
||
2235 | |||
2236 | foreach ($this->refQueue as $i => $v) { |
||
2237 | $refid = $i; |
||
2238 | if (empty($v['first'])) { |
||
2239 | $r .= '<div class="wikicitenumitem" id="ref' . $refid . '"><span class="wikicitenum">' . ($refid + 1) . '. </span>' . $v['source'] . "</div>\n"; |
||
2240 | } else { |
||
2241 | $r .= '<div class="wikiciteparenitem" id="ref' . $refid . '">' . $v['source'] . "</div>\n"; |
||
2242 | } |
||
2243 | } |
||
2244 | |||
2245 | $r .= '</div>'; |
||
2246 | |||
2247 | return $r; |
||
2248 | } |
||
2249 | |||
2250 | /** |
||
2251 | * box support callback |
||
2252 | * |
||
2253 | * @param string[] $matches preg_replace_callback matches |
||
2254 | * |
||
2255 | * @return string |
||
2256 | */ |
||
2257 | private function renderBox($matches) |
||
2258 | { |
||
2259 | $type = $matches[1]; |
||
2260 | $title = $matches[2]; |
||
2261 | $body = $matches[3]; |
||
2262 | // make sure we have a valid type |
||
2263 | $type = strtolower($type); |
||
2264 | if (!($type === 'code' || $type === 'info' || $type === 'note' || $type === 'tip' || $type === 'warn' |
||
2265 | || $type === 'folded') |
||
2266 | ) { |
||
2267 | $type = 'info'; |
||
2268 | } |
||
2269 | |||
2270 | // $title may include options ( title | align ) : |
||
2271 | // align: adds additonal class 'left' or 'right' to box so css can alter float, size, etc. |
||
2272 | $title = trim($title); |
||
2273 | $eclass = ''; |
||
2274 | $ejs = ''; |
||
2275 | $etooltip = ''; |
||
2276 | $pos = strpos($title, '|'); |
||
2277 | if ($pos !== false) { // if no delimiter - whole thing is the title |
||
2278 | $parms = explode('|', $title); |
||
2279 | $title = $parms[0]; |
||
2280 | if (!empty($parms[1]) && ($parms[1] === 'left' || $parms[1] === 'right')) { |
||
2281 | $eclass = ' ' . $parms[1]; |
||
2282 | } |
||
2283 | } |
||
2284 | if ($type === 'folded') { |
||
2285 | $foldclass = 'wikifolded' . $eclass; |
||
2286 | $unfoldclass = 'wikiunfolded' . $eclass; |
||
2287 | $ejs = ' onclick="var c=this.className; if(c==\'' . $foldclass . '\') this.className=\'' . $unfoldclass . '\'; else this.className=\'' . $foldclass . '\';"'; |
||
2288 | $etooltip = '<span>' . _MD_GWIKI_FOLDED_TT . '</span>'; |
||
2289 | } |
||
2290 | |||
2291 | $ret = '<div class="wiki' . $type . $eclass . '"' . $ejs . '><div class="wiki' . $type . 'icon"></div><div class="wiki' . $type . 'title">' . $title . $etooltip . '</div><div class="wiki' |
||
2292 | . $type . 'inner">' . $body . '<br clear="all" /></div></div>' . "\n\n"; |
||
2293 | |||
2294 | return $ret; |
||
2295 | } |
||
2296 | |||
2297 | /** |
||
2298 | * Convert entities |
||
2299 | * |
||
2300 | * @param string $body wiki text to process |
||
2301 | * |
||
2302 | * @return string |
||
2303 | */ |
||
2304 | private function convertEntities($body) |
||
2305 | { |
||
2306 | // convert some entites |
||
2307 | $sym = array(); |
||
2308 | $ent = array(); |
||
2309 | $sym[] = '{cent}'; |
||
2310 | $ent[] = '¢'; |
||
2311 | $sym[] = '{pound}'; |
||
2312 | $ent[] = '£'; |
||
2313 | $sym[] = '{yen}'; |
||
2314 | $ent[] = '¥'; |
||
2315 | $sym[] = '{euro}'; |
||
2316 | $ent[] = '€'; |
||
2317 | $sym[] = '{c}'; |
||
2318 | $ent[] = '©'; |
||
2319 | $sym[] = '(c)'; |
||
2320 | $ent[] = '©'; |
||
2321 | $sym[] = '{r}'; |
||
2322 | $ent[] = '®'; |
||
2323 | $sym[] = '(r)'; |
||
2324 | $ent[] = '®'; |
||
2325 | $sym[] = '{tm}'; |
||
2326 | $ent[] = '™'; |
||
2327 | $sym[] = '(tm)'; |
||
2328 | $ent[] = '™'; |
||
2329 | $sym[] = '{sm}'; |
||
2330 | // very poor font support for unicode code point for service mark, fake with markup |
||
2331 | $ent[] = '<span style="font-size: 50%; vertical-align: super;">SM</span>'; |
||
2332 | $sym[] = '{nbsp}'; |
||
2333 | $ent[] = ' '; |
||
2334 | |||
2335 | $body = str_ireplace($sym, $ent, $body); |
||
2336 | |||
2337 | return $body; |
||
2338 | } |
||
2339 | |||
2340 | /** |
||
2341 | * Render a teaser section. If page includes a {more} tag, teaser will be text that preceeds it. |
||
2342 | * Otherwise try to break semantically at about 400 characters. |
||
2343 | * |
||
2344 | * @param string|null $body text to process, defaults to current page body |
||
2345 | * @param string|null $title title to use |
||
2346 | * |
||
2347 | * @return string |
||
2348 | */ |
||
2349 | public function renderTeaser($body = null, $title = null) |
||
2350 | { |
||
2351 | // chop body at more tag if it is set |
||
2352 | $splitsize = 400; // arbitrary size to use when no {more} tag |
||
2353 | if (empty($body)) { |
||
2354 | $body = $this->body; |
||
2355 | } |
||
2356 | $pos = stripos($body, '{more}'); |
||
2357 | if ($pos === false && strlen($body) > $splitsize) { |
||
2358 | $search = "#\r\n?#"; |
||
2359 | $replace = "\n"; |
||
2360 | $body = preg_replace($search, $replace, $body); |
||
2361 | $pos = stripos($body, "\n\n", $splitsize); // hopefully the end of a paragraph |
||
2362 | } |
||
2363 | if ($pos !== false) { |
||
2364 | $body = substr($body, 0, $pos); |
||
2365 | $url = sprintf($this->wikiLinkURL, $this->keyword); |
||
2366 | } |
||
2367 | |||
2368 | $body = str_ireplace('{toc}', '', $body); |
||
2369 | $body = $this->renderPage($body, $title); |
||
2370 | if ($pos !== false) { |
||
2371 | $body .= '<a href="' . $url . '#more"><span class="wikimore">' . _MD_GWIKI_MORE . '</span></a>'; |
||
2372 | } |
||
2373 | |||
2374 | return $body; |
||
2375 | } |
||
2376 | |||
2377 | /** |
||
2378 | * block quote support callback |
||
2379 | * |
||
2380 | * @param string[] $matches preg_replace_callback matches |
||
2381 | * |
||
2382 | * @return string |
||
2383 | */ |
||
2384 | private function renderBlockquote($matches) |
||
2385 | { |
||
2386 | $src = str_replace("\n", ' ', preg_replace('#^> #m', '', $matches[0])); |
||
2387 | |||
2388 | return '<blockquote class=\"wikiquote\">' . $src . "</blockquote>\n"; |
||
2389 | } |
||
2390 | |||
2391 | /** |
||
2392 | * preformatted support callback |
||
2393 | * |
||
2394 | * @param string[] $matches preg_replace_callback matches |
||
2395 | * |
||
2396 | * @return string |
||
2397 | */ |
||
2398 | private function renderPreformat($matches) |
||
2399 | { |
||
2400 | $src = preg_replace('#^. #m', '', $matches[0]); |
||
2401 | |||
2402 | return '<pre>' . $src . "</pre>\n"; |
||
2403 | } |
||
2404 | |||
2405 | /** |
||
2406 | * Render a page |
||
2407 | * |
||
2408 | * @param string|null $body text to process, defaults to current page body |
||
2409 | * @param string|null $title title to use, defaults to current page title |
||
2410 | * |
||
2411 | * @return string |
||
2412 | */ |
||
2413 | public function renderPage($body = null, $title = null) |
||
2414 | { |
||
2415 | if (empty($body)) { |
||
2416 | $body = $this->body; |
||
2417 | } |
||
2418 | $this->renderedPage = ''; |
||
2419 | $this->noWikiQueue = array(); |
||
2420 | $this->noWikiIndex = 0; |
||
2421 | $this->refShown = false; |
||
2422 | |||
2423 | if (empty($title)) { |
||
2424 | $title = $this->title; |
||
2425 | } |
||
2426 | // do first because title should always be #toc0 - set in template |
||
2427 | $this->renderHeader(array('', '', '', $title)); |
||
2428 | |||
2429 | $body .= "\n"; |
||
2430 | |||
2431 | // eliminate double line endings |
||
2432 | $search = "#\r\n?#"; |
||
2433 | $replace = "\n"; |
||
2434 | $body = preg_replace($search, $replace, $body); |
||
2435 | |||
2436 | // neuter html tags |
||
2437 | $search = '#<#'; |
||
2438 | $replace = '<'; |
||
2439 | $body = preg_replace($search, $replace, $body); |
||
2440 | |||
2441 | // neuter single quotes |
||
2442 | $search = "#'#"; |
||
2443 | $replace = "\\'"; |
||
2444 | $body = preg_replace($search, $replace, $body); |
||
2445 | |||
2446 | // nowiki - tilde escape |
||
2447 | $search = "#~([^ \t\r\n\v\f])#U"; |
||
2448 | $replace = array($this, 'noWikiHoldInline'); |
||
2449 | $body = preg_replace_callback($search, $replace, $body); |
||
2450 | |||
2451 | // nowiki content gwiki style |
||
2452 | $search = '#{nowiki}(.*){endnowiki}#Umsi'; |
||
2453 | $replace = array($this, 'noWikiHoldInline'); |
||
2454 | $body = preg_replace_callback($search, $replace, $body); |
||
2455 | |||
2456 | // nowiki content block creole style (a nowiki that forces a style, how odd.) |
||
2457 | $search = "#^{{{\n(.*)^}}}\n#Umsi"; |
||
2458 | $replace = array($this, 'noWikiHoldBlock'); |
||
2459 | $body = preg_replace_callback($search, $replace, $body); |
||
2460 | |||
2461 | // nowiki content inline creole style |
||
2462 | $search = '#{{{(.*)}}}#U'; |
||
2463 | $replace = array($this, 'noWikiHoldWCInline'); |
||
2464 | $body = preg_replace_callback($search, $replace, $body); |
||
2465 | |||
2466 | // automatically nowiki content of code box - {code title}xxx{endcode} |
||
2467 | $search = "#({code [^\"<\n]+?})(.*?)({endcode})#si"; |
||
2468 | $replace = array($this, 'noWikiHoldCode'); |
||
2469 | $body = preg_replace_callback($search, $replace, $body); |
||
2470 | |||
2471 | // center ++ xxx |
||
2472 | $search = "#^(\+{2})(.*)(?=\n\n|\Z)#Usm"; |
||
2473 | $replace = "<div style=\"text-align: center;\" class=\"wikicenter\">\n\\2\n</div>\n"; |
||
2474 | $body = preg_replace($search, $replace, $body); |
||
2475 | |||
2476 | // : indent up to 5 levels |
||
2477 | $search = "#^(\:{1,5})\s(.*)(?=\n\n|\Z)#Usm"; |
||
2478 | $replace = array($this, 'renderIndent'); |
||
2479 | $body = preg_replace_callback($search, $replace, $body); |
||
2480 | |||
2481 | // lists |
||
2482 | $search = "#^( *[*\#]{1,} (.*)\n)+#m"; |
||
2483 | $replace = array($this, 'renderLists'); |
||
2484 | $body = preg_replace_callback($search, $replace, $body); |
||
2485 | |||
2486 | // bold **xxx** |
||
2487 | $search = "#\*{2}(.*?)(\*{2}|(?=\n\n))#s"; |
||
2488 | $replace = "<strong class=\"wikistrong\">\\1</strong>"; |
||
2489 | $body = preg_replace($search, $replace, $body); |
||
2490 | |||
2491 | // italic //xxx// |
||
2492 | $search = "#(?<![:])/{2}(.*?[^:])(/{2}|(?=\n\n))#s"; |
||
2493 | $replace = "<em class=\"wikiem\">\\1</em>"; |
||
2494 | $body = preg_replace($search, $replace, $body); |
||
2495 | |||
2496 | // horizontal rule ---- (not an empty strikethru; creole says 4 or more so this needs to go first) |
||
2497 | $search = "#^-{4,}$#m"; |
||
2498 | $replace = "\n<hr class=\"wikihr\"/>\n"; |
||
2499 | $body = preg_replace($search, $replace, $body); |
||
2500 | |||
2501 | // strikethru --xxx-- (this does NOT cross lines, as '--' is a common typographic convention |
||
2502 | $search = "#-{2}([^\s]{1}.*?)(-{2})#"; |
||
2503 | $replace = "<del class=\"wikidel\">\\1</del>"; |
||
2504 | $body = preg_replace($search, $replace, $body); |
||
2505 | |||
2506 | // underline __xxx__ |
||
2507 | $search = "#(?<=\s)_{2}(.*?)(_{2}|(?=\n\n))#s"; |
||
2508 | $replace = "<span class=\"wikiu\">\\1</span>"; |
||
2509 | $body = preg_replace($search, $replace, $body); |
||
2510 | |||
2511 | // superscript ^^xxx^^ |
||
2512 | $search = "#\^{2}(.*?)(\^{2}|(?=\n\n))#s"; |
||
2513 | $replace = "<sup class=\"wikisup\">\\1</sup>"; |
||
2514 | $body = preg_replace($search, $replace, $body); |
||
2515 | |||
2516 | // subscript ,,xxx,, |
||
2517 | $search = "#,{2}(.*?)(,{2}|(?=\n\n))#s"; |
||
2518 | $replace = "<sub class=\"wikisub\">\\1</sub>"; |
||
2519 | $body = preg_replace($search, $replace, $body); |
||
2520 | |||
2521 | // monospace ##xxx## |
||
2522 | $search = "#\#{2}(.*?)(\#{2}|(?=\n\n))#s"; |
||
2523 | $replace = "<span class=\"wikitt\">\\1</span>"; |
||
2524 | $body = preg_replace($search, $replace, $body); |
||
2525 | |||
2526 | // color !!color:xxx!! |
||
2527 | $search = "#!{2}(\#{0,1}[0-9A-Za-z]*):(.*?)(!{2}|(?=\n\n))#s"; |
||
2528 | $replace = "<span style=\"color:\\1;\">\\2</span>"; |
||
2529 | $body = preg_replace($search, $replace, $body); |
||
2530 | |||
2531 | // color !!color,background:xxx!! |
||
2532 | $search = "#!{2}(\#{0,1}[0-9A-Za-z]*),(\#{0,1}[0-9A-Za-z]*):(.*?)(!{2}|(?=\n\n))#s"; |
||
2533 | $replace = "<span style=\"color:\\1; background-color:\\2;\">\\3</span>"; |
||
2534 | $body = preg_replace($search, $replace, $body); |
||
2535 | |||
2536 | // forced line break creole style \\, just a bare break tag |
||
2537 | $search = "#(\\\{2})#i"; |
||
2538 | $replace = '<br>'; |
||
2539 | $body = preg_replace($search, $replace, $body); |
||
2540 | |||
2541 | // forced line break blog [[br]] or gwiki {break} styles, themed - by default clear all |
||
2542 | $search = "#(\[\[BR\]\]|{break})#i"; |
||
2543 | $replace = '<br class="wikibreak" />'; |
||
2544 | $body = preg_replace($search, $replace, $body); |
||
2545 | |||
2546 | // image {{image url|alt text|align|max width in pixels}} |
||
2547 | $search = "#\{{2}(.*)\}{2}#Um"; |
||
2548 | $replace = array($this, 'renderImage'); |
||
2549 | $body = preg_replace_callback($search, $replace, $body); |
||
2550 | |||
2551 | // info box {info title}xxx{endinfo} |
||
2552 | $search = "#{(info) ([^\"<\n]+?)?}(.*?){endinfo}#si"; |
||
2553 | $replace = array($this, 'renderBox'); |
||
2554 | $body = preg_replace_callback($search, $replace, $body); |
||
2555 | |||
2556 | // note box {note title}xxx{endnote} |
||
2557 | $search = "#{(note) ([^\"<\n]+?)?}(.*?){endnote}#si"; |
||
2558 | $replace = array($this, 'renderBox'); |
||
2559 | $body = preg_replace_callback($search, $replace, $body); |
||
2560 | |||
2561 | // tip box {tip title}xxx{endtip} |
||
2562 | $search = "#{(tip) ([^\"<\n]+?)?}(.*?){endtip}#si"; |
||
2563 | $replace = array($this, 'renderBox'); |
||
2564 | $body = preg_replace_callback($search, $replace, $body); |
||
2565 | |||
2566 | // warning box {warning title}xxx{endwarning} |
||
2567 | $search = "#{(warn)ing ([^\"<\n]+?)?}(.*?){endwarning}#si"; |
||
2568 | $replace = array($this, 'renderBox'); |
||
2569 | $body = preg_replace_callback($search, $replace, $body); |
||
2570 | |||
2571 | // code (preformatted) box {code title}xxx{endcode} |
||
2572 | $search = "#{(code) ([^\"<\n]+?)?}(.*?){endcode}#si"; |
||
2573 | $replace = array($this, 'renderBox'); |
||
2574 | $body = preg_replace_callback($search, $replace, $body); |
||
2575 | |||
2576 | // folded box {folded title}xxx{endfolded} |
||
2577 | $search = "#{(folded) ([^\"<\n]+?)?}(.*?){endfolded}#si"; |
||
2578 | $replace = array($this, 'renderBox'); |
||
2579 | $body = preg_replace_callback($search, $replace, $body); |
||
2580 | |||
2581 | // urls - smells like a link |
||
2582 | $search = "#(?<=\s)((http|https|ftp|ftps)://.{2,}\..*)(?=[,.?!:;]{0,1}\s)#Ui"; |
||
2583 | $replace = array($this, 'renderLink'); |
||
2584 | $body = preg_replace_callback($search, $replace, $body); |
||
2585 | |||
2586 | // link [[link|linktext]] |
||
2587 | $search = "#\[{2}(.*)\]{2}#Um"; |
||
2588 | $replace = array($this, 'renderLink'); |
||
2589 | $body = preg_replace_callback($search, $replace, $body); |
||
2590 | |||
2591 | // email [email protected] |
||
2592 | $search = "#(?<=\s)([A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4})(?=\s)#i"; |
||
2593 | $replace = '<a href="mailto:\\1">\\1</a>'; |
||
2594 | $body = preg_replace($search, $replace, $body); |
||
2595 | |||
2596 | // CamelCase wiki link "#^([A-Z][a-z\:]+){2,}\d*$#" |
||
2597 | // Could be between whitespace on either end or between > on start and/or < on end |
||
2598 | if ($this->useCamelCase) { |
||
2599 | $search = "#(?<=\s|>)" . _WIKI_CAMELCASE_REGEX . "(?=\s|</l|</t)#"; |
||
2600 | $replace = array($this, 'wikiCCLink'); |
||
2601 | $body = preg_replace_callback($search, $replace, $body); |
||
2602 | } |
||
2603 | |||
2604 | // =====headings up to 5 levels |
||
2605 | $search = "#(^\s{0,})(={1,5})([^=].*[^=])(={0,5})\s*$#Um"; |
||
2606 | $replace = array($this, 'renderHeader'); |
||
2607 | $body = preg_replace_callback($search, $replace, $body); |
||
2608 | |||
2609 | // blockquote > xxx |
||
2610 | $search = "#^(> .*\n)+#m"; |
||
2611 | $replace = array($this, 'renderBlockquote'); |
||
2612 | $body = preg_replace_callback($search, $replace, $body); |
||
2613 | |||
2614 | // preformated .xxx |
||
2615 | $search = "#^(\. .*\n)+#m"; |
||
2616 | $replace = array($this, 'renderPreformat'); |
||
2617 | $body = preg_replace_callback($search, $replace, $body); |
||
2618 | |||
2619 | // reference {ref id|first-ref}source{endref} |
||
2620 | $search = "#{ref( [^\"<\n]+?)?}(.*?){endref}#si"; |
||
2621 | $replace = array($this, 'renderRef'); |
||
2622 | $body = preg_replace_callback($search, $replace, $body); |
||
2623 | |||
2624 | // forced line break blog [[br]] or gwiki {break} styles, themed - by default clear all |
||
2625 | $search = '#({reflist})#i'; |
||
2626 | $replace = array($this, 'renderRefList'); |
||
2627 | $body = preg_replace_callback($search, $replace, $body); |
||
2628 | |||
2629 | // index or change list {pageindex prefix} |
||
2630 | $search = "#{(PageIndex|RecentChanges)([^\"<\n]+?)?}#si"; |
||
2631 | $replace = array($this, 'renderIndex'); |
||
2632 | $body = preg_replace_callback($search, $replace, $body); |
||
2633 | |||
2634 | // table of contents |
||
2635 | $search = "#\{toc\}#i"; |
||
2636 | $replace = array($this, 'renderToc'); |
||
2637 | $body = preg_replace_callback($search, $replace, $body); |
||
2638 | |||
2639 | // page set table of contents |
||
2640 | $search = "#\{pagesettoc\}#i"; |
||
2641 | $replace = array($this, 'renderPageSetTocWrapper'); |
||
2642 | $body = preg_replace_callback($search, $replace, $body); |
||
2643 | |||
2644 | // image gallery {gallery size} |
||
2645 | $search = "#{gallery([^\"<\n]+?)?}#si"; |
||
2646 | $replace = array($this, 'renderGallery'); |
||
2647 | $body = preg_replace_callback($search, $replace, $body); |
||
2648 | |||
2649 | // more anchor - indicates end of teaser/summary |
||
2650 | $search = "#\{more\}#i"; |
||
2651 | $replace = '<span id="more"></span>'; |
||
2652 | $body = preg_replace($search, $replace, $body); |
||
2653 | |||
2654 | // tables |
||
2655 | $search = "#^( *\|((.*)\|){1,}\s*\n)+#m"; |
||
2656 | $replace = array($this, 'renderTables'); |
||
2657 | $body = preg_replace_callback($search, $replace, $body); |
||
2658 | |||
2659 | // paragraph on 2 consecutive newlines |
||
2660 | $search = "#\n{2}#"; |
||
2661 | $replace = "\n<p>"; |
||
2662 | $body = preg_replace($search, $replace, $body); |
||
2663 | |||
2664 | // restore cached nowiki content, all styles |
||
2665 | // (if you need to use {PdNlNw:#} in your page, put it in a nowiki tag) |
||
2666 | $search = '#{PdNlNw:([0-9]{1,})}#'; |
||
2667 | $replace = array($this, 'noWikiEmit'); |
||
2668 | $body = preg_replace_callback($search, $replace, $body); |
||
2669 | |||
2670 | if ($this->refShown === false && $this->refIndex > 0) { |
||
2671 | $body .= $this->renderRefList(null); |
||
0 ignored issues
–
show
null is of type null , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
2672 | } |
||
2673 | $body = stripslashes($this->convertEntities($body)); |
||
2674 | |||
2675 | $this->renderedPage = $body; |
||
2676 | |||
2677 | return $this->renderedPage; |
||
2678 | } |
||
2679 | } |
||
2680 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: