Completed
Pull Request — authpdo (#1572)
by
unknown
04:27
created

Doku_Renderer_xhtml::linebreak()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
432
        $this->doc .= '<ul>'.DOKU_LF;
433
    }
434
435
    /**
436
     * Close an unordered list
437
     */
438
    function listu_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
439
        $this->doc .= '</ul>'.DOKU_LF;
440
    }
441
442
    /**
443
     * Open an ordered list
444
     */
445
    function listo_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
446
        $this->doc .= '<ol>'.DOKU_LF;
447
    }
448
449
    /**
450
     * Close an ordered list
451
     */
452
    function listo_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
453
        $this->doc .= '</ol>'.DOKU_LF;
454
    }
455
456
    /**
457
     * Open a list item
458
     *
459
     * @param int $level the nesting level
460
     * @param bool $node true when a node; false when a leaf
461
     */
462
    function listitem_open($level, $node=false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
463
        $branching = $node ? ' node' : '';
464
        $this->doc .= '<li class="level'.$level.$branching.'">';
465
    }
466
467
    /**
468
     * Close a list item
469
     */
470
    function listitem_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
471
        $this->doc .= '</li>'.DOKU_LF;
472
    }
473
474
    /**
475
     * Start the content of a list item
476
     */
477
    function listcontent_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
478
        $this->doc .= '<div class="li">';
479
    }
480
481
    /**
482
     * Stop the content of a list item
483
     */
484
    function listcontent_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
485
        $this->doc .= '</div>'.DOKU_LF;
486
    }
487
488
    /**
489
     * Output unformatted $text
490
     *
491
     * Defaults to $this->cdata()
492
     *
493
     * @param string $text
494
     */
495
    function unformatted($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
496
        $this->doc .= $this->_xmlEntities($text);
497
    }
498
499
    /**
500
     * Execute PHP code if allowed
501
     *
502
     * @param  string $text      PHP code that is either executed or printed
503
     * @param  string $wrapper   html element to wrap result if $conf['phpok'] is okff
504
     *
505
     * @author Andreas Gohr <[email protected]>
506
     */
507
    function php($text, $wrapper = 'code') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
508
        global $conf;
509
510
        if($conf['phpok']) {
511
            ob_start();
512
            eval($text);
513
            $this->doc .= ob_get_contents();
514
            ob_end_clean();
515
        } else {
516
            $this->doc .= p_xhtml_cached_geshi($text, 'php', $wrapper);
517
        }
518
    }
519
520
    /**
521
     * Output block level PHP code
522
     *
523
     * If $conf['phpok'] is true this should evaluate the given code and append the result
524
     * to $doc
525
     *
526
     * @param string $text The PHP code
527
     */
528
    function phpblock($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
529
        $this->php($text, 'pre');
530
    }
531
532
    /**
533
     * Insert HTML if allowed
534
     *
535
     * @param  string $text      html text
536
     * @param  string $wrapper   html element to wrap result if $conf['htmlok'] is okff
537
     *
538
     * @author Andreas Gohr <[email protected]>
539
     */
540
    function html($text, $wrapper = 'code') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
541
        global $conf;
542
543
        if($conf['htmlok']) {
544
            $this->doc .= $text;
545
        } else {
546
            $this->doc .= p_xhtml_cached_geshi($text, 'html4strict', $wrapper);
547
        }
548
    }
549
550
    /**
551
     * Output raw block-level HTML
552
     *
553
     * If $conf['htmlok'] is true this should add the code as is to $doc
554
     *
555
     * @param string $text The HTML
556
     */
557
    function htmlblock($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
558
        $this->html($text, 'pre');
559
    }
560
561
    /**
562
     * Start a block quote
563
     */
564
    function quote_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
565
        $this->doc .= '<blockquote><div class="no">'.DOKU_LF;
566
    }
567
568
    /**
569
     * Stop a block quote
570
     */
571
    function quote_close() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
572
        $this->doc .= '</div></blockquote>'.DOKU_LF;
573
    }
574
575
    /**
576
     * Output preformatted text
577
     *
578
     * @param string $text
579
     */
580
    function preformatted($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
581
        $this->doc .= '<pre class="code">'.trim($this->_xmlEntities($text), "\n\r").'</pre>'.DOKU_LF;
582
    }
583
584
    /**
585
     * Display text as file content, optionally syntax highlighted
586
     *
587
     * @param string $text     text to show
588
     * @param string $language programming language to use for syntax highlighting
589
     * @param string $filename file path label
590
     */
591
    function file($text, $language = null, $filename = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
592
        $this->_highlight('file', $text, $language, $filename);
593
    }
594
595
    /**
596
     * Display text as code content, optionally syntax highlighted
597
     *
598
     * @param string $text     text to show
599
     * @param string $language programming language to use for syntax highlighting
600
     * @param string $filename file path label
601
     */
602
    function code($text, $language = null, $filename = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
603
        $this->_highlight('code', $text, $language, $filename);
604
    }
605
606
    /**
607
     * Use GeSHi to highlight language syntax in code and file blocks
608
     *
609
     * @author Andreas Gohr <[email protected]>
610
     * @param string $type     code|file
611
     * @param string $text     text to show
612
     * @param string $language programming language to use for syntax highlighting
613
     * @param string $filename file path label
614
     */
615
    function _highlight($type, $text, $language = null, $filename = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

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

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

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

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

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

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
648
            $this->doc .= '</dd></dl>'.DOKU_LF;
649
        }
650
651
        $this->_codeblock++;
652
    }
653
654
    /**
655
     * Format an acronym
656
     *
657
     * Uses $this->acronyms
658
     *
659
     * @param string $acronym
660
     */
661
    function acronym($acronym) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
662
663
        if(array_key_exists($acronym, $this->acronyms)) {
664
665
            $title = $this->_xmlEntities($this->acronyms[$acronym]);
666
667
            $this->doc .= '<abbr title="'.$title
668
                .'">'.$this->_xmlEntities($acronym).'</abbr>';
669
670
        } else {
671
            $this->doc .= $this->_xmlEntities($acronym);
672
        }
673
    }
674
675
    /**
676
     * Format a smiley
677
     *
678
     * Uses $this->smiley
679
     *
680
     * @param string $smiley
681
     */
682
    function smiley($smiley) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
683
        if(array_key_exists($smiley, $this->smileys)) {
684
            $this->doc .= '<img src="'.DOKU_BASE.'lib/images/smileys/'.$this->smileys[$smiley].
685
                '" class="icon" alt="'.
686
                $this->_xmlEntities($smiley).'" />';
687
        } else {
688
            $this->doc .= $this->_xmlEntities($smiley);
689
        }
690
    }
691
692
    /**
693
     * Format an entity
694
     *
695
     * Entities are basically small text replacements
696
     *
697
     * Uses $this->entities
698
     *
699
     * @param string $entity
700
     */
701
    function entity($entity) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
702
        if(array_key_exists($entity, $this->entities)) {
703
            $this->doc .= $this->entities[$entity];
704
        } else {
705
            $this->doc .= $this->_xmlEntities($entity);
706
        }
707
    }
708
709
    /**
710
     * Typographically format a multiply sign
711
     *
712
     * Example: ($x=640, $y=480) should result in "640×480"
713
     *
714
     * @param string|int $x first value
715
     * @param string|int $y second value
716
     */
717
    function multiplyentity($x, $y) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
718
        $this->doc .= "$x&times;$y";
719
    }
720
721
    /**
722
     * Render an opening single quote char (language specific)
723
     */
724
    function singlequoteopening() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
725
        global $lang;
726
        $this->doc .= $lang['singlequoteopening'];
727
    }
728
729
    /**
730
     * Render a closing single quote char (language specific)
731
     */
732
    function singlequoteclosing() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
733
        global $lang;
734
        $this->doc .= $lang['singlequoteclosing'];
735
    }
736
737
    /**
738
     * Render an apostrophe char (language specific)
739
     */
740
    function apostrophe() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
741
        global $lang;
742
        $this->doc .= $lang['apostrophe'];
743
    }
744
745
    /**
746
     * Render an opening double quote char (language specific)
747
     */
748
    function doublequoteopening() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

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

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

Loading history...
757
        global $lang;
758
        $this->doc .= $lang['doublequoteclosing'];
759
    }
760
761
    /**
762
     * Render a CamelCase link
763
     *
764
     * @param string $link       The link name
765
     * @param bool   $returnonly whether to return html or write to doc attribute
766
     * @see http://en.wikipedia.org/wiki/CamelCase
767
     */
768
    function camelcaselink($link, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
769
        if($returnonly) {
770
          return $this->internallink($link, $link, null, true);
771
        } else {
772
          $this->internallink($link, $link);
773
        }
774
    }
775
776
    /**
777
     * Render a page local link
778
     *
779
     * @param string $hash       hash link identifier
780
     * @param string $name       name for the link
781
     * @param bool   $returnonly whether to return html or write to doc attribute
782
     */
783
    function locallink($hash, $name = null, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
784
        global $ID;
785
        $name  = $this->_getLinkTitle($name, $hash, $isImage);
786
        $hash  = $this->_headerToLink($hash);
787
        $title = $ID.' ↵';
788
789
        $doc = '<a href="#'.$hash.'" title="'.$title.'" class="wikilink1">';
790
        $doc .= $name;
791
        $doc .= '</a>';
792
793
        if($returnonly) {
794
          return $doc;
795
        } else {
796
          $this->doc .= $doc;
797
        }
798
    }
799
800
    /**
801
     * Render an internal Wiki Link
802
     *
803
     * $search,$returnonly & $linktype are not for the renderer but are used
804
     * elsewhere - no need to implement them in other renderers
805
     *
806
     * @author Andreas Gohr <[email protected]>
807
     * @param string      $id         pageid
808
     * @param string|null $name       link name
809
     * @param string|null $search     adds search url param
810
     * @param bool        $returnonly whether to return html or write to doc attribute
811
     * @param string      $linktype   type to set use of headings
812
     * @return void|string writes to doc attribute or returns html depends on $returnonly
813
     */
814
    function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
855
        if(!empty($hash)) $hash = $this->_headerToLink($hash);
856
857
        //prepare for formating
858
        $link['target'] = $conf['target']['wiki'];
859
        $link['style']  = '';
860
        $link['pre']    = '';
861
        $link['suf']    = '';
862
        // highlight link to current page
863
        if($id == $INFO['id']) {
864
            $link['pre'] = '<span class="curid">';
865
            $link['suf'] = '</span>';
866
        }
867
        $link['more']   = '';
868
        $link['class']  = $class;
869
        if($this->date_at) {
870
            $params['at'] = $this->date_at;
871
        }
872
        $link['url']    = wl($id, $params);
873
        $link['name']   = $name;
874
        $link['title']  = $id;
875
        //add search string
876
        if($search) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $search of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
877
            ($conf['userewrite']) ? $link['url'] .= '?' : $link['url'] .= '&amp;';
878
            if(is_array($search)) {
879
                $search = array_map('rawurlencode', $search);
880
                $link['url'] .= 's[]='.join('&amp;s[]=', $search);
881
            } else {
882
                $link['url'] .= 's='.rawurlencode($search);
883
            }
884
        }
885
886
        //keep hash
887
        if($hash) $link['url'] .= '#'.$hash;
888
889
        //output formatted
890
        if($returnonly) {
891
            return $this->_formatLink($link);
892
        } else {
893
            $this->doc .= $this->_formatLink($link);
894
        }
895
    }
896
897
    /**
898
     * Render an external link
899
     *
900
     * @param string       $url        full URL with scheme
901
     * @param string|array $name       name for the link, array for media file
902
     * @param bool         $returnonly whether to return html or write to doc attribute
903
     */
904
    function externallink($url, $name = null, $returnonly = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

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

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

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

    return array();
}

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

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

Loading history...
908
909
        // url might be an attack vector, only allow registered protocols
910
        if(is_null($this->schemes)) $this->schemes = getSchemes();
911
        list($scheme) = explode('://', $url);
912
        $scheme = strtolower($scheme);
913
        if(!in_array($scheme, $this->schemes)) $url = '';
914
915
        // is there still an URL?
916
        if(!$url) {
917
            if($returnonly) {
918
                return $name;
919
            } else {
920
                $this->doc .= $name;
921
            }
922
            return;
923
        }
924
925
        // set class
926
        if(!$isImage) {
927
            $class = 'urlextern';
928
        } else {
929
            $class = 'media';
930
        }
931
932
        //prepare for formating
933
        $link = array();
934
        $link['target'] = $conf['target']['extern'];
935
        $link['style']  = '';
936
        $link['pre']    = '';
937
        $link['suf']    = '';
938
        $link['more']   = '';
939
        $link['class']  = $class;
940
        $link['url']    = $url;
941
942
        $link['name']  = $name;
943
        $link['title'] = $this->_xmlEntities($url);
944
        if($conf['relnofollow']) $link['more'] .= ' rel="nofollow"';
945
946
        //output formatted
947
        if($returnonly) {
948
            return $this->_formatLink($link);
949
        } else {
950
            $this->doc .= $this->_formatLink($link);
951
        }
952
    }
953
954
    /**
955
     * Render an interwiki link
956
     *
957
     * You may want to use $this->_resolveInterWiki() here
958
     *
959
     * @param string       $match      original link - probably not much use
960
     * @param string|array $name       name for the link, array for media file
961
     * @param string       $wikiName   indentifier (shortcut) for the remote wiki
962
     * @param string       $wikiUri    the fragment parsed from the original link
963
     * @param bool         $returnonly whether to return html or write to doc attribute
964
     */
965
    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...
966
        global $conf;
967
968
        $link           = array();
969
        $link['target'] = $conf['target']['interwiki'];
970
        $link['pre']    = '';
971
        $link['suf']    = '';
972
        $link['more']   = '';
973
        $link['name']   = $this->_getLinkTitle($name, $wikiUri, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 965 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...
974
975
        //get interwiki URL
976
        $exists = null;
977
        $url    = $this->_resolveInterWiki($wikiName, $wikiUri, $exists);
978
979
        if(!$isImage) {
980
            $class         = preg_replace('/[^_\-a-z0-9]+/i', '_', $wikiName);
981
            $link['class'] = "interwiki iw_$class";
982
        } else {
983
            $link['class'] = 'media';
984
        }
985
986
        //do we stay at the same server? Use local target
987
        if(strpos($url, DOKU_URL) === 0 OR strpos($url, DOKU_BASE) === 0) {
988
            $link['target'] = $conf['target']['wiki'];
989
        }
990
        if($exists !== null && !$isImage) {
991
            if($exists) {
992
                $link['class'] .= ' wikilink1';
993
            } else {
994
                $link['class'] .= ' wikilink2';
995
                $link['rel'] = 'nofollow';
996
            }
997
        }
998
999
        $link['url']   = $url;
1000
        $link['title'] = htmlspecialchars($link['url']);
1001
1002
        //output formatted
1003
        if($returnonly) {
1004
            return $this->_formatLink($link);
1005
        } else {
1006
            $this->doc .= $this->_formatLink($link);
1007
        }
1008
    }
1009
1010
    /**
1011
     * Link to windows share
1012
     *
1013
     * @param string       $url        the link
1014
     * @param string|array $name       name for the link, array for media file
1015
     * @param bool         $returnonly whether to return html or write to doc attribute
1016
     */
1017
    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...
1018
        global $conf;
1019
1020
        //simple setup
1021
        $link = array();
1022
        $link['target'] = $conf['target']['windows'];
1023
        $link['pre']    = '';
1024
        $link['suf']    = '';
1025
        $link['style']  = '';
1026
1027
        $link['name'] = $this->_getLinkTitle($name, $url, $isImage);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 1017 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...
1028
        if(!$isImage) {
1029
            $link['class'] = 'windows';
1030
        } else {
1031
            $link['class'] = 'media';
1032
        }
1033
1034
        $link['title'] = $this->_xmlEntities($url);
1035
        $url           = str_replace('\\', '/', $url);
1036
        $url           = 'file:///'.$url;
1037
        $link['url']   = $url;
1038
1039
        //output formatted
1040
        if($returnonly) {
1041
            return $this->_formatLink($link);
1042
        } else {
1043
            $this->doc .= $this->_formatLink($link);
1044
        }
1045
    }
1046
1047
    /**
1048
     * Render a linked E-Mail Address
1049
     *
1050
     * Honors $conf['mailguard'] setting
1051
     *
1052
     * @param string       $address    Email-Address
1053
     * @param string|array $name       name for the link, array for media file
1054
     * @param bool         $returnonly whether to return html or write to doc attribute
1055
     */
1056
    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...
1057
        global $conf;
1058
        //simple setup
1059
        $link           = array();
1060
        $link['target'] = '';
1061
        $link['pre']    = '';
1062
        $link['suf']    = '';
1063
        $link['style']  = '';
1064
        $link['more']   = '';
1065
1066
        $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...
1067
        if(!$isImage) {
1068
            $link['class'] = 'mail';
1069
        } else {
1070
            $link['class'] = 'media';
1071
        }
1072
1073
        $address = $this->_xmlEntities($address);
1074
        $address = obfuscate($address);
1075
        $title   = $address;
1076
1077
        if(empty($name)) {
1078
            $name = $address;
1079
        }
1080
1081
        if($conf['mailguard'] == 'visible') $address = rawurlencode($address);
1082
1083
        $link['url']   = 'mailto:'.$address;
1084
        $link['name']  = $name;
1085
        $link['title'] = $title;
1086
1087
        //output formatted
1088
        if($returnonly) {
1089
            return $this->_formatLink($link);
1090
        } else {
1091
            $this->doc .= $this->_formatLink($link);
1092
        }
1093
    }
1094
1095
    /**
1096
     * Render an internal media file
1097
     *
1098
     * @param string $src       media ID
1099
     * @param string $title     descriptive text
1100
     * @param string $align     left|center|right
1101
     * @param int    $width     width of media in pixel
1102
     * @param int    $height    height of media in pixel
1103
     * @param string $cache     cache|recache|nocache
1104
     * @param string $linking   linkonly|detail|nolink
1105
     * @param bool   $return    return HTML instead of adding to $doc
1106
     * @return void|string
1107
     */
1108
    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...
1109
                           $height = null, $cache = null, $linking = null, $return = false) {
1110
        global $ID;
1111
        list($src, $hash) = explode('#', $src, 2);
1112
        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...
1113
1114
        $noLink = false;
1115
        $render = ($linking == 'linkonly') ? false : true;
1116
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1117
1118
        list($ext, $mime) = mimetype($src, false);
1119
        if(substr($mime, 0, 5) == 'image' && $render) {
1120
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src)), ($linking == 'direct'));
1121
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1122
            // don't link movies
1123
            $noLink = true;
1124
        } else {
1125
            // add file icons
1126
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1127
            $link['class'] .= ' mediafile mf_'.$class;
1128
            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache , 'rev'=>$this->_getLastMediaRevisionAt($src)), true);
1129
            if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')';
1130
        }
1131
1132
        if($hash) $link['url'] .= '#'.$hash;
1133
1134
        //markup non existing files
1135
        if(!$exists) {
1136
            $link['class'] .= ' wikilink2';
1137
        }
1138
1139
        //output formatted
1140
        if($return) {
1141
            if($linking == 'nolink' || $noLink) return $link['name'];
1142
            else return $this->_formatLink($link);
1143
        } else {
1144
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1145
            else $this->doc .= $this->_formatLink($link);
1146
        }
1147
    }
1148
1149
    /**
1150
     * Render an external media file
1151
     *
1152
     * @param string $src     full media URL
1153
     * @param string $title   descriptive text
1154
     * @param string $align   left|center|right
1155
     * @param int    $width   width of media in pixel
1156
     * @param int    $height  height of media in pixel
1157
     * @param string $cache   cache|recache|nocache
1158
     * @param string $linking linkonly|detail|nolink
1159
     * @param bool   $return  return HTML instead of adding to $doc
1160
     */
1161
    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...
1162
                           $height = null, $cache = null, $linking = null, $return = false) {
1163
        list($src, $hash) = explode('#', $src, 2);
1164
        $noLink = false;
1165
        $render = ($linking == 'linkonly') ? false : true;
1166
        $link   = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
1167
1168
        $link['url'] = ml($src, array('cache' => $cache));
1169
1170
        list($ext, $mime) = mimetype($src, false);
1171
        if(substr($mime, 0, 5) == 'image' && $render) {
1172
            // link only jpeg images
1173
            // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true;
1174
        } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
1175
            // don't link movies
1176
            $noLink = true;
1177
        } else {
1178
            // add file icons
1179
            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1180
            $link['class'] .= ' mediafile mf_'.$class;
1181
        }
1182
1183
        if($hash) $link['url'] .= '#'.$hash;
1184
1185
        //output formatted
1186
        if($return) {
1187
            if($linking == 'nolink' || $noLink) return $link['name'];
1188
            else return $this->_formatLink($link);
1189
        } else {
1190
            if($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1191
            else $this->doc .= $this->_formatLink($link);
1192
        }
1193
    }
1194
1195
    /**
1196
     * Renders an RSS feed
1197
     *
1198
     * @author Andreas Gohr <[email protected]>
1199
     */
1200
    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...
1201
        global $lang;
1202
        global $conf;
1203
1204
        require_once(DOKU_INC.'inc/FeedParser.php');
1205
        $feed = new FeedParser();
1206
        $feed->set_feed_url($url);
1207
1208
        //disable warning while fetching
1209
        if(!defined('DOKU_E_LEVEL')) {
1210
            $elvl = error_reporting(E_ERROR);
1211
        }
1212
        $rc = $feed->init();
1213
        if(isset($elvl)) {
1214
            error_reporting($elvl);
1215
        }
1216
1217
        if($params['nosort']) $feed->enable_order_by_date(false);
1218
1219
        //decide on start and end
1220
        if($params['reverse']) {
1221
            $mod   = -1;
1222
            $start = $feed->get_item_quantity() - 1;
1223
            $end   = $start - ($params['max']);
1224
            $end   = ($end < -1) ? -1 : $end;
1225
        } else {
1226
            $mod   = 1;
1227
            $start = 0;
1228
            $end   = $feed->get_item_quantity();
1229
            $end   = ($end > $params['max']) ? $params['max'] : $end;
1230
        }
1231
1232
        $this->doc .= '<ul class="rss">';
1233
        if($rc) {
1234
            for($x = $start; $x != $end; $x += $mod) {
1235
                $item = $feed->get_item($x);
1236
                $this->doc .= '<li><div class="li">';
1237
                // support feeds without links
1238
                $lnkurl = $item->get_permalink();
1239
                if($lnkurl) {
1240
                    // title is escaped by SimplePie, we unescape here because it
1241
                    // is escaped again in externallink() FS#1705
1242
                    $this->externallink(
1243
                        $item->get_permalink(),
1244
                        html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')
1245
                    );
1246
                } else {
1247
                    $this->doc .= ' '.$item->get_title();
1248
                }
1249
                if($params['author']) {
1250
                    $author = $item->get_author(0);
1251
                    if($author) {
1252
                        $name = $author->get_name();
1253
                        if(!$name) $name = $author->get_email();
1254
                        if($name) $this->doc .= ' '.$lang['by'].' '.$name;
1255
                    }
1256
                }
1257
                if($params['date']) {
1258
                    $this->doc .= ' ('.$item->get_local_date($conf['dformat']).')';
1259
                }
1260
                if($params['details']) {
1261
                    $this->doc .= '<div class="detail">';
1262
                    if($conf['htmlok']) {
1263
                        $this->doc .= $item->get_description();
1264
                    } else {
1265
                        $this->doc .= strip_tags($item->get_description());
1266
                    }
1267
                    $this->doc .= '</div>';
1268
                }
1269
1270
                $this->doc .= '</div></li>';
1271
            }
1272
        } else {
1273
            $this->doc .= '<li><div class="li">';
1274
            $this->doc .= '<em>'.$lang['rssfailed'].'</em>';
1275
            $this->externallink($url);
1276
            if($conf['allowdebug']) {
1277
                $this->doc .= '<!--'.hsc($feed->error).'-->';
1278
            }
1279
            $this->doc .= '</div></li>';
1280
        }
1281
        $this->doc .= '</ul>';
1282
    }
1283
1284
    /**
1285
     * Start a table
1286
     *
1287
     * @param int $maxcols maximum number of columns
1288
     * @param int $numrows NOT IMPLEMENTED
1289
     * @param int $pos     byte position in the original source
1290
     */
1291
    function table_open($maxcols = null, $numrows = null, $pos = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1292
        // initialize the row counter used for classes
1293
        $this->_counter['row_counter'] = 0;
1294
        $class                         = 'table';
1295
        if($pos !== null) {
1296
            $class .= ' '.$this->startSectionEdit($pos, 'table');
1297
        }
1298
        $this->doc .= '<div class="'.$class.'"><table class="inline">'.
1299
            DOKU_LF;
1300
    }
1301
1302
    /**
1303
     * Close a table
1304
     *
1305
     * @param int $pos byte position in the original source
1306
     */
1307
    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...
1308
        $this->doc .= '</table></div>'.DOKU_LF;
1309
        if($pos !== null) {
1310
            $this->finishSectionEdit($pos);
1311
        }
1312
    }
1313
1314
    /**
1315
     * Open a table header
1316
     */
1317
    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...
1318
        $this->doc .= DOKU_TAB.'<thead>'.DOKU_LF;
1319
    }
1320
1321
    /**
1322
     * Close a table header
1323
     */
1324
    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...
1325
        $this->doc .= DOKU_TAB.'</thead>'.DOKU_LF;
1326
    }
1327
1328
    /**
1329
     * Open a table body
1330
     */
1331
    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...
1332
        $this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF;
1333
    }
1334
1335
    /**
1336
     * Close a table body
1337
     */
1338
    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...
1339
        $this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF;
1340
    }
1341
1342
    /**
1343
     * Open a table row
1344
     */
1345
    function tablerow_open() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1346
        // initialize the cell counter used for classes
1347
        $this->_counter['cell_counter'] = 0;
1348
        $class                          = 'row'.$this->_counter['row_counter']++;
1349
        $this->doc .= DOKU_TAB.'<tr class="'.$class.'">'.DOKU_LF.DOKU_TAB.DOKU_TAB;
1350
    }
1351
1352
    /**
1353
     * Close a table row
1354
     */
1355
    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...
1356
        $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
1357
    }
1358
1359
    /**
1360
     * Open a table header cell
1361
     *
1362
     * @param int    $colspan
1363
     * @param string $align left|center|right
1364
     * @param int    $rowspan
1365
     */
1366
    function tableheader_open($colspan = 1, $align = null, $rowspan = 1) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1367
        $class = 'class="col'.$this->_counter['cell_counter']++;
1368
        if(!is_null($align)) {
1369
            $class .= ' '.$align.'align';
1370
        }
1371
        $class .= '"';
1372
        $this->doc .= '<th '.$class;
1373
        if($colspan > 1) {
1374
            $this->_counter['cell_counter'] += $colspan - 1;
1375
            $this->doc .= ' colspan="'.$colspan.'"';
1376
        }
1377
        if($rowspan > 1) {
1378
            $this->doc .= ' rowspan="'.$rowspan.'"';
1379
        }
1380
        $this->doc .= '>';
1381
    }
1382
1383
    /**
1384
     * Close a table header cell
1385
     */
1386
    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...
1387
        $this->doc .= '</th>';
1388
    }
1389
1390
    /**
1391
     * Open a table cell
1392
     *
1393
     * @param int    $colspan
1394
     * @param string $align left|center|right
1395
     * @param int    $rowspan
1396
     */
1397
    function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1398
        $class = 'class="col'.$this->_counter['cell_counter']++;
1399
        if(!is_null($align)) {
1400
            $class .= ' '.$align.'align';
1401
        }
1402
        $class .= '"';
1403
        $this->doc .= '<td '.$class;
1404
        if($colspan > 1) {
1405
            $this->_counter['cell_counter'] += $colspan - 1;
1406
            $this->doc .= ' colspan="'.$colspan.'"';
1407
        }
1408
        if($rowspan > 1) {
1409
            $this->doc .= ' rowspan="'.$rowspan.'"';
1410
        }
1411
        $this->doc .= '>';
1412
    }
1413
1414
    /**
1415
     * Close a table cell
1416
     */
1417
    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...
1418
        $this->doc .= '</td>';
1419
    }
1420
1421
    #region Utility functions
1422
1423
    /**
1424
     * Build a link
1425
     *
1426
     * Assembles all parts defined in $link returns HTML for the link
1427
     *
1428
     * @author Andreas Gohr <[email protected]>
1429
     */
1430
    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...
1431
        //make sure the url is XHTML compliant (skip mailto)
1432
        if(substr($link['url'], 0, 7) != 'mailto:') {
1433
            $link['url'] = str_replace('&', '&amp;', $link['url']);
1434
            $link['url'] = str_replace('&amp;amp;', '&amp;', $link['url']);
1435
        }
1436
        //remove double encodings in titles
1437
        $link['title'] = str_replace('&amp;amp;', '&amp;', $link['title']);
1438
1439
        // be sure there are no bad chars in url or title
1440
        // (we can't do this for name because it can contain an img tag)
1441
        $link['url']   = strtr($link['url'], array('>' => '%3E', '<' => '%3C', '"' => '%22'));
1442
        $link['title'] = strtr($link['title'], array('>' => '&gt;', '<' => '&lt;', '"' => '&quot;'));
1443
1444
        $ret = '';
1445
        $ret .= $link['pre'];
1446
        $ret .= '<a href="'.$link['url'].'"';
1447
        if(!empty($link['class'])) $ret .= ' class="'.$link['class'].'"';
1448
        if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"';
1449
        if(!empty($link['title'])) $ret .= ' title="'.$link['title'].'"';
1450
        if(!empty($link['style'])) $ret .= ' style="'.$link['style'].'"';
1451
        if(!empty($link['rel'])) $ret .= ' rel="'.$link['rel'].'"';
1452
        if(!empty($link['more'])) $ret .= ' '.$link['more'];
1453
        $ret .= '>';
1454
        $ret .= $link['name'];
1455
        $ret .= '</a>';
1456
        $ret .= $link['suf'];
1457
        return $ret;
1458
    }
1459
1460
    /**
1461
     * Renders internal and external media
1462
     *
1463
     * @author Andreas Gohr <[email protected]>
1464
     * @param string $src       media ID
1465
     * @param string $title     descriptive text
1466
     * @param string $align     left|center|right
1467
     * @param int    $width     width of media in pixel
1468
     * @param int    $height    height of media in pixel
1469
     * @param string $cache     cache|recache|nocache
1470
     * @param bool   $render    should the media be embedded inline or just linked
1471
     * @return string
1472
     */
1473
    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...
1474
                    $height = null, $cache = null, $render = true) {
1475
1476
        $ret = '';
1477
1478
        list($ext, $mime) = mimetype($src);
1479
        if(substr($mime, 0, 5) == 'image') {
1480
            // first get the $title
1481
            if(!is_null($title)) {
1482
                $title = $this->_xmlEntities($title);
1483
            } elseif($ext == 'jpg' || $ext == 'jpeg') {
1484
                //try to use the caption from IPTC/EXIF
1485
                require_once(DOKU_INC.'inc/JpegMeta.php');
1486
                $jpeg = new JpegMeta(mediaFN($src));
1487
                if($jpeg !== false) $cap = $jpeg->getTitle();
1488
                if(!empty($cap)) {
1489
                    $title = $this->_xmlEntities($cap);
1490
                }
1491
            }
1492
            if(!$render) {
1493
                // if the picture is not supposed to be rendered
1494
                // return the title of the picture
1495
                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...
1496
                    // just show the sourcename
1497
                    $title = $this->_xmlEntities(utf8_basename(noNS($src)));
1498
                }
1499
                return $title;
1500
            }
1501
            //add image tag
1502
            $ret .= '<img src="'.ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src))).'"';
1503
            $ret .= ' class="media'.$align.'"';
1504
1505
            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...
1506
                $ret .= ' title="'.$title.'"';
1507
                $ret .= ' alt="'.$title.'"';
1508
            } else {
1509
                $ret .= ' alt=""';
1510
            }
1511
1512
            if(!is_null($width))
1513
                $ret .= ' width="'.$this->_xmlEntities($width).'"';
1514
1515
            if(!is_null($height))
1516
                $ret .= ' height="'.$this->_xmlEntities($height).'"';
1517
1518
            $ret .= ' />';
1519
1520
        } elseif(media_supportedav($mime, 'video') || media_supportedav($mime, 'audio')) {
1521
            // first get the $title
1522
            $title = !is_null($title) ? $this->_xmlEntities($title) : false;
1523
            if(!$render) {
1524
                // if the file is not supposed to be rendered
1525
                // return the title of the file (just the sourcename if there is no title)
1526
                return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src)));
1527
            }
1528
1529
            $att          = array();
1530
            $att['class'] = "media$align";
1531
            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...
1532
                $att['title'] = $title;
1533
            }
1534
1535
            if(media_supportedav($mime, 'video')) {
1536
                //add video
1537
                $ret .= $this->_video($src, $width, $height, $att);
1538
            }
1539
            if(media_supportedav($mime, 'audio')) {
1540
                //add audio
1541
                $ret .= $this->_audio($src, $att);
1542
            }
1543
1544
        } elseif($mime == 'application/x-shockwave-flash') {
1545
            if(!$render) {
1546
                // if the flash is not supposed to be rendered
1547
                // return the title of the flash
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 = utf8_basename(noNS($src));
1551
                }
1552
                return $this->_xmlEntities($title);
1553
            }
1554
1555
            $att          = array();
1556
            $att['class'] = "media$align";
1557
            if($align == 'right') $att['align'] = 'right';
1558
            if($align == 'left') $att['align'] = 'left';
1559
            $ret .= html_flashobject(
1560
                ml($src, array('cache' => $cache), true, '&'), $width, $height,
1561
                array('quality' => 'high'),
1562
                null,
1563
                $att,
1564
                $this->_xmlEntities($title)
1565
            );
1566
        } 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...
1567
            // well at least we have a title to display
1568
            $ret .= $this->_xmlEntities($title);
1569
        } else {
1570
            // just show the sourcename
1571
            $ret .= $this->_xmlEntities(utf8_basename(noNS($src)));
1572
        }
1573
1574
        return $ret;
1575
    }
1576
1577
    /**
1578
     * Escape string for output
1579
     *
1580
     * @param $string
1581
     * @return string
1582
     */
1583
    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...
1584
        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
1585
    }
1586
1587
    /**
1588
     * Creates a linkid from a headline
1589
     *
1590
     * @author Andreas Gohr <[email protected]>
1591
     * @param string  $title   The headline title
1592
     * @param boolean $create  Create a new unique ID?
1593
     * @return string
1594
     */
1595
    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...
1596
        if($create) {
1597
            return sectionID($title, $this->headers);
1598
        } else {
1599
            $check = false;
1600
            return sectionID($title, $check);
1601
        }
1602
    }
1603
1604
    /**
1605
     * Construct a title and handle images in titles
1606
     *
1607
     * @author Harry Fuecks <[email protected]>
1608
     * @param string|array $title    either string title or media array
1609
     * @param string       $default  default title if nothing else is found
1610
     * @param bool         $isImage  will be set to true if it's a media file
1611
     * @param null|string  $id       linked page id (used to extract title from first heading)
1612
     * @param string       $linktype content|navigation
1613
     * @return string      HTML of the title, might be full image tag or just escaped text
1614
     */
1615
    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...
1616
        $isImage = false;
1617
        if(is_array($title)) {
1618
            $isImage = true;
1619
            return $this->_imageTitle($title);
1620
        } elseif(is_null($title) || trim($title) == '') {
1621
            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...
1622
                $heading = p_get_first_heading($id);
1623
                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...
1624
                    return $this->_xmlEntities($heading);
1625
                }
1626
            }
1627
            return $this->_xmlEntities($default);
1628
        } else {
1629
            return $this->_xmlEntities($title);
1630
        }
1631
    }
1632
1633
    /**
1634
     * Returns HTML code for images used in link titles
1635
     *
1636
     * @author Andreas Gohr <[email protected]>
1637
     * @param array $img
1638
     * @return string HTML img tag or similar
1639
     */
1640
    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...
1641
        global $ID;
1642
1643
        // some fixes on $img['src']
1644
        // see internalmedia() and externalmedia()
1645
        list($img['src']) = explode('#', $img['src'], 2);
1646
        if($img['type'] == 'internalmedia') {
1647
            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...
1648
        }
1649
1650
        return $this->_media(
1651
            $img['src'],
1652
            $img['title'],
1653
            $img['align'],
1654
            $img['width'],
1655
            $img['height'],
1656
            $img['cache']
1657
        );
1658
    }
1659
1660
    /**
1661
     * helperfunction to return a basic link to a media
1662
     *
1663
     * used in internalmedia() and externalmedia()
1664
     *
1665
     * @author   Pierre Spring <[email protected]>
1666
     * @param string $src       media ID
1667
     * @param string $title     descriptive text
1668
     * @param string $align     left|center|right
1669
     * @param int    $width     width of media in pixel
1670
     * @param int    $height    height of media in pixel
1671
     * @param string $cache     cache|recache|nocache
1672
     * @param bool   $render    should the media be embedded inline or just linked
1673
     * @return array associative array with link config
1674
     */
1675
    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...
1676
        global $conf;
1677
1678
        $link           = array();
1679
        $link['class']  = 'media';
1680
        $link['style']  = '';
1681
        $link['pre']    = '';
1682
        $link['suf']    = '';
1683
        $link['more']   = '';
1684
        $link['target'] = $conf['target']['media'];
1685
        $link['title']  = $this->_xmlEntities($src);
1686
        $link['name']   = $this->_media($src, $title, $align, $width, $height, $cache, $render);
1687
1688
        return $link;
1689
    }
1690
1691
    /**
1692
     * Embed video(s) in HTML
1693
     *
1694
     * @author Anika Henke <[email protected]>
1695
     *
1696
     * @param string $src         - ID of video to embed
1697
     * @param int    $width       - width of the video in pixels
1698
     * @param int    $height      - height of the video in pixels
1699
     * @param array  $atts        - additional attributes for the <video> tag
1700
     * @return string
1701
     */
1702
    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...
1703
        // prepare width and height
1704
        if(is_null($atts)) $atts = array();
1705
        $atts['width']  = (int) $width;
1706
        $atts['height'] = (int) $height;
1707
        if(!$atts['width']) $atts['width'] = 320;
1708
        if(!$atts['height']) $atts['height'] = 240;
1709
1710
        $posterUrl = '';
1711
        $files = array();
1712
        $isExternal = media_isexternal($src);
1713
1714
        if ($isExternal) {
1715
            // take direct source for external files
1716
            list(/*ext*/, $srcMime) = mimetype($src);
1717
            $files[$srcMime] = $src;
1718
        } else {
1719
            // prepare alternative formats
1720
            $extensions   = array('webm', 'ogv', 'mp4');
1721
            $files        = media_alternativefiles($src, $extensions);
1722
            $poster       = media_alternativefiles($src, array('jpg', 'png'));
1723
            if(!empty($poster)) {
1724
                $posterUrl = ml(reset($poster), '', true, '&');
1725
            }
1726
        }
1727
1728
        $out = '';
1729
        // open video tag
1730
        $out .= '<video '.buildAttributes($atts).' controls="controls"';
1731
        if($posterUrl) $out .= ' poster="'.hsc($posterUrl).'"';
1732
        $out .= '>'.NL;
1733
        $fallback = '';
1734
1735
        // output source for each alternative video format
1736
        foreach($files as $mime => $file) {
1737
            if ($isExternal) {
1738
                $url = $file;
1739
                $linkType = 'externalmedia';
1740
            } else {
1741
                $url = ml($file, '', true, '&');
1742
                $linkType = 'internalmedia';
1743
            }
1744
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1745
1746
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1747
            // alternative content (just a link to the file)
1748
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1749
        }
1750
1751
        // finish
1752
        $out .= $fallback;
1753
        $out .= '</video>'.NL;
1754
        return $out;
1755
    }
1756
1757
    /**
1758
     * Embed audio in HTML
1759
     *
1760
     * @author Anika Henke <[email protected]>
1761
     *
1762
     * @param string $src       - ID of audio to embed
1763
     * @param array  $atts      - additional attributes for the <audio> tag
1764
     * @return string
1765
     */
1766
    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...
1767
        $files = array();
1768
        $isExternal = media_isexternal($src);
1769
1770
        if ($isExternal) {
1771
            // take direct source for external files
1772
            list(/*ext*/, $srcMime) = mimetype($src);
1773
            $files[$srcMime] = $src;
1774
        } else {
1775
            // prepare alternative formats
1776
            $extensions   = array('ogg', 'mp3', 'wav');
1777
            $files        = media_alternativefiles($src, $extensions);
1778
        }
1779
1780
        $out = '';
1781
        // open audio tag
1782
        $out .= '<audio '.buildAttributes($atts).' controls="controls">'.NL;
1783
        $fallback = '';
1784
1785
        // output source for each alternative audio format
1786
        foreach($files as $mime => $file) {
1787
            if ($isExternal) {
1788
                $url = $file;
1789
                $linkType = 'externalmedia';
1790
            } else {
1791
                $url = ml($file, '', true, '&');
1792
                $linkType = 'internalmedia';
1793
            }
1794
            $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
1795
1796
            $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
1797
            // alternative content (just a link to the file)
1798
            $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
1799
        }
1800
1801
        // finish
1802
        $out .= $fallback;
1803
        $out .= '</audio>'.NL;
1804
        return $out;
1805
    }
1806
1807
    /**
1808
     * _getLastMediaRevisionAt is a helperfunction to internalmedia() and _media()
1809
     * which returns an existing media revision less or equal to rev or date_at
1810
     *
1811
     * @author lisps
1812
     * @param string $media_id
1813
     * @access protected
1814
     * @return string revision ('' for current)
1815
     */
1816
    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...
1817
        if(!$this->date_at || media_isexternal($media_id)) return '';
1818
        $pagelog = new MediaChangeLog($media_id);
1819
        return $pagelog->getLastRevisionAt($this->date_at);
1820
    }
1821
1822
    #endregion
1823
}
1824
1825
//Setup VIM: ex: et ts=4 :
1826