Completed
Push — syntaxtableclasses ( 0c4c02...2e0ebe )
by Andreas
05:40
created

Doku_Renderer_xhtml::internallink()   F

Complexity

Conditions 13
Paths 1920

Size

Total Lines 82
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 51
nc 1920
nop 5
dl 0
loc 82
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
446
        $this->doc .= '</ul>'.DOKU_LF;
447
    }
448
449
    /**
450
     * Open an ordered list
451
     *
452
     * @param string|string[] $classes css class
453
     */
454
    function listo_open($classes = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
630
        global $ID;
631
        global $lang;
632
633
        if($filename) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filename of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return array();
}

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

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

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

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

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

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

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

An additional type check may prevent trouble.

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

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

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

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

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

An additional type check may prevent trouble.

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

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

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

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

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

    return array();
}

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

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

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

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

Loading history...
1134
                           $height = null, $cache = null, $linking = null, $return = false) {
1135
        global $ID;
1136
        list($src, $hash) = explode('#', $src, 2);
1137
        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...
1138
1139
        $noLink = false;
1140
        $render = ($linking == 'linkonly') ? false : true;
1141
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1142
1143
        list($ext, $mime) = mimetype($src, false);
1144
        if(substr($mime, 0, 5) == 'image' && $render) {
1145
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src)), ($linking == 'direct'));
1146
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1147
            // don't link movies
1148
            $noLink = true;
1149
        } else {
1150
            // add file icons
1151
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1152
            $link['class'] .= ' mediafile mf_'.$class;
1153
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache , 'rev'=>$this->_getLastMediaRevisionAt($src)), true);
1154
            if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')';
1155
        }
1156
1157
        if($hash) $link['url'] .= '#'.$hash;
1158
1159
        //markup non existing files
1160
        if(!$exists) {
1161
            $link['class'] .= ' wikilink2';
1162
        }
1163
1164
        //output formatted
1165
        if($return) {
1166
            if($linking == 'nolink' || $noLink) return $link['name'];
1167
            else return $this->_formatLink($link);
1168
        } else {
1169
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1170
            else $this->doc .= $this->_formatLink($link);
1171
        }
1172
    }
1173
1174
    /**
1175
     * Render an external media file
1176
     *
1177
     * @param string $src     full media URL
1178
     * @param string $title   descriptive text
1179
     * @param string $align   left|center|right
1180
     * @param int    $width   width of media in pixel
1181
     * @param int    $height  height of media in pixel
1182
     * @param string $cache   cache|recache|nocache
1183
     * @param string $linking linkonly|detail|nolink
1184
     * @param bool   $return  return HTML instead of adding to $doc
1185
     * @return void|string writes to doc attribute or returns html depends on $return
1186
     */
1187
    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...
1188
                           $height = null, $cache = null, $linking = null, $return = false) {
1189
        list($src, $hash) = explode('#', $src, 2);
1190
        $noLink = false;
1191
        $render = ($linking == 'linkonly') ? false : true;
1192
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1193
1194
        $link['url'] = ml($src, array('cache' => $cache));
1195
1196
        list($ext, $mime) = mimetype($src, false);
1197
        if(substr($mime, 0, 5) == 'image' && $render) {
1198
            // link only jpeg images
1199
            // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true;
1200
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1201
            // don't link movies
1202
            $noLink = true;
1203
        } else {
1204
            // add file icons
1205
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1206
            $link['class'] .= ' mediafile mf_'.$class;
1207
        }
1208
1209
        if($hash) $link['url'] .= '#'.$hash;
1210
1211
        //output formatted
1212
        if($return) {
1213
            if($linking == 'nolink' || $noLink) return $link['name'];
1214
            else return $this->_formatLink($link);
1215
        } else {
1216
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1217
            else $this->doc .= $this->_formatLink($link);
1218
        }
1219
    }
1220
1221
    /**
1222
     * Renders an RSS feed
1223
     *
1224
     * @param string $url    URL of the feed
1225
     * @param array  $params Finetuning of the output
1226
     *
1227
     * @author Andreas Gohr <[email protected]>
1228
     */
1229
    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...
1230
        global $lang;
1231
        global $conf;
1232
1233
        require_once(DOKU_INC.'inc/FeedParser.php');
1234
        $feed = new FeedParser();
1235
        $feed->set_feed_url($url);
1236
1237
        //disable warning while fetching
1238
        if(!defined('DOKU_E_LEVEL')) {
1239
            $elvl = error_reporting(E_ERROR);
1240
        }
1241
        $rc = $feed->init();
1242
        if(isset($elvl)) {
1243
            error_reporting($elvl);
1244
        }
1245
1246
        if($params['nosort']) $feed->enable_order_by_date(false);
1247
1248
        //decide on start and end
1249
        if($params['reverse']) {
1250
            $mod   = -1;
1251
            $start = $feed->get_item_quantity() - 1;
1252
            $end   = $start - ($params['max']);
1253
            $end   = ($end < -1) ? -1 : $end;
1254
        } else {
1255
            $mod   = 1;
1256
            $start = 0;
1257
            $end   = $feed->get_item_quantity();
1258
            $end   = ($end > $params['max']) ? $params['max'] : $end;
1259
        }
1260
1261
        $this->doc .= '<ul class="rss">';
1262
        if($rc) {
1263
            for($x = $start; $x != $end; $x += $mod) {
1264
                $item = $feed->get_item($x);
1265
                $this->doc .= '<li><div class="li">';
1266
                // support feeds without links
1267
                $lnkurl = $item->get_permalink();
1268
                if($lnkurl) {
1269
                    // title is escaped by SimplePie, we unescape here because it
1270
                    // is escaped again in externallink() FS#1705
1271
                    $this->externallink(
1272
                        $item->get_permalink(),
1273
                        html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')
1274
                    );
1275
                } else {
1276
                    $this->doc .= ' '.$item->get_title();
1277
                }
1278
                if($params['author']) {
1279
                    $author = $item->get_author(0);
1280
                    if($author) {
1281
                        $name = $author->get_name();
1282
                        if(!$name) $name = $author->get_email();
1283
                        if($name) $this->doc .= ' '.$lang['by'].' '.$name;
1284
                    }
1285
                }
1286
                if($params['date']) {
1287
                    $this->doc .= ' ('.$item->get_local_date($conf['dformat']).')';
1288
                }
1289
                if($params['details']) {
1290
                    $this->doc .= '<div class="detail">';
1291
                    if($conf['htmlok']) {
1292
                        $this->doc .= $item->get_description();
1293
                    } else {
1294
                        $this->doc .= strip_tags($item->get_description());
1295
                    }
1296
                    $this->doc .= '</div>';
1297
                }
1298
1299
                $this->doc .= '</div></li>';
1300
            }
1301
        } else {
1302
            $this->doc .= '<li><div class="li">';
1303
            $this->doc .= '<em>'.$lang['rssfailed'].'</em>';
1304
            $this->externallink($url);
1305
            if($conf['allowdebug']) {
1306
                $this->doc .= '<!--'.hsc($feed->error).'-->';
1307
            }
1308
            $this->doc .= '</div></li>';
1309
        }
1310
        $this->doc .= '</ul>';
1311
    }
1312
1313
    /**
1314
     * Start a table
1315
     *
1316
     * @param int $maxcols maximum number of columns
1317
     * @param int $numrows NOT IMPLEMENTED
1318
     * @param int $pos byte position in the original source
1319
     * @param string|string[] $classes css class
1320
     */
1321
    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...
1322
        // initialize the row counter used for classes
1323
        $this->_counter['row_counter'] = 0;
1324
        $class                         = 'table';
1325
        if($classes !== null) {
1326
            if(is_array($classes)) $classes = join(' ', $classes);
1327
            $class .= ' ' . $classes;
1328
        }
1329
        if($pos !== null) {
1330
            $class .= ' '.$this->startSectionEdit($pos, 'table');
1331
        }
1332
        $this->doc .= '<div class="'.$class.'"><table class="inline">'.
1333
            DOKU_LF;
1334
    }
1335
1336
    /**
1337
     * Close a table
1338
     *
1339
     * @param int $pos byte position in the original source
1340
     */
1341
    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...
1342
        $this->doc .= '</table></div>'.DOKU_LF;
1343
        if($pos !== null) {
1344
            $this->finishSectionEdit($pos);
1345
        }
1346
    }
1347
1348
    /**
1349
     * Open a table header
1350
     */
1351
    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...
1352
        $this->doc .= DOKU_TAB.'<thead>'.DOKU_LF;
1353
    }
1354
1355
    /**
1356
     * Close a table header
1357
     */
1358
    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...
1359
        $this->doc .= DOKU_TAB.'</thead>'.DOKU_LF;
1360
    }
1361
1362
    /**
1363
     * Open a table body
1364
     */
1365
    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...
1366
        $this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF;
1367
    }
1368
1369
    /**
1370
     * Close a table body
1371
     */
1372
    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...
1373
        $this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF;
1374
    }
1375
1376
    /**
1377
     * Open a table row
1378
     *
1379
     * @param string|string[] $classes css class
1380
     */
1381
    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...
1382
        // initialize the cell counter used for classes
1383
        $this->_counter['cell_counter'] = 0;
1384
        $class                          = 'row'.$this->_counter['row_counter']++;
1385
        if($classes !== null) {
1386
            if(is_array($classes)) $classes = join(' ', $classes);
1387
            $class .= ' ' . $classes;
1388
        }
1389
        $this->doc .= DOKU_TAB.'<tr class="'.$class.'">'.DOKU_LF.DOKU_TAB.DOKU_TAB;
1390
    }
1391
1392
    /**
1393
     * Close a table row
1394
     */
1395
    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...
1396
        $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
1397
    }
1398
1399
    /**
1400
     * Open a table header cell
1401
     *
1402
     * @param int    $colspan
1403
     * @param string $align left|center|right
1404
     * @param int    $rowspan
1405
     * @param string|string[] $classes css class
1406
     */
1407
    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...
1408
        $class = 'class="col'.$this->_counter['cell_counter']++;
1409
        if(!is_null($align)) {
1410
            $class .= ' '.$align.'align';
1411
        }
1412
        if($classes !== null) {
1413
            if(is_array($classes)) $classes = join(' ', $classes);
1414
            $class .= ' ' . $classes;
1415
        }
1416
        $class .= '"';
1417
        $this->doc .= '<th '.$class;
1418
        if($colspan > 1) {
1419
            $this->_counter['cell_counter'] += $colspan - 1;
1420
            $this->doc .= ' colspan="'.$colspan.'"';
1421
        }
1422
        if($rowspan > 1) {
1423
            $this->doc .= ' rowspan="'.$rowspan.'"';
1424
        }
1425
        $this->doc .= '>';
1426
    }
1427
1428
    /**
1429
     * Close a table header cell
1430
     */
1431
    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...
1432
        $this->doc .= '</th>';
1433
    }
1434
1435
    /**
1436
     * Open a table cell
1437
     *
1438
     * @param int       $colspan
1439
     * @param string    $align left|center|right
1440
     * @param int       $rowspan
1441
     * @param string|string[]    $classes css class
1442
     */
1443
    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...
1444
        $class = 'class="col'.$this->_counter['cell_counter']++;
1445
        if(!is_null($align)) {
1446
            $class .= ' '.$align.'align';
1447
        }
1448
        if($classes !== null) {
1449
            if(is_array($classes)) $classes = join(' ', $classes);
1450
            $class .= ' ' . $classes;
1451
        }
1452
        $class .= '"';
1453
        $this->doc .= '<td '.$class;
1454
        if($colspan > 1) {
1455
            $this->_counter['cell_counter'] += $colspan - 1;
1456
            $this->doc .= ' colspan="'.$colspan.'"';
1457
        }
1458
        if($rowspan > 1) {
1459
            $this->doc .= ' rowspan="'.$rowspan.'"';
1460
        }
1461
        $this->doc .= '>';
1462
    }
1463
1464
    /**
1465
     * Close a table cell
1466
     */
1467
    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...
1468
        $this->doc .= '</td>';
1469
    }
1470
1471
    #region Utility functions
1472
1473
    /**
1474
     * Build a link
1475
     *
1476
     * Assembles all parts defined in $link returns HTML for the link
1477
     *
1478
     * @param array $link attributes of a link
1479
     * @return string
1480
     *
1481
     * @author Andreas Gohr <[email protected]>
1482
     */
1483
    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...
1484
        //make sure the url is XHTML compliant (skip mailto)
1485
        if(substr($link['url'], 0, 7) != 'mailto:') {
1486
            $link['url'] = str_replace('&', '&amp;', $link['url']);
1487
            $link['url'] = str_replace('&amp;amp;', '&amp;', $link['url']);
1488
        }
1489
        //remove double encodings in titles
1490
        $link['title'] = str_replace('&amp;amp;', '&amp;', $link['title']);
1491
1492
        // be sure there are no bad chars in url or title
1493
        // (we can't do this for name because it can contain an img tag)
1494
        $link['url']   = strtr($link['url'], array('>' => '%3E', '<' => '%3C', '"' => '%22'));
1495
        $link['title'] = strtr($link['title'], array('>' => '&gt;', '<' => '&lt;', '"' => '&quot;'));
1496
1497
        $ret = '';
1498
        $ret .= $link['pre'];
1499
        $ret .= '<a href="'.$link['url'].'"';
1500
        if(!empty($link['class'])) $ret .= ' class="'.$link['class'].'"';
1501
        if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"';
1502
        if(!empty($link['title'])) $ret .= ' title="'.$link['title'].'"';
1503
        if(!empty($link['style'])) $ret .= ' style="'.$link['style'].'"';
1504
        if(!empty($link['rel'])) $ret .= ' rel="'.trim($link['rel']).'"';
1505
        if(!empty($link['more'])) $ret .= ' '.$link['more'];
1506
        $ret .= '>';
1507
        $ret .= $link['name'];
1508
        $ret .= '</a>';
1509
        $ret .= $link['suf'];
1510
        return $ret;
1511
    }
1512
1513
    /**
1514
     * Renders internal and external media
1515
     *
1516
     * @author Andreas Gohr <[email protected]>
1517
     * @param string $src       media ID
1518
     * @param string $title     descriptive text
1519
     * @param string $align     left|center|right
1520
     * @param int    $width     width of media in pixel
1521
     * @param int    $height    height of media in pixel
1522
     * @param string $cache     cache|recache|nocache
1523
     * @param bool   $render    should the media be embedded inline or just linked
1524
     * @return string
1525
     */
1526
    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...
1527
                    $height = null, $cache = null, $render = true) {
1528
1529
        $ret = '';
1530
1531
        list($ext, $mime) = mimetype($src);
1532
        if(substr($mime, 0, 5) == 'image') {
1533
            // first get the $title
1534
            if(!is_null($title)) {
1535
                $title = $this->_xmlEntities($title);
1536
            } elseif($ext == 'jpg' || $ext == 'jpeg') {
1537
                //try to use the caption from IPTC/EXIF
1538
                require_once(DOKU_INC.'inc/JpegMeta.php');
1539
                $jpeg = new JpegMeta(mediaFN($src));
1540
                if($jpeg !== false) $cap = $jpeg->getTitle();
1541
                if(!empty($cap)) {
1542
                    $title = $this->_xmlEntities($cap);
1543
                }
1544
            }
1545
            if(!$render) {
1546
                // if the picture is not supposed to be rendered
1547
                // return the title of the picture
1548
                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...
1549
                    // just show the sourcename
1550
                    $title = $this->_xmlEntities(utf8_basename(noNS($src)));
1551
                }
1552
                return $title;
1553
            }
1554
            //add image tag
1555
            $ret .= '<img src="'.ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src))).'"';
1556
            $ret .= ' class="media'.$align.'"';
1557
1558
            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...
1559
                $ret .= ' title="'.$title.'"';
1560
                $ret .= ' alt="'.$title.'"';
1561
            } else {
1562
                $ret .= ' alt=""';
1563
            }
1564
1565
            if(!is_null($width))
1566
                $ret .= ' width="'.$this->_xmlEntities($width).'"';
1567
1568
            if(!is_null($height))
1569
                $ret .= ' height="'.$this->_xmlEntities($height).'"';
1570
1571
            $ret .= ' />';
1572
1573
        } elseif(media_supportedav($mime, 'video') || media_supportedav($mime, 'audio')) {
1574
            // first get the $title
1575
            $title = !is_null($title) ? $this->_xmlEntities($title) : false;
1576
            if(!$render) {
1577
                // if the file is not supposed to be rendered
1578
                // return the title of the file (just the sourcename if there is no title)
1579
                return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src)));
1580
            }
1581
1582
            $att          = array();
1583
            $att['class'] = "media$align";
1584
            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...
1585
                $att['title'] = $title;
1586
            }
1587
1588
            if(media_supportedav($mime, 'video')) {
1589
                //add video
1590
                $ret .= $this->_video($src, $width, $height, $att);
1591
            }
1592
            if(media_supportedav($mime, 'audio')) {
1593
                //add audio
1594
                $ret .= $this->_audio($src, $att);
1595
            }
1596
1597
        } elseif($mime == 'application/x-shockwave-flash') {
1598
            if(!$render) {
1599
                // if the flash is not supposed to be rendered
1600
                // return the title of the flash
1601
                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...
1602
                    // just show the sourcename
1603
                    $title = utf8_basename(noNS($src));
1604
                }
1605
                return $this->_xmlEntities($title);
1606
            }
1607
1608
            $att          = array();
1609
            $att['class'] = "media$align";
1610
            if($align == 'right') $att['align'] = 'right';
1611
            if($align == 'left') $att['align'] = 'left';
1612
            $ret .= html_flashobject(
1613
                ml($src, array('cache' => $cache), true, '&'), $width, $height,
1614
                array('quality' => 'high'),
1615
                null,
1616
                $att,
1617
                $this->_xmlEntities($title)
1618
            );
1619
        } 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...
1620
            // well at least we have a title to display
1621
            $ret .= $this->_xmlEntities($title);
1622
        } else {
1623
            // just show the sourcename
1624
            $ret .= $this->_xmlEntities(utf8_basename(noNS($src)));
1625
        }
1626
1627
        return $ret;
1628
    }
1629
1630
    /**
1631
     * Escape string for output
1632
     *
1633
     * @param $string
1634
     * @return string
1635
     */
1636
    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...
1637
        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
1638
    }
1639
1640
    /**
1641
     * Creates a linkid from a headline
1642
     *
1643
     * @author Andreas Gohr <[email protected]>
1644
     * @param string  $title   The headline title
1645
     * @param boolean $create  Create a new unique ID?
1646
     * @return string
1647
     */
1648
    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...
1649
        if($create) {
1650
            return sectionID($title, $this->headers);
1651
        } else {
1652
            $check = false;
1653
            return sectionID($title, $check);
1654
        }
1655
    }
1656
1657
    /**
1658
     * Construct a title and handle images in titles
1659
     *
1660
     * @author Harry Fuecks <[email protected]>
1661
     * @param string|array $title    either string title or media array
1662
     * @param string       $default  default title if nothing else is found
1663
     * @param bool         $isImage  will be set to true if it's a media file
1664
     * @param null|string  $id       linked page id (used to extract title from first heading)
1665
     * @param string       $linktype content|navigation
1666
     * @return string      HTML of the title, might be full image tag or just escaped text
1667
     */
1668
    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...
1669
        $isImage = false;
1670
        if(is_array($title)) {
1671
            $isImage = true;
1672
            return $this->_imageTitle($title);
1673
        } elseif(is_null($title) || trim($title) == '') {
1674
            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...
1675
                $heading = p_get_first_heading($id);
1676
                if($heading) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $heading of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1677
                    return $this->_xmlEntities($heading);
1678
                }
1679
            }
1680
            return $this->_xmlEntities($default);
1681
        } else {
1682
            return $this->_xmlEntities($title);
1683
        }
1684
    }
1685
1686
    /**
1687
     * Returns HTML code for images used in link titles
1688
     *
1689
     * @author Andreas Gohr <[email protected]>
1690
     * @param array $img
1691
     * @return string HTML img tag or similar
1692
     */
1693
    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...
1694
        global $ID;
1695
1696
        // some fixes on $img['src']
1697
        // see internalmedia() and externalmedia()
1698
        list($img['src']) = explode('#', $img['src'], 2);
1699
        if($img['type'] == 'internalmedia') {
1700
            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...
1701
        }
1702
1703
        return $this->_media(
1704
            $img['src'],
1705
            $img['title'],
1706
            $img['align'],
1707
            $img['width'],
1708
            $img['height'],
1709
            $img['cache']
1710
        );
1711
    }
1712
1713
    /**
1714
     * helperfunction to return a basic link to a media
1715
     *
1716
     * used in internalmedia() and externalmedia()
1717
     *
1718
     * @author   Pierre Spring <[email protected]>
1719
     * @param string $src       media ID
1720
     * @param string $title     descriptive text
1721
     * @param string $align     left|center|right
1722
     * @param int    $width     width of media in pixel
1723
     * @param int    $height    height of media in pixel
1724
     * @param string $cache     cache|recache|nocache
1725
     * @param bool   $render    should the media be embedded inline or just linked
1726
     * @return array associative array with link config
1727
     */
1728
    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...
1729
        global $conf;
1730
1731
        $link           = array();
1732
        $link['class']  = 'media';
1733
        $link['style']  = '';
1734
        $link['pre']    = '';
1735
        $link['suf']    = '';
1736
        $link['more']   = '';
1737
        $link['target'] = $conf['target']['media'];
1738
        if($conf['target']['media']) $link['rel'] = 'noopener';
1739
        $link['title']  = $this->_xmlEntities($src);
1740
        $link['name']   = $this->_media($src, $title, $align, $width, $height, $cache, $render);
1741
1742
        return $link;
1743
    }
1744
1745
    /**
1746
     * Embed video(s) in HTML
1747
     *
1748
     * @author Anika Henke <[email protected]>
1749
     *
1750
     * @param string $src         - ID of video to embed
1751
     * @param int    $width       - width of the video in pixels
1752
     * @param int    $height      - height of the video in pixels
1753
     * @param array  $atts        - additional attributes for the <video> tag
1754
     * @return string
1755
     */
1756
    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...
1757
        // prepare width and height
1758
        if(is_null($atts)) $atts = array();
1759
        $atts['width']  = (int) $width;
1760
        $atts['height'] = (int) $height;
1761
        if(!$atts['width']) $atts['width'] = 320;
1762
        if(!$atts['height']) $atts['height'] = 240;
1763
1764
        $posterUrl = '';
1765
        $files = array();
1766
        $isExternal = media_isexternal($src);
1767
1768
        if ($isExternal) {
1769
            // take direct source for external files
1770
            list(/*ext*/, $srcMime) = mimetype($src);
1771
            $files[$srcMime] = $src;
1772
        } else {
1773
            // prepare alternative formats
1774
            $extensions   = array('webm', 'ogv', 'mp4');
1775
            $files        = media_alternativefiles($src, $extensions);
1776
            $poster       = media_alternativefiles($src, array('jpg', 'png'));
1777
            if(!empty($poster)) {
1778
                $posterUrl = ml(reset($poster), '', true, '&');
1779
            }
1780
        }
1781
1782
        $out = '';
1783
        // open video tag
1784
        $out .= '<video '.buildAttributes($atts).' controls="controls"';
1785
        if($posterUrl) $out .= ' poster="'.hsc($posterUrl).'"';
1786
        $out .= '>'.NL;
1787
        $fallback = '';
1788
1789
        // output source for each alternative video format
1790
        foreach($files as $mime => $file) {
1791
            if ($isExternal) {
1792
                $url = $file;
1793
                $linkType = 'externalmedia';
1794
            } else {
1795
                $url = ml($file, '', true, '&');
1796
                $linkType = 'internalmedia';
1797
            }
1798
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1799
1800
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1801
            // alternative content (just a link to the file)
1802
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1803
        }
1804
1805
        // finish
1806
        $out .= $fallback;
1807
        $out .= '</video>'.NL;
1808
        return $out;
1809
    }
1810
1811
    /**
1812
     * Embed audio in HTML
1813
     *
1814
     * @author Anika Henke <[email protected]>
1815
     *
1816
     * @param string $src       - ID of audio to embed
1817
     * @param array  $atts      - additional attributes for the <audio> tag
1818
     * @return string
1819
     */
1820
    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...
1821
        $files = array();
1822
        $isExternal = media_isexternal($src);
1823
1824
        if ($isExternal) {
1825
            // take direct source for external files
1826
            list(/*ext*/, $srcMime) = mimetype($src);
1827
            $files[$srcMime] = $src;
1828
        } else {
1829
            // prepare alternative formats
1830
            $extensions   = array('ogg', 'mp3', 'wav');
1831
            $files        = media_alternativefiles($src, $extensions);
1832
        }
1833
1834
        $out = '';
1835
        // open audio tag
1836
        $out .= '<audio '.buildAttributes($atts).' controls="controls">'.NL;
1837
        $fallback = '';
1838
1839
        // output source for each alternative audio format
1840
        foreach($files as $mime => $file) {
1841
            if ($isExternal) {
1842
                $url = $file;
1843
                $linkType = 'externalmedia';
1844
            } else {
1845
                $url = ml($file, '', true, '&');
1846
                $linkType = 'internalmedia';
1847
            }
1848
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1849
1850
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1851
            // alternative content (just a link to the file)
1852
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1853
        }
1854
1855
        // finish
1856
        $out .= $fallback;
1857
        $out .= '</audio>'.NL;
1858
        return $out;
1859
    }
1860
1861
    /**
1862
     * _getLastMediaRevisionAt is a helperfunction to internalmedia() and _media()
1863
     * which returns an existing media revision less or equal to rev or date_at
1864
     *
1865
     * @author lisps
1866
     * @param string $media_id
1867
     * @access protected
1868
     * @return string revision ('' for current)
1869
     */
1870
    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...
1871
        if(!$this->date_at || media_isexternal($media_id)) return '';
1872
        $pagelog = new MediaChangeLog($media_id);
1873
        return $pagelog->getLastRevisionAt($this->date_at);
1874
    }
1875
1876
    #endregion
1877
}
1878
1879
//Setup VIM: ex: et ts=4 :
1880