Failed Conditions
Push — interwiki-remove-golucky ( 52fcdb...768be5 )
by Henry
15:30 queued 12:50
created

inc/parser/renderer.php (13 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Renderer output base class
4
 *
5
 * @author Harry Fuecks <[email protected]>
6
 * @author Andreas Gohr <[email protected]>
7
 */
8
9
use dokuwiki\Extension\Plugin;
10
use dokuwiki\Extension\SyntaxPlugin;
11
12
/**
13
 * Allowed chars in $language for code highlighting
14
 * @see GeSHi::set_language()
15
 */
16
define('PREG_PATTERN_VALID_LANGUAGE', '#[^a-zA-Z0-9\-_]#');
17
18
/**
19
 * An empty renderer, produces no output
20
 *
21
 * Inherits from dokuwiki\Plugin\DokuWiki_Plugin for giving additional functions to render plugins
22
 *
23
 * The renderer transforms the syntax instructions created by the parser and handler into the
24
 * desired output format. For each instruction a corresponding method defined in this class will
25
 * be called. That method needs to produce the desired output for the instruction and add it to the
26
 * $doc field. When all instructions are processed, the $doc field contents will be cached by
27
 * DokuWiki and sent to the user.
28
 */
29
abstract class Doku_Renderer extends Plugin {
30
    /** @var array Settings, control the behavior of the renderer */
31
    public $info = array(
32
        'cache' => true, // may the rendered result cached?
33
        'toc'   => true, // render the TOC?
34
    );
35
36
    /** @var array contains the smiley configuration, set in p_render() */
37
    public $smileys = array();
38
    /** @var array contains the entity configuration, set in p_render() */
39
    public $entities = array();
40
    /** @var array contains the acronym configuration, set in p_render() */
41
    public $acronyms = array();
42
    /** @var array contains the interwiki configuration, set in p_render() */
43
    public $interwiki = array();
44
45
    /** @var array the list of headers used to create unique link ids */
46
    protected $headers = array();
47
48
    /**
49
     * @var string the rendered document, this will be cached after the renderer ran through
50
     */
51
    public $doc = '';
52
53
    /**
54
     * clean out any per-use values
55
     *
56
     * This is called before each use of the renderer object and should be used to
57
     * completely reset the state of the renderer to be reused for a new document
58
     */
59
    public function reset(){
60
        $this->headers = array();
61
        $this->doc           = '';
62
        $this->info['cache'] = true;
63
        $this->info['toc']   = true;
64
    }
65
66
    /**
67
     * Allow the plugin to prevent DokuWiki from reusing an instance
68
     *
69
     * Since most renderer plugins fail to implement Doku_Renderer::reset() we default
70
     * to reinstantiating the renderer here
71
     *
72
     * @return bool   false if the plugin has to be instantiated
73
     */
74
    public function isSingleton() {
75
        return false;
76
    }
77
78
    /**
79
     * Returns the format produced by this renderer.
80
     *
81
     * Has to be overidden by sub classes
82
     *
83
     * @return string
84
     */
85
    abstract public function getFormat();
86
87
    /**
88
     * Disable caching of this renderer's output
89
     */
90
    public function nocache() {
91
        $this->info['cache'] = false;
92
    }
93
94
    /**
95
     * Disable TOC generation for this renderer's output
96
     *
97
     * This might not be used for certain sub renderer
98
     */
99
    public function notoc() {
100
        $this->info['toc'] = false;
101
    }
102
103
    /**
104
     * Handle plugin rendering
105
     *
106
     * Most likely this needs NOT to be overwritten by sub classes
107
     *
108
     * @param string $name  Plugin name
109
     * @param mixed  $data  custom data set by handler
110
     * @param string $state matched state if any
111
     * @param string $match raw matched syntax
112
     */
113
    public function plugin($name, $data, $state = '', $match = '') {
0 ignored issues
show
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
114
        /** @var SyntaxPlugin $plugin */
115
        $plugin = plugin_load('syntax', $name);
116
        if($plugin != null) {
117
            $plugin->render($this->getFormat(), $this, $data);
118
        }
119
    }
120
121
    /**
122
     * handle nested render instructions
123
     * this method (and nest_close method) should not be overloaded in actual renderer output classes
124
     *
125
     * @param array $instructions
126
     */
127
    public function nest($instructions) {
128
        foreach($instructions as $instruction) {
129
            // execute the callback against ourself
130
            if(method_exists($this, $instruction[0])) {
131
                call_user_func_array(array($this, $instruction[0]), $instruction[1] ? $instruction[1] : array());
132
            }
133
        }
134
    }
135
136
    /**
137
     * dummy closing instruction issued by Doku_Handler_Nest
138
     *
139
     * normally the syntax mode should override this instruction when instantiating Doku_Handler_Nest -
140
     * however plugins will not be able to - as their instructions require data.
141
     */
142
    public function nest_close() {
143
    }
144
145
    #region Syntax modes - sub classes will need to implement them to fill $doc
146
147
    /**
148
     * Initialize the document
149
     */
150
    public function document_start() {
151
    }
152
153
    /**
154
     * Finalize the document
155
     */
156
    public function document_end() {
157
    }
158
159
    /**
160
     * Render the Table of Contents
161
     *
162
     * @return string
163
     */
164
    public function render_TOC() {
165
        return '';
166
    }
167
168
    /**
169
     * Add an item to the TOC
170
     *
171
     * @param string $id       the hash link
172
     * @param string $text     the text to display
173
     * @param int    $level    the nesting level
174
     */
175
    public function toc_additem($id, $text, $level) {
176
    }
177
178
    /**
179
     * Render a heading
180
     *
181
     * @param string $text  the text to display
182
     * @param int    $level header level
183
     * @param int    $pos   byte position in the original source
184
     */
185
    public function header($text, $level, $pos) {
186
    }
187
188
    /**
189
     * Open a new section
190
     *
191
     * @param int $level section level (as determined by the previous header)
192
     */
193
    public function section_open($level) {
194
    }
195
196
    /**
197
     * Close the current section
198
     */
199
    public function section_close() {
200
    }
201
202
    /**
203
     * Render plain text data
204
     *
205
     * @param string $text
206
     */
207
    public function cdata($text) {
208
    }
209
210
    /**
211
     * Open a paragraph
212
     */
213
    public function p_open() {
214
    }
215
216
    /**
217
     * Close a paragraph
218
     */
219
    public function p_close() {
220
    }
221
222
    /**
223
     * Create a line break
224
     */
225
    public function linebreak() {
226
    }
227
228
    /**
229
     * Create a horizontal line
230
     */
231
    public function hr() {
232
    }
233
234
    /**
235
     * Start strong (bold) formatting
236
     */
237
    public function strong_open() {
238
    }
239
240
    /**
241
     * Stop strong (bold) formatting
242
     */
243
    public function strong_close() {
244
    }
245
246
    /**
247
     * Start emphasis (italics) formatting
248
     */
249
    public function emphasis_open() {
250
    }
251
252
    /**
253
     * Stop emphasis (italics) formatting
254
     */
255
    public function emphasis_close() {
256
    }
257
258
    /**
259
     * Start underline formatting
260
     */
261
    public function underline_open() {
262
    }
263
264
    /**
265
     * Stop underline formatting
266
     */
267
    public function underline_close() {
268
    }
269
270
    /**
271
     * Start monospace formatting
272
     */
273
    public function monospace_open() {
274
    }
275
276
    /**
277
     * Stop monospace formatting
278
     */
279
    public function monospace_close() {
280
    }
281
282
    /**
283
     * Start a subscript
284
     */
285
    public function subscript_open() {
286
    }
287
288
    /**
289
     * Stop a subscript
290
     */
291
    public function subscript_close() {
292
    }
293
294
    /**
295
     * Start a superscript
296
     */
297
    public function superscript_open() {
298
    }
299
300
    /**
301
     * Stop a superscript
302
     */
303
    public function superscript_close() {
304
    }
305
306
    /**
307
     * Start deleted (strike-through) formatting
308
     */
309
    public function deleted_open() {
310
    }
311
312
    /**
313
     * Stop deleted (strike-through) formatting
314
     */
315
    public function deleted_close() {
316
    }
317
318
    /**
319
     * Start a footnote
320
     */
321
    public function footnote_open() {
322
    }
323
324
    /**
325
     * Stop a footnote
326
     */
327
    public function footnote_close() {
328
    }
329
330
    /**
331
     * Open an unordered list
332
     */
333
    public function listu_open() {
334
    }
335
336
    /**
337
     * Close an unordered list
338
     */
339
    public function listu_close() {
340
    }
341
342
    /**
343
     * Open an ordered list
344
     */
345
    public function listo_open() {
346
    }
347
348
    /**
349
     * Close an ordered list
350
     */
351
    public function listo_close() {
352
    }
353
354
    /**
355
     * Open a list item
356
     *
357
     * @param int $level the nesting level
358
     * @param bool $node true when a node; false when a leaf
359
     */
360
    public function listitem_open($level,$node=false) {
361
    }
362
363
    /**
364
     * Close a list item
365
     */
366
    public function listitem_close() {
367
    }
368
369
    /**
370
     * Start the content of a list item
371
     */
372
    public function listcontent_open() {
373
    }
374
375
    /**
376
     * Stop the content of a list item
377
     */
378
    public function listcontent_close() {
379
    }
380
381
    /**
382
     * Output unformatted $text
383
     *
384
     * Defaults to $this->cdata()
385
     *
386
     * @param string $text
387
     */
388
    public function unformatted($text) {
389
        $this->cdata($text);
390
    }
391
392
    /**
393
     * Output inline PHP code
394
     *
395
     * If $conf['phpok'] is true this should evaluate the given code and append the result
396
     * to $doc
397
     *
398
     * @param string $text The PHP code
399
     */
400
    public function php($text) {
401
    }
402
403
    /**
404
     * Output block level PHP code
405
     *
406
     * If $conf['phpok'] is true this should evaluate the given code and append the result
407
     * to $doc
408
     *
409
     * @param string $text The PHP code
410
     */
411
    public function phpblock($text) {
412
    }
413
414
    /**
415
     * Output raw inline HTML
416
     *
417
     * If $conf['htmlok'] is true this should add the code as is to $doc
418
     *
419
     * @param string $text The HTML
420
     */
421
    public function html($text) {
422
    }
423
424
    /**
425
     * Output raw block-level HTML
426
     *
427
     * If $conf['htmlok'] is true this should add the code as is to $doc
428
     *
429
     * @param string $text The HTML
430
     */
431
    public function htmlblock($text) {
432
    }
433
434
    /**
435
     * Output preformatted text
436
     *
437
     * @param string $text
438
     */
439
    public function preformatted($text) {
440
    }
441
442
    /**
443
     * Start a block quote
444
     */
445
    public function quote_open() {
446
    }
447
448
    /**
449
     * Stop a block quote
450
     */
451
    public function quote_close() {
452
    }
453
454
    /**
455
     * Display text as file content, optionally syntax highlighted
456
     *
457
     * @param string $text text to show
458
     * @param string $lang programming language to use for syntax highlighting
459
     * @param string $file file path label
460
     */
461
    public function file($text, $lang = null, $file = null) {
462
    }
463
464
    /**
465
     * Display text as code content, optionally syntax highlighted
466
     *
467
     * @param string $text text to show
468
     * @param string $lang programming language to use for syntax highlighting
469
     * @param string $file file path label
470
     */
471
    public function code($text, $lang = null, $file = null) {
472
    }
473
474
    /**
475
     * Format an acronym
476
     *
477
     * Uses $this->acronyms
478
     *
479
     * @param string $acronym
480
     */
481
    public function acronym($acronym) {
482
    }
483
484
    /**
485
     * Format a smiley
486
     *
487
     * Uses $this->smiley
488
     *
489
     * @param string $smiley
490
     */
491
    public function smiley($smiley) {
492
    }
493
494
    /**
495
     * Format an entity
496
     *
497
     * Entities are basically small text replacements
498
     *
499
     * Uses $this->entities
500
     *
501
     * @param string $entity
502
     */
503
    public function entity($entity) {
504
    }
505
506
    /**
507
     * Typographically format a multiply sign
508
     *
509
     * Example: ($x=640, $y=480) should result in "640×480"
510
     *
511
     * @param string|int $x first value
512
     * @param string|int $y second value
513
     */
514
    public function multiplyentity($x, $y) {
515
    }
516
517
    /**
518
     * Render an opening single quote char (language specific)
519
     */
520
    public function singlequoteopening() {
521
    }
522
523
    /**
524
     * Render a closing single quote char (language specific)
525
     */
526
    public function singlequoteclosing() {
527
    }
528
529
    /**
530
     * Render an apostrophe char (language specific)
531
     */
532
    public function apostrophe() {
533
    }
534
535
    /**
536
     * Render an opening double quote char (language specific)
537
     */
538
    public function doublequoteopening() {
539
    }
540
541
    /**
542
     * Render an closinging double quote char (language specific)
543
     */
544
    public function doublequoteclosing() {
545
    }
546
547
    /**
548
     * Render a CamelCase link
549
     *
550
     * @param string $link The link name
551
     * @see http://en.wikipedia.org/wiki/CamelCase
552
     */
553
    public function camelcaselink($link) {
554
    }
555
556
    /**
557
     * Render a page local link
558
     *
559
     * @param string $hash hash link identifier
560
     * @param string $name name for the link
561
     */
562
    public function locallink($hash, $name = null) {
563
    }
564
565
    /**
566
     * Render a wiki internal link
567
     *
568
     * @param string       $link  page ID to link to. eg. 'wiki:syntax'
569
     * @param string|array $title name for the link, array for media file
570
     */
571
    public function internallink($link, $title = null) {
572
    }
573
574
    /**
575
     * Render an external link
576
     *
577
     * @param string       $link  full URL with scheme
578
     * @param string|array $title name for the link, array for media file
579
     */
580
    public function externallink($link, $title = null) {
581
    }
582
583
    /**
584
     * Render the output of an RSS feed
585
     *
586
     * @param string $url    URL of the feed
587
     * @param array  $params Finetuning of the output
588
     */
589
    public function rss($url, $params) {
590
    }
591
592
    /**
593
     * Render an interwiki link
594
     *
595
     * You may want to use $this->_resolveInterWiki() here
596
     *
597
     * @param string       $link     original link - probably not much use
598
     * @param string|array $title    name for the link, array for media file
599
     * @param string       $wikiName indentifier (shortcut) for the remote wiki
600
     * @param string       $wikiUri  the fragment parsed from the original link
601
     */
602
    public function interwikilink($link, $title, $wikiName, $wikiUri) {
0 ignored issues
show
The parameter $link is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
603
    }
604
605
    /**
606
     * Link to file on users OS
607
     *
608
     * @param string       $link  the link
609
     * @param string|array $title name for the link, array for media file
610
     */
611
    public function filelink($link, $title = null) {
0 ignored issues
show
The parameter $link is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $title is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
612
    }
613
614
    /**
615
     * Link to windows share
616
     *
617
     * @param string       $link  the link
618
     * @param string|array $title name for the link, array for media file
619
     */
620
    public function windowssharelink($link, $title = null) {
621
    }
622
623
    /**
624
     * Render a linked E-Mail Address
625
     *
626
     * Should honor $conf['mailguard'] setting
627
     *
628
     * @param string $address Email-Address
629
     * @param string|array $name name for the link, array for media file
630
     */
631
    public function emaillink($address, $name = null) {
632
    }
633
634
    /**
635
     * Render an internal media file
636
     *
637
     * @param string $src     media ID
638
     * @param string $title   descriptive text
639
     * @param string $align   left|center|right
640
     * @param int    $width   width of media in pixel
641
     * @param int    $height  height of media in pixel
642
     * @param string $cache   cache|recache|nocache
643
     * @param string $linking linkonly|detail|nolink
644
     */
645
    public function internalmedia($src, $title = null, $align = null, $width = null,
646
                           $height = null, $cache = null, $linking = null) {
647
    }
648
649
    /**
650
     * Render an external media file
651
     *
652
     * @param string $src     full media URL
653
     * @param string $title   descriptive text
654
     * @param string $align   left|center|right
655
     * @param int    $width   width of media in pixel
656
     * @param int    $height  height of media in pixel
657
     * @param string $cache   cache|recache|nocache
658
     * @param string $linking linkonly|detail|nolink
659
     */
660
    public function externalmedia($src, $title = null, $align = null, $width = null,
661
                           $height = null, $cache = null, $linking = null) {
662
    }
663
664
    /**
665
     * Render a link to an internal media file
666
     *
667
     * @param string $src     media ID
668
     * @param string $title   descriptive text
669
     * @param string $align   left|center|right
670
     * @param int    $width   width of media in pixel
671
     * @param int    $height  height of media in pixel
672
     * @param string $cache   cache|recache|nocache
673
     */
674
    public function internalmedialink($src, $title = null, $align = null,
0 ignored issues
show
The parameter $src is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $title is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $align is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
675
                               $width = null, $height = null, $cache = null) {
676
    }
677
678
    /**
679
     * Render a link to an external media file
680
     *
681
     * @param string $src     media ID
682
     * @param string $title   descriptive text
683
     * @param string $align   left|center|right
684
     * @param int    $width   width of media in pixel
685
     * @param int    $height  height of media in pixel
686
     * @param string $cache   cache|recache|nocache
687
     */
688
    public function externalmedialink($src, $title = null, $align = null,
0 ignored issues
show
The parameter $src is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $title is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $align is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
689
                               $width = null, $height = null, $cache = null) {
690
    }
691
692
    /**
693
     * Start a table
694
     *
695
     * @param int $maxcols maximum number of columns
696
     * @param int $numrows NOT IMPLEMENTED
697
     * @param int $pos     byte position in the original source
698
     */
699
    public function table_open($maxcols = null, $numrows = null, $pos = null) {
0 ignored issues
show
The parameter $maxcols is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $numrows is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
700
    }
701
702
    /**
703
     * Close a table
704
     *
705
     * @param int $pos byte position in the original source
706
     */
707
    public function table_close($pos = null) {
708
    }
709
710
    /**
711
     * Open a table header
712
     */
713
    public function tablethead_open() {
714
    }
715
716
    /**
717
     * Close a table header
718
     */
719
    public function tablethead_close() {
720
    }
721
722
    /**
723
     * Open a table body
724
     */
725
    public function tabletbody_open() {
726
    }
727
728
    /**
729
     * Close a table body
730
     */
731
    public function tabletbody_close() {
732
    }
733
734
    /**
735
     * Open a table footer
736
     */
737
    public function tabletfoot_open() {
738
    }
739
740
    /**
741
     * Close a table footer
742
     */
743
    public function tabletfoot_close() {
744
    }
745
746
    /**
747
     * Open a table row
748
     */
749
    public function tablerow_open() {
750
    }
751
752
    /**
753
     * Close a table row
754
     */
755
    public function tablerow_close() {
756
    }
757
758
    /**
759
     * Open a table header cell
760
     *
761
     * @param int    $colspan
762
     * @param string $align left|center|right
763
     * @param int    $rowspan
764
     */
765
    public function tableheader_open($colspan = 1, $align = null, $rowspan = 1) {
766
    }
767
768
    /**
769
     * Close a table header cell
770
     */
771
    public function tableheader_close() {
772
    }
773
774
    /**
775
     * Open a table cell
776
     *
777
     * @param int    $colspan
778
     * @param string $align left|center|right
779
     * @param int    $rowspan
780
     */
781
    public function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
782
    }
783
784
    /**
785
     * Close a table cell
786
     */
787
    public function tablecell_close() {
788
    }
789
790
    #endregion
791
792
    #region util functions, you probably won't need to reimplement them
793
794
    /**
795
     * Creates a linkid from a headline
796
     *
797
     * @author Andreas Gohr <[email protected]>
798
     * @param string  $title   The headline title
799
     * @param boolean $create  Create a new unique ID?
800
     * @return string
801
     */
802
    public function _headerToLink($title, $create = false) {
803
        if($create) {
804
            return sectionID($title, $this->headers);
805
        } else {
806
            $check = false;
807
            return sectionID($title, $check);
808
        }
809
    }
810
811
    /**
812
     * Removes any Namespace from the given name but keeps
813
     * casing and special chars
814
     *
815
     * @author Andreas Gohr <[email protected]>
816
     *
817
     * @param string $name
818
     * @return string
819
     */
820
    protected function _simpleTitle($name) {
821
        global $conf;
822
823
        //if there is a hash we use the ancor name only
824
        @list($name, $hash) = explode('#', $name, 2);
825
        if($hash) return $hash;
826
827
        if($conf['useslash']) {
828
            $name = strtr($name, ';/', ';:');
829
        } else {
830
            $name = strtr($name, ';', ':');
831
        }
832
833
        return noNSorNS($name);
834
    }
835
836
    /**
837
     * Resolve an interwikilink
838
     *
839
     * @param string    $shortcut  identifier for the interwiki link
840
     * @param string    $reference fragment that refers the content
841
     * @param null|bool $exists    reference which returns if an internal page exists
842
     * @return string interwikilink
843
     */
844
    public function _resolveInterWiki(&$shortcut, $reference, &$exists = null) {
845
        //get interwiki URL
846
        if(isset($this->interwiki[$shortcut])) {
847
            $url = $this->interwiki[$shortcut];
848
        }elseif(isset($this->interwiki['default'])) {
849
            $shortcut = 'default';
850
            $url = $this->interwiki[$shortcut];
851
        }else{
852
            // not parsable interwiki outputs '' to make sure string manipluation works
853
            $shortcut = '';
854
            $url      = '';
855
        }
856
857
        //split into hash and url part
858
        $hash = strrchr($reference, '#');
859
        if($hash) {
860
            $reference = substr($reference, 0, -strlen($hash));
861
            $hash = substr($hash, 1);
862
        }
863
864
        //replace placeholder
865
        if(preg_match('#\{(URL|NAME|SCHEME|HOST|PORT|PATH|QUERY)\}#', $url)) {
866
            //use placeholders
867
            $url    = str_replace('{URL}', rawurlencode($reference), $url);
868
            //wiki names will be cleaned next, otherwise urlencode unsafe chars
869
            $url    = str_replace('{NAME}', ($url{0} === ':') ? $reference :
870
                                  preg_replace_callback('/[[\\\\\]^`{|}#%]/', function($match) {
871
                                    return rawurlencode($match[0]);
872
                                  }, $reference), $url);
873
            $parsed = parse_url($reference);
874
            if (empty($parsed['scheme'])) $parsed['scheme'] = '';
875
            if (empty($parsed['host'])) $parsed['host'] = '';
876
            if (empty($parsed['port'])) $parsed['port'] = 80;
877
            if (empty($parsed['path'])) $parsed['path'] = '';
878
            if (empty($parsed['query'])) $parsed['query'] = '';
879
            $url = strtr($url,[
880
                '{SCHEME}' => $parsed['scheme'],
881
                '{HOST}' => $parsed['host'],
882
                '{PORT}' => $parsed['port'],
883
                '{PATH}' => $parsed['path'],
884
                '{QUERY}' => $parsed['query'] ,
885
            ]);
886
        } else if($url != '') {
887
            // make sure when no url is defined, we keep it null
888
            // default
889
            $url = $url.rawurlencode($reference);
890
        }
891
        //handle as wiki links
892
        if($url{0} === ':') {
893
            $urlparam = null;
894
            $id = $url;
895
            if (strpos($url, '?') !== false) {
896
                list($id, $urlparam) = explode('?', $url, 2);
897
            }
898
            $url    = wl(cleanID($id), $urlparam);
899
            $exists = page_exists($id);
900
        }
901
        if($hash) $url .= '#'.rawurlencode($hash);
902
903
        return $url;
904
    }
905
906
    #endregion
907
}
908
909
910
//Setup VIM: ex: et ts=4 :
911