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