Completed
Push — master ( f20cfb...c6162b )
by Andreas
03:22
created

Doku_Renderer_xhtml::internalmedia()   F

Complexity

Conditions 16
Paths 256

Size

Total Lines 42
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 28
nc 256
nop 8
dl 0
loc 42
rs 3.7109
c 0
b 0
f 0

How to fix   Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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) {
70
        $this->sectionedits[] = array(++$this->lastsecid, $start, $type, $title);
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) {
82
        list($id, $start, $type, $title) = 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
        $this->doc .= "[$start-".(is_null($end) ? '' : $end).'] -->';
91
    }
92
93
    /**
94
     * Returns the format produced by this renderer.
95
     *
96
     * @return string always 'xhtml'
97
     */
98
    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...
99
        return 'xhtml';
100
    }
101
102
    /**
103
     * Initialize the document
104
     */
105
    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...
106
        //reset some internals
107
        $this->toc     = array();
108
        $this->headers = array();
109
    }
110
111
    /**
112
     * Finalize the document
113
     */
114
    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...
115
        // Finish open section edits.
116
        while(count($this->sectionedits) > 0) {
117
            if($this->sectionedits[count($this->sectionedits) - 1][1] <= 1) {
118
                // If there is only one section, do not write a section edit
119
                // marker.
120
                array_pop($this->sectionedits);
121
            } else {
122
                $this->finishSectionEdit();
123
            }
124
        }
125
126
        if(count($this->footnotes) > 0) {
127
            $this->doc .= '<div class="footnotes">'.DOKU_LF;
128
129
            foreach($this->footnotes as $id => $footnote) {
130
                // check its not a placeholder that indicates actual footnote text is elsewhere
131
                if(substr($footnote, 0, 5) != "@@FNT") {
132
133
                    // open the footnote and set the anchor and backlink
134
                    $this->doc .= '<div class="fn">';
135
                    $this->doc .= '<sup><a href="#fnt__'.$id.'" id="fn__'.$id.'" class="fn_bot">';
136
                    $this->doc .= $id.')</a></sup> '.DOKU_LF;
137
138
                    // get any other footnotes that use the same markup
139
                    $alt = array_keys($this->footnotes, "@@FNT$id");
140
141
                    if(count($alt)) {
142
                        foreach($alt as $ref) {
143
                            // set anchor and backlink for the other footnotes
144
                            $this->doc .= ', <sup><a href="#fnt__'.($ref).'" id="fn__'.($ref).'" class="fn_bot">';
145
                            $this->doc .= ($ref).')</a></sup> '.DOKU_LF;
146
                        }
147
                    }
148
149
                    // add footnote markup and close this footnote
150
                    $this->doc .= '<div class="content">'.$footnote.'</div>';
151
                    $this->doc .= '</div>'.DOKU_LF;
152
                }
153
            }
154
            $this->doc .= '</div>'.DOKU_LF;
155
        }
156
157
        // Prepare the TOC
158
        global $conf;
159
        if($this->info['toc'] && is_array($this->toc) && $conf['tocminheads'] && count($this->toc) >= $conf['tocminheads']) {
160
            global $TOC;
161
            $TOC = $this->toc;
162
        }
163
164
        // make sure there are no empty paragraphs
165
        $this->doc = preg_replace('#<p>\s*</p>#', '', $this->doc);
166
    }
167
168
    /**
169
     * Add an item to the TOC
170
     *
171
     * @param string $id       the hash link
172
     * @param string $text     the text to display
173
     * @param int    $level    the nesting level
174
     */
175
    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...
176
        global $conf;
177
178
        //handle TOC
179
        if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) {
180
            $this->toc[] = html_mktocitem($id, $text, $level - $conf['toptoclevel'] + 1);
181
        }
182
    }
183
184
    /**
185
     * Render a heading
186
     *
187
     * @param string $text  the text to display
188
     * @param int    $level header level
189
     * @param int    $pos   byte position in the original source
190
     */
191
    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...
192
        global $conf;
193
194
        if(blank($text)) return; //skip empty headlines
195
196
        $hid = $this->_headerToLink($text, true);
197
198
        //only add items within configured levels
199
        $this->toc_additem($hid, $text, $level);
200
201
        // adjust $node to reflect hierarchy of levels
202
        $this->node[$level - 1]++;
203
        if($level < $this->lastlevel) {
204
            for($i = 0; $i < $this->lastlevel - $level; $i++) {
205
                $this->node[$this->lastlevel - $i - 1] = 0;
206
            }
207
        }
208
        $this->lastlevel = $level;
209
210
        if($level <= $conf['maxseclevel'] &&
211
            count($this->sectionedits) > 0 &&
212
            $this->sectionedits[count($this->sectionedits) - 1][2] === 'section'
213
        ) {
214
            $this->finishSectionEdit($pos - 1);
215
        }
216
217
        // write the header
218
        $this->doc .= DOKU_LF.'<h'.$level;
219
        if($level <= $conf['maxseclevel']) {
220
            $this->doc .= ' class="'.$this->startSectionEdit($pos, 'section', $text).'"';
221
        }
222
        $this->doc .= ' id="'.$hid.'">';
223
        $this->doc .= $this->_xmlEntities($text);
224
        $this->doc .= "</h$level>".DOKU_LF;
225
    }
226
227
    /**
228
     * Open a new section
229
     *
230
     * @param int $level section level (as determined by the previous header)
231
     */
232
    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...
233
        $this->doc .= '<div class="level'.$level.'">'.DOKU_LF;
234
    }
235
236
    /**
237
     * Close the current section
238
     */
239
    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...
240
        $this->doc .= DOKU_LF.'</div>'.DOKU_LF;
241
    }
242
243
    /**
244
     * Render plain text data
245
     *
246
     * @param $text
247
     */
248
    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...
249
        $this->doc .= $this->_xmlEntities($text);
250
    }
251
252
    /**
253
     * Open a paragraph
254
     */
255
    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...
256
        $this->doc .= DOKU_LF.'<p>'.DOKU_LF;
257
    }
258
259
    /**
260
     * Close a paragraph
261
     */
262
    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...
263
        $this->doc .= DOKU_LF.'</p>'.DOKU_LF;
264
    }
265
266
    /**
267
     * Create a line break
268
     */
269
    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...
270
        $this->doc .= '<br/>'.DOKU_LF;
271
    }
272
273
    /**
274
     * Create a horizontal line
275
     */
276
    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...
277
        $this->doc .= '<hr />'.DOKU_LF;
278
    }
279
280
    /**
281
     * Start strong (bold) formatting
282
     */
283
    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...
284
        $this->doc .= '<strong>';
285
    }
286
287
    /**
288
     * Stop strong (bold) formatting
289
     */
290
    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...
291
        $this->doc .= '</strong>';
292
    }
293
294
    /**
295
     * Start emphasis (italics) formatting
296
     */
297
    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...
298
        $this->doc .= '<em>';
299
    }
300
301
    /**
302
     * Stop emphasis (italics) formatting
303
     */
304
    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...
305
        $this->doc .= '</em>';
306
    }
307
308
    /**
309
     * Start underline formatting
310
     */
311
    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...
312
        $this->doc .= '<em class="u">';
313
    }
314
315
    /**
316
     * Stop underline formatting
317
     */
318
    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...
319
        $this->doc .= '</em>';
320
    }
321
322
    /**
323
     * Start monospace formatting
324
     */
325
    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...
326
        $this->doc .= '<code>';
327
    }
328
329
    /**
330
     * Stop monospace formatting
331
     */
332
    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...
333
        $this->doc .= '</code>';
334
    }
335
336
    /**
337
     * Start a subscript
338
     */
339
    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...
340
        $this->doc .= '<sub>';
341
    }
342
343
    /**
344
     * Stop a subscript
345
     */
346
    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...
347
        $this->doc .= '</sub>';
348
    }
349
350
    /**
351
     * Start a superscript
352
     */
353
    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...
354
        $this->doc .= '<sup>';
355
    }
356
357
    /**
358
     * Stop a superscript
359
     */
360
    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...
361
        $this->doc .= '</sup>';
362
    }
363
364
    /**
365
     * Start deleted (strike-through) formatting
366
     */
367
    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...
368
        $this->doc .= '<del>';
369
    }
370
371
    /**
372
     * Stop deleted (strike-through) formatting
373
     */
374
    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...
375
        $this->doc .= '</del>';
376
    }
377
378
    /**
379
     * Callback for footnote start syntax
380
     *
381
     * All following content will go to the footnote instead of
382
     * the document. To achieve this the previous rendered content
383
     * is moved to $store and $doc is cleared
384
     *
385
     * @author Andreas Gohr <[email protected]>
386
     */
387
    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...
388
389
        // move current content to store and record footnote
390
        $this->store = $this->doc;
391
        $this->doc   = '';
392
    }
393
394
    /**
395
     * Callback for footnote end syntax
396
     *
397
     * All rendered content is moved to the $footnotes array and the old
398
     * content is restored from $store again
399
     *
400
     * @author Andreas Gohr
401
     */
402
    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...
403
        /** @var $fnid int takes track of seen footnotes, assures they are unique even across multiple docs FS#2841 */
404
        static $fnid = 0;
405
        // assign new footnote id (we start at 1)
406
        $fnid++;
407
408
        // recover footnote into the stack and restore old content
409
        $footnote    = $this->doc;
410
        $this->doc   = $this->store;
411
        $this->store = '';
412
413
        // check to see if this footnote has been seen before
414
        $i = array_search($footnote, $this->footnotes);
415
416
        if($i === false) {
417
            // its a new footnote, add it to the $footnotes array
418
            $this->footnotes[$fnid] = $footnote;
419
        } else {
420
            // seen this one before, save a placeholder
421
            $this->footnotes[$fnid] = "@@FNT".($i);
422
        }
423
424
        // output the footnote reference and link
425
        $this->doc .= '<sup><a href="#fn__'.$fnid.'" id="fnt__'.$fnid.'" class="fn_top">'.$fnid.')</a></sup>';
426
    }
427
428
    /**
429
     * Open an unordered list
430
     *
431
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
432
     */
433
    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...
434
        $class = '';
435
        if($classes !== null) {
436
            if(is_array($classes)) $classes = join(' ', $classes);
437
            $class = " class=\"$classes\"";
438
        }
439
        $this->doc .= "<ul$class>".DOKU_LF;
440
    }
441
442
    /**
443
     * Close an unordered list
444
     */
445
    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...
446
        $this->doc .= '</ul>'.DOKU_LF;
447
    }
448
449
    /**
450
     * Open an ordered list
451
     *
452
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
453
     */
454
    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...
455
        $class = '';
456
        if($classes !== null) {
457
            if(is_array($classes)) $classes = join(' ', $classes);
458
            $class = " class=\"$classes\"";
459
        }
460
        $this->doc .= "<ol$class>".DOKU_LF;
461
    }
462
463
    /**
464
     * Close an ordered list
465
     */
466
    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...
467
        $this->doc .= '</ol>'.DOKU_LF;
468
    }
469
470
    /**
471
     * Open a list item
472
     *
473
     * @param int $level the nesting level
474
     * @param bool $node true when a node; false when a leaf
475
     */
476
    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...
477
        $branching = $node ? ' node' : '';
478
        $this->doc .= '<li class="level'.$level.$branching.'">';
479
    }
480
481
    /**
482
     * Close a list item
483
     */
484
    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...
485
        $this->doc .= '</li>'.DOKU_LF;
486
    }
487
488
    /**
489
     * Start the content of a list item
490
     */
491
    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...
492
        $this->doc .= '<div class="li">';
493
    }
494
495
    /**
496
     * Stop the content of a list item
497
     */
498
    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...
499
        $this->doc .= '</div>'.DOKU_LF;
500
    }
501
502
    /**
503
     * Output unformatted $text
504
     *
505
     * Defaults to $this->cdata()
506
     *
507
     * @param string $text
508
     */
509
    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...
510
        $this->doc .= $this->_xmlEntities($text);
511
    }
512
513
    /**
514
     * Execute PHP code if allowed
515
     *
516
     * @param  string $text      PHP code that is either executed or printed
517
     * @param  string $wrapper   html element to wrap result if $conf['phpok'] is okff
518
     *
519
     * @author Andreas Gohr <[email protected]>
520
     */
521
    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...
522
        global $conf;
523
524
        if($conf['phpok']) {
525
            ob_start();
526
            eval($text);
527
            $this->doc .= ob_get_contents();
528
            ob_end_clean();
529
        } else {
530
            $this->doc .= p_xhtml_cached_geshi($text, 'php', $wrapper);
531
        }
532
    }
533
534
    /**
535
     * Output block level PHP code
536
     *
537
     * If $conf['phpok'] is true this should evaluate the given code and append the result
538
     * to $doc
539
     *
540
     * @param string $text The PHP code
541
     */
542
    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...
543
        $this->php($text, 'pre');
544
    }
545
546
    /**
547
     * Insert HTML if allowed
548
     *
549
     * @param  string $text      html text
550
     * @param  string $wrapper   html element to wrap result if $conf['htmlok'] is okff
551
     *
552
     * @author Andreas Gohr <[email protected]>
553
     */
554
    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...
555
        global $conf;
556
557
        if($conf['htmlok']) {
558
            $this->doc .= $text;
559
        } else {
560
            $this->doc .= p_xhtml_cached_geshi($text, 'html4strict', $wrapper);
561
        }
562
    }
563
564
    /**
565
     * Output raw block-level HTML
566
     *
567
     * If $conf['htmlok'] is true this should add the code as is to $doc
568
     *
569
     * @param string $text The HTML
570
     */
571
    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...
572
        $this->html($text, 'pre');
573
    }
574
575
    /**
576
     * Start a block quote
577
     */
578
    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...
579
        $this->doc .= '<blockquote><div class="no">'.DOKU_LF;
580
    }
581
582
    /**
583
     * Stop a block quote
584
     */
585
    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...
586
        $this->doc .= '</div></blockquote>'.DOKU_LF;
587
    }
588
589
    /**
590
     * Output preformatted text
591
     *
592
     * @param string $text
593
     */
594
    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...
595
        $this->doc .= '<pre class="code">'.trim($this->_xmlEntities($text), "\n\r").'</pre>'.DOKU_LF;
596
    }
597
598
    /**
599
     * Display text as file content, optionally syntax highlighted
600
     *
601
     * @param string $text     text to show
602
     * @param string $language programming language to use for syntax highlighting
603
     * @param string $filename file path label
604
     */
605
    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...
606
        $this->_highlight('file', $text, $language, $filename);
607
    }
608
609
    /**
610
     * Display text as code content, optionally syntax highlighted
611
     *
612
     * @param string $text     text to show
613
     * @param string $language programming language to use for syntax highlighting
614
     * @param string $filename file path label
615
     */
616
    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...
617
        $this->_highlight('code', $text, $language, $filename);
618
    }
619
620
    /**
621
     * Use GeSHi to highlight language syntax in code and file blocks
622
     *
623
     * @author Andreas Gohr <[email protected]>
624
     * @param string $type     code|file
625
     * @param string $text     text to show
626
     * @param string $language programming language to use for syntax highlighting
627
     * @param string $filename file path label
628
     */
629
    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...
630
        global $ID;
631
        global $lang;
632
633
        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...
634
            // add icon
635
            list($ext) = mimetype($filename, false);
636
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
637
            $class = 'mediafile mf_'.$class;
638
639
            $this->doc .= '<dl class="'.$type.'">'.DOKU_LF;
640
            $this->doc .= '<dt><a href="'.exportlink($ID, 'code', array('codeblock' => $this->_codeblock)).'" title="'.$lang['download'].'" class="'.$class.'">';
641
            $this->doc .= hsc($filename);
642
            $this->doc .= '</a></dt>'.DOKU_LF.'<dd>';
643
        }
644
645
        if($text{0} == "\n") {
646
            $text = substr($text, 1);
647
        }
648
        if(substr($text, -1) == "\n") {
649
            $text = substr($text, 0, -1);
650
        }
651
652
        if(is_null($language)) {
653
            $this->doc .= '<pre class="'.$type.'">'.$this->_xmlEntities($text).'</pre>'.DOKU_LF;
654
        } else {
655
            $class = 'code'; //we always need the code class to make the syntax highlighting apply
656
            if($type != 'code') $class .= ' '.$type;
657
658
            $this->doc .= "<pre class=\"$class $language\">".p_xhtml_cached_geshi($text, $language, '').'</pre>'.DOKU_LF;
659
        }
660
661
        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...
662
            $this->doc .= '</dd></dl>'.DOKU_LF;
663
        }
664
665
        $this->_codeblock++;
666
    }
667
668
    /**
669
     * Format an acronym
670
     *
671
     * Uses $this->acronyms
672
     *
673
     * @param string $acronym
674
     */
675
    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...
676
677
        if(array_key_exists($acronym, $this->acronyms)) {
678
679
            $title = $this->_xmlEntities($this->acronyms[$acronym]);
680
681
            $this->doc .= '<abbr title="'.$title
682
                .'">'.$this->_xmlEntities($acronym).'</abbr>';
683
684
        } else {
685
            $this->doc .= $this->_xmlEntities($acronym);
686
        }
687
    }
688
689
    /**
690
     * Format a smiley
691
     *
692
     * Uses $this->smiley
693
     *
694
     * @param string $smiley
695
     */
696
    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...
697
        if(array_key_exists($smiley, $this->smileys)) {
698
            $this->doc .= '<img src="'.DOKU_BASE.'lib/images/smileys/'.$this->smileys[$smiley].
699
                '" class="icon" alt="'.
700
                $this->_xmlEntities($smiley).'" />';
701
        } else {
702
            $this->doc .= $this->_xmlEntities($smiley);
703
        }
704
    }
705
706
    /**
707
     * Format an entity
708
     *
709
     * Entities are basically small text replacements
710
     *
711
     * Uses $this->entities
712
     *
713
     * @param string $entity
714
     */
715
    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...
716
        if(array_key_exists($entity, $this->entities)) {
717
            $this->doc .= $this->entities[$entity];
718
        } else {
719
            $this->doc .= $this->_xmlEntities($entity);
720
        }
721
    }
722
723
    /**
724
     * Typographically format a multiply sign
725
     *
726
     * Example: ($x=640, $y=480) should result in "640×480"
727
     *
728
     * @param string|int $x first value
729
     * @param string|int $y second value
730
     */
731
    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...
732
        $this->doc .= "$x&times;$y";
733
    }
734
735
    /**
736
     * Render an opening single quote char (language specific)
737
     */
738
    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...
739
        global $lang;
740
        $this->doc .= $lang['singlequoteopening'];
741
    }
742
743
    /**
744
     * Render a closing single quote char (language specific)
745
     */
746
    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...
747
        global $lang;
748
        $this->doc .= $lang['singlequoteclosing'];
749
    }
750
751
    /**
752
     * Render an apostrophe char (language specific)
753
     */
754
    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...
755
        global $lang;
756
        $this->doc .= $lang['apostrophe'];
757
    }
758
759
    /**
760
     * Render an opening double quote char (language specific)
761
     */
762
    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...
763
        global $lang;
764
        $this->doc .= $lang['doublequoteopening'];
765
    }
766
767
    /**
768
     * Render an closinging double quote char (language specific)
769
     */
770
    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...
771
        global $lang;
772
        $this->doc .= $lang['doublequoteclosing'];
773
    }
774
775
    /**
776
     * Render a CamelCase link
777
     *
778
     * @param string $link       The link name
779
     * @param bool   $returnonly whether to return html or write to doc attribute
780
     * @return void|string writes to doc attribute or returns html depends on $returnonly
781
     *
782
     * @see http://en.wikipedia.org/wiki/CamelCase
783
     */
784
    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...
785
        if($returnonly) {
786
          return $this->internallink($link, $link, null, true);
787
        } else {
788
          $this->internallink($link, $link);
789
        }
790
    }
791
792
    /**
793
     * Render a page local link
794
     *
795
     * @param string $hash       hash link identifier
796
     * @param string $name       name for the link
797
     * @param bool   $returnonly whether to return html or write to doc attribute
798
     * @return void|string writes to doc attribute or returns html depends on $returnonly
799
     */
800
    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...
801
        global $ID;
802
        $name  = $this->_getLinkTitle($name, $hash, $isImage);
803
        $hash  = $this->_headerToLink($hash);
804
        $title = $ID.' ↵';
805
806
        $doc = '<a href="#'.$hash.'" title="'.$title.'" class="wikilink1">';
807
        $doc .= $name;
808
        $doc .= '</a>';
809
810
        if($returnonly) {
811
          return $doc;
812
        } else {
813
          $this->doc .= $doc;
814
        }
815
    }
816
817
    /**
818
     * Render an internal Wiki Link
819
     *
820
     * $search,$returnonly & $linktype are not for the renderer but are used
821
     * elsewhere - no need to implement them in other renderers
822
     *
823
     * @author Andreas Gohr <[email protected]>
824
     * @param string      $id         pageid
825
     * @param string|null $name       link name
826
     * @param string|null $search     adds search url param
827
     * @param bool        $returnonly whether to return html or write to doc attribute
828
     * @param string      $linktype   type to set use of headings
829
     * @return void|string writes to doc attribute or returns html depends on $returnonly
830
     */
831
    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...
832
        global $conf;
833
        global $ID;
834
        global $INFO;
835
836
        $params = '';
837
        $parts  = explode('?', $id, 2);
838
        if(count($parts) === 2) {
839
            $id     = $parts[0];
840
            $params = $parts[1];
841
        }
842
843
        // For empty $id we need to know the current $ID
844
        // We need this check because _simpleTitle needs
845
        // correct $id and resolve_pageid() use cleanID($id)
846
        // (some things could be lost)
847
        if($id === '') {
848
            $id = $ID;
849
        }
850
851
        // default name is based on $id as given
852
        $default = $this->_simpleTitle($id);
853
854
        // now first resolve and clean up the $id
855
        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...
856
857
        $link = array();
858
        $name = $this->_getLinkTitle($name, $default, $isImage, $id, $linktype);
859
        if(!$isImage) {
860
            if($exists) {
861
                $class = 'wikilink1';
862
            } else {
863
                $class       = 'wikilink2';
864
                $link['rel'] = 'nofollow';
865
            }
866
        } else {
867
            $class = 'media';
868
        }
869
870
        //keep hash anchor
871
        @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...
872
        if(!empty($hash)) $hash = $this->_headerToLink($hash);
873
874
        //prepare for formating
875
        $link['target'] = $conf['target']['wiki'];
876
        $link['style']  = '';
877
        $link['pre']    = '';
878
        $link['suf']    = '';
879
        // highlight link to current page
880
        if($id == $INFO['id']) {
881
            $link['pre'] = '<span class="curid">';
882
            $link['suf'] = '</span>';
883
        }
884
        $link['more']   = '';
885
        $link['class']  = $class;
886
        if($this->date_at) {
887
            $params['at'] = $this->date_at;
888
        }
889
        $link['url']    = wl($id, $params);
890
        $link['name']   = $name;
891
        $link['title']  = $id;
892
        //add search string
893
        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...
894
            ($conf['userewrite']) ? $link['url'] .= '?' : $link['url'] .= '&amp;';
895
            if(is_array($search)) {
896
                $search = array_map('rawurlencode', $search);
897
                $link['url'] .= 's[]='.join('&amp;s[]=', $search);
898
            } else {
899
                $link['url'] .= 's='.rawurlencode($search);
900
            }
901
        }
902
903
        //keep hash
904
        if($hash) $link['url'] .= '#'.$hash;
905
906
        //output formatted
907
        if($returnonly) {
908
            return $this->_formatLink($link);
909
        } else {
910
            $this->doc .= $this->_formatLink($link);
911
        }
912
    }
913
914
    /**
915
     * Render an external link
916
     *
917
     * @param string       $url        full URL with scheme
918
     * @param string|array $name       name for the link, array for media file
919
     * @param bool         $returnonly whether to return html or write to doc attribute
920
     * @return void|string writes to doc attribute or returns html depends on $returnonly
921
     */
922
    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...
923
        global $conf;
924
925
        $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...
926
927
        // url might be an attack vector, only allow registered protocols
928
        if(is_null($this->schemes)) $this->schemes = getSchemes();
929
        list($scheme) = explode('://', $url);
930
        $scheme = strtolower($scheme);
931
        if(!in_array($scheme, $this->schemes)) $url = '';
932
933
        // is there still an URL?
934
        if(!$url) {
935
            if($returnonly) {
936
                return $name;
937
            } else {
938
                $this->doc .= $name;
939
            }
940
            return;
941
        }
942
943
        // set class
944
        if(!$isImage) {
945
            $class = 'urlextern';
946
        } else {
947
            $class = 'media';
948
        }
949
950
        //prepare for formating
951
        $link = array();
952
        $link['target'] = $conf['target']['extern'];
953
        $link['style']  = '';
954
        $link['pre']    = '';
955
        $link['suf']    = '';
956
        $link['more']   = '';
957
        $link['class']  = $class;
958
        $link['url']    = $url;
959
        $link['rel']    = '';
960
961
        $link['name']  = $name;
962
        $link['title'] = $this->_xmlEntities($url);
963
        if($conf['relnofollow']) $link['rel'] .= ' nofollow';
964
        if($conf['target']['extern']) $link['rel'] .= ' noopener';
965
966
        //output formatted
967
        if($returnonly) {
968
            return $this->_formatLink($link);
969
        } else {
970
            $this->doc .= $this->_formatLink($link);
971
        }
972
    }
973
974
    /**
975
     * Render an interwiki link
976
     *
977
     * You may want to use $this->_resolveInterWiki() here
978
     *
979
     * @param string       $match      original link - probably not much use
980
     * @param string|array $name       name for the link, array for media file
981
     * @param string       $wikiName   indentifier (shortcut) for the remote wiki
982
     * @param string       $wikiUri    the fragment parsed from the original link
983
     * @param bool         $returnonly whether to return html or write to doc attribute
984
     * @return void|string writes to doc attribute or returns html depends on $returnonly
985
     */
986
    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...
987
        global $conf;
988
989
        $link           = array();
990
        $link['target'] = $conf['target']['interwiki'];
991
        $link['pre']    = '';
992
        $link['suf']    = '';
993
        $link['more']   = '';
994
        $link['name']   = $this->_getLinkTitle($name, $wikiUri, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 986 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...
995
        $link['rel']    = '';
996
997
        //get interwiki URL
998
        $exists = null;
999
        $url    = $this->_resolveInterWiki($wikiName, $wikiUri, $exists);
1000
1001
        if(!$isImage) {
1002
            $class         = preg_replace('/[^_\-a-z0-9]+/i', '_', $wikiName);
1003
            $link['class'] = "interwiki iw_$class";
1004
        } else {
1005
            $link['class'] = 'media';
1006
        }
1007
1008
        //do we stay at the same server? Use local target
1009
        if(strpos($url, DOKU_URL) === 0 OR strpos($url, DOKU_BASE) === 0) {
1010
            $link['target'] = $conf['target']['wiki'];
1011
        }
1012
        if($exists !== null && !$isImage) {
1013
            if($exists) {
1014
                $link['class'] .= ' wikilink1';
1015
            } else {
1016
                $link['class'] .= ' wikilink2';
1017
                $link['rel'] .= ' nofollow';
1018
            }
1019
        }
1020
        if($conf['target']['interwiki']) $link['rel'] .= ' noopener';
1021
1022
        $link['url']   = $url;
1023
        $link['title'] = htmlspecialchars($link['url']);
1024
1025
        //output formatted
1026
        if($returnonly) {
1027
            return $this->_formatLink($link);
1028
        } else {
1029
            $this->doc .= $this->_formatLink($link);
1030
        }
1031
    }
1032
1033
    /**
1034
     * Link to windows share
1035
     *
1036
     * @param string       $url        the link
1037
     * @param string|array $name       name for the link, array for media file
1038
     * @param bool         $returnonly whether to return html or write to doc attribute
1039
     * @return void|string writes to doc attribute or returns html depends on $returnonly
1040
     */
1041
    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...
1042
        global $conf;
1043
1044
        //simple setup
1045
        $link = array();
1046
        $link['target'] = $conf['target']['windows'];
1047
        $link['pre']    = '';
1048
        $link['suf']    = '';
1049
        $link['style']  = '';
1050
1051
        $link['name'] = $this->_getLinkTitle($name, $url, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 1041 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...
1052
        if(!$isImage) {
1053
            $link['class'] = 'windows';
1054
        } else {
1055
            $link['class'] = 'media';
1056
        }
1057
1058
        $link['title'] = $this->_xmlEntities($url);
1059
        $url           = str_replace('\\', '/', $url);
1060
        $url           = 'file:///'.$url;
1061
        $link['url']   = $url;
1062
1063
        //output formatted
1064
        if($returnonly) {
1065
            return $this->_formatLink($link);
1066
        } else {
1067
            $this->doc .= $this->_formatLink($link);
1068
        }
1069
    }
1070
1071
    /**
1072
     * Render a linked E-Mail Address
1073
     *
1074
     * Honors $conf['mailguard'] setting
1075
     *
1076
     * @param string       $address    Email-Address
1077
     * @param string|array $name       name for the link, array for media file
1078
     * @param bool         $returnonly whether to return html or write to doc attribute
1079
     * @return void|string writes to doc attribute or returns html depends on $returnonly
1080
     */
1081
    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...
1082
        global $conf;
1083
        //simple setup
1084
        $link           = array();
1085
        $link['target'] = '';
1086
        $link['pre']    = '';
1087
        $link['suf']    = '';
1088
        $link['style']  = '';
1089
        $link['more']   = '';
1090
1091
        $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...
1092
        if(!$isImage) {
1093
            $link['class'] = 'mail';
1094
        } else {
1095
            $link['class'] = 'media';
1096
        }
1097
1098
        $address = $this->_xmlEntities($address);
1099
        $address = obfuscate($address);
1100
        $title   = $address;
1101
1102
        if(empty($name)) {
1103
            $name = $address;
1104
        }
1105
1106
        if($conf['mailguard'] == 'visible') $address = rawurlencode($address);
1107
1108
        $link['url']   = 'mailto:'.$address;
1109
        $link['name']  = $name;
1110
        $link['title'] = $title;
1111
1112
        //output formatted
1113
        if($returnonly) {
1114
            return $this->_formatLink($link);
1115
        } else {
1116
            $this->doc .= $this->_formatLink($link);
1117
        }
1118
    }
1119
1120
    /**
1121
     * Render an internal media file
1122
     *
1123
     * @param string $src       media ID
1124
     * @param string $title     descriptive text
1125
     * @param string $align     left|center|right
1126
     * @param int    $width     width of media in pixel
1127
     * @param int    $height    height of media in pixel
1128
     * @param string $cache     cache|recache|nocache
1129
     * @param string $linking   linkonly|detail|nolink
1130
     * @param bool   $return    return HTML instead of adding to $doc
1131
     * @return void|string writes to doc attribute or returns html depends on $return
1132
     */
1133
    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...
1134
                           $height = null, $cache = null, $linking = null, $return = false) {
1135
        global $ID;
1136
        if (strpos($src, '#') !== false) {
1137
            list($src, $hash) = explode('#', $src, 2);
1138
        }
1139
        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...
1140
1141
        $noLink = false;
1142
        $render = ($linking == 'linkonly') ? false : true;
1143
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1144
1145
        list($ext, $mime) = mimetype($src, false);
1146
        if(substr($mime, 0, 5) == 'image' && $render) {
1147
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src)), ($linking == 'direct'));
1148
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1149
            // don't link movies
1150
            $noLink = true;
1151
        } else {
1152
            // add file icons
1153
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1154
            $link['class'] .= ' mediafile mf_'.$class;
1155
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache , 'rev'=>$this->_getLastMediaRevisionAt($src)), true);
1156
            if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')';
1157
        }
1158
1159
        if (!empty($hash)) $link['url'] .= '#'.$hash;
1160
1161
        //markup non existing files
1162
        if(!$exists) {
1163
            $link['class'] .= ' wikilink2';
1164
        }
1165
1166
        //output formatted
1167
        if($return) {
1168
            if($linking == 'nolink' || $noLink) return $link['name'];
1169
            else return $this->_formatLink($link);
1170
        } else {
1171
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1172
            else $this->doc .= $this->_formatLink($link);
1173
        }
1174
    }
1175
1176
    /**
1177
     * Render an external media file
1178
     *
1179
     * @param string $src     full media URL
1180
     * @param string $title   descriptive text
1181
     * @param string $align   left|center|right
1182
     * @param int    $width   width of media in pixel
1183
     * @param int    $height  height of media in pixel
1184
     * @param string $cache   cache|recache|nocache
1185
     * @param string $linking linkonly|detail|nolink
1186
     * @param bool   $return  return HTML instead of adding to $doc
1187
     * @return void|string writes to doc attribute or returns html depends on $return
1188
     */
1189
    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...
1190
                           $height = null, $cache = null, $linking = null, $return = false) {
1191
        if(link_isinterwiki($src)){
1192
            list($shortcut, $reference) = explode('>', $src, 2);
1193
            $exists = null;
1194
            $src = $this->_resolveInterWiki($shortcut, $reference, $exists);
1195
        }
1196
        list($src, $hash) = explode('#', $src, 2);
1197
        $noLink = false;
1198
        $render = ($linking == 'linkonly') ? false : true;
1199
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1200
1201
        $link['url'] = ml($src, array('cache' => $cache));
1202
1203
        list($ext, $mime) = mimetype($src, false);
1204
        if(substr($mime, 0, 5) == 'image' && $render) {
1205
            // link only jpeg images
1206
            // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true;
1207
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1208
            // don't link movies
1209
            $noLink = true;
1210
        } else {
1211
            // add file icons
1212
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1213
            $link['class'] .= ' mediafile mf_'.$class;
1214
        }
1215
1216
        if($hash) $link['url'] .= '#'.$hash;
1217
1218
        //output formatted
1219
        if($return) {
1220
            if($linking == 'nolink' || $noLink) return $link['name'];
1221
            else return $this->_formatLink($link);
1222
        } else {
1223
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1224
            else $this->doc .= $this->_formatLink($link);
1225
        }
1226
    }
1227
1228
    /**
1229
     * Renders an RSS feed
1230
     *
1231
     * @param string $url    URL of the feed
1232
     * @param array  $params Finetuning of the output
1233
     *
1234
     * @author Andreas Gohr <[email protected]>
1235
     */
1236
    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...
1237
        global $lang;
1238
        global $conf;
1239
1240
        require_once(DOKU_INC.'inc/FeedParser.php');
1241
        $feed = new FeedParser();
1242
        $feed->set_feed_url($url);
1243
1244
        //disable warning while fetching
1245
        if(!defined('DOKU_E_LEVEL')) {
1246
            $elvl = error_reporting(E_ERROR);
1247
        }
1248
        $rc = $feed->init();
1249
        if(isset($elvl)) {
1250
            error_reporting($elvl);
1251
        }
1252
1253
        if($params['nosort']) $feed->enable_order_by_date(false);
1254
1255
        //decide on start and end
1256
        if($params['reverse']) {
1257
            $mod   = -1;
1258
            $start = $feed->get_item_quantity() - 1;
1259
            $end   = $start - ($params['max']);
1260
            $end   = ($end < -1) ? -1 : $end;
1261
        } else {
1262
            $mod   = 1;
1263
            $start = 0;
1264
            $end   = $feed->get_item_quantity();
1265
            $end   = ($end > $params['max']) ? $params['max'] : $end;
1266
        }
1267
1268
        $this->doc .= '<ul class="rss">';
1269
        if($rc) {
1270
            for($x = $start; $x != $end; $x += $mod) {
1271
                $item = $feed->get_item($x);
1272
                $this->doc .= '<li><div class="li">';
1273
                // support feeds without links
1274
                $lnkurl = $item->get_permalink();
1275
                if($lnkurl) {
1276
                    // title is escaped by SimplePie, we unescape here because it
1277
                    // is escaped again in externallink() FS#1705
1278
                    $this->externallink(
1279
                        $item->get_permalink(),
1280
                        html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')
1281
                    );
1282
                } else {
1283
                    $this->doc .= ' '.$item->get_title();
1284
                }
1285
                if($params['author']) {
1286
                    $author = $item->get_author(0);
1287
                    if($author) {
1288
                        $name = $author->get_name();
1289
                        if(!$name) $name = $author->get_email();
1290
                        if($name) $this->doc .= ' '.$lang['by'].' '.$name;
1291
                    }
1292
                }
1293
                if($params['date']) {
1294
                    $this->doc .= ' ('.$item->get_local_date($conf['dformat']).')';
1295
                }
1296
                if($params['details']) {
1297
                    $this->doc .= '<div class="detail">';
1298
                    if($conf['htmlok']) {
1299
                        $this->doc .= $item->get_description();
1300
                    } else {
1301
                        $this->doc .= strip_tags($item->get_description());
1302
                    }
1303
                    $this->doc .= '</div>';
1304
                }
1305
1306
                $this->doc .= '</div></li>';
1307
            }
1308
        } else {
1309
            $this->doc .= '<li><div class="li">';
1310
            $this->doc .= '<em>'.$lang['rssfailed'].'</em>';
1311
            $this->externallink($url);
1312
            if($conf['allowdebug']) {
1313
                $this->doc .= '<!--'.hsc($feed->error).'-->';
1314
            }
1315
            $this->doc .= '</div></li>';
1316
        }
1317
        $this->doc .= '</ul>';
1318
    }
1319
1320
    /**
1321
     * Start a table
1322
     *
1323
     * @param int $maxcols maximum number of columns
1324
     * @param int $numrows NOT IMPLEMENTED
1325
     * @param int $pos byte position in the original source
1326
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1327
     */
1328
    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...
1329
        // initialize the row counter used for classes
1330
        $this->_counter['row_counter'] = 0;
1331
        $class                         = 'table';
1332
        if($classes !== null) {
1333
            if(is_array($classes)) $classes = join(' ', $classes);
1334
            $class .= ' ' . $classes;
1335
        }
1336
        if($pos !== null) {
1337
            $class .= ' '.$this->startSectionEdit($pos, 'table');
1338
        }
1339
        $this->doc .= '<div class="'.$class.'"><table class="inline">'.
1340
            DOKU_LF;
1341
    }
1342
1343
    /**
1344
     * Close a table
1345
     *
1346
     * @param int $pos byte position in the original source
1347
     */
1348
    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...
1349
        $this->doc .= '</table></div>'.DOKU_LF;
1350
        if($pos !== null) {
1351
            $this->finishSectionEdit($pos);
1352
        }
1353
    }
1354
1355
    /**
1356
     * Open a table header
1357
     */
1358
    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...
1359
        $this->doc .= DOKU_TAB.'<thead>'.DOKU_LF;
1360
    }
1361
1362
    /**
1363
     * Close a table header
1364
     */
1365
    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...
1366
        $this->doc .= DOKU_TAB.'</thead>'.DOKU_LF;
1367
    }
1368
1369
    /**
1370
     * Open a table body
1371
     */
1372
    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...
1373
        $this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF;
1374
    }
1375
1376
    /**
1377
     * Close a table body
1378
     */
1379
    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...
1380
        $this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF;
1381
    }
1382
1383
    /**
1384
     * Open a table footer
1385
     */
1386
    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...
1387
        $this->doc .= DOKU_TAB.'<tfoot>'.DOKU_LF;
1388
    }
1389
1390
    /**
1391
     * Close a table footer
1392
     */
1393
    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...
1394
        $this->doc .= DOKU_TAB.'</tfoot>'.DOKU_LF;
1395
    }
1396
1397
    /**
1398
     * Open a table row
1399
     *
1400
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1401
     */
1402
    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...
1403
        // initialize the cell counter used for classes
1404
        $this->_counter['cell_counter'] = 0;
1405
        $class                          = 'row'.$this->_counter['row_counter']++;
1406
        if($classes !== null) {
1407
            if(is_array($classes)) $classes = join(' ', $classes);
1408
            $class .= ' ' . $classes;
1409
        }
1410
        $this->doc .= DOKU_TAB.'<tr class="'.$class.'">'.DOKU_LF.DOKU_TAB.DOKU_TAB;
1411
    }
1412
1413
    /**
1414
     * Close a table row
1415
     */
1416
    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...
1417
        $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
1418
    }
1419
1420
    /**
1421
     * Open a table header cell
1422
     *
1423
     * @param int    $colspan
1424
     * @param string $align left|center|right
1425
     * @param int    $rowspan
1426
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1427
     */
1428
    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...
1429
        $class = 'class="col'.$this->_counter['cell_counter']++;
1430
        if(!is_null($align)) {
1431
            $class .= ' '.$align.'align';
1432
        }
1433
        if($classes !== null) {
1434
            if(is_array($classes)) $classes = join(' ', $classes);
1435
            $class .= ' ' . $classes;
1436
        }
1437
        $class .= '"';
1438
        $this->doc .= '<th '.$class;
1439
        if($colspan > 1) {
1440
            $this->_counter['cell_counter'] += $colspan - 1;
1441
            $this->doc .= ' colspan="'.$colspan.'"';
1442
        }
1443
        if($rowspan > 1) {
1444
            $this->doc .= ' rowspan="'.$rowspan.'"';
1445
        }
1446
        $this->doc .= '>';
1447
    }
1448
1449
    /**
1450
     * Close a table header cell
1451
     */
1452
    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...
1453
        $this->doc .= '</th>';
1454
    }
1455
1456
    /**
1457
     * Open a table cell
1458
     *
1459
     * @param int       $colspan
1460
     * @param string    $align left|center|right
1461
     * @param int       $rowspan
1462
     * @param string|string[]    $classes css classes - have to be valid, do not pass unfiltered user input
1463
     */
1464
    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...
1465
        $class = 'class="col'.$this->_counter['cell_counter']++;
1466
        if(!is_null($align)) {
1467
            $class .= ' '.$align.'align';
1468
        }
1469
        if($classes !== null) {
1470
            if(is_array($classes)) $classes = join(' ', $classes);
1471
            $class .= ' ' . $classes;
1472
        }
1473
        $class .= '"';
1474
        $this->doc .= '<td '.$class;
1475
        if($colspan > 1) {
1476
            $this->_counter['cell_counter'] += $colspan - 1;
1477
            $this->doc .= ' colspan="'.$colspan.'"';
1478
        }
1479
        if($rowspan > 1) {
1480
            $this->doc .= ' rowspan="'.$rowspan.'"';
1481
        }
1482
        $this->doc .= '>';
1483
    }
1484
1485
    /**
1486
     * Close a table cell
1487
     */
1488
    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...
1489
        $this->doc .= '</td>';
1490
    }
1491
1492
    /**
1493
     * Returns the current header level.
1494
     * (required e.g. by the filelist plugin)
1495
     *
1496
     * @return int The current header level
1497
     */
1498
    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...
1499
        return $this->lastlevel;
1500
    }
1501
1502
    #region Utility functions
1503
1504
    /**
1505
     * Build a link
1506
     *
1507
     * Assembles all parts defined in $link returns HTML for the link
1508
     *
1509
     * @param array $link attributes of a link
1510
     * @return string
1511
     *
1512
     * @author Andreas Gohr <[email protected]>
1513
     */
1514
    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...
1515
        //make sure the url is XHTML compliant (skip mailto)
1516
        if(substr($link['url'], 0, 7) != 'mailto:') {
1517
            $link['url'] = str_replace('&', '&amp;', $link['url']);
1518
            $link['url'] = str_replace('&amp;amp;', '&amp;', $link['url']);
1519
        }
1520
        //remove double encodings in titles
1521
        $link['title'] = str_replace('&amp;amp;', '&amp;', $link['title']);
1522
1523
        // be sure there are no bad chars in url or title
1524
        // (we can't do this for name because it can contain an img tag)
1525
        $link['url']   = strtr($link['url'], array('>' => '%3E', '<' => '%3C', '"' => '%22'));
1526
        $link['title'] = strtr($link['title'], array('>' => '&gt;', '<' => '&lt;', '"' => '&quot;'));
1527
1528
        $ret = '';
1529
        $ret .= $link['pre'];
1530
        $ret .= '<a href="'.$link['url'].'"';
1531
        if(!empty($link['class'])) $ret .= ' class="'.$link['class'].'"';
1532
        if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"';
1533
        if(!empty($link['title'])) $ret .= ' title="'.$link['title'].'"';
1534
        if(!empty($link['style'])) $ret .= ' style="'.$link['style'].'"';
1535
        if(!empty($link['rel'])) $ret .= ' rel="'.trim($link['rel']).'"';
1536
        if(!empty($link['more'])) $ret .= ' '.$link['more'];
1537
        $ret .= '>';
1538
        $ret .= $link['name'];
1539
        $ret .= '</a>';
1540
        $ret .= $link['suf'];
1541
        return $ret;
1542
    }
1543
1544
    /**
1545
     * Renders internal and external media
1546
     *
1547
     * @author Andreas Gohr <[email protected]>
1548
     * @param string $src       media ID
1549
     * @param string $title     descriptive text
1550
     * @param string $align     left|center|right
1551
     * @param int    $width     width of media in pixel
1552
     * @param int    $height    height of media in pixel
1553
     * @param string $cache     cache|recache|nocache
1554
     * @param bool   $render    should the media be embedded inline or just linked
1555
     * @return string
1556
     */
1557
    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...
1558
                    $height = null, $cache = null, $render = true) {
1559
1560
        $ret = '';
1561
1562
        list($ext, $mime) = mimetype($src);
1563
        if(substr($mime, 0, 5) == 'image') {
1564
            // first get the $title
1565
            if(!is_null($title)) {
1566
                $title = $this->_xmlEntities($title);
1567
            } elseif($ext == 'jpg' || $ext == 'jpeg') {
1568
                //try to use the caption from IPTC/EXIF
1569
                require_once(DOKU_INC.'inc/JpegMeta.php');
1570
                $jpeg = new JpegMeta(mediaFN($src));
1571
                if($jpeg !== false) $cap = $jpeg->getTitle();
1572
                if(!empty($cap)) {
1573
                    $title = $this->_xmlEntities($cap);
1574
                }
1575
            }
1576
            if(!$render) {
1577
                // if the picture is not supposed to be rendered
1578
                // return the title of the picture
1579
                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...
1580
                    // just show the sourcename
1581
                    $title = $this->_xmlEntities(utf8_basename(noNS($src)));
1582
                }
1583
                return $title;
1584
            }
1585
            //add image tag
1586
            $ret .= '<img src="'.ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src))).'"';
1587
            $ret .= ' class="media'.$align.'"';
1588
1589
            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...
1590
                $ret .= ' title="'.$title.'"';
1591
                $ret .= ' alt="'.$title.'"';
1592
            } else {
1593
                $ret .= ' alt=""';
1594
            }
1595
1596
            if(!is_null($width))
1597
                $ret .= ' width="'.$this->_xmlEntities($width).'"';
1598
1599
            if(!is_null($height))
1600
                $ret .= ' height="'.$this->_xmlEntities($height).'"';
1601
1602
            $ret .= ' />';
1603
1604
        } elseif(media_supportedav($mime, 'video') || media_supportedav($mime, 'audio')) {
1605
            // first get the $title
1606
            $title = !is_null($title) ? $this->_xmlEntities($title) : false;
1607
            if(!$render) {
1608
                // if the file is not supposed to be rendered
1609
                // return the title of the file (just the sourcename if there is no title)
1610
                return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src)));
1611
            }
1612
1613
            $att          = array();
1614
            $att['class'] = "media$align";
1615
            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...
1616
                $att['title'] = $title;
1617
            }
1618
1619
            if(media_supportedav($mime, 'video')) {
1620
                //add video
1621
                $ret .= $this->_video($src, $width, $height, $att);
1622
            }
1623
            if(media_supportedav($mime, 'audio')) {
1624
                //add audio
1625
                $ret .= $this->_audio($src, $att);
1626
            }
1627
1628
        } elseif($mime == 'application/x-shockwave-flash') {
1629
            if(!$render) {
1630
                // if the flash is not supposed to be rendered
1631
                // return the title of the flash
1632
                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...
1633
                    // just show the sourcename
1634
                    $title = utf8_basename(noNS($src));
1635
                }
1636
                return $this->_xmlEntities($title);
1637
            }
1638
1639
            $att          = array();
1640
            $att['class'] = "media$align";
1641
            if($align == 'right') $att['align'] = 'right';
1642
            if($align == 'left') $att['align'] = 'left';
1643
            $ret .= html_flashobject(
1644
                ml($src, array('cache' => $cache), true, '&'), $width, $height,
1645
                array('quality' => 'high'),
1646
                null,
1647
                $att,
1648
                $this->_xmlEntities($title)
1649
            );
1650
        } 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...
1651
            // well at least we have a title to display
1652
            $ret .= $this->_xmlEntities($title);
1653
        } else {
1654
            // just show the sourcename
1655
            $ret .= $this->_xmlEntities(utf8_basename(noNS($src)));
1656
        }
1657
1658
        return $ret;
1659
    }
1660
1661
    /**
1662
     * Escape string for output
1663
     *
1664
     * @param $string
1665
     * @return string
1666
     */
1667
    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...
1668
        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
1669
    }
1670
1671
    /**
1672
     * Creates a linkid from a headline
1673
     *
1674
     * @author Andreas Gohr <[email protected]>
1675
     * @param string  $title   The headline title
1676
     * @param boolean $create  Create a new unique ID?
1677
     * @return string
1678
     */
1679
    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...
1680
        if($create) {
1681
            return sectionID($title, $this->headers);
1682
        } else {
1683
            $check = false;
1684
            return sectionID($title, $check);
1685
        }
1686
    }
1687
1688
    /**
1689
     * Construct a title and handle images in titles
1690
     *
1691
     * @author Harry Fuecks <[email protected]>
1692
     * @param string|array $title    either string title or media array
1693
     * @param string       $default  default title if nothing else is found
1694
     * @param bool         $isImage  will be set to true if it's a media file
1695
     * @param null|string  $id       linked page id (used to extract title from first heading)
1696
     * @param string       $linktype content|navigation
1697
     * @return string      HTML of the title, might be full image tag or just escaped text
1698
     */
1699
    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...
1700
        $isImage = false;
1701
        if(is_array($title)) {
1702
            $isImage = true;
1703
            return $this->_imageTitle($title);
1704
        } elseif(is_null($title) || trim($title) == '') {
1705
            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...
1706
                $heading = p_get_first_heading($id);
1707
                if(!blank($heading)) {
1708
                    return $this->_xmlEntities($heading);
1709
                }
1710
            }
1711
            return $this->_xmlEntities($default);
1712
        } else {
1713
            return $this->_xmlEntities($title);
1714
        }
1715
    }
1716
1717
    /**
1718
     * Returns HTML code for images used in link titles
1719
     *
1720
     * @author Andreas Gohr <[email protected]>
1721
     * @param array $img
1722
     * @return string HTML img tag or similar
1723
     */
1724
    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...
1725
        global $ID;
1726
1727
        // some fixes on $img['src']
1728
        // see internalmedia() and externalmedia()
1729
        list($img['src']) = explode('#', $img['src'], 2);
1730
        if($img['type'] == 'internalmedia') {
1731
            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...
1732
        }
1733
1734
        return $this->_media(
1735
            $img['src'],
1736
            $img['title'],
1737
            $img['align'],
1738
            $img['width'],
1739
            $img['height'],
1740
            $img['cache']
1741
        );
1742
    }
1743
1744
    /**
1745
     * helperfunction to return a basic link to a media
1746
     *
1747
     * used in internalmedia() and externalmedia()
1748
     *
1749
     * @author   Pierre Spring <[email protected]>
1750
     * @param string $src       media ID
1751
     * @param string $title     descriptive text
1752
     * @param string $align     left|center|right
1753
     * @param int    $width     width of media in pixel
1754
     * @param int    $height    height of media in pixel
1755
     * @param string $cache     cache|recache|nocache
1756
     * @param bool   $render    should the media be embedded inline or just linked
1757
     * @return array associative array with link config
1758
     */
1759
    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...
1760
        global $conf;
1761
1762
        $link           = array();
1763
        $link['class']  = 'media';
1764
        $link['style']  = '';
1765
        $link['pre']    = '';
1766
        $link['suf']    = '';
1767
        $link['more']   = '';
1768
        $link['target'] = $conf['target']['media'];
1769
        if($conf['target']['media']) $link['rel'] = 'noopener';
1770
        $link['title']  = $this->_xmlEntities($src);
1771
        $link['name']   = $this->_media($src, $title, $align, $width, $height, $cache, $render);
1772
1773
        return $link;
1774
    }
1775
1776
    /**
1777
     * Embed video(s) in HTML
1778
     *
1779
     * @author Anika Henke <[email protected]>
1780
     *
1781
     * @param string $src         - ID of video to embed
1782
     * @param int    $width       - width of the video in pixels
1783
     * @param int    $height      - height of the video in pixels
1784
     * @param array  $atts        - additional attributes for the <video> tag
1785
     * @return string
1786
     */
1787
    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...
1788
        // prepare width and height
1789
        if(is_null($atts)) $atts = array();
1790
        $atts['width']  = (int) $width;
1791
        $atts['height'] = (int) $height;
1792
        if(!$atts['width']) $atts['width'] = 320;
1793
        if(!$atts['height']) $atts['height'] = 240;
1794
1795
        $posterUrl = '';
1796
        $files = array();
1797
        $isExternal = media_isexternal($src);
1798
1799
        if ($isExternal) {
1800
            // take direct source for external files
1801
            list(/*ext*/, $srcMime) = mimetype($src);
1802
            $files[$srcMime] = $src;
1803
        } else {
1804
            // prepare alternative formats
1805
            $extensions   = array('webm', 'ogv', 'mp4');
1806
            $files        = media_alternativefiles($src, $extensions);
1807
            $poster       = media_alternativefiles($src, array('jpg', 'png'));
1808
            if(!empty($poster)) {
1809
                $posterUrl = ml(reset($poster), '', true, '&');
1810
            }
1811
        }
1812
1813
        $out = '';
1814
        // open video tag
1815
        $out .= '<video '.buildAttributes($atts).' controls="controls"';
1816
        if($posterUrl) $out .= ' poster="'.hsc($posterUrl).'"';
1817
        $out .= '>'.NL;
1818
        $fallback = '';
1819
1820
        // output source for each alternative video format
1821
        foreach($files as $mime => $file) {
1822
            if ($isExternal) {
1823
                $url = $file;
1824
                $linkType = 'externalmedia';
1825
            } else {
1826
                $url = ml($file, '', true, '&');
1827
                $linkType = 'internalmedia';
1828
            }
1829
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1830
1831
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1832
            // alternative content (just a link to the file)
1833
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1834
        }
1835
1836
        // finish
1837
        $out .= $fallback;
1838
        $out .= '</video>'.NL;
1839
        return $out;
1840
    }
1841
1842
    /**
1843
     * Embed audio in HTML
1844
     *
1845
     * @author Anika Henke <[email protected]>
1846
     *
1847
     * @param string $src       - ID of audio to embed
1848
     * @param array  $atts      - additional attributes for the <audio> tag
1849
     * @return string
1850
     */
1851
    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...
1852
        $files = array();
1853
        $isExternal = media_isexternal($src);
1854
1855
        if ($isExternal) {
1856
            // take direct source for external files
1857
            list(/*ext*/, $srcMime) = mimetype($src);
1858
            $files[$srcMime] = $src;
1859
        } else {
1860
            // prepare alternative formats
1861
            $extensions   = array('ogg', 'mp3', 'wav');
1862
            $files        = media_alternativefiles($src, $extensions);
1863
        }
1864
1865
        $out = '';
1866
        // open audio tag
1867
        $out .= '<audio '.buildAttributes($atts).' controls="controls">'.NL;
1868
        $fallback = '';
1869
1870
        // output source for each alternative audio format
1871
        foreach($files as $mime => $file) {
1872
            if ($isExternal) {
1873
                $url = $file;
1874
                $linkType = 'externalmedia';
1875
            } else {
1876
                $url = ml($file, '', true, '&');
1877
                $linkType = 'internalmedia';
1878
            }
1879
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1880
1881
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1882
            // alternative content (just a link to the file)
1883
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1884
        }
1885
1886
        // finish
1887
        $out .= $fallback;
1888
        $out .= '</audio>'.NL;
1889
        return $out;
1890
    }
1891
1892
    /**
1893
     * _getLastMediaRevisionAt is a helperfunction to internalmedia() and _media()
1894
     * which returns an existing media revision less or equal to rev or date_at
1895
     *
1896
     * @author lisps
1897
     * @param string $media_id
1898
     * @access protected
1899
     * @return string revision ('' for current)
1900
     */
1901
    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...
1902
        if(!$this->date_at || media_isexternal($media_id)) return '';
1903
        $pagelog = new MediaChangeLog($media_id);
1904
        return $pagelog->getLastRevisionAt($this->date_at);
1905
    }
1906
1907
    #endregion
1908
}
1909
1910
//Setup VIM: ex: et ts=4 :
1911