Failed Conditions
Push — psr2 ( 64159a )
by Andreas
07:54 queued 04:15
created

Doku_Renderer_xhtml::getFormat()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Renderer for XHTML output
4
 *
5
 * This is DokuWiki's main renderer used to display page content in the wiki
6
 *
7
 * @author Harry Fuecks <[email protected]>
8
 * @author Andreas Gohr <[email protected]>
9
 *
10
 */
11
class Doku_Renderer_xhtml extends Doku_Renderer {
12
    /** @var array store the table of contents */
13
    public $toc = array();
14
15
    /** @var array A stack of section edit data */
16
    protected $sectionedits = array();
17
    var $date_at = '';    // link pages and media against this revision
18
19
    /** @var int last section edit id, used by startSectionEdit */
20
    protected $lastsecid = 0;
21
22
    /** @var array the list of headers used to create unique link ids */
23
    protected $headers = array();
24
25
    /** @var array a list of footnotes, list starts at 1! */
26
    protected $footnotes = array();
27
28
    /** @var int current section level */
29
    protected $lastlevel = 0;
30
    /** @var array section node tracker */
31
    protected $node = array(0, 0, 0, 0, 0);
32
33
    /** @var string temporary $doc store */
34
    protected $store = '';
35
36
    /** @var array global counter, for table classes etc. */
37
    protected $_counter = array(); //
38
39
    /** @var int counts the code and file blocks, used to provide download links */
40
    protected $_codeblock = 0;
41
42
    /** @var array list of allowed URL schemes */
43
    protected $schemes = null;
44
45
    /**
46
     * Register a new edit section range
47
     *
48
     * @param int    $start  The byte position for the edit start
49
     * @param array  $data   Associative array with section data:
50
     *                       Key 'name': the section name/title
51
     *                       Key 'target': the target for the section edit,
52
     *                                     e.g. 'section' or 'table'
53
     *                       Key 'hid': header id
54
     *                       Key 'codeblockOffset': actual code block index
55
     *                       Key 'start': set in startSectionEdit(),
56
     *                                    do not set yourself
57
     *                       Key 'range': calculated from 'start' and
58
     *                                    $key in finishSectionEdit(),
59
     *                                    do not set yourself
60
     * @return string  A marker class for the starting HTML element
61
     *
62
     * @author Adrian Lang <[email protected]>
63
     */
64
    public function startSectionEdit($start, $data) {
65
        if (!is_array($data)) {
66
            msg(
67
                sprintf(
68
                    'startSectionEdit: $data "%s" is NOT an array! One of your plugins needs an update.',
69
                    hsc((string) $data)
70
                ), -1
71
            );
72
73
            // @deprecated 2018-04-14, backward compatibility
74
            $args = func_get_args();
75
            $data = array();
76
            if(isset($args[1])) $data['target'] = $args[1];
77
            if(isset($args[2])) $data['name'] = $args[2];
78
            if(isset($args[3])) $data['hid'] = $args[3];
79
        }
80
        $data['secid'] = ++$this->lastsecid;
81
        $data['start'] = $start;
82
        $this->sectionedits[] = $data;
83
        return 'sectionedit'.$data['secid'];
84
    }
85
86
    /**
87
     * Finish an edit section range
88
     *
89
     * @param int  $end     The byte position for the edit end; null for the rest of the page
90
     *
91
     * @author Adrian Lang <[email protected]>
92
     */
93
    public function finishSectionEdit($end = null, $hid = null) {
94
        $data = array_pop($this->sectionedits);
95
        if(!is_null($end) && $end <= $data['start']) {
96
            return;
97
        }
98
        if(!is_null($hid)) {
99
            $data['hid'] .= $hid;
100
        }
101
        $data['range'] = $data['start'].'-'.(is_null($end) ? '' : $end);
102
        unset($data['start']);
103
        $this->doc .= '<!-- EDIT'.hsc(json_encode ($data)).' -->';
104
    }
105
106
    /**
107
     * Returns the format produced by this renderer.
108
     *
109
     * @return string always 'xhtml'
110
     */
111
    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...
112
        return 'xhtml';
113
    }
114
115
    /**
116
     * Initialize the document
117
     */
118
    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...
119
        //reset some internals
120
        $this->toc     = array();
121
        $this->headers = array();
122
    }
123
124
    /**
125
     * Finalize the document
126
     */
127
    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...
128
        // Finish open section edits.
129
        while(count($this->sectionedits) > 0) {
130
            if($this->sectionedits[count($this->sectionedits) - 1]['start'] <= 1) {
131
                // If there is only one section, do not write a section edit
132
                // marker.
133
                array_pop($this->sectionedits);
134
            } else {
135
                $this->finishSectionEdit();
136
            }
137
        }
138
139
        if(count($this->footnotes) > 0) {
140
            $this->doc .= '<div class="footnotes">'.DOKU_LF;
141
142
            foreach($this->footnotes as $id => $footnote) {
143
                // check its not a placeholder that indicates actual footnote text is elsewhere
144
                if(substr($footnote, 0, 5) != "@@FNT") {
145
146
                    // open the footnote and set the anchor and backlink
147
                    $this->doc .= '<div class="fn">';
148
                    $this->doc .= '<sup><a href="#fnt__'.$id.'" id="fn__'.$id.'" class="fn_bot">';
149
                    $this->doc .= $id.')</a></sup> '.DOKU_LF;
150
151
                    // get any other footnotes that use the same markup
152
                    $alt = array_keys($this->footnotes, "@@FNT$id");
153
154
                    if(count($alt)) {
155
                        foreach($alt as $ref) {
156
                            // set anchor and backlink for the other footnotes
157
                            $this->doc .= ', <sup><a href="#fnt__'.($ref).'" id="fn__'.($ref).'" class="fn_bot">';
158
                            $this->doc .= ($ref).')</a></sup> '.DOKU_LF;
159
                        }
160
                    }
161
162
                    // add footnote markup and close this footnote
163
                    $this->doc .= '<div class="content">'.$footnote.'</div>';
164
                    $this->doc .= '</div>'.DOKU_LF;
165
                }
166
            }
167
            $this->doc .= '</div>'.DOKU_LF;
168
        }
169
170
        // Prepare the TOC
171
        global $conf;
172
        if(
173
            $this->info['toc'] &&
174
            is_array($this->toc) &&
175
            $conf['tocminheads'] && count($this->toc) >= $conf['tocminheads']
176
        ) {
177
            global $TOC;
178
            $TOC = $this->toc;
179
        }
180
181
        // make sure there are no empty paragraphs
182
        $this->doc = preg_replace('#<p>\s*</p>#', '', $this->doc);
183
    }
184
185
    /**
186
     * Add an item to the TOC
187
     *
188
     * @param string $id       the hash link
189
     * @param string $text     the text to display
190
     * @param int    $level    the nesting level
191
     */
192
    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...
193
        global $conf;
194
195
        //handle TOC
196
        if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) {
197
            $this->toc[] = html_mktocitem($id, $text, $level - $conf['toptoclevel'] + 1);
198
        }
199
    }
200
201
    /**
202
     * Render a heading
203
     *
204
     * @param string $text  the text to display
205
     * @param int    $level header level
206
     * @param int    $pos   byte position in the original source
207
     */
208
    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...
209
        global $conf;
210
211
        if(blank($text)) return; //skip empty headlines
212
213
        $hid = $this->_headerToLink($text, true);
214
215
        //only add items within configured levels
216
        $this->toc_additem($hid, $text, $level);
217
218
        // adjust $node to reflect hierarchy of levels
219
        $this->node[$level - 1]++;
220
        if($level < $this->lastlevel) {
221
            for($i = 0; $i < $this->lastlevel - $level; $i++) {
222
                $this->node[$this->lastlevel - $i - 1] = 0;
223
            }
224
        }
225
        $this->lastlevel = $level;
226
227
        if($level <= $conf['maxseclevel'] &&
228
            count($this->sectionedits) > 0 &&
229
            $this->sectionedits[count($this->sectionedits) - 1]['target'] === 'section'
230
        ) {
231
            $this->finishSectionEdit($pos - 1);
232
        }
233
234
        // write the header
235
        $this->doc .= DOKU_LF.'<h'.$level;
236
        if($level <= $conf['maxseclevel']) {
237
            $data = array();
238
            $data['target'] = 'section';
239
            $data['name'] = $text;
240
            $data['hid'] = $hid;
241
            $data['codeblockOffset'] = $this->_codeblock;
242
            $this->doc .= ' class="'.$this->startSectionEdit($pos, $data).'"';
243
        }
244
        $this->doc .= ' id="'.$hid.'">';
245
        $this->doc .= $this->_xmlEntities($text);
246
        $this->doc .= "</h$level>".DOKU_LF;
247
    }
248
249
    /**
250
     * Open a new section
251
     *
252
     * @param int $level section level (as determined by the previous header)
253
     */
254
    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...
255
        $this->doc .= '<div class="level'.$level.'">'.DOKU_LF;
256
    }
257
258
    /**
259
     * Close the current section
260
     */
261
    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...
262
        $this->doc .= DOKU_LF.'</div>'.DOKU_LF;
263
    }
264
265
    /**
266
     * Render plain text data
267
     *
268
     * @param $text
269
     */
270
    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...
271
        $this->doc .= $this->_xmlEntities($text);
272
    }
273
274
    /**
275
     * Open a paragraph
276
     */
277
    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...
278
        $this->doc .= DOKU_LF.'<p>'.DOKU_LF;
279
    }
280
281
    /**
282
     * Close a paragraph
283
     */
284
    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...
285
        $this->doc .= DOKU_LF.'</p>'.DOKU_LF;
286
    }
287
288
    /**
289
     * Create a line break
290
     */
291
    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...
292
        $this->doc .= '<br/>'.DOKU_LF;
293
    }
294
295
    /**
296
     * Create a horizontal line
297
     */
298
    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...
299
        $this->doc .= '<hr />'.DOKU_LF;
300
    }
301
302
    /**
303
     * Start strong (bold) formatting
304
     */
305
    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...
306
        $this->doc .= '<strong>';
307
    }
308
309
    /**
310
     * Stop strong (bold) formatting
311
     */
312
    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...
313
        $this->doc .= '</strong>';
314
    }
315
316
    /**
317
     * Start emphasis (italics) formatting
318
     */
319
    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...
320
        $this->doc .= '<em>';
321
    }
322
323
    /**
324
     * Stop emphasis (italics) formatting
325
     */
326
    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...
327
        $this->doc .= '</em>';
328
    }
329
330
    /**
331
     * Start underline formatting
332
     */
333
    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...
334
        $this->doc .= '<em class="u">';
335
    }
336
337
    /**
338
     * Stop underline formatting
339
     */
340
    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...
341
        $this->doc .= '</em>';
342
    }
343
344
    /**
345
     * Start monospace formatting
346
     */
347
    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...
348
        $this->doc .= '<code>';
349
    }
350
351
    /**
352
     * Stop monospace formatting
353
     */
354
    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...
355
        $this->doc .= '</code>';
356
    }
357
358
    /**
359
     * Start a subscript
360
     */
361
    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...
362
        $this->doc .= '<sub>';
363
    }
364
365
    /**
366
     * Stop a subscript
367
     */
368
    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...
369
        $this->doc .= '</sub>';
370
    }
371
372
    /**
373
     * Start a superscript
374
     */
375
    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...
376
        $this->doc .= '<sup>';
377
    }
378
379
    /**
380
     * Stop a superscript
381
     */
382
    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...
383
        $this->doc .= '</sup>';
384
    }
385
386
    /**
387
     * Start deleted (strike-through) formatting
388
     */
389
    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...
390
        $this->doc .= '<del>';
391
    }
392
393
    /**
394
     * Stop deleted (strike-through) formatting
395
     */
396
    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...
397
        $this->doc .= '</del>';
398
    }
399
400
    /**
401
     * Callback for footnote start syntax
402
     *
403
     * All following content will go to the footnote instead of
404
     * the document. To achieve this the previous rendered content
405
     * is moved to $store and $doc is cleared
406
     *
407
     * @author Andreas Gohr <[email protected]>
408
     */
409
    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...
410
411
        // move current content to store and record footnote
412
        $this->store = $this->doc;
413
        $this->doc   = '';
414
    }
415
416
    /**
417
     * Callback for footnote end syntax
418
     *
419
     * All rendered content is moved to the $footnotes array and the old
420
     * content is restored from $store again
421
     *
422
     * @author Andreas Gohr
423
     */
424
    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...
425
        /** @var $fnid int takes track of seen footnotes, assures they are unique even across multiple docs FS#2841 */
426
        static $fnid = 0;
427
        // assign new footnote id (we start at 1)
428
        $fnid++;
429
430
        // recover footnote into the stack and restore old content
431
        $footnote    = $this->doc;
432
        $this->doc   = $this->store;
433
        $this->store = '';
434
435
        // check to see if this footnote has been seen before
436
        $i = array_search($footnote, $this->footnotes);
437
438
        if($i === false) {
439
            // its a new footnote, add it to the $footnotes array
440
            $this->footnotes[$fnid] = $footnote;
441
        } else {
442
            // seen this one before, save a placeholder
443
            $this->footnotes[$fnid] = "@@FNT".($i);
444
        }
445
446
        // output the footnote reference and link
447
        $this->doc .= '<sup><a href="#fn__'.$fnid.'" id="fnt__'.$fnid.'" class="fn_top">'.$fnid.')</a></sup>';
448
    }
449
450
    /**
451
     * Open an unordered list
452
     *
453
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
454
     */
455
    function listu_open($classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
456
        $class = '';
457
        if($classes !== null) {
458
            if(is_array($classes)) $classes = join(' ', $classes);
459
            $class = " class=\"$classes\"";
460
        }
461
        $this->doc .= "<ul$class>".DOKU_LF;
462
    }
463
464
    /**
465
     * Close an unordered list
466
     */
467
    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...
468
        $this->doc .= '</ul>'.DOKU_LF;
469
    }
470
471
    /**
472
     * Open an ordered list
473
     *
474
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
475
     */
476
    function listo_open($classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
477
        $class = '';
478
        if($classes !== null) {
479
            if(is_array($classes)) $classes = join(' ', $classes);
480
            $class = " class=\"$classes\"";
481
        }
482
        $this->doc .= "<ol$class>".DOKU_LF;
483
    }
484
485
    /**
486
     * Close an ordered list
487
     */
488
    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...
489
        $this->doc .= '</ol>'.DOKU_LF;
490
    }
491
492
    /**
493
     * Open a list item
494
     *
495
     * @param int $level the nesting level
496
     * @param bool $node true when a node; false when a leaf
497
     */
498
    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...
499
        $branching = $node ? ' node' : '';
500
        $this->doc .= '<li class="level'.$level.$branching.'">';
501
    }
502
503
    /**
504
     * Close a list item
505
     */
506
    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...
507
        $this->doc .= '</li>'.DOKU_LF;
508
    }
509
510
    /**
511
     * Start the content of a list item
512
     */
513
    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...
514
        $this->doc .= '<div class="li">';
515
    }
516
517
    /**
518
     * Stop the content of a list item
519
     */
520
    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...
521
        $this->doc .= '</div>'.DOKU_LF;
522
    }
523
524
    /**
525
     * Output unformatted $text
526
     *
527
     * Defaults to $this->cdata()
528
     *
529
     * @param string $text
530
     */
531
    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...
532
        $this->doc .= $this->_xmlEntities($text);
533
    }
534
535
    /**
536
     * Execute PHP code if allowed
537
     *
538
     * @param  string $text      PHP code that is either executed or printed
539
     * @param  string $wrapper   html element to wrap result if $conf['phpok'] is okff
540
     *
541
     * @author Andreas Gohr <[email protected]>
542
     */
543
    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...
544
        global $conf;
545
546
        if($conf['phpok']) {
547
            ob_start();
548
            eval($text);
549
            $this->doc .= ob_get_contents();
550
            ob_end_clean();
551
        } else {
552
            $this->doc .= p_xhtml_cached_geshi($text, 'php', $wrapper);
553
        }
554
    }
555
556
    /**
557
     * Output block level PHP code
558
     *
559
     * If $conf['phpok'] is true this should evaluate the given code and append the result
560
     * to $doc
561
     *
562
     * @param string $text The PHP code
563
     */
564
    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...
565
        $this->php($text, 'pre');
566
    }
567
568
    /**
569
     * Insert HTML if allowed
570
     *
571
     * @param  string $text      html text
572
     * @param  string $wrapper   html element to wrap result if $conf['htmlok'] is okff
573
     *
574
     * @author Andreas Gohr <[email protected]>
575
     */
576
    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...
577
        global $conf;
578
579
        if($conf['htmlok']) {
580
            $this->doc .= $text;
581
        } else {
582
            $this->doc .= p_xhtml_cached_geshi($text, 'html4strict', $wrapper);
583
        }
584
    }
585
586
    /**
587
     * Output raw block-level HTML
588
     *
589
     * If $conf['htmlok'] is true this should add the code as is to $doc
590
     *
591
     * @param string $text The HTML
592
     */
593
    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...
594
        $this->html($text, 'pre');
595
    }
596
597
    /**
598
     * Start a block quote
599
     */
600
    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...
601
        $this->doc .= '<blockquote><div class="no">'.DOKU_LF;
602
    }
603
604
    /**
605
     * Stop a block quote
606
     */
607
    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...
608
        $this->doc .= '</div></blockquote>'.DOKU_LF;
609
    }
610
611
    /**
612
     * Output preformatted text
613
     *
614
     * @param string $text
615
     */
616
    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...
617
        $this->doc .= '<pre class="code">'.trim($this->_xmlEntities($text), "\n\r").'</pre>'.DOKU_LF;
618
    }
619
620
    /**
621
     * Display text as file content, optionally syntax highlighted
622
     *
623
     * @param string $text     text to show
624
     * @param string $language programming language to use for syntax highlighting
625
     * @param string $filename file path label
626
     * @param array  $options  assoziative array with additional geshi options
627
     */
628
    function file($text, $language = null, $filename = null, $options=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...
629
        $this->_highlight('file', $text, $language, $filename, $options);
630
    }
631
632
    /**
633
     * Display text as code content, optionally syntax highlighted
634
     *
635
     * @param string $text     text to show
636
     * @param string $language programming language to use for syntax highlighting
637
     * @param string $filename file path label
638
     * @param array  $options  assoziative array with additional geshi options
639
     */
640
    function code($text, $language = null, $filename = null, $options=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...
641
        $this->_highlight('code', $text, $language, $filename, $options);
642
    }
643
644
    /**
645
     * Use GeSHi to highlight language syntax in code and file blocks
646
     *
647
     * @author Andreas Gohr <[email protected]>
648
     * @param string $type     code|file
649
     * @param string $text     text to show
650
     * @param string $language programming language to use for syntax highlighting
651
     * @param string $filename file path label
652
     * @param array  $options  assoziative array with additional geshi options
653
     */
654
    function _highlight($type, $text, $language = null, $filename = null, $options = 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...
655
        global $ID;
656
        global $lang;
657
        global $INPUT;
658
659
        $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language);
660
661
        if($filename) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filename of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
662
            // add icon
663
            list($ext) = mimetype($filename, false);
664
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
665
            $class = 'mediafile mf_'.$class;
666
667
            $offset = 0;
668
            if ($INPUT->has('codeblockOffset')) {
669
                $offset = $INPUT->str('codeblockOffset');
670
            }
671
            $this->doc .= '<dl class="'.$type.'">'.DOKU_LF;
672
            $this->doc .= '<dt><a href="' .
673
                exportlink(
674
                    $ID,
675
                    'code',
676
                    array('codeblock' => $offset + $this->_codeblock)
677
                ) . '" title="' . $lang['download'] . '" class="' . $class . '">';
678
            $this->doc .= hsc($filename);
679
            $this->doc .= '</a></dt>'.DOKU_LF.'<dd>';
680
        }
681
682
        if($text{0} == "\n") {
683
            $text = substr($text, 1);
684
        }
685
        if(substr($text, -1) == "\n") {
686
            $text = substr($text, 0, -1);
687
        }
688
689
        if(empty($language)) { // empty is faster than is_null and can prevent '' string
690
            $this->doc .= '<pre class="'.$type.'">'.$this->_xmlEntities($text).'</pre>'.DOKU_LF;
691
        } else {
692
            $class = 'code'; //we always need the code class to make the syntax highlighting apply
693
            if($type != 'code') $class .= ' '.$type;
694
695
            $this->doc .= "<pre class=\"$class $language\">" .
696
                p_xhtml_cached_geshi($text, $language, '', $options) .
697
                '</pre>' . DOKU_LF;
698
        }
699
700
        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...
701
            $this->doc .= '</dd></dl>'.DOKU_LF;
702
        }
703
704
        $this->_codeblock++;
705
    }
706
707
    /**
708
     * Format an acronym
709
     *
710
     * Uses $this->acronyms
711
     *
712
     * @param string $acronym
713
     */
714
    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...
715
716
        if(array_key_exists($acronym, $this->acronyms)) {
717
718
            $title = $this->_xmlEntities($this->acronyms[$acronym]);
719
720
            $this->doc .= '<abbr title="'.$title
721
                .'">'.$this->_xmlEntities($acronym).'</abbr>';
722
723
        } else {
724
            $this->doc .= $this->_xmlEntities($acronym);
725
        }
726
    }
727
728
    /**
729
     * Format a smiley
730
     *
731
     * Uses $this->smiley
732
     *
733
     * @param string $smiley
734
     */
735
    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...
736
        if(array_key_exists($smiley, $this->smileys)) {
737
            $this->doc .= '<img src="'.DOKU_BASE.'lib/images/smileys/'.$this->smileys[$smiley].
738
                '" class="icon" alt="'.
739
                $this->_xmlEntities($smiley).'" />';
740
        } else {
741
            $this->doc .= $this->_xmlEntities($smiley);
742
        }
743
    }
744
745
    /**
746
     * Format an entity
747
     *
748
     * Entities are basically small text replacements
749
     *
750
     * Uses $this->entities
751
     *
752
     * @param string $entity
753
     */
754
    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...
755
        if(array_key_exists($entity, $this->entities)) {
756
            $this->doc .= $this->entities[$entity];
757
        } else {
758
            $this->doc .= $this->_xmlEntities($entity);
759
        }
760
    }
761
762
    /**
763
     * Typographically format a multiply sign
764
     *
765
     * Example: ($x=640, $y=480) should result in "640×480"
766
     *
767
     * @param string|int $x first value
768
     * @param string|int $y second value
769
     */
770
    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...
771
        $this->doc .= "$x&times;$y";
772
    }
773
774
    /**
775
     * Render an opening single quote char (language specific)
776
     */
777
    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...
778
        global $lang;
779
        $this->doc .= $lang['singlequoteopening'];
780
    }
781
782
    /**
783
     * Render a closing single quote char (language specific)
784
     */
785
    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...
786
        global $lang;
787
        $this->doc .= $lang['singlequoteclosing'];
788
    }
789
790
    /**
791
     * Render an apostrophe char (language specific)
792
     */
793
    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...
794
        global $lang;
795
        $this->doc .= $lang['apostrophe'];
796
    }
797
798
    /**
799
     * Render an opening double quote char (language specific)
800
     */
801
    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...
802
        global $lang;
803
        $this->doc .= $lang['doublequoteopening'];
804
    }
805
806
    /**
807
     * Render an closinging double quote char (language specific)
808
     */
809
    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...
810
        global $lang;
811
        $this->doc .= $lang['doublequoteclosing'];
812
    }
813
814
    /**
815
     * Render a CamelCase link
816
     *
817
     * @param string $link       The link name
818
     * @param bool   $returnonly whether to return html or write to doc attribute
819
     * @return void|string writes to doc attribute or returns html depends on $returnonly
820
     *
821
     * @see http://en.wikipedia.org/wiki/CamelCase
822
     */
823
    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...
824
        if($returnonly) {
825
          return $this->internallink($link, $link, null, true);
826
        } else {
827
          $this->internallink($link, $link);
828
        }
829
    }
830
831
    /**
832
     * Render a page local link
833
     *
834
     * @param string $hash       hash link identifier
835
     * @param string $name       name for the link
836
     * @param bool   $returnonly whether to return html or write to doc attribute
837
     * @return void|string writes to doc attribute or returns html depends on $returnonly
838
     */
839
    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...
840
        global $ID;
841
        $name  = $this->_getLinkTitle($name, $hash, $isImage);
842
        $hash  = $this->_headerToLink($hash);
843
        $title = $ID.' ↵';
844
845
        $doc = '<a href="#'.$hash.'" title="'.$title.'" class="wikilink1">';
846
        $doc .= $name;
847
        $doc .= '</a>';
848
849
        if($returnonly) {
850
          return $doc;
851
        } else {
852
          $this->doc .= $doc;
853
        }
854
    }
855
856
    /**
857
     * Render an internal Wiki Link
858
     *
859
     * $search,$returnonly & $linktype are not for the renderer but are used
860
     * elsewhere - no need to implement them in other renderers
861
     *
862
     * @author Andreas Gohr <[email protected]>
863
     * @param string      $id         pageid
864
     * @param string|null $name       link name
865
     * @param string|null $search     adds search url param
866
     * @param bool        $returnonly whether to return html or write to doc attribute
867
     * @param string      $linktype   type to set use of headings
868
     * @return void|string writes to doc attribute or returns html depends on $returnonly
869
     */
870
    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...
871
        global $conf;
872
        global $ID;
873
        global $INFO;
874
875
        $params = '';
876
        $parts  = explode('?', $id, 2);
877
        if(count($parts) === 2) {
878
            $id     = $parts[0];
879
            $params = $parts[1];
880
        }
881
882
        // For empty $id we need to know the current $ID
883
        // We need this check because _simpleTitle needs
884
        // correct $id and resolve_pageid() use cleanID($id)
885
        // (some things could be lost)
886
        if($id === '') {
887
            $id = $ID;
888
        }
889
890
        // default name is based on $id as given
891
        $default = $this->_simpleTitle($id);
892
893
        // now first resolve and clean up the $id
894
        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...
895
896
        $link = array();
897
        $name = $this->_getLinkTitle($name, $default, $isImage, $id, $linktype);
898
        if(!$isImage) {
899
            if($exists) {
900
                $class = 'wikilink1';
901
            } else {
902
                $class       = 'wikilink2';
903
                $link['rel'] = 'nofollow';
904
            }
905
        } else {
906
            $class = 'media';
907
        }
908
909
        //keep hash anchor
910
        @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...
911
        if(!empty($hash)) $hash = $this->_headerToLink($hash);
912
913
        //prepare for formating
914
        $link['target'] = $conf['target']['wiki'];
915
        $link['style']  = '';
916
        $link['pre']    = '';
917
        $link['suf']    = '';
918
        // highlight link to current page
919
        if($id == $INFO['id']) {
920
            $link['pre'] = '<span class="curid">';
921
            $link['suf'] = '</span>';
922
        }
923
        $link['more']   = '';
924
        $link['class']  = $class;
925
        if($this->date_at) {
926
            $params = $params.'&at='.rawurlencode($this->date_at);
927
        }
928
        $link['url']    = wl($id, $params);
929
        $link['name']   = $name;
930
        $link['title']  = $id;
931
        //add search string
932
        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...
933
            ($conf['userewrite']) ? $link['url'] .= '?' : $link['url'] .= '&amp;';
934
            if(is_array($search)) {
935
                $search = array_map('rawurlencode', $search);
936
                $link['url'] .= 's[]='.join('&amp;s[]=', $search);
937
            } else {
938
                $link['url'] .= 's='.rawurlencode($search);
939
            }
940
        }
941
942
        //keep hash
943
        if($hash) $link['url'] .= '#'.$hash;
944
945
        //output formatted
946
        if($returnonly) {
947
            return $this->_formatLink($link);
948
        } else {
949
            $this->doc .= $this->_formatLink($link);
950
        }
951
    }
952
953
    /**
954
     * Render an external link
955
     *
956
     * @param string       $url        full URL with scheme
957
     * @param string|array $name       name for the link, array for media file
958
     * @param bool         $returnonly whether to return html or write to doc attribute
959
     * @return void|string writes to doc attribute or returns html depends on $returnonly
960
     */
961
    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...
962
        global $conf;
963
964
        $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...
965
966
        // url might be an attack vector, only allow registered protocols
967
        if(is_null($this->schemes)) $this->schemes = getSchemes();
968
        list($scheme) = explode('://', $url);
969
        $scheme = strtolower($scheme);
970
        if(!in_array($scheme, $this->schemes)) $url = '';
971
972
        // is there still an URL?
973
        if(!$url) {
974
            if($returnonly) {
975
                return $name;
976
            } else {
977
                $this->doc .= $name;
978
            }
979
            return;
980
        }
981
982
        // set class
983
        if(!$isImage) {
984
            $class = 'urlextern';
985
        } else {
986
            $class = 'media';
987
        }
988
989
        //prepare for formating
990
        $link = array();
991
        $link['target'] = $conf['target']['extern'];
992
        $link['style']  = '';
993
        $link['pre']    = '';
994
        $link['suf']    = '';
995
        $link['more']   = '';
996
        $link['class']  = $class;
997
        $link['url']    = $url;
998
        $link['rel']    = '';
999
1000
        $link['name']  = $name;
1001
        $link['title'] = $this->_xmlEntities($url);
1002
        if($conf['relnofollow']) $link['rel'] .= ' nofollow';
1003
        if($conf['target']['extern']) $link['rel'] .= ' noopener';
1004
1005
        //output formatted
1006
        if($returnonly) {
1007
            return $this->_formatLink($link);
1008
        } else {
1009
            $this->doc .= $this->_formatLink($link);
1010
        }
1011
    }
1012
1013
    /**
1014
     * Render an interwiki link
1015
     *
1016
     * You may want to use $this->_resolveInterWiki() here
1017
     *
1018
     * @param string       $match      original link - probably not much use
1019
     * @param string|array $name       name for the link, array for media file
1020
     * @param string       $wikiName   indentifier (shortcut) for the remote wiki
1021
     * @param string       $wikiUri    the fragment parsed from the original link
1022
     * @param bool         $returnonly whether to return html or write to doc attribute
1023
     * @return void|string writes to doc attribute or returns html depends on $returnonly
1024
     */
1025
    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...
1026
        global $conf;
1027
1028
        $link           = array();
1029
        $link['target'] = $conf['target']['interwiki'];
1030
        $link['pre']    = '';
1031
        $link['suf']    = '';
1032
        $link['more']   = '';
1033
        $link['name']   = $this->_getLinkTitle($name, $wikiUri, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 1025 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...
1034
        $link['rel']    = '';
1035
1036
        //get interwiki URL
1037
        $exists = null;
1038
        $url    = $this->_resolveInterWiki($wikiName, $wikiUri, $exists);
1039
1040
        if(!$isImage) {
1041
            $class         = preg_replace('/[^_\-a-z0-9]+/i', '_', $wikiName);
1042
            $link['class'] = "interwiki iw_$class";
1043
        } else {
1044
            $link['class'] = 'media';
1045
        }
1046
1047
        //do we stay at the same server? Use local target
1048
        if(strpos($url, DOKU_URL) === 0 OR strpos($url, DOKU_BASE) === 0) {
1049
            $link['target'] = $conf['target']['wiki'];
1050
        }
1051
        if($exists !== null && !$isImage) {
1052
            if($exists) {
1053
                $link['class'] .= ' wikilink1';
1054
            } else {
1055
                $link['class'] .= ' wikilink2';
1056
                $link['rel'] .= ' nofollow';
1057
            }
1058
        }
1059
        if($conf['target']['interwiki']) $link['rel'] .= ' noopener';
1060
1061
        $link['url']   = $url;
1062
        $link['title'] = htmlspecialchars($link['url']);
1063
1064
        //output formatted
1065
        if($returnonly) {
1066
            return $this->_formatLink($link);
1067
        } else {
1068
            $this->doc .= $this->_formatLink($link);
1069
        }
1070
    }
1071
1072
    /**
1073
     * Link to windows share
1074
     *
1075
     * @param string       $url        the link
1076
     * @param string|array $name       name for the link, array for media file
1077
     * @param bool         $returnonly whether to return html or write to doc attribute
1078
     * @return void|string writes to doc attribute or returns html depends on $returnonly
1079
     */
1080
    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...
1081
        global $conf;
1082
1083
        //simple setup
1084
        $link = array();
1085
        $link['target'] = $conf['target']['windows'];
1086
        $link['pre']    = '';
1087
        $link['suf']    = '';
1088
        $link['style']  = '';
1089
1090
        $link['name'] = $this->_getLinkTitle($name, $url, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 1080 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...
1091
        if(!$isImage) {
1092
            $link['class'] = 'windows';
1093
        } else {
1094
            $link['class'] = 'media';
1095
        }
1096
1097
        $link['title'] = $this->_xmlEntities($url);
1098
        $url           = str_replace('\\', '/', $url);
1099
        $url           = 'file:///'.$url;
1100
        $link['url']   = $url;
1101
1102
        //output formatted
1103
        if($returnonly) {
1104
            return $this->_formatLink($link);
1105
        } else {
1106
            $this->doc .= $this->_formatLink($link);
1107
        }
1108
    }
1109
1110
    /**
1111
     * Render a linked E-Mail Address
1112
     *
1113
     * Honors $conf['mailguard'] setting
1114
     *
1115
     * @param string       $address    Email-Address
1116
     * @param string|array $name       name for the link, array for media file
1117
     * @param bool         $returnonly whether to return html or write to doc attribute
1118
     * @return void|string writes to doc attribute or returns html depends on $returnonly
1119
     */
1120
    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...
1121
        global $conf;
1122
        //simple setup
1123
        $link           = array();
1124
        $link['target'] = '';
1125
        $link['pre']    = '';
1126
        $link['suf']    = '';
1127
        $link['style']  = '';
1128
        $link['more']   = '';
1129
1130
        $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...
1131
        if(!$isImage) {
1132
            $link['class'] = 'mail';
1133
        } else {
1134
            $link['class'] = 'media';
1135
        }
1136
1137
        $address = $this->_xmlEntities($address);
1138
        $address = obfuscate($address);
1139
        $title   = $address;
1140
1141
        if(empty($name)) {
1142
            $name = $address;
1143
        }
1144
1145
        if($conf['mailguard'] == 'visible') $address = rawurlencode($address);
1146
1147
        $link['url']   = 'mailto:'.$address;
1148
        $link['name']  = $name;
1149
        $link['title'] = $title;
1150
1151
        //output formatted
1152
        if($returnonly) {
1153
            return $this->_formatLink($link);
1154
        } else {
1155
            $this->doc .= $this->_formatLink($link);
1156
        }
1157
    }
1158
1159
    /**
1160
     * Render an internal media file
1161
     *
1162
     * @param string $src       media ID
1163
     * @param string $title     descriptive text
1164
     * @param string $align     left|center|right
1165
     * @param int    $width     width of media in pixel
1166
     * @param int    $height    height of media in pixel
1167
     * @param string $cache     cache|recache|nocache
1168
     * @param string $linking   linkonly|detail|nolink
1169
     * @param bool   $return    return HTML instead of adding to $doc
1170
     * @return void|string writes to doc attribute or returns html depends on $return
1171
     */
1172
    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...
1173
                           $height = null, $cache = null, $linking = null, $return = false) {
1174
        global $ID;
1175
        if (strpos($src, '#') !== false) {
1176
            list($src, $hash) = explode('#', $src, 2);
1177
        }
1178
        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...
1179
1180
        $noLink = false;
1181
        $render = ($linking == 'linkonly') ? false : true;
1182
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1183
1184
        list($ext, $mime) = mimetype($src, false);
1185
        if(substr($mime, 0, 5) == 'image' && $render) {
1186
            $link['url'] = ml(
1187
                $src,
1188
                array(
1189
                    'id' => $ID,
1190
                    'cache' => $cache,
1191
                    'rev' => $this->_getLastMediaRevisionAt($src)
1192
                ),
1193
                ($linking == 'direct')
1194
            );
1195
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1196
            // don't link movies
1197
            $noLink = true;
1198
        } else {
1199
            // add file icons
1200
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1201
            $link['class'] .= ' mediafile mf_'.$class;
1202
            $link['url'] = ml(
1203
                $src,
1204
                array(
1205
                    'id' => $ID,
1206
                    'cache' => $cache,
1207
                    'rev' => $this->_getLastMediaRevisionAt($src)
1208
                ),
1209
                true
1210
            );
1211
            if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')';
1212
        }
1213
1214
        if (!empty($hash)) $link['url'] .= '#'.$hash;
1215
1216
        //markup non existing files
1217
        if(!$exists) {
1218
            $link['class'] .= ' wikilink2';
1219
        }
1220
1221
        //output formatted
1222
        if($return) {
1223
            if($linking == 'nolink' || $noLink) return $link['name'];
1224
            else return $this->_formatLink($link);
1225
        } else {
1226
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1227
            else $this->doc .= $this->_formatLink($link);
1228
        }
1229
    }
1230
1231
    /**
1232
     * Render an external media file
1233
     *
1234
     * @param string $src     full media URL
1235
     * @param string $title   descriptive text
1236
     * @param string $align   left|center|right
1237
     * @param int    $width   width of media in pixel
1238
     * @param int    $height  height of media in pixel
1239
     * @param string $cache   cache|recache|nocache
1240
     * @param string $linking linkonly|detail|nolink
1241
     * @param bool   $return  return HTML instead of adding to $doc
1242
     * @return void|string writes to doc attribute or returns html depends on $return
1243
     */
1244
    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...
1245
                           $height = null, $cache = null, $linking = null, $return = false) {
1246
        if(link_isinterwiki($src)){
1247
            list($shortcut, $reference) = explode('>', $src, 2);
1248
            $exists = null;
1249
            $src = $this->_resolveInterWiki($shortcut, $reference, $exists);
1250
        }
1251
        list($src, $hash) = explode('#', $src, 2);
1252
        $noLink = false;
1253
        $render = ($linking == 'linkonly') ? false : true;
1254
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1255
1256
        $link['url'] = ml($src, array('cache' => $cache));
1257
1258
        list($ext, $mime) = mimetype($src, false);
1259
        if(substr($mime, 0, 5) == 'image' && $render) {
1260
            // link only jpeg images
1261
            // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true;
1262
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1263
            // don't link movies
1264
            $noLink = true;
1265
        } else {
1266
            // add file icons
1267
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1268
            $link['class'] .= ' mediafile mf_'.$class;
1269
        }
1270
1271
        if($hash) $link['url'] .= '#'.$hash;
1272
1273
        //output formatted
1274
        if($return) {
1275
            if($linking == 'nolink' || $noLink) return $link['name'];
1276
            else return $this->_formatLink($link);
1277
        } else {
1278
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1279
            else $this->doc .= $this->_formatLink($link);
1280
        }
1281
    }
1282
1283
    /**
1284
     * Renders an RSS feed
1285
     *
1286
     * @param string $url    URL of the feed
1287
     * @param array  $params Finetuning of the output
1288
     *
1289
     * @author Andreas Gohr <[email protected]>
1290
     */
1291
    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...
1292
        global $lang;
1293
        global $conf;
1294
1295
        require_once(DOKU_INC.'inc/FeedParser.php');
1296
        $feed = new FeedParser();
1297
        $feed->set_feed_url($url);
1298
1299
        //disable warning while fetching
1300
        if(!defined('DOKU_E_LEVEL')) {
1301
            $elvl = error_reporting(E_ERROR);
1302
        }
1303
        $rc = $feed->init();
1304
        if(isset($elvl)) {
1305
            error_reporting($elvl);
1306
        }
1307
1308
        if($params['nosort']) $feed->enable_order_by_date(false);
1309
1310
        //decide on start and end
1311
        if($params['reverse']) {
1312
            $mod   = -1;
1313
            $start = $feed->get_item_quantity() - 1;
1314
            $end   = $start - ($params['max']);
1315
            $end   = ($end < -1) ? -1 : $end;
1316
        } else {
1317
            $mod   = 1;
1318
            $start = 0;
1319
            $end   = $feed->get_item_quantity();
1320
            $end   = ($end > $params['max']) ? $params['max'] : $end;
1321
        }
1322
1323
        $this->doc .= '<ul class="rss">';
1324
        if($rc) {
1325
            for($x = $start; $x != $end; $x += $mod) {
1326
                $item = $feed->get_item($x);
1327
                $this->doc .= '<li><div class="li">';
1328
                // support feeds without links
1329
                $lnkurl = $item->get_permalink();
1330
                if($lnkurl) {
1331
                    // title is escaped by SimplePie, we unescape here because it
1332
                    // is escaped again in externallink() FS#1705
1333
                    $this->externallink(
1334
                        $item->get_permalink(),
1335
                        html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')
1336
                    );
1337
                } else {
1338
                    $this->doc .= ' '.$item->get_title();
1339
                }
1340
                if($params['author']) {
1341
                    $author = $item->get_author(0);
1342
                    if($author) {
1343
                        $name = $author->get_name();
1344
                        if(!$name) $name = $author->get_email();
1345
                        if($name) $this->doc .= ' '.$lang['by'].' '.hsc($name);
1346
                    }
1347
                }
1348
                if($params['date']) {
1349
                    $this->doc .= ' ('.$item->get_local_date($conf['dformat']).')';
1350
                }
1351
                if($params['details']) {
1352
                    $this->doc .= '<div class="detail">';
1353
                    if($conf['htmlok']) {
1354
                        $this->doc .= $item->get_description();
1355
                    } else {
1356
                        $this->doc .= strip_tags($item->get_description());
1357
                    }
1358
                    $this->doc .= '</div>';
1359
                }
1360
1361
                $this->doc .= '</div></li>';
1362
            }
1363
        } else {
1364
            $this->doc .= '<li><div class="li">';
1365
            $this->doc .= '<em>'.$lang['rssfailed'].'</em>';
1366
            $this->externallink($url);
1367
            if($conf['allowdebug']) {
1368
                $this->doc .= '<!--'.hsc($feed->error).'-->';
1369
            }
1370
            $this->doc .= '</div></li>';
1371
        }
1372
        $this->doc .= '</ul>';
1373
    }
1374
1375
    /**
1376
     * Start a table
1377
     *
1378
     * @param int $maxcols maximum number of columns
1379
     * @param int $numrows NOT IMPLEMENTED
1380
     * @param int $pos byte position in the original source
1381
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1382
     */
1383
    function table_open($maxcols = null, $numrows = null, $pos = null, $classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1384
        // initialize the row counter used for classes
1385
        $this->_counter['row_counter'] = 0;
1386
        $class                         = 'table';
1387
        if($classes !== null) {
1388
            if(is_array($classes)) $classes = join(' ', $classes);
1389
            $class .= ' ' . $classes;
1390
        }
1391
        if($pos !== null) {
1392
            $hid = $this->_headerToLink($class, true);
1393
            $data = array();
1394
            $data['target'] = 'table';
1395
            $data['name'] = '';
1396
            $data['hid'] = $hid;
1397
            $class .= ' '.$this->startSectionEdit($pos, $data);
1398
        }
1399
        $this->doc .= '<div class="'.$class.'"><table class="inline">'.
1400
            DOKU_LF;
1401
    }
1402
1403
    /**
1404
     * Close a table
1405
     *
1406
     * @param int $pos byte position in the original source
1407
     */
1408
    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...
1409
        $this->doc .= '</table></div>'.DOKU_LF;
1410
        if($pos !== null) {
1411
            $this->finishSectionEdit($pos);
1412
        }
1413
    }
1414
1415
    /**
1416
     * Open a table header
1417
     */
1418
    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...
1419
        $this->doc .= DOKU_TAB.'<thead>'.DOKU_LF;
1420
    }
1421
1422
    /**
1423
     * Close a table header
1424
     */
1425
    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...
1426
        $this->doc .= DOKU_TAB.'</thead>'.DOKU_LF;
1427
    }
1428
1429
    /**
1430
     * Open a table body
1431
     */
1432
    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...
1433
        $this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF;
1434
    }
1435
1436
    /**
1437
     * Close a table body
1438
     */
1439
    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...
1440
        $this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF;
1441
    }
1442
1443
    /**
1444
     * Open a table footer
1445
     */
1446
    function tabletfoot_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1447
        $this->doc .= DOKU_TAB.'<tfoot>'.DOKU_LF;
1448
    }
1449
1450
    /**
1451
     * Close a table footer
1452
     */
1453
    function tabletfoot_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1454
        $this->doc .= DOKU_TAB.'</tfoot>'.DOKU_LF;
1455
    }
1456
1457
    /**
1458
     * Open a table row
1459
     *
1460
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1461
     */
1462
    function tablerow_open($classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1463
        // initialize the cell counter used for classes
1464
        $this->_counter['cell_counter'] = 0;
1465
        $class                          = 'row'.$this->_counter['row_counter']++;
1466
        if($classes !== null) {
1467
            if(is_array($classes)) $classes = join(' ', $classes);
1468
            $class .= ' ' . $classes;
1469
        }
1470
        $this->doc .= DOKU_TAB.'<tr class="'.$class.'">'.DOKU_LF.DOKU_TAB.DOKU_TAB;
1471
    }
1472
1473
    /**
1474
     * Close a table row
1475
     */
1476
    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...
1477
        $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
1478
    }
1479
1480
    /**
1481
     * Open a table header cell
1482
     *
1483
     * @param int    $colspan
1484
     * @param string $align left|center|right
1485
     * @param int    $rowspan
1486
     * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
1487
     */
1488
    function tableheader_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1489
        $class = 'class="col'.$this->_counter['cell_counter']++;
1490
        if(!is_null($align)) {
1491
            $class .= ' '.$align.'align';
1492
        }
1493
        if($classes !== null) {
1494
            if(is_array($classes)) $classes = join(' ', $classes);
1495
            $class .= ' ' . $classes;
1496
        }
1497
        $class .= '"';
1498
        $this->doc .= '<th '.$class;
1499
        if($colspan > 1) {
1500
            $this->_counter['cell_counter'] += $colspan - 1;
1501
            $this->doc .= ' colspan="'.$colspan.'"';
1502
        }
1503
        if($rowspan > 1) {
1504
            $this->doc .= ' rowspan="'.$rowspan.'"';
1505
        }
1506
        $this->doc .= '>';
1507
    }
1508
1509
    /**
1510
     * Close a table header cell
1511
     */
1512
    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...
1513
        $this->doc .= '</th>';
1514
    }
1515
1516
    /**
1517
     * Open a table cell
1518
     *
1519
     * @param int       $colspan
1520
     * @param string    $align left|center|right
1521
     * @param int       $rowspan
1522
     * @param string|string[]    $classes css classes - have to be valid, do not pass unfiltered user input
1523
     */
1524
    function tablecell_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1525
        $class = 'class="col'.$this->_counter['cell_counter']++;
1526
        if(!is_null($align)) {
1527
            $class .= ' '.$align.'align';
1528
        }
1529
        if($classes !== null) {
1530
            if(is_array($classes)) $classes = join(' ', $classes);
1531
            $class .= ' ' . $classes;
1532
        }
1533
        $class .= '"';
1534
        $this->doc .= '<td '.$class;
1535
        if($colspan > 1) {
1536
            $this->_counter['cell_counter'] += $colspan - 1;
1537
            $this->doc .= ' colspan="'.$colspan.'"';
1538
        }
1539
        if($rowspan > 1) {
1540
            $this->doc .= ' rowspan="'.$rowspan.'"';
1541
        }
1542
        $this->doc .= '>';
1543
    }
1544
1545
    /**
1546
     * Close a table cell
1547
     */
1548
    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...
1549
        $this->doc .= '</td>';
1550
    }
1551
1552
    /**
1553
     * Returns the current header level.
1554
     * (required e.g. by the filelist plugin)
1555
     *
1556
     * @return int The current header level
1557
     */
1558
    function getLastlevel() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1559
        return $this->lastlevel;
1560
    }
1561
1562
    #region Utility functions
1563
1564
    /**
1565
     * Build a link
1566
     *
1567
     * Assembles all parts defined in $link returns HTML for the link
1568
     *
1569
     * @param array $link attributes of a link
1570
     * @return string
1571
     *
1572
     * @author Andreas Gohr <[email protected]>
1573
     */
1574
    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...
1575
        //make sure the url is XHTML compliant (skip mailto)
1576
        if(substr($link['url'], 0, 7) != 'mailto:') {
1577
            $link['url'] = str_replace('&', '&amp;', $link['url']);
1578
            $link['url'] = str_replace('&amp;amp;', '&amp;', $link['url']);
1579
        }
1580
        //remove double encodings in titles
1581
        $link['title'] = str_replace('&amp;amp;', '&amp;', $link['title']);
1582
1583
        // be sure there are no bad chars in url or title
1584
        // (we can't do this for name because it can contain an img tag)
1585
        $link['url']   = strtr($link['url'], array('>' => '%3E', '<' => '%3C', '"' => '%22'));
1586
        $link['title'] = strtr($link['title'], array('>' => '&gt;', '<' => '&lt;', '"' => '&quot;'));
1587
1588
        $ret = '';
1589
        $ret .= $link['pre'];
1590
        $ret .= '<a href="'.$link['url'].'"';
1591
        if(!empty($link['class'])) $ret .= ' class="'.$link['class'].'"';
1592
        if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"';
1593
        if(!empty($link['title'])) $ret .= ' title="'.$link['title'].'"';
1594
        if(!empty($link['style'])) $ret .= ' style="'.$link['style'].'"';
1595
        if(!empty($link['rel'])) $ret .= ' rel="'.trim($link['rel']).'"';
1596
        if(!empty($link['more'])) $ret .= ' '.$link['more'];
1597
        $ret .= '>';
1598
        $ret .= $link['name'];
1599
        $ret .= '</a>';
1600
        $ret .= $link['suf'];
1601
        return $ret;
1602
    }
1603
1604
    /**
1605
     * Renders internal and external media
1606
     *
1607
     * @author Andreas Gohr <[email protected]>
1608
     * @param string $src       media ID
1609
     * @param string $title     descriptive text
1610
     * @param string $align     left|center|right
1611
     * @param int    $width     width of media in pixel
1612
     * @param int    $height    height of media in pixel
1613
     * @param string $cache     cache|recache|nocache
1614
     * @param bool   $render    should the media be embedded inline or just linked
1615
     * @return string
1616
     */
1617
    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...
1618
                    $height = null, $cache = null, $render = true) {
1619
1620
        $ret = '';
1621
1622
        list($ext, $mime) = mimetype($src);
1623
        if(substr($mime, 0, 5) == 'image') {
1624
            // first get the $title
1625
            if(!is_null($title)) {
1626
                $title = $this->_xmlEntities($title);
1627
            } elseif($ext == 'jpg' || $ext == 'jpeg') {
1628
                //try to use the caption from IPTC/EXIF
1629
                require_once(DOKU_INC.'inc/JpegMeta.php');
1630
                $jpeg = new JpegMeta(mediaFN($src));
1631
                if($jpeg !== false) $cap = $jpeg->getTitle();
1632
                if(!empty($cap)) {
1633
                    $title = $this->_xmlEntities($cap);
1634
                }
1635
            }
1636
            if(!$render) {
1637
                // if the picture is not supposed to be rendered
1638
                // return the title of the picture
1639
                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...
1640
                    // just show the sourcename
1641
                    $title = $this->_xmlEntities(utf8_basename(noNS($src)));
1642
                }
1643
                return $title;
1644
            }
1645
            //add image tag
1646
            $ret .= '<img src="' . ml(
1647
                    $src,
1648
                    array(
1649
                        'w' => $width, 'h' => $height,
1650
                        'cache' => $cache,
1651
                        'rev' => $this->_getLastMediaRevisionAt($src)
1652
                    )
1653
                ) . '"';
1654
            $ret .= ' class="media'.$align.'"';
1655
1656
            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...
1657
                $ret .= ' title="'.$title.'"';
1658
                $ret .= ' alt="'.$title.'"';
1659
            } else {
1660
                $ret .= ' alt=""';
1661
            }
1662
1663
            if(!is_null($width))
1664
                $ret .= ' width="'.$this->_xmlEntities($width).'"';
1665
1666
            if(!is_null($height))
1667
                $ret .= ' height="'.$this->_xmlEntities($height).'"';
1668
1669
            $ret .= ' />';
1670
1671
        } elseif(media_supportedav($mime, 'video') || media_supportedav($mime, 'audio')) {
1672
            // first get the $title
1673
            $title = !is_null($title) ? $this->_xmlEntities($title) : false;
1674
            if(!$render) {
1675
                // if the file is not supposed to be rendered
1676
                // return the title of the file (just the sourcename if there is no title)
1677
                return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src)));
1678
            }
1679
1680
            $att          = array();
1681
            $att['class'] = "media$align";
1682
            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...
1683
                $att['title'] = $title;
1684
            }
1685
1686
            if(media_supportedav($mime, 'video')) {
1687
                //add video
1688
                $ret .= $this->_video($src, $width, $height, $att);
1689
            }
1690
            if(media_supportedav($mime, 'audio')) {
1691
                //add audio
1692
                $ret .= $this->_audio($src, $att);
1693
            }
1694
1695
        } elseif($mime == 'application/x-shockwave-flash') {
1696
            if(!$render) {
1697
                // if the flash is not supposed to be rendered
1698
                // return the title of the flash
1699
                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...
1700
                    // just show the sourcename
1701
                    $title = utf8_basename(noNS($src));
1702
                }
1703
                return $this->_xmlEntities($title);
1704
            }
1705
1706
            $att          = array();
1707
            $att['class'] = "media$align";
1708
            if($align == 'right') $att['align'] = 'right';
1709
            if($align == 'left') $att['align'] = 'left';
1710
            $ret .= html_flashobject(
1711
                ml($src, array('cache' => $cache), true, '&'), $width, $height,
1712
                array('quality' => 'high'),
1713
                null,
1714
                $att,
1715
                $this->_xmlEntities($title)
1716
            );
1717
        } 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...
1718
            // well at least we have a title to display
1719
            $ret .= $this->_xmlEntities($title);
1720
        } else {
1721
            // just show the sourcename
1722
            $ret .= $this->_xmlEntities(utf8_basename(noNS($src)));
1723
        }
1724
1725
        return $ret;
1726
    }
1727
1728
    /**
1729
     * Escape string for output
1730
     *
1731
     * @param $string
1732
     * @return string
1733
     */
1734
    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...
1735
        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
1736
    }
1737
1738
    /**
1739
     * Creates a linkid from a headline
1740
     *
1741
     * @author Andreas Gohr <[email protected]>
1742
     * @param string  $title   The headline title
1743
     * @param boolean $create  Create a new unique ID?
1744
     * @return string
1745
     */
1746
    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...
1747
        if($create) {
1748
            return sectionID($title, $this->headers);
1749
        } else {
1750
            $check = false;
1751
            return sectionID($title, $check);
1752
        }
1753
    }
1754
1755
    /**
1756
     * Construct a title and handle images in titles
1757
     *
1758
     * @author Harry Fuecks <[email protected]>
1759
     * @param string|array $title    either string title or media array
1760
     * @param string       $default  default title if nothing else is found
1761
     * @param bool         $isImage  will be set to true if it's a media file
1762
     * @param null|string  $id       linked page id (used to extract title from first heading)
1763
     * @param string       $linktype content|navigation
1764
     * @return string      HTML of the title, might be full image tag or just escaped text
1765
     */
1766
    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...
1767
        $isImage = false;
1768
        if(is_array($title)) {
1769
            $isImage = true;
1770
            return $this->_imageTitle($title);
1771
        } elseif(is_null($title) || trim($title) == '') {
1772
            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...
1773
                $heading = p_get_first_heading($id);
1774
                if(!blank($heading)) {
1775
                    return $this->_xmlEntities($heading);
1776
                }
1777
            }
1778
            return $this->_xmlEntities($default);
1779
        } else {
1780
            return $this->_xmlEntities($title);
1781
        }
1782
    }
1783
1784
    /**
1785
     * Returns HTML code for images used in link titles
1786
     *
1787
     * @author Andreas Gohr <[email protected]>
1788
     * @param array $img
1789
     * @return string HTML img tag or similar
1790
     */
1791
    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...
1792
        global $ID;
1793
1794
        // some fixes on $img['src']
1795
        // see internalmedia() and externalmedia()
1796
        list($img['src']) = explode('#', $img['src'], 2);
1797
        if($img['type'] == 'internalmedia') {
1798
            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...
1799
        }
1800
1801
        return $this->_media(
1802
            $img['src'],
1803
            $img['title'],
1804
            $img['align'],
1805
            $img['width'],
1806
            $img['height'],
1807
            $img['cache']
1808
        );
1809
    }
1810
1811
    /**
1812
     * helperfunction to return a basic link to a media
1813
     *
1814
     * used in internalmedia() and externalmedia()
1815
     *
1816
     * @author   Pierre Spring <[email protected]>
1817
     * @param string $src       media ID
1818
     * @param string $title     descriptive text
1819
     * @param string $align     left|center|right
1820
     * @param int    $width     width of media in pixel
1821
     * @param int    $height    height of media in pixel
1822
     * @param string $cache     cache|recache|nocache
1823
     * @param bool   $render    should the media be embedded inline or just linked
1824
     * @return array associative array with link config
1825
     */
1826
    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...
1827
        global $conf;
1828
1829
        $link           = array();
1830
        $link['class']  = 'media';
1831
        $link['style']  = '';
1832
        $link['pre']    = '';
1833
        $link['suf']    = '';
1834
        $link['more']   = '';
1835
        $link['target'] = $conf['target']['media'];
1836
        if($conf['target']['media']) $link['rel'] = 'noopener';
1837
        $link['title']  = $this->_xmlEntities($src);
1838
        $link['name']   = $this->_media($src, $title, $align, $width, $height, $cache, $render);
1839
1840
        return $link;
1841
    }
1842
1843
    /**
1844
     * Embed video(s) in HTML
1845
     *
1846
     * @author Anika Henke <[email protected]>
1847
     * @author Schplurtz le Déboulonné <[email protected]>
1848
     *
1849
     * @param string $src         - ID of video to embed
1850
     * @param int    $width       - width of the video in pixels
1851
     * @param int    $height      - height of the video in pixels
1852
     * @param array  $atts        - additional attributes for the <video> tag
1853
     * @return string
1854
     */
1855
    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...
1856
        // prepare width and height
1857
        if(is_null($atts)) $atts = array();
1858
        $atts['width']  = (int) $width;
1859
        $atts['height'] = (int) $height;
1860
        if(!$atts['width']) $atts['width'] = 320;
1861
        if(!$atts['height']) $atts['height'] = 240;
1862
1863
        $posterUrl = '';
1864
        $files = array();
1865
        $tracks = array();
1866
        $isExternal = media_isexternal($src);
1867
1868
        if ($isExternal) {
1869
            // take direct source for external files
1870
            list(/*ext*/, $srcMime) = mimetype($src);
1871
            $files[$srcMime] = $src;
1872
        } else {
1873
            // prepare alternative formats
1874
            $extensions   = array('webm', 'ogv', 'mp4');
1875
            $files        = media_alternativefiles($src, $extensions);
1876
            $poster       = media_alternativefiles($src, array('jpg', 'png'));
1877
            $tracks       = media_trackfiles($src);
1878
            if(!empty($poster)) {
1879
                $posterUrl = ml(reset($poster), '', true, '&');
1880
            }
1881
        }
1882
1883
        $out = '';
1884
        // open video tag
1885
        $out .= '<video '.buildAttributes($atts).' controls="controls"';
1886
        if($posterUrl) $out .= ' poster="'.hsc($posterUrl).'"';
1887
        $out .= '>'.NL;
1888
        $fallback = '';
1889
1890
        // output source for each alternative video format
1891
        foreach($files as $mime => $file) {
1892
            if ($isExternal) {
1893
                $url = $file;
1894
                $linkType = 'externalmedia';
1895
            } else {
1896
                $url = ml($file, '', true, '&');
1897
                $linkType = 'internalmedia';
1898
            }
1899
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1900
1901
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1902
            // alternative content (just a link to the file)
1903
            $fallback .= $this->$linkType(
1904
                $file,
1905
                $title,
1906
                null,
1907
                null,
1908
                null,
1909
                $cache = null,
1910
                $linking = 'linkonly',
1911
                $return = true
1912
            );
1913
        }
1914
1915
        // output each track if any
1916
        foreach( $tracks as $trackid => $info ) {
1917
            list( $kind, $srclang ) = array_map( 'hsc', $info );
1918
            $out .= "<track kind=\"$kind\" srclang=\"$srclang\" ";
1919
            $out .= "label=\"$srclang\" ";
1920
            $out .= 'src="'.ml($trackid, '', true).'">'.NL;
1921
        }
1922
1923
        // finish
1924
        $out .= $fallback;
1925
        $out .= '</video>'.NL;
1926
        return $out;
1927
    }
1928
1929
    /**
1930
     * Embed audio in HTML
1931
     *
1932
     * @author Anika Henke <[email protected]>
1933
     *
1934
     * @param string $src       - ID of audio to embed
1935
     * @param array  $atts      - additional attributes for the <audio> tag
1936
     * @return string
1937
     */
1938
    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...
1939
        $files = array();
1940
        $isExternal = media_isexternal($src);
1941
1942
        if ($isExternal) {
1943
            // take direct source for external files
1944
            list(/*ext*/, $srcMime) = mimetype($src);
1945
            $files[$srcMime] = $src;
1946
        } else {
1947
            // prepare alternative formats
1948
            $extensions   = array('ogg', 'mp3', 'wav');
1949
            $files        = media_alternativefiles($src, $extensions);
1950
        }
1951
1952
        $out = '';
1953
        // open audio tag
1954
        $out .= '<audio '.buildAttributes($atts).' controls="controls">'.NL;
1955
        $fallback = '';
1956
1957
        // output source for each alternative audio format
1958
        foreach($files as $mime => $file) {
1959
            if ($isExternal) {
1960
                $url = $file;
1961
                $linkType = 'externalmedia';
1962
            } else {
1963
                $url = ml($file, '', true, '&');
1964
                $linkType = 'internalmedia';
1965
            }
1966
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1967
1968
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1969
            // alternative content (just a link to the file)
1970
            $fallback .= $this->$linkType(
1971
                $file,
1972
                $title,
1973
                null,
1974
                null,
1975
                null,
1976
                $cache = null,
1977
                $linking = 'linkonly',
1978
                $return = true
1979
            );
1980
        }
1981
1982
        // finish
1983
        $out .= $fallback;
1984
        $out .= '</audio>'.NL;
1985
        return $out;
1986
    }
1987
1988
    /**
1989
     * _getLastMediaRevisionAt is a helperfunction to internalmedia() and _media()
1990
     * which returns an existing media revision less or equal to rev or date_at
1991
     *
1992
     * @author lisps
1993
     * @param string $media_id
1994
     * @access protected
1995
     * @return string revision ('' for current)
1996
     */
1997
    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...
1998
        if(!$this->date_at || media_isexternal($media_id)) return '';
1999
        $pagelog = new MediaChangeLog($media_id);
2000
        return $pagelog->getLastRevisionAt($this->date_at);
2001
    }
2002
2003
    #endregion
2004
}
2005
2006
//Setup VIM: ex: et ts=4 :
2007