Completed
Push — master ( 680cee...345058 )
by Andreas
04:06
created

Doku_Renderer_xhtml::underline_close()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Renderer for XHTML output
4
 *
5
 * @author Harry Fuecks <[email protected]>
6
 * @author Andreas Gohr <[email protected]>
7
 */
8
if(!defined('DOKU_INC')) die('meh.');
9
10
if(!defined('DOKU_LF')) {
11
    // Some whitespace to help View > Source
12
    define ('DOKU_LF', "\n");
13
}
14
15
if(!defined('DOKU_TAB')) {
16
    // Some whitespace to help View > Source
17
    define ('DOKU_TAB', "\t");
18
}
19
20
/**
21
 * The XHTML Renderer
22
 *
23
 * This is DokuWiki's main renderer used to display page content in the wiki
24
 */
25
class Doku_Renderer_xhtml extends Doku_Renderer {
26
    /** @var array store the table of contents */
27
    public $toc = array();
28
29
    /** @var array A stack of section edit data */
30
    protected $sectionedits = array();
31
    var $date_at = '';    // link pages and media against this revision
32
33
    /** @var int last section edit id, used by startSectionEdit */
34
    protected $lastsecid = 0;
35
36
    /** @var array the list of headers used to create unique link ids */
37
    protected $headers = array();
38
39
    /** @var array a list of footnotes, list starts at 1! */
40
    protected $footnotes = array();
41
42
    /** @var int current section level */
43
    protected $lastlevel = 0;
44
    /** @var array section node tracker */
45
    protected $node = array(0, 0, 0, 0, 0);
46
47
    /** @var string temporary $doc store */
48
    protected $store = '';
49
50
    /** @var array global counter, for table classes etc. */
51
    protected $_counter = array(); //
52
53
    /** @var int counts the code and file blocks, used to provide download links */
54
    protected $_codeblock = 0;
55
56
    /** @var array list of allowed URL schemes */
57
    protected $schemes = null;
58
59
    /**
60
     * Register a new edit section range
61
     *
62
     * @param string $type   The section type identifier
63
     * @param string $title  The section title
64
     * @param int    $start  The byte position for the edit start
65
     * @return string  A marker class for the starting HTML element
66
     *
67
     * @author Adrian Lang <[email protected]>
68
     */
69
    public function startSectionEdit($start, $type, $title = null, $hid = null) {
70
        $this->sectionedits[] = array(++$this->lastsecid, $start, $type, $title, $hid);
71
        return 'sectionedit'.$this->lastsecid;
72
    }
73
74
    /**
75
     * Finish an edit section range
76
     *
77
     * @param int  $end     The byte position for the edit end; null for the rest of the page
78
     *
79
     * @author Adrian Lang <[email protected]>
80
     */
81
    public function finishSectionEdit($end = null, $hid = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $hid 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...
82
        list($id, $start, $type, $title, $hid) = array_pop($this->sectionedits);
83
        if(!is_null($end) && $end <= $start) {
84
            return;
85
        }
86
        $this->doc .= "<!-- EDIT$id ".strtoupper($type).' ';
87
        if(!is_null($title)) {
88
            $this->doc .= '"'.str_replace('"', '', $title).'" ';
89
        }
90
        if(!is_null($hid)) {
91
            $this->doc .= '"'.$hid.'" ';
92
        }
93
        $this->doc .= "[$start-".(is_null($end) ? '' : $end).'] -->';
94
    }
95
96
    /**
97
     * Returns the format produced by this renderer.
98
     *
99
     * @return string always 'xhtml'
100
     */
101
    function getFormat() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
102
        return 'xhtml';
103
    }
104
105
    /**
106
     * Initialize the document
107
     */
108
    function document_start() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
109
        //reset some internals
110
        $this->toc     = array();
111
        $this->headers = array();
112
    }
113
114
    /**
115
     * Finalize the document
116
     */
117
    function document_end() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
118
        // Finish open section edits.
119
        while(count($this->sectionedits) > 0) {
120
            if($this->sectionedits[count($this->sectionedits) - 1][1] <= 1) {
121
                // If there is only one section, do not write a section edit
122
                // marker.
123
                array_pop($this->sectionedits);
124
            } else {
125
                $this->finishSectionEdit();
126
            }
127
        }
128
129
        if(count($this->footnotes) > 0) {
130
            $this->doc .= '<div class="footnotes">'.DOKU_LF;
131
132
            foreach($this->footnotes as $id => $footnote) {
133
                // check its not a placeholder that indicates actual footnote text is elsewhere
134
                if(substr($footnote, 0, 5) != "@@FNT") {
135
136
                    // open the footnote and set the anchor and backlink
137
                    $this->doc .= '<div class="fn">';
138
                    $this->doc .= '<sup><a href="#fnt__'.$id.'" id="fn__'.$id.'" class="fn_bot">';
139
                    $this->doc .= $id.')</a></sup> '.DOKU_LF;
140
141
                    // get any other footnotes that use the same markup
142
                    $alt = array_keys($this->footnotes, "@@FNT$id");
143
144
                    if(count($alt)) {
145
                        foreach($alt as $ref) {
146
                            // set anchor and backlink for the other footnotes
147
                            $this->doc .= ', <sup><a href="#fnt__'.($ref).'" id="fn__'.($ref).'" class="fn_bot">';
148
                            $this->doc .= ($ref).')</a></sup> '.DOKU_LF;
149
                        }
150
                    }
151
152
                    // add footnote markup and close this footnote
153
                    $this->doc .= '<div class="content">'.$footnote.'</div>';
154
                    $this->doc .= '</div>'.DOKU_LF;
155
                }
156
            }
157
            $this->doc .= '</div>'.DOKU_LF;
158
        }
159
160
        // Prepare the TOC
161
        global $conf;
162
        if($this->info['toc'] && is_array($this->toc) && $conf['tocminheads'] && count($this->toc) >= $conf['tocminheads']) {
163
            global $TOC;
164
            $TOC = $this->toc;
165
        }
166
167
        // make sure there are no empty paragraphs
168
        $this->doc = preg_replace('#<p>\s*</p>#', '', $this->doc);
169
    }
170
171
    /**
172
     * Add an item to the TOC
173
     *
174
     * @param string $id       the hash link
175
     * @param string $text     the text to display
176
     * @param int    $level    the nesting level
177
     */
178
    function toc_additem($id, $text, $level) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
179
        global $conf;
180
181
        //handle TOC
182
        if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) {
183
            $this->toc[] = html_mktocitem($id, $text, $level - $conf['toptoclevel'] + 1);
184
        }
185
    }
186
187
    /**
188
     * Render a heading
189
     *
190
     * @param string $text  the text to display
191
     * @param int    $level header level
192
     * @param int    $pos   byte position in the original source
193
     */
194
    function header($text, $level, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
195
        global $conf;
196
197
        if(blank($text)) return; //skip empty headlines
198
199
        $hid = $this->_headerToLink($text, true);
200
201
        //only add items within configured levels
202
        $this->toc_additem($hid, $text, $level);
203
204
        // adjust $node to reflect hierarchy of levels
205
        $this->node[$level - 1]++;
206
        if($level < $this->lastlevel) {
207
            for($i = 0; $i < $this->lastlevel - $level; $i++) {
208
                $this->node[$this->lastlevel - $i - 1] = 0;
209
            }
210
        }
211
        $this->lastlevel = $level;
212
213
        if($level <= $conf['maxseclevel'] &&
214
            count($this->sectionedits) > 0 &&
215
            $this->sectionedits[count($this->sectionedits) - 1][2] === 'section'
216
        ) {
217
            $this->finishSectionEdit($pos - 1);
218
        }
219
220
        // write the header
221
        $this->doc .= DOKU_LF.'<h'.$level;
222
        if($level <= $conf['maxseclevel']) {
223
            $this->doc .= ' class="'.$this->startSectionEdit($pos, 'section', $text, $hid).'"';
224
        }
225
        $this->doc .= ' id="'.$hid.'">';
226
        $this->doc .= $this->_xmlEntities($text);
227
        $this->doc .= "</h$level>".DOKU_LF;
228
    }
229
230
    /**
231
     * Open a new section
232
     *
233
     * @param int $level section level (as determined by the previous header)
234
     */
235
    function section_open($level) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
236
        $this->doc .= '<div class="level'.$level.'">'.DOKU_LF;
237
    }
238
239
    /**
240
     * Close the current section
241
     */
242
    function section_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
243
        $this->doc .= DOKU_LF.'</div>'.DOKU_LF;
244
    }
245
246
    /**
247
     * Render plain text data
248
     *
249
     * @param $text
250
     */
251
    function cdata($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
252
        $this->doc .= $this->_xmlEntities($text);
253
    }
254
255
    /**
256
     * Open a paragraph
257
     */
258
    function p_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
259
        $this->doc .= DOKU_LF.'<p>'.DOKU_LF;
260
    }
261
262
    /**
263
     * Close a paragraph
264
     */
265
    function p_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
266
        $this->doc .= DOKU_LF.'</p>'.DOKU_LF;
267
    }
268
269
    /**
270
     * Create a line break
271
     */
272
    function linebreak() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
273
        $this->doc .= '<br/>'.DOKU_LF;
274
    }
275
276
    /**
277
     * Create a horizontal line
278
     */
279
    function hr() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
280
        $this->doc .= '<hr />'.DOKU_LF;
281
    }
282
283
    /**
284
     * Start strong (bold) formatting
285
     */
286
    function strong_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
287
        $this->doc .= '<strong>';
288
    }
289
290
    /**
291
     * Stop strong (bold) formatting
292
     */
293
    function strong_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
294
        $this->doc .= '</strong>';
295
    }
296
297
    /**
298
     * Start emphasis (italics) formatting
299
     */
300
    function emphasis_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
301
        $this->doc .= '<em>';
302
    }
303
304
    /**
305
     * Stop emphasis (italics) formatting
306
     */
307
    function emphasis_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
308
        $this->doc .= '</em>';
309
    }
310
311
    /**
312
     * Start underline formatting
313
     */
314
    function underline_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
315
        $this->doc .= '<em class="u">';
316
    }
317
318
    /**
319
     * Stop underline formatting
320
     */
321
    function underline_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
322
        $this->doc .= '</em>';
323
    }
324
325
    /**
326
     * Start monospace formatting
327
     */
328
    function monospace_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
329
        $this->doc .= '<code>';
330
    }
331
332
    /**
333
     * Stop monospace formatting
334
     */
335
    function monospace_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
336
        $this->doc .= '</code>';
337
    }
338
339
    /**
340
     * Start a subscript
341
     */
342
    function subscript_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
343
        $this->doc .= '<sub>';
344
    }
345
346
    /**
347
     * Stop a subscript
348
     */
349
    function subscript_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
350
        $this->doc .= '</sub>';
351
    }
352
353
    /**
354
     * Start a superscript
355
     */
356
    function superscript_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
357
        $this->doc .= '<sup>';
358
    }
359
360
    /**
361
     * Stop a superscript
362
     */
363
    function superscript_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
364
        $this->doc .= '</sup>';
365
    }
366
367
    /**
368
     * Start deleted (strike-through) formatting
369
     */
370
    function deleted_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
371
        $this->doc .= '<del>';
372
    }
373
374
    /**
375
     * Stop deleted (strike-through) formatting
376
     */
377
    function deleted_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
378
        $this->doc .= '</del>';
379
    }
380
381
    /**
382
     * Callback for footnote start syntax
383
     *
384
     * All following content will go to the footnote instead of
385
     * the document. To achieve this the previous rendered content
386
     * is moved to $store and $doc is cleared
387
     *
388
     * @author Andreas Gohr <[email protected]>
389
     */
390
    function footnote_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
391
392
        // move current content to store and record footnote
393
        $this->store = $this->doc;
394
        $this->doc   = '';
395
    }
396
397
    /**
398
     * Callback for footnote end syntax
399
     *
400
     * All rendered content is moved to the $footnotes array and the old
401
     * content is restored from $store again
402
     *
403
     * @author Andreas Gohr
404
     */
405
    function footnote_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
406
        /** @var $fnid int takes track of seen footnotes, assures they are unique even across multiple docs FS#2841 */
407
        static $fnid = 0;
408
        // assign new footnote id (we start at 1)
409
        $fnid++;
410
411
        // recover footnote into the stack and restore old content
412
        $footnote    = $this->doc;
413
        $this->doc   = $this->store;
414
        $this->store = '';
415
416
        // check to see if this footnote has been seen before
417
        $i = array_search($footnote, $this->footnotes);
418
419
        if($i === false) {
420
            // its a new footnote, add it to the $footnotes array
421
            $this->footnotes[$fnid] = $footnote;
422
        } else {
423
            // seen this one before, save a placeholder
424
            $this->footnotes[$fnid] = "@@FNT".($i);
425
        }
426
427
        // output the footnote reference and link
428
        $this->doc .= '<sup><a href="#fn__'.$fnid.'" id="fnt__'.$fnid.'" class="fn_top">'.$fnid.')</a></sup>';
429
    }
430
431
    /**
432
     * Open an unordered list
433
     *
434
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
435
     */
436
    function listu_open($classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
437
        $class = '';
438
        if($classes !== null) {
439
            if(is_array($classes)) $classes = join(' ', $classes);
440
            $class = " class=\"$classes\"";
441
        }
442
        $this->doc .= "<ul$class>".DOKU_LF;
443
    }
444
445
    /**
446
     * Close an unordered list
447
     */
448
    function listu_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
449
        $this->doc .= '</ul>'.DOKU_LF;
450
    }
451
452
    /**
453
     * Open an ordered list
454
     *
455
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
456
     */
457
    function listo_open($classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
458
        $class = '';
459
        if($classes !== null) {
460
            if(is_array($classes)) $classes = join(' ', $classes);
461
            $class = " class=\"$classes\"";
462
        }
463
        $this->doc .= "<ol$class>".DOKU_LF;
464
    }
465
466
    /**
467
     * Close an ordered list
468
     */
469
    function listo_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
470
        $this->doc .= '</ol>'.DOKU_LF;
471
    }
472
473
    /**
474
     * Open a list item
475
     *
476
     * @param int $level the nesting level
477
     * @param bool $node true when a node; false when a leaf
478
     */
479
    function listitem_open($level, $node=false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
480
        $branching = $node ? ' node' : '';
481
        $this->doc .= '<li class="level'.$level.$branching.'">';
482
    }
483
484
    /**
485
     * Close a list item
486
     */
487
    function listitem_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
488
        $this->doc .= '</li>'.DOKU_LF;
489
    }
490
491
    /**
492
     * Start the content of a list item
493
     */
494
    function listcontent_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
495
        $this->doc .= '<div class="li">';
496
    }
497
498
    /**
499
     * Stop the content of a list item
500
     */
501
    function listcontent_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
502
        $this->doc .= '</div>'.DOKU_LF;
503
    }
504
505
    /**
506
     * Output unformatted $text
507
     *
508
     * Defaults to $this->cdata()
509
     *
510
     * @param string $text
511
     */
512
    function unformatted($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
513
        $this->doc .= $this->_xmlEntities($text);
514
    }
515
516
    /**
517
     * Execute PHP code if allowed
518
     *
519
     * @param  string $text      PHP code that is either executed or printed
520
     * @param  string $wrapper   html element to wrap result if $conf['phpok'] is okff
521
     *
522
     * @author Andreas Gohr <[email protected]>
523
     */
524
    function php($text, $wrapper = 'code') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
525
        global $conf;
526
527
        if($conf['phpok']) {
528
            ob_start();
529
            eval($text);
530
            $this->doc .= ob_get_contents();
531
            ob_end_clean();
532
        } else {
533
            $this->doc .= p_xhtml_cached_geshi($text, 'php', $wrapper);
534
        }
535
    }
536
537
    /**
538
     * Output block level PHP code
539
     *
540
     * If $conf['phpok'] is true this should evaluate the given code and append the result
541
     * to $doc
542
     *
543
     * @param string $text The PHP code
544
     */
545
    function phpblock($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
546
        $this->php($text, 'pre');
547
    }
548
549
    /**
550
     * Insert HTML if allowed
551
     *
552
     * @param  string $text      html text
553
     * @param  string $wrapper   html element to wrap result if $conf['htmlok'] is okff
554
     *
555
     * @author Andreas Gohr <[email protected]>
556
     */
557
    function html($text, $wrapper = 'code') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
558
        global $conf;
559
560
        if($conf['htmlok']) {
561
            $this->doc .= $text;
562
        } else {
563
            $this->doc .= p_xhtml_cached_geshi($text, 'html4strict', $wrapper);
564
        }
565
    }
566
567
    /**
568
     * Output raw block-level HTML
569
     *
570
     * If $conf['htmlok'] is true this should add the code as is to $doc
571
     *
572
     * @param string $text The HTML
573
     */
574
    function htmlblock($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
575
        $this->html($text, 'pre');
576
    }
577
578
    /**
579
     * Start a block quote
580
     */
581
    function quote_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
582
        $this->doc .= '<blockquote><div class="no">'.DOKU_LF;
583
    }
584
585
    /**
586
     * Stop a block quote
587
     */
588
    function quote_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
589
        $this->doc .= '</div></blockquote>'.DOKU_LF;
590
    }
591
592
    /**
593
     * Output preformatted text
594
     *
595
     * @param string $text
596
     */
597
    function preformatted($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
598
        $this->doc .= '<pre class="code">'.trim($this->_xmlEntities($text), "\n\r").'</pre>'.DOKU_LF;
599
    }
600
601
    /**
602
     * Display text as file content, optionally syntax highlighted
603
     *
604
     * @param string $text     text to show
605
     * @param string $language programming language to use for syntax highlighting
606
     * @param string $filename file path label
607
     */
608
    function file($text, $language = null, $filename = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
609
        $this->_highlight('file', $text, $language, $filename);
610
    }
611
612
    /**
613
     * Display text as code content, optionally syntax highlighted
614
     *
615
     * @param string $text     text to show
616
     * @param string $language programming language to use for syntax highlighting
617
     * @param string $filename file path label
618
     */
619
    function code($text, $language = null, $filename = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
620
        $this->_highlight('code', $text, $language, $filename);
621
    }
622
623
    /**
624
     * Use GeSHi to highlight language syntax in code and file blocks
625
     *
626
     * @author Andreas Gohr <[email protected]>
627
     * @param string $type     code|file
628
     * @param string $text     text to show
629
     * @param string $language programming language to use for syntax highlighting
630
     * @param string $filename file path label
631
     */
632
    function _highlight($type, $text, $language = null, $filename = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
633
        global $ID;
634
        global $lang;
635
636
        $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language);
637
638
        if($filename) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filename of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
639
            // add icon
640
            list($ext) = mimetype($filename, false);
641
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
642
            $class = 'mediafile mf_'.$class;
643
644
            $this->doc .= '<dl class="'.$type.'">'.DOKU_LF;
645
            $this->doc .= '<dt><a href="'.exportlink($ID, 'code', array('codeblock' => $this->_codeblock)).'" title="'.$lang['download'].'" class="'.$class.'">';
646
            $this->doc .= hsc($filename);
647
            $this->doc .= '</a></dt>'.DOKU_LF.'<dd>';
648
        }
649
650
        if($text{0} == "\n") {
651
            $text = substr($text, 1);
652
        }
653
        if(substr($text, -1) == "\n") {
654
            $text = substr($text, 0, -1);
655
        }
656
657
        if(empty($language)) { // empty is faster than is_null and can prevent '' string
658
            $this->doc .= '<pre class="'.$type.'">'.$this->_xmlEntities($text).'</pre>'.DOKU_LF;
659
        } else {
660
            $class = 'code'; //we always need the code class to make the syntax highlighting apply
661
            if($type != 'code') $class .= ' '.$type;
662
663
            $this->doc .= "<pre class=\"$class $language\">".p_xhtml_cached_geshi($text, $language, '').'</pre>'.DOKU_LF;
664
        }
665
666
        if($filename) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filename of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
667
            $this->doc .= '</dd></dl>'.DOKU_LF;
668
        }
669
670
        $this->_codeblock++;
671
    }
672
673
    /**
674
     * Format an acronym
675
     *
676
     * Uses $this->acronyms
677
     *
678
     * @param string $acronym
679
     */
680
    function acronym($acronym) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
681
682
        if(array_key_exists($acronym, $this->acronyms)) {
683
684
            $title = $this->_xmlEntities($this->acronyms[$acronym]);
685
686
            $this->doc .= '<abbr title="'.$title
687
                .'">'.$this->_xmlEntities($acronym).'</abbr>';
688
689
        } else {
690
            $this->doc .= $this->_xmlEntities($acronym);
691
        }
692
    }
693
694
    /**
695
     * Format a smiley
696
     *
697
     * Uses $this->smiley
698
     *
699
     * @param string $smiley
700
     */
701
    function smiley($smiley) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
702
        if(array_key_exists($smiley, $this->smileys)) {
703
            $this->doc .= '<img src="'.DOKU_BASE.'lib/images/smileys/'.$this->smileys[$smiley].
704
                '" class="icon" alt="'.
705
                $this->_xmlEntities($smiley).'" />';
706
        } else {
707
            $this->doc .= $this->_xmlEntities($smiley);
708
        }
709
    }
710
711
    /**
712
     * Format an entity
713
     *
714
     * Entities are basically small text replacements
715
     *
716
     * Uses $this->entities
717
     *
718
     * @param string $entity
719
     */
720
    function entity($entity) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
721
        if(array_key_exists($entity, $this->entities)) {
722
            $this->doc .= $this->entities[$entity];
723
        } else {
724
            $this->doc .= $this->_xmlEntities($entity);
725
        }
726
    }
727
728
    /**
729
     * Typographically format a multiply sign
730
     *
731
     * Example: ($x=640, $y=480) should result in "640×480"
732
     *
733
     * @param string|int $x first value
734
     * @param string|int $y second value
735
     */
736
    function multiplyentity($x, $y) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
737
        $this->doc .= "$x&times;$y";
738
    }
739
740
    /**
741
     * Render an opening single quote char (language specific)
742
     */
743
    function singlequoteopening() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
744
        global $lang;
745
        $this->doc .= $lang['singlequoteopening'];
746
    }
747
748
    /**
749
     * Render a closing single quote char (language specific)
750
     */
751
    function singlequoteclosing() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
752
        global $lang;
753
        $this->doc .= $lang['singlequoteclosing'];
754
    }
755
756
    /**
757
     * Render an apostrophe char (language specific)
758
     */
759
    function apostrophe() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
760
        global $lang;
761
        $this->doc .= $lang['apostrophe'];
762
    }
763
764
    /**
765
     * Render an opening double quote char (language specific)
766
     */
767
    function doublequoteopening() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
768
        global $lang;
769
        $this->doc .= $lang['doublequoteopening'];
770
    }
771
772
    /**
773
     * Render an closinging double quote char (language specific)
774
     */
775
    function doublequoteclosing() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
776
        global $lang;
777
        $this->doc .= $lang['doublequoteclosing'];
778
    }
779
780
    /**
781
     * Render a CamelCase link
782
     *
783
     * @param string $link       The link name
784
     * @param bool   $returnonly whether to return html or write to doc attribute
785
     * @return void|string writes to doc attribute or returns html depends on $returnonly
786
     *
787
     * @see http://en.wikipedia.org/wiki/CamelCase
788
     */
789
    function camelcaselink($link, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
790
        if($returnonly) {
791
          return $this->internallink($link, $link, null, true);
792
        } else {
793
          $this->internallink($link, $link);
794
        }
795
    }
796
797
    /**
798
     * Render a page local link
799
     *
800
     * @param string $hash       hash link identifier
801
     * @param string $name       name for the link
802
     * @param bool   $returnonly whether to return html or write to doc attribute
803
     * @return void|string writes to doc attribute or returns html depends on $returnonly
804
     */
805
    function locallink($hash, $name = null, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
806
        global $ID;
807
        $name  = $this->_getLinkTitle($name, $hash, $isImage);
808
        $hash  = $this->_headerToLink($hash);
809
        $title = $ID.' ↵';
810
811
        $doc = '<a href="#'.$hash.'" title="'.$title.'" class="wikilink1">';
812
        $doc .= $name;
813
        $doc .= '</a>';
814
815
        if($returnonly) {
816
          return $doc;
817
        } else {
818
          $this->doc .= $doc;
819
        }
820
    }
821
822
    /**
823
     * Render an internal Wiki Link
824
     *
825
     * $search,$returnonly & $linktype are not for the renderer but are used
826
     * elsewhere - no need to implement them in other renderers
827
     *
828
     * @author Andreas Gohr <[email protected]>
829
     * @param string      $id         pageid
830
     * @param string|null $name       link name
831
     * @param string|null $search     adds search url param
832
     * @param bool        $returnonly whether to return html or write to doc attribute
833
     * @param string      $linktype   type to set use of headings
834
     * @return void|string writes to doc attribute or returns html depends on $returnonly
835
     */
836
    function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
837
        global $conf;
838
        global $ID;
839
        global $INFO;
840
841
        $params = '';
842
        $parts  = explode('?', $id, 2);
843
        if(count($parts) === 2) {
844
            $id     = $parts[0];
845
            $params = $parts[1];
846
        }
847
848
        // For empty $id we need to know the current $ID
849
        // We need this check because _simpleTitle needs
850
        // correct $id and resolve_pageid() use cleanID($id)
851
        // (some things could be lost)
852
        if($id === '') {
853
            $id = $ID;
854
        }
855
856
        // default name is based on $id as given
857
        $default = $this->_simpleTitle($id);
858
859
        // now first resolve and clean up the $id
860
        resolve_pageid(getNS($ID), $id, $exists, $this->date_at, true);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, resolve_pageid() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
861
862
        $link = array();
863
        $name = $this->_getLinkTitle($name, $default, $isImage, $id, $linktype);
864
        if(!$isImage) {
865
            if($exists) {
866
                $class = 'wikilink1';
867
            } else {
868
                $class       = 'wikilink2';
869
                $link['rel'] = 'nofollow';
870
            }
871
        } else {
872
            $class = 'media';
873
        }
874
875
        //keep hash anchor
876
        @list($id, $hash) = explode('#', $id, 2);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
877
        if(!empty($hash)) $hash = $this->_headerToLink($hash);
878
879
        //prepare for formating
880
        $link['target'] = $conf['target']['wiki'];
881
        $link['style']  = '';
882
        $link['pre']    = '';
883
        $link['suf']    = '';
884
        // highlight link to current page
885
        if($id == $INFO['id']) {
886
            $link['pre'] = '<span class="curid">';
887
            $link['suf'] = '</span>';
888
        }
889
        $link['more']   = '';
890
        $link['class']  = $class;
891
        if($this->date_at) {
892
            $params = $params.'&at='.rawurlencode($this->date_at);
893
        }
894
        $link['url']    = wl($id, $params);
895
        $link['name']   = $name;
896
        $link['title']  = $id;
897
        //add search string
898
        if($search) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $search of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
899
            ($conf['userewrite']) ? $link['url'] .= '?' : $link['url'] .= '&amp;';
900
            if(is_array($search)) {
901
                $search = array_map('rawurlencode', $search);
902
                $link['url'] .= 's[]='.join('&amp;s[]=', $search);
903
            } else {
904
                $link['url'] .= 's='.rawurlencode($search);
905
            }
906
        }
907
908
        //keep hash
909
        if($hash) $link['url'] .= '#'.$hash;
910
911
        //output formatted
912
        if($returnonly) {
913
            return $this->_formatLink($link);
914
        } else {
915
            $this->doc .= $this->_formatLink($link);
916
        }
917
    }
918
919
    /**
920
     * Render an external link
921
     *
922
     * @param string       $url        full URL with scheme
923
     * @param string|array $name       name for the link, array for media file
924
     * @param bool         $returnonly whether to return html or write to doc attribute
925
     * @return void|string writes to doc attribute or returns html depends on $returnonly
926
     */
927
    function externallink($url, $name = null, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
928
        global $conf;
929
930
        $name = $this->_getLinkTitle($name, $url, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type null; however, Doku_Renderer_xhtml::_getLinkTitle() does only seem to accept string|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
931
932
        // url might be an attack vector, only allow registered protocols
933
        if(is_null($this->schemes)) $this->schemes = getSchemes();
934
        list($scheme) = explode('://', $url);
935
        $scheme = strtolower($scheme);
936
        if(!in_array($scheme, $this->schemes)) $url = '';
937
938
        // is there still an URL?
939
        if(!$url) {
940
            if($returnonly) {
941
                return $name;
942
            } else {
943
                $this->doc .= $name;
944
            }
945
            return;
946
        }
947
948
        // set class
949
        if(!$isImage) {
950
            $class = 'urlextern';
951
        } else {
952
            $class = 'media';
953
        }
954
955
        //prepare for formating
956
        $link = array();
957
        $link['target'] = $conf['target']['extern'];
958
        $link['style']  = '';
959
        $link['pre']    = '';
960
        $link['suf']    = '';
961
        $link['more']   = '';
962
        $link['class']  = $class;
963
        $link['url']    = $url;
964
        $link['rel']    = '';
965
966
        $link['name']  = $name;
967
        $link['title'] = $this->_xmlEntities($url);
968
        if($conf['relnofollow']) $link['rel'] .= ' nofollow';
969
        if($conf['target']['extern']) $link['rel'] .= ' noopener';
970
971
        //output formatted
972
        if($returnonly) {
973
            return $this->_formatLink($link);
974
        } else {
975
            $this->doc .= $this->_formatLink($link);
976
        }
977
    }
978
979
    /**
980
     * Render an interwiki link
981
     *
982
     * You may want to use $this->_resolveInterWiki() here
983
     *
984
     * @param string       $match      original link - probably not much use
985
     * @param string|array $name       name for the link, array for media file
986
     * @param string       $wikiName   indentifier (shortcut) for the remote wiki
987
     * @param string       $wikiUri    the fragment parsed from the original link
988
     * @param bool         $returnonly whether to return html or write to doc attribute
989
     * @return void|string writes to doc attribute or returns html depends on $returnonly
990
     */
991
    function interwikilink($match, $name = null, $wikiName, $wikiUri, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
992
        global $conf;
993
994
        $link           = array();
995
        $link['target'] = $conf['target']['interwiki'];
996
        $link['pre']    = '';
997
        $link['suf']    = '';
998
        $link['more']   = '';
999
        $link['name']   = $this->_getLinkTitle($name, $wikiUri, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 991 can also be of type null; however, Doku_Renderer_xhtml::_getLinkTitle() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1000
        $link['rel']    = '';
1001
1002
        //get interwiki URL
1003
        $exists = null;
1004
        $url    = $this->_resolveInterWiki($wikiName, $wikiUri, $exists);
1005
1006
        if(!$isImage) {
1007
            $class         = preg_replace('/[^_\-a-z0-9]+/i', '_', $wikiName);
1008
            $link['class'] = "interwiki iw_$class";
1009
        } else {
1010
            $link['class'] = 'media';
1011
        }
1012
1013
        //do we stay at the same server? Use local target
1014
        if(strpos($url, DOKU_URL) === 0 OR strpos($url, DOKU_BASE) === 0) {
1015
            $link['target'] = $conf['target']['wiki'];
1016
        }
1017
        if($exists !== null && !$isImage) {
1018
            if($exists) {
1019
                $link['class'] .= ' wikilink1';
1020
            } else {
1021
                $link['class'] .= ' wikilink2';
1022
                $link['rel'] .= ' nofollow';
1023
            }
1024
        }
1025
        if($conf['target']['interwiki']) $link['rel'] .= ' noopener';
1026
1027
        $link['url']   = $url;
1028
        $link['title'] = htmlspecialchars($link['url']);
1029
1030
        //output formatted
1031
        if($returnonly) {
1032
            return $this->_formatLink($link);
1033
        } else {
1034
            $this->doc .= $this->_formatLink($link);
1035
        }
1036
    }
1037
1038
    /**
1039
     * Link to windows share
1040
     *
1041
     * @param string       $url        the link
1042
     * @param string|array $name       name for the link, array for media file
1043
     * @param bool         $returnonly whether to return html or write to doc attribute
1044
     * @return void|string writes to doc attribute or returns html depends on $returnonly
1045
     */
1046
    function windowssharelink($url, $name = null, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1047
        global $conf;
1048
1049
        //simple setup
1050
        $link = array();
1051
        $link['target'] = $conf['target']['windows'];
1052
        $link['pre']    = '';
1053
        $link['suf']    = '';
1054
        $link['style']  = '';
1055
1056
        $link['name'] = $this->_getLinkTitle($name, $url, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 1046 can also be of type null; however, Doku_Renderer_xhtml::_getLinkTitle() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1057
        if(!$isImage) {
1058
            $link['class'] = 'windows';
1059
        } else {
1060
            $link['class'] = 'media';
1061
        }
1062
1063
        $link['title'] = $this->_xmlEntities($url);
1064
        $url           = str_replace('\\', '/', $url);
1065
        $url           = 'file:///'.$url;
1066
        $link['url']   = $url;
1067
1068
        //output formatted
1069
        if($returnonly) {
1070
            return $this->_formatLink($link);
1071
        } else {
1072
            $this->doc .= $this->_formatLink($link);
1073
        }
1074
    }
1075
1076
    /**
1077
     * Render a linked E-Mail Address
1078
     *
1079
     * Honors $conf['mailguard'] setting
1080
     *
1081
     * @param string       $address    Email-Address
1082
     * @param string|array $name       name for the link, array for media file
1083
     * @param bool         $returnonly whether to return html or write to doc attribute
1084
     * @return void|string writes to doc attribute or returns html depends on $returnonly
1085
     */
1086
    function emaillink($address, $name = null, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1087
        global $conf;
1088
        //simple setup
1089
        $link           = array();
1090
        $link['target'] = '';
1091
        $link['pre']    = '';
1092
        $link['suf']    = '';
1093
        $link['style']  = '';
1094
        $link['more']   = '';
1095
1096
        $name = $this->_getLinkTitle($name, '', $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type null; however, Doku_Renderer_xhtml::_getLinkTitle() does only seem to accept string|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1097
        if(!$isImage) {
1098
            $link['class'] = 'mail';
1099
        } else {
1100
            $link['class'] = 'media';
1101
        }
1102
1103
        $address = $this->_xmlEntities($address);
1104
        $address = obfuscate($address);
1105
        $title   = $address;
1106
1107
        if(empty($name)) {
1108
            $name = $address;
1109
        }
1110
1111
        if($conf['mailguard'] == 'visible') $address = rawurlencode($address);
1112
1113
        $link['url']   = 'mailto:'.$address;
1114
        $link['name']  = $name;
1115
        $link['title'] = $title;
1116
1117
        //output formatted
1118
        if($returnonly) {
1119
            return $this->_formatLink($link);
1120
        } else {
1121
            $this->doc .= $this->_formatLink($link);
1122
        }
1123
    }
1124
1125
    /**
1126
     * Render an internal media file
1127
     *
1128
     * @param string $src       media ID
1129
     * @param string $title     descriptive text
1130
     * @param string $align     left|center|right
1131
     * @param int    $width     width of media in pixel
1132
     * @param int    $height    height of media in pixel
1133
     * @param string $cache     cache|recache|nocache
1134
     * @param string $linking   linkonly|detail|nolink
1135
     * @param bool   $return    return HTML instead of adding to $doc
1136
     * @return void|string writes to doc attribute or returns html depends on $return
1137
     */
1138
    function internalmedia($src, $title = null, $align = null, $width = null,
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1139
                           $height = null, $cache = null, $linking = null, $return = false) {
1140
        global $ID;
1141
        if (strpos($src, '#') !== false) {
1142
            list($src, $hash) = explode('#', $src, 2);
1143
        }
1144
        resolve_mediaid(getNS($ID), $src, $exists, $this->date_at, true);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, resolve_mediaid() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1145
1146
        $noLink = false;
1147
        $render = ($linking == 'linkonly') ? false : true;
1148
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1149
1150
        list($ext, $mime) = mimetype($src, false);
1151
        if(substr($mime, 0, 5) == 'image' && $render) {
1152
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src)), ($linking == 'direct'));
1153
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1154
            // don't link movies
1155
            $noLink = true;
1156
        } else {
1157
            // add file icons
1158
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1159
            $link['class'] .= ' mediafile mf_'.$class;
1160
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache , 'rev'=>$this->_getLastMediaRevisionAt($src)), true);
1161
            if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')';
1162
        }
1163
1164
        if (!empty($hash)) $link['url'] .= '#'.$hash;
1165
1166
        //markup non existing files
1167
        if(!$exists) {
1168
            $link['class'] .= ' wikilink2';
1169
        }
1170
1171
        //output formatted
1172
        if($return) {
1173
            if($linking == 'nolink' || $noLink) return $link['name'];
1174
            else return $this->_formatLink($link);
1175
        } else {
1176
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1177
            else $this->doc .= $this->_formatLink($link);
1178
        }
1179
    }
1180
1181
    /**
1182
     * Render an external media file
1183
     *
1184
     * @param string $src     full media URL
1185
     * @param string $title   descriptive text
1186
     * @param string $align   left|center|right
1187
     * @param int    $width   width of media in pixel
1188
     * @param int    $height  height of media in pixel
1189
     * @param string $cache   cache|recache|nocache
1190
     * @param string $linking linkonly|detail|nolink
1191
     * @param bool   $return  return HTML instead of adding to $doc
1192
     * @return void|string writes to doc attribute or returns html depends on $return
1193
     */
1194
    function externalmedia($src, $title = null, $align = null, $width = null,
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1195
                           $height = null, $cache = null, $linking = null, $return = false) {
1196
        if(link_isinterwiki($src)){
1197
            list($shortcut, $reference) = explode('>', $src, 2);
1198
            $exists = null;
1199
            $src = $this->_resolveInterWiki($shortcut, $reference, $exists);
1200
        }
1201
        list($src, $hash) = explode('#', $src, 2);
1202
        $noLink = false;
1203
        $render = ($linking == 'linkonly') ? false : true;
1204
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1205
1206
        $link['url'] = ml($src, array('cache' => $cache));
1207
1208
        list($ext, $mime) = mimetype($src, false);
1209
        if(substr($mime, 0, 5) == 'image' && $render) {
1210
            // link only jpeg images
1211
            // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true;
1212
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1213
            // don't link movies
1214
            $noLink = true;
1215
        } else {
1216
            // add file icons
1217
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1218
            $link['class'] .= ' mediafile mf_'.$class;
1219
        }
1220
1221
        if($hash) $link['url'] .= '#'.$hash;
1222
1223
        //output formatted
1224
        if($return) {
1225
            if($linking == 'nolink' || $noLink) return $link['name'];
1226
            else return $this->_formatLink($link);
1227
        } else {
1228
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1229
            else $this->doc .= $this->_formatLink($link);
1230
        }
1231
    }
1232
1233
    /**
1234
     * Renders an RSS feed
1235
     *
1236
     * @param string $url    URL of the feed
1237
     * @param array  $params Finetuning of the output
1238
     *
1239
     * @author Andreas Gohr <[email protected]>
1240
     */
1241
    function rss($url, $params) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1242
        global $lang;
1243
        global $conf;
1244
1245
        require_once(DOKU_INC.'inc/FeedParser.php');
1246
        $feed = new FeedParser();
1247
        $feed->set_feed_url($url);
1248
1249
        //disable warning while fetching
1250
        if(!defined('DOKU_E_LEVEL')) {
1251
            $elvl = error_reporting(E_ERROR);
1252
        }
1253
        $rc = $feed->init();
1254
        if(isset($elvl)) {
1255
            error_reporting($elvl);
1256
        }
1257
1258
        if($params['nosort']) $feed->enable_order_by_date(false);
1259
1260
        //decide on start and end
1261
        if($params['reverse']) {
1262
            $mod   = -1;
1263
            $start = $feed->get_item_quantity() - 1;
1264
            $end   = $start - ($params['max']);
1265
            $end   = ($end < -1) ? -1 : $end;
1266
        } else {
1267
            $mod   = 1;
1268
            $start = 0;
1269
            $end   = $feed->get_item_quantity();
1270
            $end   = ($end > $params['max']) ? $params['max'] : $end;
1271
        }
1272
1273
        $this->doc .= '<ul class="rss">';
1274
        if($rc) {
1275
            for($x = $start; $x != $end; $x += $mod) {
1276
                $item = $feed->get_item($x);
1277
                $this->doc .= '<li><div class="li">';
1278
                // support feeds without links
1279
                $lnkurl = $item->get_permalink();
1280
                if($lnkurl) {
1281
                    // title is escaped by SimplePie, we unescape here because it
1282
                    // is escaped again in externallink() FS#1705
1283
                    $this->externallink(
1284
                        $item->get_permalink(),
1285
                        html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')
1286
                    );
1287
                } else {
1288
                    $this->doc .= ' '.$item->get_title();
1289
                }
1290
                if($params['author']) {
1291
                    $author = $item->get_author(0);
1292
                    if($author) {
1293
                        $name = $author->get_name();
1294
                        if(!$name) $name = $author->get_email();
1295
                        if($name) $this->doc .= ' '.$lang['by'].' '.hsc($name);
1296
                    }
1297
                }
1298
                if($params['date']) {
1299
                    $this->doc .= ' ('.$item->get_local_date($conf['dformat']).')';
1300
                }
1301
                if($params['details']) {
1302
                    $this->doc .= '<div class="detail">';
1303
                    if($conf['htmlok']) {
1304
                        $this->doc .= $item->get_description();
1305
                    } else {
1306
                        $this->doc .= strip_tags($item->get_description());
1307
                    }
1308
                    $this->doc .= '</div>';
1309
                }
1310
1311
                $this->doc .= '</div></li>';
1312
            }
1313
        } else {
1314
            $this->doc .= '<li><div class="li">';
1315
            $this->doc .= '<em>'.$lang['rssfailed'].'</em>';
1316
            $this->externallink($url);
1317
            if($conf['allowdebug']) {
1318
                $this->doc .= '<!--'.hsc($feed->error).'-->';
1319
            }
1320
            $this->doc .= '</div></li>';
1321
        }
1322
        $this->doc .= '</ul>';
1323
    }
1324
1325
    /**
1326
     * Start a table
1327
     *
1328
     * @param int $maxcols maximum number of columns
1329
     * @param int $numrows NOT IMPLEMENTED
1330
     * @param int $pos byte position in the original source
1331
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1332
     */
1333
    function table_open($maxcols = null, $numrows = null, $pos = null, $classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1334
        // initialize the row counter used for classes
1335
        $this->_counter['row_counter'] = 0;
1336
        $class                         = 'table';
1337
        if($classes !== null) {
1338
            if(is_array($classes)) $classes = join(' ', $classes);
1339
            $class .= ' ' . $classes;
1340
        }
1341
        if($pos !== null) {
1342
            $hid = $this->_headerToLink($class, true);
1343
            $class .= ' '.$this->startSectionEdit($pos, 'table', '', $hid);
1344
        }
1345
        $this->doc .= '<div class="'.$class.'"><table class="inline">'.
1346
            DOKU_LF;
1347
    }
1348
1349
    /**
1350
     * Close a table
1351
     *
1352
     * @param int $pos byte position in the original source
1353
     */
1354
    function table_close($pos = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1355
        $this->doc .= '</table></div>'.DOKU_LF;
1356
        if($pos !== null) {
1357
            $this->finishSectionEdit($pos);
1358
        }
1359
    }
1360
1361
    /**
1362
     * Open a table header
1363
     */
1364
    function tablethead_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1365
        $this->doc .= DOKU_TAB.'<thead>'.DOKU_LF;
1366
    }
1367
1368
    /**
1369
     * Close a table header
1370
     */
1371
    function tablethead_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1372
        $this->doc .= DOKU_TAB.'</thead>'.DOKU_LF;
1373
    }
1374
1375
    /**
1376
     * Open a table body
1377
     */
1378
    function tabletbody_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1379
        $this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF;
1380
    }
1381
1382
    /**
1383
     * Close a table body
1384
     */
1385
    function tabletbody_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1386
        $this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF;
1387
    }
1388
1389
    /**
1390
     * Open a table footer
1391
     */
1392
    function tabletfoot_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1393
        $this->doc .= DOKU_TAB.'<tfoot>'.DOKU_LF;
1394
    }
1395
1396
    /**
1397
     * Close a table footer
1398
     */
1399
    function tabletfoot_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1400
        $this->doc .= DOKU_TAB.'</tfoot>'.DOKU_LF;
1401
    }
1402
1403
    /**
1404
     * Open a table row
1405
     *
1406
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1407
     */
1408
    function tablerow_open($classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1409
        // initialize the cell counter used for classes
1410
        $this->_counter['cell_counter'] = 0;
1411
        $class                          = 'row'.$this->_counter['row_counter']++;
1412
        if($classes !== null) {
1413
            if(is_array($classes)) $classes = join(' ', $classes);
1414
            $class .= ' ' . $classes;
1415
        }
1416
        $this->doc .= DOKU_TAB.'<tr class="'.$class.'">'.DOKU_LF.DOKU_TAB.DOKU_TAB;
1417
    }
1418
1419
    /**
1420
     * Close a table row
1421
     */
1422
    function tablerow_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1423
        $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
1424
    }
1425
1426
    /**
1427
     * Open a table header cell
1428
     *
1429
     * @param int    $colspan
1430
     * @param string $align left|center|right
1431
     * @param int    $rowspan
1432
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1433
     */
1434
    function tableheader_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1435
        $class = 'class="col'.$this->_counter['cell_counter']++;
1436
        if(!is_null($align)) {
1437
            $class .= ' '.$align.'align';
1438
        }
1439
        if($classes !== null) {
1440
            if(is_array($classes)) $classes = join(' ', $classes);
1441
            $class .= ' ' . $classes;
1442
        }
1443
        $class .= '"';
1444
        $this->doc .= '<th '.$class;
1445
        if($colspan > 1) {
1446
            $this->_counter['cell_counter'] += $colspan - 1;
1447
            $this->doc .= ' colspan="'.$colspan.'"';
1448
        }
1449
        if($rowspan > 1) {
1450
            $this->doc .= ' rowspan="'.$rowspan.'"';
1451
        }
1452
        $this->doc .= '>';
1453
    }
1454
1455
    /**
1456
     * Close a table header cell
1457
     */
1458
    function tableheader_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1459
        $this->doc .= '</th>';
1460
    }
1461
1462
    /**
1463
     * Open a table cell
1464
     *
1465
     * @param int       $colspan
1466
     * @param string    $align left|center|right
1467
     * @param int       $rowspan
1468
     * @param string|string[]    $classes css classes - have to be valid, do not pass unfiltered user input
1469
     */
1470
    function tablecell_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1471
        $class = 'class="col'.$this->_counter['cell_counter']++;
1472
        if(!is_null($align)) {
1473
            $class .= ' '.$align.'align';
1474
        }
1475
        if($classes !== null) {
1476
            if(is_array($classes)) $classes = join(' ', $classes);
1477
            $class .= ' ' . $classes;
1478
        }
1479
        $class .= '"';
1480
        $this->doc .= '<td '.$class;
1481
        if($colspan > 1) {
1482
            $this->_counter['cell_counter'] += $colspan - 1;
1483
            $this->doc .= ' colspan="'.$colspan.'"';
1484
        }
1485
        if($rowspan > 1) {
1486
            $this->doc .= ' rowspan="'.$rowspan.'"';
1487
        }
1488
        $this->doc .= '>';
1489
    }
1490
1491
    /**
1492
     * Close a table cell
1493
     */
1494
    function tablecell_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1495
        $this->doc .= '</td>';
1496
    }
1497
1498
    /**
1499
     * Returns the current header level.
1500
     * (required e.g. by the filelist plugin)
1501
     *
1502
     * @return int The current header level
1503
     */
1504
    function getLastlevel() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1505
        return $this->lastlevel;
1506
    }
1507
1508
    #region Utility functions
1509
1510
    /**
1511
     * Build a link
1512
     *
1513
     * Assembles all parts defined in $link returns HTML for the link
1514
     *
1515
     * @param array $link attributes of a link
1516
     * @return string
1517
     *
1518
     * @author Andreas Gohr <[email protected]>
1519
     */
1520
    function _formatLink($link) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1521
        //make sure the url is XHTML compliant (skip mailto)
1522
        if(substr($link['url'], 0, 7) != 'mailto:') {
1523
            $link['url'] = str_replace('&', '&amp;', $link['url']);
1524
            $link['url'] = str_replace('&amp;amp;', '&amp;', $link['url']);
1525
        }
1526
        //remove double encodings in titles
1527
        $link['title'] = str_replace('&amp;amp;', '&amp;', $link['title']);
1528
1529
        // be sure there are no bad chars in url or title
1530
        // (we can't do this for name because it can contain an img tag)
1531
        $link['url']   = strtr($link['url'], array('>' => '%3E', '<' => '%3C', '"' => '%22'));
1532
        $link['title'] = strtr($link['title'], array('>' => '&gt;', '<' => '&lt;', '"' => '&quot;'));
1533
1534
        $ret = '';
1535
        $ret .= $link['pre'];
1536
        $ret .= '<a href="'.$link['url'].'"';
1537
        if(!empty($link['class'])) $ret .= ' class="'.$link['class'].'"';
1538
        if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"';
1539
        if(!empty($link['title'])) $ret .= ' title="'.$link['title'].'"';
1540
        if(!empty($link['style'])) $ret .= ' style="'.$link['style'].'"';
1541
        if(!empty($link['rel'])) $ret .= ' rel="'.trim($link['rel']).'"';
1542
        if(!empty($link['more'])) $ret .= ' '.$link['more'];
1543
        $ret .= '>';
1544
        $ret .= $link['name'];
1545
        $ret .= '</a>';
1546
        $ret .= $link['suf'];
1547
        return $ret;
1548
    }
1549
1550
    /**
1551
     * Renders internal and external media
1552
     *
1553
     * @author Andreas Gohr <[email protected]>
1554
     * @param string $src       media ID
1555
     * @param string $title     descriptive text
1556
     * @param string $align     left|center|right
1557
     * @param int    $width     width of media in pixel
1558
     * @param int    $height    height of media in pixel
1559
     * @param string $cache     cache|recache|nocache
1560
     * @param bool   $render    should the media be embedded inline or just linked
1561
     * @return string
1562
     */
1563
    function _media($src, $title = null, $align = null, $width = null,
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1564
                    $height = null, $cache = null, $render = true) {
1565
1566
        $ret = '';
1567
1568
        list($ext, $mime) = mimetype($src);
1569
        if(substr($mime, 0, 5) == 'image') {
1570
            // first get the $title
1571
            if(!is_null($title)) {
1572
                $title = $this->_xmlEntities($title);
1573
            } elseif($ext == 'jpg' || $ext == 'jpeg') {
1574
                //try to use the caption from IPTC/EXIF
1575
                require_once(DOKU_INC.'inc/JpegMeta.php');
1576
                $jpeg = new JpegMeta(mediaFN($src));
1577
                if($jpeg !== false) $cap = $jpeg->getTitle();
1578
                if(!empty($cap)) {
1579
                    $title = $this->_xmlEntities($cap);
1580
                }
1581
            }
1582
            if(!$render) {
1583
                // if the picture is not supposed to be rendered
1584
                // return the title of the picture
1585
                if(!$title) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $title of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1586
                    // just show the sourcename
1587
                    $title = $this->_xmlEntities(utf8_basename(noNS($src)));
1588
                }
1589
                return $title;
1590
            }
1591
            //add image tag
1592
            $ret .= '<img src="'.ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src))).'"';
1593
            $ret .= ' class="media'.$align.'"';
1594
1595
            if($title) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $title of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1596
                $ret .= ' title="'.$title.'"';
1597
                $ret .= ' alt="'.$title.'"';
1598
            } else {
1599
                $ret .= ' alt=""';
1600
            }
1601
1602
            if(!is_null($width))
1603
                $ret .= ' width="'.$this->_xmlEntities($width).'"';
1604
1605
            if(!is_null($height))
1606
                $ret .= ' height="'.$this->_xmlEntities($height).'"';
1607
1608
            $ret .= ' />';
1609
1610
        } elseif(media_supportedav($mime, 'video') || media_supportedav($mime, 'audio')) {
1611
            // first get the $title
1612
            $title = !is_null($title) ? $this->_xmlEntities($title) : false;
1613
            if(!$render) {
1614
                // if the file is not supposed to be rendered
1615
                // return the title of the file (just the sourcename if there is no title)
1616
                return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src)));
1617
            }
1618
1619
            $att          = array();
1620
            $att['class'] = "media$align";
1621
            if($title) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $title of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1622
                $att['title'] = $title;
1623
            }
1624
1625
            if(media_supportedav($mime, 'video')) {
1626
                //add video
1627
                $ret .= $this->_video($src, $width, $height, $att);
1628
            }
1629
            if(media_supportedav($mime, 'audio')) {
1630
                //add audio
1631
                $ret .= $this->_audio($src, $att);
1632
            }
1633
1634
        } elseif($mime == 'application/x-shockwave-flash') {
1635
            if(!$render) {
1636
                // if the flash is not supposed to be rendered
1637
                // return the title of the flash
1638
                if(!$title) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $title of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1639
                    // just show the sourcename
1640
                    $title = utf8_basename(noNS($src));
1641
                }
1642
                return $this->_xmlEntities($title);
1643
            }
1644
1645
            $att          = array();
1646
            $att['class'] = "media$align";
1647
            if($align == 'right') $att['align'] = 'right';
1648
            if($align == 'left') $att['align'] = 'left';
1649
            $ret .= html_flashobject(
1650
                ml($src, array('cache' => $cache), true, '&'), $width, $height,
1651
                array('quality' => 'high'),
1652
                null,
1653
                $att,
1654
                $this->_xmlEntities($title)
1655
            );
1656
        } elseif($title) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $title of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1657
            // well at least we have a title to display
1658
            $ret .= $this->_xmlEntities($title);
1659
        } else {
1660
            // just show the sourcename
1661
            $ret .= $this->_xmlEntities(utf8_basename(noNS($src)));
1662
        }
1663
1664
        return $ret;
1665
    }
1666
1667
    /**
1668
     * Escape string for output
1669
     *
1670
     * @param $string
1671
     * @return string
1672
     */
1673
    function _xmlEntities($string) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1674
        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
1675
    }
1676
1677
    /**
1678
     * Creates a linkid from a headline
1679
     *
1680
     * @author Andreas Gohr <[email protected]>
1681
     * @param string  $title   The headline title
1682
     * @param boolean $create  Create a new unique ID?
1683
     * @return string
1684
     */
1685
    function _headerToLink($title, $create = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1686
        if($create) {
1687
            return sectionID($title, $this->headers);
1688
        } else {
1689
            $check = false;
1690
            return sectionID($title, $check);
1691
        }
1692
    }
1693
1694
    /**
1695
     * Construct a title and handle images in titles
1696
     *
1697
     * @author Harry Fuecks <[email protected]>
1698
     * @param string|array $title    either string title or media array
1699
     * @param string       $default  default title if nothing else is found
1700
     * @param bool         $isImage  will be set to true if it's a media file
1701
     * @param null|string  $id       linked page id (used to extract title from first heading)
1702
     * @param string       $linktype content|navigation
1703
     * @return string      HTML of the title, might be full image tag or just escaped text
1704
     */
1705
    function _getLinkTitle($title, $default, &$isImage, $id = null, $linktype = 'content') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1706
        $isImage = false;
1707
        if(is_array($title)) {
1708
            $isImage = true;
1709
            return $this->_imageTitle($title);
1710
        } elseif(is_null($title) || trim($title) == '') {
1711
            if(useHeading($linktype) && $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1712
                $heading = p_get_first_heading($id);
1713
                if(!blank($heading)) {
1714
                    return $this->_xmlEntities($heading);
1715
                }
1716
            }
1717
            return $this->_xmlEntities($default);
1718
        } else {
1719
            return $this->_xmlEntities($title);
1720
        }
1721
    }
1722
1723
    /**
1724
     * Returns HTML code for images used in link titles
1725
     *
1726
     * @author Andreas Gohr <[email protected]>
1727
     * @param array $img
1728
     * @return string HTML img tag or similar
1729
     */
1730
    function _imageTitle($img) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1731
        global $ID;
1732
1733
        // some fixes on $img['src']
1734
        // see internalmedia() and externalmedia()
1735
        list($img['src']) = explode('#', $img['src'], 2);
1736
        if($img['type'] == 'internalmedia') {
1737
            resolve_mediaid(getNS($ID), $img['src'], $exists ,$this->date_at, true);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, resolve_mediaid() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1738
        }
1739
1740
        return $this->_media(
1741
            $img['src'],
1742
            $img['title'],
1743
            $img['align'],
1744
            $img['width'],
1745
            $img['height'],
1746
            $img['cache']
1747
        );
1748
    }
1749
1750
    /**
1751
     * helperfunction to return a basic link to a media
1752
     *
1753
     * used in internalmedia() and externalmedia()
1754
     *
1755
     * @author   Pierre Spring <[email protected]>
1756
     * @param string $src       media ID
1757
     * @param string $title     descriptive text
1758
     * @param string $align     left|center|right
1759
     * @param int    $width     width of media in pixel
1760
     * @param int    $height    height of media in pixel
1761
     * @param string $cache     cache|recache|nocache
1762
     * @param bool   $render    should the media be embedded inline or just linked
1763
     * @return array associative array with link config
1764
     */
1765
    function _getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1766
        global $conf;
1767
1768
        $link           = array();
1769
        $link['class']  = 'media';
1770
        $link['style']  = '';
1771
        $link['pre']    = '';
1772
        $link['suf']    = '';
1773
        $link['more']   = '';
1774
        $link['target'] = $conf['target']['media'];
1775
        if($conf['target']['media']) $link['rel'] = 'noopener';
1776
        $link['title']  = $this->_xmlEntities($src);
1777
        $link['name']   = $this->_media($src, $title, $align, $width, $height, $cache, $render);
1778
1779
        return $link;
1780
    }
1781
1782
    /**
1783
     * Embed video(s) in HTML
1784
     *
1785
     * @author Anika Henke <[email protected]>
1786
     * @author Schplurtz le Déboulonné <[email protected]>
1787
     *
1788
     * @param string $src         - ID of video to embed
1789
     * @param int    $width       - width of the video in pixels
1790
     * @param int    $height      - height of the video in pixels
1791
     * @param array  $atts        - additional attributes for the <video> tag
1792
     * @return string
1793
     */
1794
    function _video($src, $width, $height, $atts = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1795
        // prepare width and height
1796
        if(is_null($atts)) $atts = array();
1797
        $atts['width']  = (int) $width;
1798
        $atts['height'] = (int) $height;
1799
        if(!$atts['width']) $atts['width'] = 320;
1800
        if(!$atts['height']) $atts['height'] = 240;
1801
1802
        $posterUrl = '';
1803
        $files = array();
1804
        $tracks = array();
1805
        $isExternal = media_isexternal($src);
1806
1807
        if ($isExternal) {
1808
            // take direct source for external files
1809
            list(/*ext*/, $srcMime) = mimetype($src);
1810
            $files[$srcMime] = $src;
1811
        } else {
1812
            // prepare alternative formats
1813
            $extensions   = array('webm', 'ogv', 'mp4');
1814
            $files        = media_alternativefiles($src, $extensions);
1815
            $poster       = media_alternativefiles($src, array('jpg', 'png'));
1816
            $tracks       = media_trackfiles($src);
1817
            if(!empty($poster)) {
1818
                $posterUrl = ml(reset($poster), '', true, '&');
1819
            }
1820
        }
1821
1822
        $out = '';
1823
        // open video tag
1824
        $out .= '<video '.buildAttributes($atts).' controls="controls"';
1825
        if($posterUrl) $out .= ' poster="'.hsc($posterUrl).'"';
1826
        $out .= '>'.NL;
1827
        $fallback = '';
1828
1829
        // output source for each alternative video format
1830
        foreach($files as $mime => $file) {
1831
            if ($isExternal) {
1832
                $url = $file;
1833
                $linkType = 'externalmedia';
1834
            } else {
1835
                $url = ml($file, '', true, '&');
1836
                $linkType = 'internalmedia';
1837
            }
1838
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1839
1840
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1841
            // alternative content (just a link to the file)
1842
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1843
        }
1844
1845
        // output each track if any
1846
        foreach( $tracks as $trackid => $info ) {
1847
            list( $kind, $srclang ) = array_map( 'hsc', $info );
1848
            $out .= "<track kind=\"$kind\" srclang=\"$srclang\" ";
1849
            $out .= "label=\"$srclang\" ";
1850
            $out .= 'src="'.ml($trackid, '', true).'">'.NL;
1851
        }
1852
1853
        // finish
1854
        $out .= $fallback;
1855
        $out .= '</video>'.NL;
1856
        return $out;
1857
    }
1858
1859
    /**
1860
     * Embed audio in HTML
1861
     *
1862
     * @author Anika Henke <[email protected]>
1863
     *
1864
     * @param string $src       - ID of audio to embed
1865
     * @param array  $atts      - additional attributes for the <audio> tag
1866
     * @return string
1867
     */
1868
    function _audio($src, $atts = array()) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1869
        $files = array();
1870
        $isExternal = media_isexternal($src);
1871
1872
        if ($isExternal) {
1873
            // take direct source for external files
1874
            list(/*ext*/, $srcMime) = mimetype($src);
1875
            $files[$srcMime] = $src;
1876
        } else {
1877
            // prepare alternative formats
1878
            $extensions   = array('ogg', 'mp3', 'wav');
1879
            $files        = media_alternativefiles($src, $extensions);
1880
        }
1881
1882
        $out = '';
1883
        // open audio tag
1884
        $out .= '<audio '.buildAttributes($atts).' controls="controls">'.NL;
1885
        $fallback = '';
1886
1887
        // output source for each alternative audio format
1888
        foreach($files as $mime => $file) {
1889
            if ($isExternal) {
1890
                $url = $file;
1891
                $linkType = 'externalmedia';
1892
            } else {
1893
                $url = ml($file, '', true, '&');
1894
                $linkType = 'internalmedia';
1895
            }
1896
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1897
1898
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1899
            // alternative content (just a link to the file)
1900
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1901
        }
1902
1903
        // finish
1904
        $out .= $fallback;
1905
        $out .= '</audio>'.NL;
1906
        return $out;
1907
    }
1908
1909
    /**
1910
     * _getLastMediaRevisionAt is a helperfunction to internalmedia() and _media()
1911
     * which returns an existing media revision less or equal to rev or date_at
1912
     *
1913
     * @author lisps
1914
     * @param string $media_id
1915
     * @access protected
1916
     * @return string revision ('' for current)
1917
     */
1918
    function _getLastMediaRevisionAt($media_id){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1919
        if(!$this->date_at || media_isexternal($media_id)) return '';
1920
        $pagelog = new MediaChangeLog($media_id);
1921
        return $pagelog->getLastRevisionAt($this->date_at);
1922
    }
1923
1924
    #endregion
1925
}
1926
1927
//Setup VIM: ex: et ts=4 :
1928