Completed
Push — remoteapiGetversions ( 33fe8b...b2f4ab )
by Gerrit
12s
created

Doku_Renderer_xhtml::internallink()   F

Complexity

Conditions 13
Paths 1920

Size

Total Lines 82
Code Lines 51

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 82
rs 2
cc 13
eloc 51
nc 1920
nop 5

How to fix   Long Method    Complexity   

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:

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 .= $footnote;
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(!$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
    function listu_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...
432
        $this->doc .= '<ul>'.DOKU_LF;
433
    }
434
435
    /**
436
     * Close an unordered list
437
     */
438
    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...
439
        $this->doc .= '</ul>'.DOKU_LF;
440
    }
441
442
    /**
443
     * Open an ordered list
444
     */
445
    function listo_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...
446
        $this->doc .= '<ol>'.DOKU_LF;
447
    }
448
449
    /**
450
     * Close an ordered list
451
     */
452
    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...
453
        $this->doc .= '</ol>'.DOKU_LF;
454
    }
455
456
    /**
457
     * Open a list item
458
     *
459
     * @param int $level the nesting level
460
     * @param bool $node true when a node; false when a leaf
461
     */
462
    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...
463
        $branching = $node ? ' node' : '';
464
        $this->doc .= '<li class="level'.$level.$branching.'">';
465
    }
466
467
    /**
468
     * Close a list item
469
     */
470
    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...
471
        $this->doc .= '</li>'.DOKU_LF;
472
    }
473
474
    /**
475
     * Start the content of a list item
476
     */
477
    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...
478
        $this->doc .= '<div class="li">';
479
    }
480
481
    /**
482
     * Stop the content of a list item
483
     */
484
    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...
485
        $this->doc .= '</div>'.DOKU_LF;
486
    }
487
488
    /**
489
     * Output unformatted $text
490
     *
491
     * Defaults to $this->cdata()
492
     *
493
     * @param string $text
494
     */
495
    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...
496
        $this->doc .= $this->_xmlEntities($text);
497
    }
498
499
    /**
500
     * Execute PHP code if allowed
501
     *
502
     * @param  string $text      PHP code that is either executed or printed
503
     * @param  string $wrapper   html element to wrap result if $conf['phpok'] is okff
504
     *
505
     * @author Andreas Gohr <[email protected]>
506
     */
507
    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...
508
        global $conf;
509
510
        if($conf['phpok']) {
511
            ob_start();
512
            eval($text);
513
            $this->doc .= ob_get_contents();
514
            ob_end_clean();
515
        } else {
516
            $this->doc .= p_xhtml_cached_geshi($text, 'php', $wrapper);
517
        }
518
    }
519
520
    /**
521
     * Output block level PHP code
522
     *
523
     * If $conf['phpok'] is true this should evaluate the given code and append the result
524
     * to $doc
525
     *
526
     * @param string $text The PHP code
527
     */
528
    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...
529
        $this->php($text, 'pre');
530
    }
531
532
    /**
533
     * Insert HTML if allowed
534
     *
535
     * @param  string $text      html text
536
     * @param  string $wrapper   html element to wrap result if $conf['htmlok'] is okff
537
     *
538
     * @author Andreas Gohr <[email protected]>
539
     */
540
    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...
541
        global $conf;
542
543
        if($conf['htmlok']) {
544
            $this->doc .= $text;
545
        } else {
546
            $this->doc .= p_xhtml_cached_geshi($text, 'html4strict', $wrapper);
547
        }
548
    }
549
550
    /**
551
     * Output raw block-level HTML
552
     *
553
     * If $conf['htmlok'] is true this should add the code as is to $doc
554
     *
555
     * @param string $text The HTML
556
     */
557
    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...
558
        $this->html($text, 'pre');
559
    }
560
561
    /**
562
     * Start a block quote
563
     */
564
    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...
565
        $this->doc .= '<blockquote><div class="no">'.DOKU_LF;
566
    }
567
568
    /**
569
     * Stop a block quote
570
     */
571
    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...
572
        $this->doc .= '</div></blockquote>'.DOKU_LF;
573
    }
574
575
    /**
576
     * Output preformatted text
577
     *
578
     * @param string $text
579
     */
580
    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...
581
        $this->doc .= '<pre class="code">'.trim($this->_xmlEntities($text), "\n\r").'</pre>'.DOKU_LF;
582
    }
583
584
    /**
585
     * Display text as file content, optionally syntax highlighted
586
     *
587
     * @param string $text     text to show
588
     * @param string $language programming language to use for syntax highlighting
589
     * @param string $filename file path label
590
     */
591
    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...
592
        $this->_highlight('file', $text, $language, $filename);
593
    }
594
595
    /**
596
     * Display text as code content, optionally syntax highlighted
597
     *
598
     * @param string $text     text to show
599
     * @param string $language programming language to use for syntax highlighting
600
     * @param string $filename file path label
601
     */
602
    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...
603
        $this->_highlight('code', $text, $language, $filename);
604
    }
605
606
    /**
607
     * Use GeSHi to highlight language syntax in code and file blocks
608
     *
609
     * @author Andreas Gohr <[email protected]>
610
     * @param string $type     code|file
611
     * @param string $text     text to show
612
     * @param string $language programming language to use for syntax highlighting
613
     * @param string $filename file path label
614
     */
615
    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...
616
        global $ID;
617
        global $lang;
618
619
        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...
620
            // add icon
621
            list($ext) = mimetype($filename, false);
622
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
623
            $class = 'mediafile mf_'.$class;
624
625
            $this->doc .= '<dl class="'.$type.'">'.DOKU_LF;
626
            $this->doc .= '<dt><a href="'.exportlink($ID, 'code', array('codeblock' => $this->_codeblock)).'" title="'.$lang['download'].'" class="'.$class.'">';
627
            $this->doc .= hsc($filename);
628
            $this->doc .= '</a></dt>'.DOKU_LF.'<dd>';
629
        }
630
631
        if($text{0} == "\n") {
632
            $text = substr($text, 1);
633
        }
634
        if(substr($text, -1) == "\n") {
635
            $text = substr($text, 0, -1);
636
        }
637
638
        if(is_null($language)) {
639
            $this->doc .= '<pre class="'.$type.'">'.$this->_xmlEntities($text).'</pre>'.DOKU_LF;
640
        } else {
641
            $class = 'code'; //we always need the code class to make the syntax highlighting apply
642
            if($type != 'code') $class .= ' '.$type;
643
644
            $this->doc .= "<pre class=\"$class $language\">".p_xhtml_cached_geshi($text, $language, '').'</pre>'.DOKU_LF;
645
        }
646
647
        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...
648
            $this->doc .= '</dd></dl>'.DOKU_LF;
649
        }
650
651
        $this->_codeblock++;
652
    }
653
654
    /**
655
     * Format an acronym
656
     *
657
     * Uses $this->acronyms
658
     *
659
     * @param string $acronym
660
     */
661
    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...
662
663
        if(array_key_exists($acronym, $this->acronyms)) {
664
665
            $title = $this->_xmlEntities($this->acronyms[$acronym]);
666
667
            $this->doc .= '<abbr title="'.$title
668
                .'">'.$this->_xmlEntities($acronym).'</abbr>';
669
670
        } else {
671
            $this->doc .= $this->_xmlEntities($acronym);
672
        }
673
    }
674
675
    /**
676
     * Format a smiley
677
     *
678
     * Uses $this->smiley
679
     *
680
     * @param string $smiley
681
     */
682
    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...
683
        if(array_key_exists($smiley, $this->smileys)) {
684
            $this->doc .= '<img src="'.DOKU_BASE.'lib/images/smileys/'.$this->smileys[$smiley].
685
                '" class="icon" alt="'.
686
                $this->_xmlEntities($smiley).'" />';
687
        } else {
688
            $this->doc .= $this->_xmlEntities($smiley);
689
        }
690
    }
691
692
    /**
693
     * Format an entity
694
     *
695
     * Entities are basically small text replacements
696
     *
697
     * Uses $this->entities
698
     *
699
     * @param string $entity
700
     */
701
    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...
702
        if(array_key_exists($entity, $this->entities)) {
703
            $this->doc .= $this->entities[$entity];
704
        } else {
705
            $this->doc .= $this->_xmlEntities($entity);
706
        }
707
    }
708
709
    /**
710
     * Typographically format a multiply sign
711
     *
712
     * Example: ($x=640, $y=480) should result in "640×480"
713
     *
714
     * @param string|int $x first value
715
     * @param string|int $y second value
716
     */
717
    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...
718
        $this->doc .= "$x&times;$y";
719
    }
720
721
    /**
722
     * Render an opening single quote char (language specific)
723
     */
724
    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...
725
        global $lang;
726
        $this->doc .= $lang['singlequoteopening'];
727
    }
728
729
    /**
730
     * Render a closing single quote char (language specific)
731
     */
732
    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...
733
        global $lang;
734
        $this->doc .= $lang['singlequoteclosing'];
735
    }
736
737
    /**
738
     * Render an apostrophe char (language specific)
739
     */
740
    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...
741
        global $lang;
742
        $this->doc .= $lang['apostrophe'];
743
    }
744
745
    /**
746
     * Render an opening double quote char (language specific)
747
     */
748
    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...
749
        global $lang;
750
        $this->doc .= $lang['doublequoteopening'];
751
    }
752
753
    /**
754
     * Render an closinging double quote char (language specific)
755
     */
756
    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...
757
        global $lang;
758
        $this->doc .= $lang['doublequoteclosing'];
759
    }
760
761
    /**
762
     * Render a CamelCase link
763
     *
764
     * @param string $link       The link name
765
     * @param bool   $returnonly whether to return html or write to doc attribute
766
     * @see http://en.wikipedia.org/wiki/CamelCase
767
     */
768
    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...
769
        if($returnonly) {
770
          return $this->internallink($link, $link, null, true);
771
        } else {
772
          $this->internallink($link, $link);
773
        }
774
    }
775
776
    /**
777
     * Render a page local link
778
     *
779
     * @param string $hash       hash link identifier
780
     * @param string $name       name for the link
781
     * @param bool   $returnonly whether to return html or write to doc attribute
782
     */
783
    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...
784
        global $ID;
785
        $name  = $this->_getLinkTitle($name, $hash, $isImage);
786
        $hash  = $this->_headerToLink($hash);
787
        $title = $ID.' ↵';
788
789
        $doc = '<a href="#'.$hash.'" title="'.$title.'" class="wikilink1">';
790
        $doc .= $name;
791
        $doc .= '</a>';
792
793
        if($returnonly) {
794
          return $doc;
795
        } else {
796
          $this->doc .= $doc;
797
        }
798
    }
799
800
    /**
801
     * Render an internal Wiki Link
802
     *
803
     * $search,$returnonly & $linktype are not for the renderer but are used
804
     * elsewhere - no need to implement them in other renderers
805
     *
806
     * @author Andreas Gohr <[email protected]>
807
     * @param string      $id         pageid
808
     * @param string|null $name       link name
809
     * @param string|null $search     adds search url param
810
     * @param bool        $returnonly whether to return html or write to doc attribute
811
     * @param string      $linktype   type to set use of headings
812
     * @return void|string writes to doc attribute or returns html depends on $returnonly
813
     */
814
    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...
815
        global $conf;
816
        global $ID;
817
        global $INFO;
818
819
        $params = '';
820
        $parts  = explode('?', $id, 2);
821
        if(count($parts) === 2) {
822
            $id     = $parts[0];
823
            $params = $parts[1];
824
        }
825
826
        // For empty $id we need to know the current $ID
827
        // We need this check because _simpleTitle needs
828
        // correct $id and resolve_pageid() use cleanID($id)
829
        // (some things could be lost)
830
        if($id === '') {
831
            $id = $ID;
832
        }
833
834
        // default name is based on $id as given
835
        $default = $this->_simpleTitle($id);
836
837
        // now first resolve and clean up the $id
838
        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...
839
840
        $link = array();
841
        $name = $this->_getLinkTitle($name, $default, $isImage, $id, $linktype);
842
        if(!$isImage) {
843
            if($exists) {
844
                $class = 'wikilink1';
845
            } else {
846
                $class       = 'wikilink2';
847
                $link['rel'] = 'nofollow';
848
            }
849
        } else {
850
            $class = 'media';
851
        }
852
853
        //keep hash anchor
854
        @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...
855
        if(!empty($hash)) $hash = $this->_headerToLink($hash);
856
857
        //prepare for formating
858
        $link['target'] = $conf['target']['wiki'];
859
        $link['style']  = '';
860
        $link['pre']    = '';
861
        $link['suf']    = '';
862
        // highlight link to current page
863
        if($id == $INFO['id']) {
864
            $link['pre'] = '<span class="curid">';
865
            $link['suf'] = '</span>';
866
        }
867
        $link['more']   = '';
868
        $link['class']  = $class;
869
        if($this->date_at) {
870
            $params['at'] = $this->date_at;
871
        }
872
        $link['url']    = wl($id, $params);
873
        $link['name']   = $name;
874
        $link['title']  = $id;
875
        //add search string
876
        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...
877
            ($conf['userewrite']) ? $link['url'] .= '?' : $link['url'] .= '&amp;';
878
            if(is_array($search)) {
879
                $search = array_map('rawurlencode', $search);
880
                $link['url'] .= 's[]='.join('&amp;s[]=', $search);
881
            } else {
882
                $link['url'] .= 's='.rawurlencode($search);
883
            }
884
        }
885
886
        //keep hash
887
        if($hash) $link['url'] .= '#'.$hash;
888
889
        //output formatted
890
        if($returnonly) {
891
            return $this->_formatLink($link);
892
        } else {
893
            $this->doc .= $this->_formatLink($link);
894
        }
895
    }
896
897
    /**
898
     * Render an external link
899
     *
900
     * @param string       $url        full URL with scheme
901
     * @param string|array $name       name for the link, array for media file
902
     * @param bool         $returnonly whether to return html or write to doc attribute
903
     */
904
    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...
905
        global $conf;
906
907
        $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...
908
909
        // url might be an attack vector, only allow registered protocols
910
        if(is_null($this->schemes)) $this->schemes = getSchemes();
911
        list($scheme) = explode('://', $url);
912
        $scheme = strtolower($scheme);
913
        if(!in_array($scheme, $this->schemes)) $url = '';
914
915
        // is there still an URL?
916
        if(!$url) {
917
            if($returnonly) {
918
                return $name;
919
            } else {
920
                $this->doc .= $name;
921
            }
922
            return;
923
        }
924
925
        // set class
926
        if(!$isImage) {
927
            $class = 'urlextern';
928
        } else {
929
            $class = 'media';
930
        }
931
932
        //prepare for formating
933
        $link = array();
934
        $link['target'] = $conf['target']['extern'];
935
        $link['style']  = '';
936
        $link['pre']    = '';
937
        $link['suf']    = '';
938
        $link['more']   = '';
939
        $link['class']  = $class;
940
        $link['url']    = $url;
941
        $link['rel']    = '';
942
943
        $link['name']  = $name;
944
        $link['title'] = $this->_xmlEntities($url);
945
        if($conf['relnofollow']) $link['rel'] .= ' nofollow';
946
        if($conf['target']['extern']) $link['rel'] .= ' noopener';
947
948
        //output formatted
949
        if($returnonly) {
950
            return $this->_formatLink($link);
951
        } else {
952
            $this->doc .= $this->_formatLink($link);
953
        }
954
    }
955
956
    /**
957
     * Render an interwiki link
958
     *
959
     * You may want to use $this->_resolveInterWiki() here
960
     *
961
     * @param string       $match      original link - probably not much use
962
     * @param string|array $name       name for the link, array for media file
963
     * @param string       $wikiName   indentifier (shortcut) for the remote wiki
964
     * @param string       $wikiUri    the fragment parsed from the original link
965
     * @param bool         $returnonly whether to return html or write to doc attribute
966
     */
967
    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...
968
        global $conf;
969
970
        $link           = array();
971
        $link['target'] = $conf['target']['interwiki'];
972
        $link['pre']    = '';
973
        $link['suf']    = '';
974
        $link['more']   = '';
975
        $link['name']   = $this->_getLinkTitle($name, $wikiUri, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 967 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...
976
        $link['rel']    = '';
977
978
        //get interwiki URL
979
        $exists = null;
980
        $url    = $this->_resolveInterWiki($wikiName, $wikiUri, $exists);
981
982
        if(!$isImage) {
983
            $class         = preg_replace('/[^_\-a-z0-9]+/i', '_', $wikiName);
984
            $link['class'] = "interwiki iw_$class";
985
        } else {
986
            $link['class'] = 'media';
987
        }
988
989
        //do we stay at the same server? Use local target
990
        if(strpos($url, DOKU_URL) === 0 OR strpos($url, DOKU_BASE) === 0) {
991
            $link['target'] = $conf['target']['wiki'];
992
        }
993
        if($exists !== null && !$isImage) {
994
            if($exists) {
995
                $link['class'] .= ' wikilink1';
996
            } else {
997
                $link['class'] .= ' wikilink2';
998
                $link['rel'] .= ' nofollow';
999
            }
1000
        }
1001
        if($conf['target']['interwiki']) $link['rel'] .= ' noopener';
1002
1003
        $link['url']   = $url;
1004
        $link['title'] = htmlspecialchars($link['url']);
1005
1006
        //output formatted
1007
        if($returnonly) {
1008
            return $this->_formatLink($link);
1009
        } else {
1010
            $this->doc .= $this->_formatLink($link);
1011
        }
1012
    }
1013
1014
    /**
1015
     * Link to windows share
1016
     *
1017
     * @param string       $url        the link
1018
     * @param string|array $name       name for the link, array for media file
1019
     * @param bool         $returnonly whether to return html or write to doc attribute
1020
     */
1021
    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...
1022
        global $conf;
1023
1024
        //simple setup
1025
        $link = array();
1026
        $link['target'] = $conf['target']['windows'];
1027
        $link['pre']    = '';
1028
        $link['suf']    = '';
1029
        $link['style']  = '';
1030
1031
        $link['name'] = $this->_getLinkTitle($name, $url, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 1021 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...
1032
        if(!$isImage) {
1033
            $link['class'] = 'windows';
1034
        } else {
1035
            $link['class'] = 'media';
1036
        }
1037
1038
        $link['title'] = $this->_xmlEntities($url);
1039
        $url           = str_replace('\\', '/', $url);
1040
        $url           = 'file:///'.$url;
1041
        $link['url']   = $url;
1042
1043
        //output formatted
1044
        if($returnonly) {
1045
            return $this->_formatLink($link);
1046
        } else {
1047
            $this->doc .= $this->_formatLink($link);
1048
        }
1049
    }
1050
1051
    /**
1052
     * Render a linked E-Mail Address
1053
     *
1054
     * Honors $conf['mailguard'] setting
1055
     *
1056
     * @param string       $address    Email-Address
1057
     * @param string|array $name       name for the link, array for media file
1058
     * @param bool         $returnonly whether to return html or write to doc attribute
1059
     */
1060
    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...
1061
        global $conf;
1062
        //simple setup
1063
        $link           = array();
1064
        $link['target'] = '';
1065
        $link['pre']    = '';
1066
        $link['suf']    = '';
1067
        $link['style']  = '';
1068
        $link['more']   = '';
1069
1070
        $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...
1071
        if(!$isImage) {
1072
            $link['class'] = 'mail';
1073
        } else {
1074
            $link['class'] = 'media';
1075
        }
1076
1077
        $address = $this->_xmlEntities($address);
1078
        $address = obfuscate($address);
1079
        $title   = $address;
1080
1081
        if(empty($name)) {
1082
            $name = $address;
1083
        }
1084
1085
        if($conf['mailguard'] == 'visible') $address = rawurlencode($address);
1086
1087
        $link['url']   = 'mailto:'.$address;
1088
        $link['name']  = $name;
1089
        $link['title'] = $title;
1090
1091
        //output formatted
1092
        if($returnonly) {
1093
            return $this->_formatLink($link);
1094
        } else {
1095
            $this->doc .= $this->_formatLink($link);
1096
        }
1097
    }
1098
1099
    /**
1100
     * Render an internal media file
1101
     *
1102
     * @param string $src       media ID
1103
     * @param string $title     descriptive text
1104
     * @param string $align     left|center|right
1105
     * @param int    $width     width of media in pixel
1106
     * @param int    $height    height of media in pixel
1107
     * @param string $cache     cache|recache|nocache
1108
     * @param string $linking   linkonly|detail|nolink
1109
     * @param bool   $return    return HTML instead of adding to $doc
1110
     * @return void|string
1111
     */
1112
    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...
1113
                           $height = null, $cache = null, $linking = null, $return = false) {
1114
        global $ID;
1115
        list($src, $hash) = explode('#', $src, 2);
1116
        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...
1117
1118
        $noLink = false;
1119
        $render = ($linking == 'linkonly') ? false : true;
1120
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1121
1122
        list($ext, $mime) = mimetype($src, false);
1123
        if(substr($mime, 0, 5) == 'image' && $render) {
1124
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src)), ($linking == 'direct'));
1125
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1126
            // don't link movies
1127
            $noLink = true;
1128
        } else {
1129
            // add file icons
1130
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1131
            $link['class'] .= ' mediafile mf_'.$class;
1132
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache , 'rev'=>$this->_getLastMediaRevisionAt($src)), true);
1133
            if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')';
1134
        }
1135
1136
        if($hash) $link['url'] .= '#'.$hash;
1137
1138
        //markup non existing files
1139
        if(!$exists) {
1140
            $link['class'] .= ' wikilink2';
1141
        }
1142
1143
        //output formatted
1144
        if($return) {
1145
            if($linking == 'nolink' || $noLink) return $link['name'];
1146
            else return $this->_formatLink($link);
1147
        } else {
1148
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1149
            else $this->doc .= $this->_formatLink($link);
1150
        }
1151
    }
1152
1153
    /**
1154
     * Render an external media file
1155
     *
1156
     * @param string $src     full media URL
1157
     * @param string $title   descriptive text
1158
     * @param string $align   left|center|right
1159
     * @param int    $width   width of media in pixel
1160
     * @param int    $height  height of media in pixel
1161
     * @param string $cache   cache|recache|nocache
1162
     * @param string $linking linkonly|detail|nolink
1163
     * @param bool   $return  return HTML instead of adding to $doc
1164
     */
1165
    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...
1166
                           $height = null, $cache = null, $linking = null, $return = false) {
1167
        list($src, $hash) = explode('#', $src, 2);
1168
        $noLink = false;
1169
        $render = ($linking == 'linkonly') ? false : true;
1170
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1171
1172
        $link['url'] = ml($src, array('cache' => $cache));
1173
1174
        list($ext, $mime) = mimetype($src, false);
1175
        if(substr($mime, 0, 5) == 'image' && $render) {
1176
            // link only jpeg images
1177
            // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true;
1178
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1179
            // don't link movies
1180
            $noLink = true;
1181
        } else {
1182
            // add file icons
1183
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1184
            $link['class'] .= ' mediafile mf_'.$class;
1185
        }
1186
1187
        if($hash) $link['url'] .= '#'.$hash;
1188
1189
        //output formatted
1190
        if($return) {
1191
            if($linking == 'nolink' || $noLink) return $link['name'];
1192
            else return $this->_formatLink($link);
1193
        } else {
1194
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1195
            else $this->doc .= $this->_formatLink($link);
1196
        }
1197
    }
1198
1199
    /**
1200
     * Renders an RSS feed
1201
     *
1202
     * @author Andreas Gohr <[email protected]>
1203
     */
1204
    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...
1205
        global $lang;
1206
        global $conf;
1207
1208
        require_once(DOKU_INC.'inc/FeedParser.php');
1209
        $feed = new FeedParser();
1210
        $feed->set_feed_url($url);
1211
1212
        //disable warning while fetching
1213
        if(!defined('DOKU_E_LEVEL')) {
1214
            $elvl = error_reporting(E_ERROR);
1215
        }
1216
        $rc = $feed->init();
1217
        if(isset($elvl)) {
1218
            error_reporting($elvl);
1219
        }
1220
1221
        if($params['nosort']) $feed->enable_order_by_date(false);
1222
1223
        //decide on start and end
1224
        if($params['reverse']) {
1225
            $mod   = -1;
1226
            $start = $feed->get_item_quantity() - 1;
1227
            $end   = $start - ($params['max']);
1228
            $end   = ($end < -1) ? -1 : $end;
1229
        } else {
1230
            $mod   = 1;
1231
            $start = 0;
1232
            $end   = $feed->get_item_quantity();
1233
            $end   = ($end > $params['max']) ? $params['max'] : $end;
1234
        }
1235
1236
        $this->doc .= '<ul class="rss">';
1237
        if($rc) {
1238
            for($x = $start; $x != $end; $x += $mod) {
1239
                $item = $feed->get_item($x);
1240
                $this->doc .= '<li><div class="li">';
1241
                // support feeds without links
1242
                $lnkurl = $item->get_permalink();
1243
                if($lnkurl) {
1244
                    // title is escaped by SimplePie, we unescape here because it
1245
                    // is escaped again in externallink() FS#1705
1246
                    $this->externallink(
1247
                        $item->get_permalink(),
1248
                        html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')
1249
                    );
1250
                } else {
1251
                    $this->doc .= ' '.$item->get_title();
1252
                }
1253
                if($params['author']) {
1254
                    $author = $item->get_author(0);
1255
                    if($author) {
1256
                        $name = $author->get_name();
1257
                        if(!$name) $name = $author->get_email();
1258
                        if($name) $this->doc .= ' '.$lang['by'].' '.$name;
1259
                    }
1260
                }
1261
                if($params['date']) {
1262
                    $this->doc .= ' ('.$item->get_local_date($conf['dformat']).')';
1263
                }
1264
                if($params['details']) {
1265
                    $this->doc .= '<div class="detail">';
1266
                    if($conf['htmlok']) {
1267
                        $this->doc .= $item->get_description();
1268
                    } else {
1269
                        $this->doc .= strip_tags($item->get_description());
1270
                    }
1271
                    $this->doc .= '</div>';
1272
                }
1273
1274
                $this->doc .= '</div></li>';
1275
            }
1276
        } else {
1277
            $this->doc .= '<li><div class="li">';
1278
            $this->doc .= '<em>'.$lang['rssfailed'].'</em>';
1279
            $this->externallink($url);
1280
            if($conf['allowdebug']) {
1281
                $this->doc .= '<!--'.hsc($feed->error).'-->';
1282
            }
1283
            $this->doc .= '</div></li>';
1284
        }
1285
        $this->doc .= '</ul>';
1286
    }
1287
1288
    /**
1289
     * Start a table
1290
     *
1291
     * @param int $maxcols maximum number of columns
1292
     * @param int $numrows NOT IMPLEMENTED
1293
     * @param int $pos     byte position in the original source
1294
     */
1295
    function table_open($maxcols = null, $numrows = null, $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...
1296
        // initialize the row counter used for classes
1297
        $this->_counter['row_counter'] = 0;
1298
        $class                         = 'table';
1299
        if($pos !== null) {
1300
            $class .= ' '.$this->startSectionEdit($pos, 'table');
1301
        }
1302
        $this->doc .= '<div class="'.$class.'"><table class="inline">'.
1303
            DOKU_LF;
1304
    }
1305
1306
    /**
1307
     * Close a table
1308
     *
1309
     * @param int $pos byte position in the original source
1310
     */
1311
    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...
1312
        $this->doc .= '</table></div>'.DOKU_LF;
1313
        if($pos !== null) {
1314
            $this->finishSectionEdit($pos);
1315
        }
1316
    }
1317
1318
    /**
1319
     * Open a table header
1320
     */
1321
    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...
1322
        $this->doc .= DOKU_TAB.'<thead>'.DOKU_LF;
1323
    }
1324
1325
    /**
1326
     * Close a table header
1327
     */
1328
    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...
1329
        $this->doc .= DOKU_TAB.'</thead>'.DOKU_LF;
1330
    }
1331
1332
    /**
1333
     * Open a table body
1334
     */
1335
    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...
1336
        $this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF;
1337
    }
1338
1339
    /**
1340
     * Close a table body
1341
     */
1342
    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...
1343
        $this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF;
1344
    }
1345
1346
    /**
1347
     * Open a table row
1348
     */
1349
    function tablerow_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...
1350
        // initialize the cell counter used for classes
1351
        $this->_counter['cell_counter'] = 0;
1352
        $class                          = 'row'.$this->_counter['row_counter']++;
1353
        $this->doc .= DOKU_TAB.'<tr class="'.$class.'">'.DOKU_LF.DOKU_TAB.DOKU_TAB;
1354
    }
1355
1356
    /**
1357
     * Close a table row
1358
     */
1359
    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...
1360
        $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
1361
    }
1362
1363
    /**
1364
     * Open a table header cell
1365
     *
1366
     * @param int    $colspan
1367
     * @param string $align left|center|right
1368
     * @param int    $rowspan
1369
     */
1370
    function tableheader_open($colspan = 1, $align = null, $rowspan = 1) {
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...
1371
        $class = 'class="col'.$this->_counter['cell_counter']++;
1372
        if(!is_null($align)) {
1373
            $class .= ' '.$align.'align';
1374
        }
1375
        $class .= '"';
1376
        $this->doc .= '<th '.$class;
1377
        if($colspan > 1) {
1378
            $this->_counter['cell_counter'] += $colspan - 1;
1379
            $this->doc .= ' colspan="'.$colspan.'"';
1380
        }
1381
        if($rowspan > 1) {
1382
            $this->doc .= ' rowspan="'.$rowspan.'"';
1383
        }
1384
        $this->doc .= '>';
1385
    }
1386
1387
    /**
1388
     * Close a table header cell
1389
     */
1390
    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...
1391
        $this->doc .= '</th>';
1392
    }
1393
1394
    /**
1395
     * Open a table cell
1396
     *
1397
     * @param int    $colspan
1398
     * @param string $align left|center|right
1399
     * @param int    $rowspan
1400
     */
1401
    function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
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...
1402
        $class = 'class="col'.$this->_counter['cell_counter']++;
1403
        if(!is_null($align)) {
1404
            $class .= ' '.$align.'align';
1405
        }
1406
        $class .= '"';
1407
        $this->doc .= '<td '.$class;
1408
        if($colspan > 1) {
1409
            $this->_counter['cell_counter'] += $colspan - 1;
1410
            $this->doc .= ' colspan="'.$colspan.'"';
1411
        }
1412
        if($rowspan > 1) {
1413
            $this->doc .= ' rowspan="'.$rowspan.'"';
1414
        }
1415
        $this->doc .= '>';
1416
    }
1417
1418
    /**
1419
     * Close a table cell
1420
     */
1421
    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...
1422
        $this->doc .= '</td>';
1423
    }
1424
1425
    #region Utility functions
1426
1427
    /**
1428
     * Build a link
1429
     *
1430
     * Assembles all parts defined in $link returns HTML for the link
1431
     *
1432
     * @author Andreas Gohr <[email protected]>
1433
     */
1434
    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...
1435
        //make sure the url is XHTML compliant (skip mailto)
1436
        if(substr($link['url'], 0, 7) != 'mailto:') {
1437
            $link['url'] = str_replace('&', '&amp;', $link['url']);
1438
            $link['url'] = str_replace('&amp;amp;', '&amp;', $link['url']);
1439
        }
1440
        //remove double encodings in titles
1441
        $link['title'] = str_replace('&amp;amp;', '&amp;', $link['title']);
1442
1443
        // be sure there are no bad chars in url or title
1444
        // (we can't do this for name because it can contain an img tag)
1445
        $link['url']   = strtr($link['url'], array('>' => '%3E', '<' => '%3C', '"' => '%22'));
1446
        $link['title'] = strtr($link['title'], array('>' => '&gt;', '<' => '&lt;', '"' => '&quot;'));
1447
1448
        $ret = '';
1449
        $ret .= $link['pre'];
1450
        $ret .= '<a href="'.$link['url'].'"';
1451
        if(!empty($link['class'])) $ret .= ' class="'.$link['class'].'"';
1452
        if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"';
1453
        if(!empty($link['title'])) $ret .= ' title="'.$link['title'].'"';
1454
        if(!empty($link['style'])) $ret .= ' style="'.$link['style'].'"';
1455
        if(!empty($link['rel'])) $ret .= ' rel="'.trim($link['rel']).'"';
1456
        if(!empty($link['more'])) $ret .= ' '.$link['more'];
1457
        $ret .= '>';
1458
        $ret .= $link['name'];
1459
        $ret .= '</a>';
1460
        $ret .= $link['suf'];
1461
        return $ret;
1462
    }
1463
1464
    /**
1465
     * Renders internal and external media
1466
     *
1467
     * @author Andreas Gohr <[email protected]>
1468
     * @param string $src       media ID
1469
     * @param string $title     descriptive text
1470
     * @param string $align     left|center|right
1471
     * @param int    $width     width of media in pixel
1472
     * @param int    $height    height of media in pixel
1473
     * @param string $cache     cache|recache|nocache
1474
     * @param bool   $render    should the media be embedded inline or just linked
1475
     * @return string
1476
     */
1477
    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...
1478
                    $height = null, $cache = null, $render = true) {
1479
1480
        $ret = '';
1481
1482
        list($ext, $mime) = mimetype($src);
1483
        if(substr($mime, 0, 5) == 'image') {
1484
            // first get the $title
1485
            if(!is_null($title)) {
1486
                $title = $this->_xmlEntities($title);
1487
            } elseif($ext == 'jpg' || $ext == 'jpeg') {
1488
                //try to use the caption from IPTC/EXIF
1489
                require_once(DOKU_INC.'inc/JpegMeta.php');
1490
                $jpeg = new JpegMeta(mediaFN($src));
1491
                if($jpeg !== false) $cap = $jpeg->getTitle();
1492
                if(!empty($cap)) {
1493
                    $title = $this->_xmlEntities($cap);
1494
                }
1495
            }
1496
            if(!$render) {
1497
                // if the picture is not supposed to be rendered
1498
                // return the title of the picture
1499
                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...
1500
                    // just show the sourcename
1501
                    $title = $this->_xmlEntities(utf8_basename(noNS($src)));
1502
                }
1503
                return $title;
1504
            }
1505
            //add image tag
1506
            $ret .= '<img src="'.ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src))).'"';
1507
            $ret .= ' class="media'.$align.'"';
1508
1509
            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...
1510
                $ret .= ' title="'.$title.'"';
1511
                $ret .= ' alt="'.$title.'"';
1512
            } else {
1513
                $ret .= ' alt=""';
1514
            }
1515
1516
            if(!is_null($width))
1517
                $ret .= ' width="'.$this->_xmlEntities($width).'"';
1518
1519
            if(!is_null($height))
1520
                $ret .= ' height="'.$this->_xmlEntities($height).'"';
1521
1522
            $ret .= ' />';
1523
1524
        } elseif(media_supportedav($mime, 'video') || media_supportedav($mime, 'audio')) {
1525
            // first get the $title
1526
            $title = !is_null($title) ? $this->_xmlEntities($title) : false;
1527
            if(!$render) {
1528
                // if the file is not supposed to be rendered
1529
                // return the title of the file (just the sourcename if there is no title)
1530
                return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src)));
1531
            }
1532
1533
            $att          = array();
1534
            $att['class'] = "media$align";
1535
            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...
1536
                $att['title'] = $title;
1537
            }
1538
1539
            if(media_supportedav($mime, 'video')) {
1540
                //add video
1541
                $ret .= $this->_video($src, $width, $height, $att);
1542
            }
1543
            if(media_supportedav($mime, 'audio')) {
1544
                //add audio
1545
                $ret .= $this->_audio($src, $att);
1546
            }
1547
1548
        } elseif($mime == 'application/x-shockwave-flash') {
1549
            if(!$render) {
1550
                // if the flash is not supposed to be rendered
1551
                // return the title of the flash
1552
                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...
1553
                    // just show the sourcename
1554
                    $title = utf8_basename(noNS($src));
1555
                }
1556
                return $this->_xmlEntities($title);
1557
            }
1558
1559
            $att          = array();
1560
            $att['class'] = "media$align";
1561
            if($align == 'right') $att['align'] = 'right';
1562
            if($align == 'left') $att['align'] = 'left';
1563
            $ret .= html_flashobject(
1564
                ml($src, array('cache' => $cache), true, '&'), $width, $height,
1565
                array('quality' => 'high'),
1566
                null,
1567
                $att,
1568
                $this->_xmlEntities($title)
1569
            );
1570
        } 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...
1571
            // well at least we have a title to display
1572
            $ret .= $this->_xmlEntities($title);
1573
        } else {
1574
            // just show the sourcename
1575
            $ret .= $this->_xmlEntities(utf8_basename(noNS($src)));
1576
        }
1577
1578
        return $ret;
1579
    }
1580
1581
    /**
1582
     * Escape string for output
1583
     *
1584
     * @param $string
1585
     * @return string
1586
     */
1587
    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...
1588
        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
1589
    }
1590
1591
    /**
1592
     * Creates a linkid from a headline
1593
     *
1594
     * @author Andreas Gohr <[email protected]>
1595
     * @param string  $title   The headline title
1596
     * @param boolean $create  Create a new unique ID?
1597
     * @return string
1598
     */
1599
    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...
1600
        if($create) {
1601
            return sectionID($title, $this->headers);
1602
        } else {
1603
            $check = false;
1604
            return sectionID($title, $check);
1605
        }
1606
    }
1607
1608
    /**
1609
     * Construct a title and handle images in titles
1610
     *
1611
     * @author Harry Fuecks <[email protected]>
1612
     * @param string|array $title    either string title or media array
1613
     * @param string       $default  default title if nothing else is found
1614
     * @param bool         $isImage  will be set to true if it's a media file
1615
     * @param null|string  $id       linked page id (used to extract title from first heading)
1616
     * @param string       $linktype content|navigation
1617
     * @return string      HTML of the title, might be full image tag or just escaped text
1618
     */
1619
    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...
1620
        $isImage = false;
1621
        if(is_array($title)) {
1622
            $isImage = true;
1623
            return $this->_imageTitle($title);
1624
        } elseif(is_null($title) || trim($title) == '') {
1625
            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...
1626
                $heading = p_get_first_heading($id);
1627
                if($heading) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $heading 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...
1628
                    return $this->_xmlEntities($heading);
1629
                }
1630
            }
1631
            return $this->_xmlEntities($default);
1632
        } else {
1633
            return $this->_xmlEntities($title);
1634
        }
1635
    }
1636
1637
    /**
1638
     * Returns HTML code for images used in link titles
1639
     *
1640
     * @author Andreas Gohr <[email protected]>
1641
     * @param array $img
1642
     * @return string HTML img tag or similar
1643
     */
1644
    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...
1645
        global $ID;
1646
1647
        // some fixes on $img['src']
1648
        // see internalmedia() and externalmedia()
1649
        list($img['src']) = explode('#', $img['src'], 2);
1650
        if($img['type'] == 'internalmedia') {
1651
            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...
1652
        }
1653
1654
        return $this->_media(
1655
            $img['src'],
1656
            $img['title'],
1657
            $img['align'],
1658
            $img['width'],
1659
            $img['height'],
1660
            $img['cache']
1661
        );
1662
    }
1663
1664
    /**
1665
     * helperfunction to return a basic link to a media
1666
     *
1667
     * used in internalmedia() and externalmedia()
1668
     *
1669
     * @author   Pierre Spring <[email protected]>
1670
     * @param string $src       media ID
1671
     * @param string $title     descriptive text
1672
     * @param string $align     left|center|right
1673
     * @param int    $width     width of media in pixel
1674
     * @param int    $height    height of media in pixel
1675
     * @param string $cache     cache|recache|nocache
1676
     * @param bool   $render    should the media be embedded inline or just linked
1677
     * @return array associative array with link config
1678
     */
1679
    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...
1680
        global $conf;
1681
1682
        $link           = array();
1683
        $link['class']  = 'media';
1684
        $link['style']  = '';
1685
        $link['pre']    = '';
1686
        $link['suf']    = '';
1687
        $link['more']   = '';
1688
        $link['target'] = $conf['target']['media'];
1689
        if($conf['target']['media']) $link['rel'] = 'noopener';
1690
        $link['title']  = $this->_xmlEntities($src);
1691
        $link['name']   = $this->_media($src, $title, $align, $width, $height, $cache, $render);
1692
1693
        return $link;
1694
    }
1695
1696
    /**
1697
     * Embed video(s) in HTML
1698
     *
1699
     * @author Anika Henke <[email protected]>
1700
     *
1701
     * @param string $src         - ID of video to embed
1702
     * @param int    $width       - width of the video in pixels
1703
     * @param int    $height      - height of the video in pixels
1704
     * @param array  $atts        - additional attributes for the <video> tag
1705
     * @return string
1706
     */
1707
    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...
1708
        // prepare width and height
1709
        if(is_null($atts)) $atts = array();
1710
        $atts['width']  = (int) $width;
1711
        $atts['height'] = (int) $height;
1712
        if(!$atts['width']) $atts['width'] = 320;
1713
        if(!$atts['height']) $atts['height'] = 240;
1714
1715
        $posterUrl = '';
1716
        $files = array();
1717
        $isExternal = media_isexternal($src);
1718
1719
        if ($isExternal) {
1720
            // take direct source for external files
1721
            list(/*ext*/, $srcMime) = mimetype($src);
1722
            $files[$srcMime] = $src;
1723
        } else {
1724
            // prepare alternative formats
1725
            $extensions   = array('webm', 'ogv', 'mp4');
1726
            $files        = media_alternativefiles($src, $extensions);
1727
            $poster       = media_alternativefiles($src, array('jpg', 'png'));
1728
            if(!empty($poster)) {
1729
                $posterUrl = ml(reset($poster), '', true, '&');
1730
            }
1731
        }
1732
1733
        $out = '';
1734
        // open video tag
1735
        $out .= '<video '.buildAttributes($atts).' controls="controls"';
1736
        if($posterUrl) $out .= ' poster="'.hsc($posterUrl).'"';
1737
        $out .= '>'.NL;
1738
        $fallback = '';
1739
1740
        // output source for each alternative video format
1741
        foreach($files as $mime => $file) {
1742
            if ($isExternal) {
1743
                $url = $file;
1744
                $linkType = 'externalmedia';
1745
            } else {
1746
                $url = ml($file, '', true, '&');
1747
                $linkType = 'internalmedia';
1748
            }
1749
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1750
1751
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1752
            // alternative content (just a link to the file)
1753
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1754
        }
1755
1756
        // finish
1757
        $out .= $fallback;
1758
        $out .= '</video>'.NL;
1759
        return $out;
1760
    }
1761
1762
    /**
1763
     * Embed audio in HTML
1764
     *
1765
     * @author Anika Henke <[email protected]>
1766
     *
1767
     * @param string $src       - ID of audio to embed
1768
     * @param array  $atts      - additional attributes for the <audio> tag
1769
     * @return string
1770
     */
1771
    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...
1772
        $files = array();
1773
        $isExternal = media_isexternal($src);
1774
1775
        if ($isExternal) {
1776
            // take direct source for external files
1777
            list(/*ext*/, $srcMime) = mimetype($src);
1778
            $files[$srcMime] = $src;
1779
        } else {
1780
            // prepare alternative formats
1781
            $extensions   = array('ogg', 'mp3', 'wav');
1782
            $files        = media_alternativefiles($src, $extensions);
1783
        }
1784
1785
        $out = '';
1786
        // open audio tag
1787
        $out .= '<audio '.buildAttributes($atts).' controls="controls">'.NL;
1788
        $fallback = '';
1789
1790
        // output source for each alternative audio format
1791
        foreach($files as $mime => $file) {
1792
            if ($isExternal) {
1793
                $url = $file;
1794
                $linkType = 'externalmedia';
1795
            } else {
1796
                $url = ml($file, '', true, '&');
1797
                $linkType = 'internalmedia';
1798
            }
1799
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1800
1801
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1802
            // alternative content (just a link to the file)
1803
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1804
        }
1805
1806
        // finish
1807
        $out .= $fallback;
1808
        $out .= '</audio>'.NL;
1809
        return $out;
1810
    }
1811
1812
    /**
1813
     * _getLastMediaRevisionAt is a helperfunction to internalmedia() and _media()
1814
     * which returns an existing media revision less or equal to rev or date_at
1815
     *
1816
     * @author lisps
1817
     * @param string $media_id
1818
     * @access protected
1819
     * @return string revision ('' for current)
1820
     */
1821
    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...
1822
        if(!$this->date_at || media_isexternal($media_id)) return '';
1823
        $pagelog = new MediaChangeLog($media_id);
1824
        return $pagelog->getLastRevisionAt($this->date_at);
1825
    }
1826
1827
    #endregion
1828
}
1829
1830
//Setup VIM: ex: et ts=4 :
1831