Completed
Push — master ( 9b78f7...5dcb4f )
by Andreas
08:15 queued 03:39
created

template.php ➔ tpl_get_action()   C

Complexity

Conditions 8
Paths 64

Size

Total Lines 41
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 30
nc 64
nop 1
dl 0
loc 41
rs 5.3846
c 0
b 0
f 0
1
<?php
2
/**
3
 * DokuWiki template functions
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
if(!defined('DOKU_INC')) die('meh.');
10
11
/**
12
 * Access a template file
13
 *
14
 * Returns the path to the given file inside the current template, uses
15
 * default template if the custom version doesn't exist.
16
 *
17
 * @author Andreas Gohr <[email protected]>
18
 * @param string $file
19
 * @return string
20
 */
21
function template($file) {
22
    global $conf;
23
24
    if(@is_readable(DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$file))
25
        return DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$file;
26
27
    return DOKU_INC.'lib/tpl/dokuwiki/'.$file;
28
}
29
30
/**
31
 * Convenience function to access template dir from local FS
32
 *
33
 * This replaces the deprecated DOKU_TPLINC constant
34
 *
35
 * @author Andreas Gohr <[email protected]>
36
 * @param string $tpl The template to use, default to current one
37
 * @return string
38
 */
39
function tpl_incdir($tpl='') {
40
    global $conf;
41
    if(!$tpl) $tpl = $conf['template'];
42
    return DOKU_INC.'lib/tpl/'.$tpl.'/';
43
}
44
45
/**
46
 * Convenience function to access template dir from web
47
 *
48
 * This replaces the deprecated DOKU_TPL constant
49
 *
50
 * @author Andreas Gohr <[email protected]>
51
 * @param string $tpl The template to use, default to current one
52
 * @return string
53
 */
54
function tpl_basedir($tpl='') {
55
    global $conf;
56
    if(!$tpl) $tpl = $conf['template'];
57
    return DOKU_BASE.'lib/tpl/'.$tpl.'/';
58
}
59
60
/**
61
 * Print the content
62
 *
63
 * This function is used for printing all the usual content
64
 * (defined by the global $ACT var) by calling the appropriate
65
 * outputfunction(s) from html.php
66
 *
67
 * Everything that doesn't use the main template file isn't
68
 * handled by this function. ACL stuff is not done here either.
69
 *
70
 * @author Andreas Gohr <[email protected]>
71
 *
72
 * @triggers TPL_ACT_RENDER
73
 * @triggers TPL_CONTENT_DISPLAY
74
 * @param bool $prependTOC should the TOC be displayed here?
75
 * @return bool true if any output
76
 */
77
function tpl_content($prependTOC = true) {
78
    global $ACT;
79
    global $INFO;
80
    $INFO['prependTOC'] = $prependTOC;
81
82
    ob_start();
83
    trigger_event('TPL_ACT_RENDER', $ACT, 'tpl_content_core');
84
    $html_output = ob_get_clean();
85
    trigger_event('TPL_CONTENT_DISPLAY', $html_output, 'ptln');
86
87
    return !empty($html_output);
88
}
89
90
/**
91
 * Default Action of TPL_ACT_RENDER
92
 *
93
 * @return bool
94
 */
95
function tpl_content_core() {
96
    $router = \dokuwiki\ActionRouter::getInstance();
97
    try {
98
        $router->getAction()->tplContent();
99
    } catch(\dokuwiki\Action\Exception\FatalException $e) {
100
        // there was no content for the action
101
        msg(hsc($e->getMessage()), -1);
102
        return false;
103
    }
104
    return true;
105
}
106
107
/**
108
 * Places the TOC where the function is called
109
 *
110
 * If you use this you most probably want to call tpl_content with
111
 * a false argument
112
 *
113
 * @author Andreas Gohr <[email protected]>
114
 *
115
 * @param bool $return Should the TOC be returned instead to be printed?
116
 * @return string
117
 */
118
function tpl_toc($return = false) {
119
    global $TOC;
120
    global $ACT;
121
    global $ID;
122
    global $REV;
123
    global $INFO;
124
    global $conf;
125
    global $INPUT;
126
    $toc = array();
127
128
    if(is_array($TOC)) {
129
        // if a TOC was prepared in global scope, always use it
130
        $toc = $TOC;
131
    } elseif(($ACT == 'show' || substr($ACT, 0, 6) == 'export') && !$REV && $INFO['exists']) {
132
        // get TOC from metadata, render if neccessary
133
        $meta = p_get_metadata($ID, '', METADATA_RENDER_USING_CACHE);
134
        if(isset($meta['internal']['toc'])) {
135
            $tocok = $meta['internal']['toc'];
136
        } else {
137
            $tocok = true;
138
        }
139
        $toc = isset($meta['description']['tableofcontents']) ? $meta['description']['tableofcontents'] : null;
140
        if(!$tocok || !is_array($toc) || !$conf['tocminheads'] || count($toc) < $conf['tocminheads']) {
141
            $toc = array();
142
        }
143
    } elseif($ACT == 'admin') {
144
        // try to load admin plugin TOC
145
        /** @var $plugin DokuWiki_Admin_Plugin */
146
        if ($plugin = plugin_getRequestAdminPlugin()) {
147
            $toc = $plugin->getTOC();
148
            $TOC = $toc; // avoid later rebuild
149
        }
150
    }
151
152
    trigger_event('TPL_TOC_RENDER', $toc, null, false);
153
    $html = html_TOC($toc);
154
    if($return) return $html;
155
    echo $html;
156
    return '';
157
}
158
159
/**
160
 * Handle the admin page contents
161
 *
162
 * @author Andreas Gohr <[email protected]>
163
 *
164
 * @return bool
165
 */
166
function tpl_admin() {
167
    global $INFO;
168
    global $TOC;
169
    global $INPUT;
170
171
    $plugin = null;
172
    $class  = $INPUT->str('page');
173
    if(!empty($class)) {
174
        $pluginlist = plugin_list('admin');
175
176
        if(in_array($class, $pluginlist)) {
177
            // attempt to load the plugin
178
            /** @var $plugin DokuWiki_Admin_Plugin */
179
            $plugin = plugin_load('admin', $class);
180
        }
181
    }
182
183
    if($plugin !== null) {
184
        if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet
185
        if($INFO['prependTOC']) tpl_toc();
186
        $plugin->html();
187
    } else {
188
        $admin = new dokuwiki\Ui\Admin();
189
        $admin->show();
190
    }
191
    return true;
192
}
193
194
/**
195
 * Print the correct HTML meta headers
196
 *
197
 * This has to go into the head section of your template.
198
 *
199
 * @author Andreas Gohr <[email protected]>
200
 *
201
 * @triggers TPL_METAHEADER_OUTPUT
202
 * @param  bool $alt Should feeds and alternative format links be added?
203
 * @return bool
204
 */
205
function tpl_metaheaders($alt = true) {
206
    global $ID;
207
    global $REV;
208
    global $INFO;
209
    global $JSINFO;
210
    global $ACT;
211
    global $QUERY;
212
    global $lang;
213
    global $conf;
214
    global $updateVersion;
215
    /** @var Input $INPUT */
216
    global $INPUT;
217
218
    // prepare the head array
219
    $head = array();
220
221
    // prepare seed for js and css
222
    $tseed   = $updateVersion;
223
    $depends = getConfigFiles('main');
224
    $depends[] = DOKU_CONF."tpl/".$conf['template']."/style.ini";
225
    foreach($depends as $f) $tseed .= @filemtime($f);
226
    $tseed   = md5($tseed);
227
228
    // the usual stuff
229
    $head['meta'][] = array('name'=> 'generator', 'content'=> 'DokuWiki');
230
    if(actionOK('search')) {
231
        $head['link'][] = array(
232
            'rel' => 'search', 'type'=> 'application/opensearchdescription+xml',
233
            'href'=> DOKU_BASE.'lib/exe/opensearch.php', 'title'=> $conf['title']
234
        );
235
    }
236
237
    $head['link'][] = array('rel'=> 'start', 'href'=> DOKU_BASE);
238
    if(actionOK('index')) {
239
        $head['link'][] = array(
240
            'rel'  => 'contents', 'href'=> wl($ID, 'do=index', false, '&'),
241
            'title'=> $lang['btn_index']
242
        );
243
    }
244
245
    if($alt) {
246
        if(actionOK('rss')) {
247
            $head['link'][] = array(
248
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
249
                'title'=> $lang['btn_recent'], 'href'=> DOKU_BASE.'feed.php'
250
            );
251
            $head['link'][] = array(
252
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
253
                'title'=> $lang['currentns'],
254
                'href' => DOKU_BASE.'feed.php?mode=list&ns='.$INFO['namespace']
255
            );
256
        }
257
        if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']) {
258
            $head['link'][] = array(
259
                'rel'  => 'edit',
260
                'title'=> $lang['btn_edit'],
261
                'href' => wl($ID, 'do=edit', false, '&')
262
            );
263
        }
264
265
        if(actionOK('rss') && $ACT == 'search') {
266
            $head['link'][] = array(
267
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
268
                'title'=> $lang['searchresult'],
269
                'href' => DOKU_BASE.'feed.php?mode=search&q='.$QUERY
270
            );
271
        }
272
273
        if(actionOK('export_xhtml')) {
274
            $head['link'][] = array(
275
                'rel' => 'alternate', 'type'=> 'text/html', 'title'=> $lang['plainhtml'],
276
                'href'=> exportlink($ID, 'xhtml', '', false, '&')
277
            );
278
        }
279
280
        if(actionOK('export_raw')) {
281
            $head['link'][] = array(
282
                'rel' => 'alternate', 'type'=> 'text/plain', 'title'=> $lang['wikimarkup'],
283
                'href'=> exportlink($ID, 'raw', '', false, '&')
284
            );
285
        }
286
    }
287
288
    // setup robot tags apropriate for different modes
289
    if(($ACT == 'show' || $ACT == 'export_xhtml') && !$REV) {
290
        if($INFO['exists']) {
291
            //delay indexing:
292
            if((time() - $INFO['lastmod']) >= $conf['indexdelay']) {
293
                $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
294
            } else {
295
                $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
296
            }
297
            $canonicalUrl = wl($ID, '', true, '&');
298
            if ($ID == $conf['start']) {
299
                $canonicalUrl = DOKU_URL;
300
            }
301
            $head['link'][] = array('rel'=> 'canonical', 'href'=> $canonicalUrl);
302
        } else {
303
            $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,follow');
304
        }
305
    } elseif(defined('DOKU_MEDIADETAIL')) {
306
        $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
307
    } else {
308
        $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
309
    }
310
311
    // set metadata
312
    if($ACT == 'show' || $ACT == 'export_xhtml') {
313
        // keywords (explicit or implicit)
314
        if(!empty($INFO['meta']['subject'])) {
315
            $head['meta'][] = array('name'=> 'keywords', 'content'=> join(',', $INFO['meta']['subject']));
316
        } else {
317
            $head['meta'][] = array('name'=> 'keywords', 'content'=> str_replace(':', ',', $ID));
318
        }
319
    }
320
321
    // load stylesheets
322
    $head['link'][] = array(
323
        'rel' => 'stylesheet', 'type'=> 'text/css',
324
        'href'=> DOKU_BASE.'lib/exe/css.php?t='.rawurlencode($conf['template']).'&tseed='.$tseed
325
    );
326
327
    // make $INFO and other vars available to JavaScripts
328
    $json   = new JSON();
329
    $script = "var NS='".$INFO['namespace']."';";
330
    if($conf['useacl'] && $INPUT->server->str('REMOTE_USER')) {
331
        $script .= "var SIG='".toolbar_signature()."';";
332
    }
333
    $script .= 'var JSINFO = '.$json->encode($JSINFO).';';
334
    $head['script'][] = array('type'=> 'text/javascript', '_data'=> $script);
335
336
    // load jquery
337
    $jquery = getCdnUrls();
338
    foreach($jquery as $src) {
339
        $head['script'][] = array(
340
            'type' => 'text/javascript', 'charset' => 'utf-8', '_data' => '', 'src' => $src
341
        );
342
    }
343
344
    // load our javascript dispatcher
345
    $head['script'][] = array(
346
        'type'=> 'text/javascript', 'charset'=> 'utf-8', '_data'=> '',
347
        'src' => DOKU_BASE.'lib/exe/js.php'.'?t='.rawurlencode($conf['template']).'&tseed='.$tseed
348
    );
349
350
    // trigger event here
351
    trigger_event('TPL_METAHEADER_OUTPUT', $head, '_tpl_metaheaders_action', true);
352
    return true;
353
}
354
355
/**
356
 * prints the array build by tpl_metaheaders
357
 *
358
 * $data is an array of different header tags. Each tag can have multiple
359
 * instances. Attributes are given as key value pairs. Values will be HTML
360
 * encoded automatically so they should be provided as is in the $data array.
361
 *
362
 * For tags having a body attribute specify the body data in the special
363
 * attribute '_data'. This field will NOT BE ESCAPED automatically.
364
 *
365
 * @author Andreas Gohr <[email protected]>
366
 *
367
 * @param array $data
368
 */
369
function _tpl_metaheaders_action($data) {
370
    foreach($data as $tag => $inst) {
371
        if($tag == 'script') {
372
            echo "<!--[if gte IE 9]><!-->\n"; // no scripts for old IE
373
        }
374
        foreach($inst as $attr) {
375
            if ( empty($attr) ) { continue; }
376
            echo '<', $tag, ' ', buildAttributes($attr);
377
            if(isset($attr['_data']) || $tag == 'script') {
378
                if($tag == 'script' && $attr['_data'])
379
                    $attr['_data'] = "/*<![CDATA[*/".
380
                        $attr['_data'].
381
                        "\n/*!]]>*/";
382
383
                echo '>', $attr['_data'], '</', $tag, '>';
384
            } else {
385
                echo '/>';
386
            }
387
            echo "\n";
388
        }
389
        if($tag == 'script') {
390
            echo "<!--<![endif]-->\n";
391
        }
392
    }
393
}
394
395
/**
396
 * Print a link
397
 *
398
 * Just builds a link.
399
 *
400
 * @author Andreas Gohr <[email protected]>
401
 *
402
 * @param string $url
403
 * @param string $name
404
 * @param string $more
405
 * @param bool $return if true return the link html, otherwise print
406
 * @return bool|string html of the link, or true if printed
407
 */
408
function tpl_link($url, $name, $more = '', $return = false) {
409
    $out = '<a href="'.$url.'" ';
410
    if($more) $out .= ' '.$more;
411
    $out .= ">$name</a>";
412
    if($return) return $out;
413
    print $out;
414
    return true;
415
}
416
417
/**
418
 * Prints a link to a WikiPage
419
 *
420
 * Wrapper around html_wikilink
421
 *
422
 * @author Andreas Gohr <[email protected]>
423
 *
424
 * @param string      $id   page id
425
 * @param string|null $name the name of the link
426
 * @return bool true
427
 */
428
function tpl_pagelink($id, $name = null) {
429
    print '<bdi>'.html_wikilink($id, $name).'</bdi>';
430
    return true;
431
}
432
433
/**
434
 * get the parent page
435
 *
436
 * Tries to find out which page is parent.
437
 * returns false if none is available
438
 *
439
 * @author Andreas Gohr <[email protected]>
440
 *
441
 * @param string $id page id
442
 * @return false|string
443
 */
444
function tpl_getparent($id) {
445
    $parent = getNS($id).':';
446
    resolve_pageid('', $parent, $exists);
447
    if($parent == $id) {
448
        $pos    = strrpos(getNS($id), ':');
449
        $parent = substr($parent, 0, $pos).':';
450
        resolve_pageid('', $parent, $exists);
451
        if($parent == $id) return false;
452
    }
453
    return $parent;
454
}
455
456
/**
457
 * Print one of the buttons
458
 *
459
 * @author Adrian Lang <[email protected]>
460
 * @see    tpl_get_action
461
 *
462
 * @param string $type
463
 * @param bool $return
464
 * @return bool|string html, or false if no data, true if printed
465
 */
466
function tpl_button($type, $return = false) {
467
    $data = tpl_get_action($type);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_get_action() has been deprecated with message: use \dokuwiki\Menu\Item\AbstractItem descendants instead

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
468
    if($data === false) {
469
        return false;
470
    } elseif(!is_array($data)) {
471
        $out = sprintf($data, 'button');
472
    } else {
473
        /**
474
         * @var string $accesskey
475
         * @var string $id
476
         * @var string $method
477
         * @var array  $params
478
         */
479
        extract($data);
480
        if($id === '#dokuwiki__top') {
481
            $out = html_topbtn();
482
        } else {
483
            $out = html_btn($type, $id, $accesskey, $params, $method);
484
        }
485
    }
486
    if($return) return $out;
487
    echo $out;
488
    return true;
489
}
490
491
/**
492
 * Like the action buttons but links
493
 *
494
 * @author Adrian Lang <[email protected]>
495
 * @see    tpl_get_action
496
 *
497
 * @param string $type    action command
498
 * @param string $pre     prefix of link
499
 * @param string $suf     suffix of link
500
 * @param string $inner   innerHML of link
501
 * @param bool   $return  if true it returns html, otherwise prints
502
 * @return bool|string html or false if no data, true if printed
503
 */
504
function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = false) {
505
    global $lang;
506
    $data = tpl_get_action($type);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_get_action() has been deprecated with message: use \dokuwiki\Menu\Item\AbstractItem descendants instead

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
507
    if($data === false) {
508
        return false;
509
    } elseif(!is_array($data)) {
510
        $out = sprintf($data, 'link');
511
    } else {
512
        /**
513
         * @var string $accesskey
514
         * @var string $id
515
         * @var string $method
516
         * @var bool   $nofollow
517
         * @var array  $params
518
         * @var string $replacement
519
         */
520
        extract($data);
521
        if(strpos($id, '#') === 0) {
522
            $linktarget = $id;
523
        } else {
524
            $linktarget = wl($id, $params);
525
        }
526
        $caption = $lang['btn_'.$type];
527
        if(strpos($caption, '%s')){
528
            $caption = sprintf($caption, $replacement);
529
        }
530
        $akey    = $addTitle = '';
531
        if($accesskey) {
532
            $akey     = 'accesskey="'.$accesskey.'" ';
533
            $addTitle = ' ['.strtoupper($accesskey).']';
534
        }
535
        $rel = $nofollow ? 'rel="nofollow" ' : '';
536
        $out = tpl_link(
537
            $linktarget, $pre.(($inner) ? $inner : $caption).$suf,
538
            'class="action '.$type.'" '.
539
                $akey.$rel.
540
                'title="'.hsc($caption).$addTitle.'"', true
541
        );
542
    }
543
    if($return) return $out;
544
    echo $out;
545
    return true;
546
}
547
548
/**
549
 * Check the actions and get data for buttons and links
550
 *
551
 * @deprecated use \dokuwiki\Menu\Item\AbstractItem descendants instead
552
 *
553
 * @author Andreas Gohr <[email protected]>
554
 * @author Matthias Grimm <[email protected]>
555
 * @author Adrian Lang <[email protected]>
556
 *
557
 * @param string $type
558
 * @return array|bool|string
559
 */
560
function tpl_get_action($type) {
561
    if($type == 'history') $type = 'revisions';
562
    if($type == 'subscription') $type = 'subscribe';
563
    if($type == 'img_backto') $type = 'imgBackto';
564
565
    $class = '\\dokuwiki\\Menu\\Item\\' . ucfirst($type);
566
    if(class_exists($class)) {
567
        try {
568
            /** @var \dokuwiki\Menu\Item\AbstractItem $item */
569
            $item = new $class;
570
            $data = $item->getLegacyData();
571
            $unknown = false;
572
        } catch(\RuntimeException $ignored) {
573
            return false;
574
        }
575
    } else {
576
        global $ID;
577
        $data = array(
578
            'accesskey' => null,
579
            'type' => $type,
580
            'id' => $ID,
581
            'method' => 'get',
582
            'params' => array('do' => $type),
583
            'nofollow' => true,
584
            'replacement' => '',
585
        );
586
        $unknown = true;
587
    }
588
589
    $evt = new Doku_Event('TPL_ACTION_GET', $data);
590
    if($evt->advise_before()) {
591
        //handle unknown types
592
        if($unknown) {
593
            $data = '[unknown %s type]';
594
        }
595
    }
596
    $evt->advise_after();
597
    unset($evt);
598
599
    return $data;
600
}
601
602
/**
603
 * Wrapper around tpl_button() and tpl_actionlink()
604
 *
605
 * @author Anika Henke <[email protected]>
606
 *
607
 * @param string        $type action command
608
 * @param bool          $link link or form button?
609
 * @param string|bool   $wrapper HTML element wrapper
610
 * @param bool          $return return or print
611
 * @param string        $pre prefix for links
612
 * @param string        $suf suffix for links
613
 * @param string        $inner inner HTML for links
614
 * @return bool|string
615
 */
616
function tpl_action($type, $link = false, $wrapper = false, $return = false, $pre = '', $suf = '', $inner = '') {
617
    $out = '';
618
    if($link) {
619
        $out .= tpl_actionlink($type, $pre, $suf, $inner, true);
620
    } else {
621
        $out .= tpl_button($type, true);
622
    }
623
    if($out && $wrapper) $out = "<$wrapper>$out</$wrapper>";
624
625
    if($return) return $out;
626
    print $out;
627
    return $out ? true : false;
628
}
629
630
/**
631
 * Print the search form
632
 *
633
 * If the first parameter is given a div with the ID 'qsearch_out' will
634
 * be added which instructs the ajax pagequicksearch to kick in and place
635
 * its output into this div. The second parameter controls the propritary
636
 * attribute autocomplete. If set to false this attribute will be set with an
637
 * value of "off" to instruct the browser to disable it's own built in
638
 * autocompletion feature (MSIE and Firefox)
639
 *
640
 * @author Andreas Gohr <[email protected]>
641
 *
642
 * @param bool $ajax
643
 * @param bool $autocomplete
644
 * @return bool
645
 */
646
function tpl_searchform($ajax = true, $autocomplete = true) {
647
    global $lang;
648
    global $ACT;
649
    global $QUERY;
650
651
    // don't print the search form if search action has been disabled
652
    if(!actionOK('search')) return false;
653
654
    print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get" role="search"><div class="no">';
655
    print '<input type="hidden" name="do" value="search" />';
656
    print '<input type="text" ';
657
    if($ACT == 'search') print 'value="'.htmlspecialchars($QUERY).'" ';
658
    print 'placeholder="'.$lang['btn_search'].'" ';
659
    if(!$autocomplete) print 'autocomplete="off" ';
660
    print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />';
661
    print '<button type="submit" title="'.$lang['btn_search'].'">'.$lang['btn_search'].'</button>';
662
    if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>';
663
    print '</div></form>';
664
    return true;
665
}
666
667
/**
668
 * Print the breadcrumbs trace
669
 *
670
 * @author Andreas Gohr <[email protected]>
671
 *
672
 * @param string $sep Separator between entries
673
 * @return bool
674
 */
675
function tpl_breadcrumbs($sep = '•') {
676
    global $lang;
677
    global $conf;
678
679
    //check if enabled
680
    if(!$conf['breadcrumbs']) return false;
681
682
    $crumbs = breadcrumbs(); //setup crumb trace
683
684
    $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
685
686
    //render crumbs, highlight the last one
687
    print '<span class="bchead">'.$lang['breadcrumb'].'</span>';
688
    $last = count($crumbs);
689
    $i    = 0;
690
    foreach($crumbs as $id => $name) {
691
        $i++;
692
        echo $crumbs_sep;
693
        if($i == $last) print '<span class="curid">';
694
        print '<bdi>';
695
        tpl_link(wl($id), hsc($name), 'class="breadcrumbs" title="'.$id.'"');
696
        print '</bdi>';
697
        if($i == $last) print '</span>';
698
    }
699
    return true;
700
}
701
702
/**
703
 * Hierarchical breadcrumbs
704
 *
705
 * This code was suggested as replacement for the usual breadcrumbs.
706
 * It only makes sense with a deep site structure.
707
 *
708
 * @author Andreas Gohr <[email protected]>
709
 * @author Nigel McNie <[email protected]>
710
 * @author Sean Coates <[email protected]>
711
 * @author <[email protected]>
712
 * @todo   May behave strangely in RTL languages
713
 *
714
 * @param string $sep Separator between entries
715
 * @return bool
716
 */
717
function tpl_youarehere($sep = ' » ') {
718
    global $conf;
719
    global $ID;
720
    global $lang;
721
722
    // check if enabled
723
    if(!$conf['youarehere']) return false;
724
725
    $parts = explode(':', $ID);
726
    $count = count($parts);
727
728
    echo '<span class="bchead">'.$lang['youarehere'].' </span>';
729
730
    // always print the startpage
731
    echo '<span class="home">';
732
    tpl_pagelink(':'.$conf['start']);
733
    echo '</span>';
734
735
    // print intermediate namespace links
736
    $part = '';
737
    for($i = 0; $i < $count - 1; $i++) {
738
        $part .= $parts[$i].':';
739
        $page = $part;
740
        if($page == $conf['start']) continue; // Skip startpage
741
742
        // output
743
        echo $sep;
744
        tpl_pagelink($page);
745
    }
746
747
    // print current page, skipping start page, skipping for namespace index
748
    resolve_pageid('', $page, $exists);
749
    if(isset($page) && $page == $part.$parts[$i]) return true;
750
    $page = $part.$parts[$i];
751
    if($page == $conf['start']) return true;
752
    echo $sep;
753
    tpl_pagelink($page);
754
    return true;
755
}
756
757
/**
758
 * Print info if the user is logged in
759
 * and show full name in that case
760
 *
761
 * Could be enhanced with a profile link in future?
762
 *
763
 * @author Andreas Gohr <[email protected]>
764
 *
765
 * @return bool
766
 */
767
function tpl_userinfo() {
768
    global $lang;
769
    /** @var Input $INPUT */
770
    global $INPUT;
771
772
    if($INPUT->server->str('REMOTE_USER')) {
773
        print $lang['loggedinas'].' '.userlink();
774
        return true;
775
    }
776
    return false;
777
}
778
779
/**
780
 * Print some info about the current page
781
 *
782
 * @author Andreas Gohr <[email protected]>
783
 *
784
 * @param bool $ret return content instead of printing it
785
 * @return bool|string
786
 */
787
function tpl_pageinfo($ret = false) {
788
    global $conf;
789
    global $lang;
790
    global $INFO;
791
    global $ID;
792
793
    // return if we are not allowed to view the page
794
    if(!auth_quickaclcheck($ID)) {
795
        return false;
796
    }
797
798
    // prepare date and path
799
    $fn = $INFO['filepath'];
800
    if(!$conf['fullpath']) {
801
        if($INFO['rev']) {
802
            $fn = str_replace($conf['olddir'].'/', '', $fn);
803
        } else {
804
            $fn = str_replace($conf['datadir'].'/', '', $fn);
805
        }
806
    }
807
    $fn   = utf8_decodeFN($fn);
808
    $date = dformat($INFO['lastmod']);
809
810
    // print it
811
    if($INFO['exists']) {
812
        $out = '';
813
        $out .= '<bdi>'.$fn.'</bdi>';
814
        $out .= ' · ';
815
        $out .= $lang['lastmod'];
816
        $out .= ' ';
817
        $out .= $date;
818
        if($INFO['editor']) {
819
            $out .= ' '.$lang['by'].' ';
820
            $out .= '<bdi>'.editorinfo($INFO['editor']).'</bdi>';
821
        } else {
822
            $out .= ' ('.$lang['external_edit'].')';
823
        }
824
        if($INFO['locked']) {
825
            $out .= ' · ';
826
            $out .= $lang['lockedby'];
827
            $out .= ' ';
828
            $out .= '<bdi>'.editorinfo($INFO['locked']).'</bdi>';
829
        }
830
        if($ret) {
831
            return $out;
832
        } else {
833
            echo $out;
834
            return true;
835
        }
836
    }
837
    return false;
838
}
839
840
/**
841
 * Prints or returns the name of the given page (current one if none given).
842
 *
843
 * If useheading is enabled this will use the first headline else
844
 * the given ID is used.
845
 *
846
 * @author Andreas Gohr <[email protected]>
847
 *
848
 * @param string $id page id
849
 * @param bool   $ret return content instead of printing
850
 * @return bool|string
851
 */
852
function tpl_pagetitle($id = null, $ret = false) {
853
    global $ACT, $INPUT, $conf, $lang;
854
855
    if(is_null($id)) {
856
        global $ID;
857
        $id = $ID;
858
    }
859
860
    $name = $id;
861
    if(useHeading('navigation')) {
862
        $first_heading = p_get_first_heading($id);
863
        if($first_heading) $name = $first_heading;
0 ignored issues
show
Bug Best Practice introduced by
The expression $first_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...
864
    }
865
866
    // default page title is the page name, modify with the current action
867
    switch ($ACT) {
868
        // admin functions
869
        case 'admin' :
870
            $page_title = $lang['btn_admin'];
871
            // try to get the plugin name
872
            /** @var $plugin DokuWiki_Admin_Plugin */
873
            if ($plugin = plugin_getRequestAdminPlugin()){
874
                $plugin_title = $plugin->getMenuText($conf['lang']);
875
                $page_title = $plugin_title ? $plugin_title : $plugin->getPluginName();
876
            }
877
            break;
878
879
        // user functions
880
        case 'login' :
881
        case 'profile' :
882
        case 'register' :
883
        case 'resendpwd' :
884
            $page_title = $lang['btn_'.$ACT];
885
            break;
886
887
         // wiki functions
888
        case 'search' :
889
        case 'index' :
890
            $page_title = $lang['btn_'.$ACT];
891
            break;
892
893
        // page functions
894
        case 'edit' :
895
            $page_title = "✎ ".$name;
896
            break;
897
898
        case 'revisions' :
899
            $page_title = $name . ' - ' . $lang['btn_revs'];
900
            break;
901
902
        case 'backlink' :
903
        case 'recent' :
904
        case 'subscribe' :
905
            $page_title = $name . ' - ' . $lang['btn_'.$ACT];
906
            break;
907
908
        default : // SHOW and anything else not included
909
            $page_title = $name;
910
    }
911
912
    if($ret) {
913
        return hsc($page_title);
914
    } else {
915
        print hsc($page_title);
916
        return true;
917
    }
918
}
919
920
/**
921
 * Returns the requested EXIF/IPTC tag from the current image
922
 *
923
 * If $tags is an array all given tags are tried until a
924
 * value is found. If no value is found $alt is returned.
925
 *
926
 * Which texts are known is defined in the functions _exifTagNames
927
 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
928
 * to the names of the latter one)
929
 *
930
 * Only allowed in: detail.php
931
 *
932
 * @author Andreas Gohr <[email protected]>
933
 *
934
 * @param array|string $tags tag or array of tags to try
935
 * @param string       $alt  alternative output if no data was found
936
 * @param null|string  $src  the image src, uses global $SRC if not given
937
 * @return string
938
 */
939
function tpl_img_getTag($tags, $alt = '', $src = null) {
940
    // Init Exif Reader
941
    global $SRC;
942
943
    if(is_null($src)) $src = $SRC;
944
945
    static $meta = null;
946
    if(is_null($meta)) $meta = new JpegMeta($src);
947
    if($meta === false) return $alt;
948
    $info = cleanText($meta->getField($tags));
949
    if($info == false) return $alt;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $info of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
950
    return $info;
951
}
952
953
/**
954
 * Returns a description list of the metatags of the current image
955
 *
956
 * @return string html of description list
957
 */
958
function tpl_img_meta() {
959
    global $lang;
960
961
    $tags = tpl_get_img_meta();
962
963
    echo '<dl>';
964
    foreach($tags as $tag) {
965
        $label = $lang[$tag['langkey']];
966
        if(!$label) $label = $tag['langkey'] . ':';
967
968
        echo '<dt>'.$label.'</dt><dd>';
969
        if ($tag['type'] == 'date') {
970
            echo dformat($tag['value']);
971
        } else {
972
            echo hsc($tag['value']);
973
        }
974
        echo '</dd>';
975
    }
976
    echo '</dl>';
977
}
978
979
/**
980
 * Returns metadata as configured in mediameta config file, ready for creating html
981
 *
982
 * @return array with arrays containing the entries:
983
 *   - string langkey  key to lookup in the $lang var, if not found printed as is
984
 *   - string type     type of value
985
 *   - string value    tag value (unescaped)
986
 */
987
function tpl_get_img_meta() {
988
989
    $config_files = getConfigFiles('mediameta');
990
    foreach ($config_files as $config_file) {
991
        if(file_exists($config_file)) {
992
            include($config_file);
993
        }
994
    }
995
    /** @var array $fields the included array with metadata */
996
997
    $tags = array();
998
    foreach($fields as $tag){
0 ignored issues
show
Bug introduced by
The variable $fields does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
999
        $t = array();
1000
        if (!empty($tag[0])) {
1001
            $t = array($tag[0]);
1002
        }
1003
        if(is_array($tag[3])) {
1004
            $t = array_merge($t,$tag[3]);
1005
        }
1006
        $value = tpl_img_getTag($t);
1007
        if ($value) {
1008
            $tags[] = array('langkey' => $tag[1], 'type' => $tag[2], 'value' => $value);
1009
        }
1010
    }
1011
    return $tags;
1012
}
1013
1014
/**
1015
 * Prints the image with a link to the full sized version
1016
 *
1017
 * Only allowed in: detail.php
1018
 *
1019
 * @triggers TPL_IMG_DISPLAY
1020
 * @param $maxwidth  int - maximal width of the image
1021
 * @param $maxheight int - maximal height of the image
1022
 * @param $link bool     - link to the orginal size?
1023
 * @param $params array  - additional image attributes
1024
 * @return bool Result of TPL_IMG_DISPLAY
1025
 */
1026
function tpl_img($maxwidth = 0, $maxheight = 0, $link = true, $params = null) {
1027
    global $IMG;
1028
    /** @var Input $INPUT */
1029
    global $INPUT;
1030
    global $REV;
1031
    $w = (int) tpl_img_getTag('File.Width');
1032
    $h = (int) tpl_img_getTag('File.Height');
1033
1034
    //resize to given max values
1035
    $ratio = 1;
1036
    if($w >= $h) {
1037
        if($maxwidth && $w >= $maxwidth) {
1038
            $ratio = $maxwidth / $w;
1039
        } elseif($maxheight && $h > $maxheight) {
1040
            $ratio = $maxheight / $h;
1041
        }
1042
    } else {
1043
        if($maxheight && $h >= $maxheight) {
1044
            $ratio = $maxheight / $h;
1045
        } elseif($maxwidth && $w > $maxwidth) {
1046
            $ratio = $maxwidth / $w;
1047
        }
1048
    }
1049
    if($ratio) {
1050
        $w = floor($ratio * $w);
1051
        $h = floor($ratio * $h);
1052
    }
1053
1054
    //prepare URLs
1055
    $url = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV), true, '&');
1056
    $src = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV, 'w'=> $w, 'h'=> $h), true, '&');
1057
1058
    //prepare attributes
1059
    $alt = tpl_img_getTag('Simple.Title');
1060
    if(is_null($params)) {
1061
        $p = array();
1062
    } else {
1063
        $p = $params;
1064
    }
1065
    if($w) $p['width'] = $w;
1066
    if($h) $p['height'] = $h;
1067
    $p['class'] = 'img_detail';
1068
    if($alt) {
1069
        $p['alt']   = $alt;
1070
        $p['title'] = $alt;
1071
    } else {
1072
        $p['alt'] = '';
1073
    }
1074
    $p['src'] = $src;
1075
1076
    $data = array('url'=> ($link ? $url : null), 'params'=> $p);
1077
    return trigger_event('TPL_IMG_DISPLAY', $data, '_tpl_img_action', true);
1078
}
1079
1080
/**
1081
 * Default action for TPL_IMG_DISPLAY
1082
 *
1083
 * @param array $data
1084
 * @return bool
1085
 */
1086
function _tpl_img_action($data) {
1087
    global $lang;
1088
    $p = buildAttributes($data['params']);
1089
1090
    if($data['url']) print '<a href="'.hsc($data['url']).'" title="'.$lang['mediaview'].'">';
1091
    print '<img '.$p.'/>';
1092
    if($data['url']) print '</a>';
1093
    return true;
1094
}
1095
1096
/**
1097
 * This function inserts a small gif which in reality is the indexer function.
1098
 *
1099
 * Should be called somewhere at the very end of the main.php
1100
 * template
1101
 *
1102
 * @return bool
1103
 */
1104
function tpl_indexerWebBug() {
1105
    global $ID;
1106
1107
    $p           = array();
1108
    $p['src']    = DOKU_BASE.'lib/exe/indexer.php?id='.rawurlencode($ID).
1109
        '&'.time();
1110
    $p['width']  = 2; //no more 1x1 px image because we live in times of ad blockers...
1111
    $p['height'] = 1;
1112
    $p['alt']    = '';
1113
    $att         = buildAttributes($p);
1114
    print "<img $att />";
1115
    return true;
1116
}
1117
1118
/**
1119
 * tpl_getConf($id)
1120
 *
1121
 * use this function to access template configuration variables
1122
 *
1123
 * @param string $id      name of the value to access
1124
 * @param mixed  $notset  what to return if the setting is not available
1125
 * @return mixed
1126
 */
1127
function tpl_getConf($id, $notset=false) {
1128
    global $conf;
1129
    static $tpl_configloaded = false;
1130
1131
    $tpl = $conf['template'];
1132
1133
    if(!$tpl_configloaded) {
1134
        $tconf = tpl_loadConfig();
1135
        if($tconf !== false) {
1136
            foreach($tconf as $key => $value) {
1137
                if(isset($conf['tpl'][$tpl][$key])) continue;
1138
                $conf['tpl'][$tpl][$key] = $value;
1139
            }
1140
            $tpl_configloaded = true;
1141
        }
1142
    }
1143
1144
    if(isset($conf['tpl'][$tpl][$id])){
1145
        return $conf['tpl'][$tpl][$id];
1146
    }
1147
1148
    return $notset;
1149
}
1150
1151
/**
1152
 * tpl_loadConfig()
1153
 *
1154
 * reads all template configuration variables
1155
 * this function is automatically called by tpl_getConf()
1156
 *
1157
 * @return array
1158
 */
1159
function tpl_loadConfig() {
1160
1161
    $file = tpl_incdir().'/conf/default.php';
1162
    $conf = array();
1163
1164
    if(!file_exists($file)) return false;
1165
1166
    // load default config file
1167
    include($file);
1168
1169
    return $conf;
1170
}
1171
1172
// language methods
1173
/**
1174
 * tpl_getLang($id)
1175
 *
1176
 * use this function to access template language variables
1177
 *
1178
 * @param string $id key of language string
1179
 * @return string
1180
 */
1181
function tpl_getLang($id) {
1182
    static $lang = array();
1183
1184
    if(count($lang) === 0) {
1185
        global $conf, $config_cascade; // definitely don't invoke "global $lang"
1186
1187
        $path = tpl_incdir() . 'lang/';
1188
1189
        $lang = array();
1190
1191
        // don't include once
1192
        @include($path . 'en/lang.php');
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...
1193
        foreach($config_cascade['lang']['template'] as $config_file) {
1194
            if(file_exists($config_file . $conf['template'] . '/en/lang.php')) {
1195
                include($config_file . $conf['template'] . '/en/lang.php');
1196
            }
1197
        }
1198
1199
        if($conf['lang'] != 'en') {
1200
            @include($path . $conf['lang'] . '/lang.php');
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...
1201
            foreach($config_cascade['lang']['template'] as $config_file) {
1202
                if(file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
1203
                    include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
1204
                }
1205
            }
1206
        }
1207
    }
1208
    return $lang[$id];
1209
}
1210
1211
/**
1212
 * Retrieve a language dependent file and pass to xhtml renderer for display
1213
 * template equivalent of p_locale_xhtml()
1214
 *
1215
 * @param   string $id id of language dependent wiki page
1216
 * @return  string     parsed contents of the wiki page in xhtml format
1217
 */
1218
function tpl_locale_xhtml($id) {
1219
    return p_cached_output(tpl_localeFN($id));
1220
}
1221
1222
/**
1223
 * Prepends appropriate path for a language dependent filename
1224
 *
1225
 * @param string $id id of localized text
1226
 * @return string wiki text
1227
 */
1228
function tpl_localeFN($id) {
1229
    $path = tpl_incdir().'lang/';
1230
    global $conf;
1231
    $file = DOKU_CONF.'template_lang/'.$conf['template'].'/'.$conf['lang'].'/'.$id.'.txt';
1232
    if (!file_exists($file)){
1233
        $file = $path.$conf['lang'].'/'.$id.'.txt';
1234
        if(!file_exists($file)){
1235
            //fall back to english
1236
            $file = $path.'en/'.$id.'.txt';
1237
        }
1238
    }
1239
    return $file;
1240
}
1241
1242
/**
1243
 * prints the "main content" in the mediamanager popup
1244
 *
1245
 * Depending on the user's actions this may be a list of
1246
 * files in a namespace, the meta editing dialog or
1247
 * a message of referencing pages
1248
 *
1249
 * Only allowed in mediamanager.php
1250
 *
1251
 * @triggers MEDIAMANAGER_CONTENT_OUTPUT
1252
 * @param bool $fromajax - set true when calling this function via ajax
1253
 * @param string $sort
1254
 *
1255
 * @author Andreas Gohr <[email protected]>
1256
 */
1257
function tpl_mediaContent($fromajax = false, $sort='natural') {
1258
    global $IMG;
1259
    global $AUTH;
1260
    global $INUSE;
1261
    global $NS;
1262
    global $JUMPTO;
1263
    /** @var Input $INPUT */
1264
    global $INPUT;
1265
1266
    $do = $INPUT->extract('do')->str('do');
1267
    if(in_array($do, array('save', 'cancel'))) $do = '';
1268
1269
    if(!$do) {
1270
        if($INPUT->bool('edit')) {
1271
            $do = 'metaform';
1272
        } elseif(is_array($INUSE)) {
1273
            $do = 'filesinuse';
1274
        } else {
1275
            $do = 'filelist';
1276
        }
1277
    }
1278
1279
    // output the content pane, wrapped in an event.
1280
    if(!$fromajax) ptln('<div id="media__content">');
1281
    $data = array('do' => $do);
1282
    $evt  = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
1283
    if($evt->advise_before()) {
1284
        $do = $data['do'];
1285
        if($do == 'filesinuse') {
1286
            media_filesinuse($INUSE, $IMG);
1287
        } elseif($do == 'filelist') {
1288
            media_filelist($NS, $AUTH, $JUMPTO,false,$sort);
1289
        } elseif($do == 'searchlist') {
1290
            media_searchlist($INPUT->str('q'), $NS, $AUTH);
1291
        } else {
1292
            msg('Unknown action '.hsc($do), -1);
1293
        }
1294
    }
1295
    $evt->advise_after();
1296
    unset($evt);
1297
    if(!$fromajax) ptln('</div>');
1298
1299
}
1300
1301
/**
1302
 * Prints the central column in full-screen media manager
1303
 * Depending on the opened tab this may be a list of
1304
 * files in a namespace, upload form or search form
1305
 *
1306
 * @author Kate Arzamastseva <[email protected]>
1307
 */
1308
function tpl_mediaFileList() {
1309
    global $AUTH;
1310
    global $NS;
1311
    global $JUMPTO;
1312
    global $lang;
1313
    /** @var Input $INPUT */
1314
    global $INPUT;
1315
1316
    $opened_tab = $INPUT->str('tab_files');
1317
    if(!$opened_tab || !in_array($opened_tab, array('files', 'upload', 'search'))) $opened_tab = 'files';
1318
    if($INPUT->str('mediado') == 'update') $opened_tab = 'upload';
1319
1320
    echo '<h2 class="a11y">'.$lang['mediaselect'].'</h2>'.NL;
1321
1322
    media_tabs_files($opened_tab);
1323
1324
    echo '<div class="panelHeader">'.NL;
1325
    echo '<h3>';
1326
    $tabTitle = ($NS) ? $NS : '['.$lang['mediaroot'].']';
1327
    printf($lang['media_'.$opened_tab], '<strong>'.hsc($tabTitle).'</strong>');
1328
    echo '</h3>'.NL;
1329
    if($opened_tab === 'search' || $opened_tab === 'files') {
1330
        media_tab_files_options();
1331
    }
1332
    echo '</div>'.NL;
1333
1334
    echo '<div class="panelContent">'.NL;
1335
    if($opened_tab == 'files') {
1336
        media_tab_files($NS, $AUTH, $JUMPTO);
1337
    } elseif($opened_tab == 'upload') {
1338
        media_tab_upload($NS, $AUTH, $JUMPTO);
1339
    } elseif($opened_tab == 'search') {
1340
        media_tab_search($NS, $AUTH);
1341
    }
1342
    echo '</div>'.NL;
1343
}
1344
1345
/**
1346
 * Prints the third column in full-screen media manager
1347
 * Depending on the opened tab this may be details of the
1348
 * selected file, the meta editing dialog or
1349
 * list of file revisions
1350
 *
1351
 * @author Kate Arzamastseva <[email protected]>
1352
 *
1353
 * @param string $image
1354
 * @param boolean $rev
1355
 */
1356
function tpl_mediaFileDetails($image, $rev) {
1357
    global $conf, $DEL, $lang;
1358
    /** @var Input $INPUT */
1359
    global $INPUT;
1360
1361
    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')) && $conf['mediarevisions']);
1362
    if(!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return;
1363
    if($rev && !file_exists(mediaFN($image, $rev))) $rev = false;
0 ignored issues
show
Documentation introduced by
$rev is of type boolean, but the function expects a string|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1364
    $ns = getNS($image);
1365
    $do = $INPUT->str('mediado');
1366
1367
    $opened_tab = $INPUT->str('tab_details');
1368
1369
    $tab_array = array('view');
1370
    list(, $mime) = mimetype($image);
1371
    if($mime == 'image/jpeg') {
1372
        $tab_array[] = 'edit';
1373
    }
1374
    if($conf['mediarevisions']) {
1375
        $tab_array[] = 'history';
1376
    }
1377
1378
    if(!$opened_tab || !in_array($opened_tab, $tab_array)) $opened_tab = 'view';
1379
    if($INPUT->bool('edit')) $opened_tab = 'edit';
1380
    if($do == 'restore') $opened_tab = 'view';
1381
1382
    media_tabs_details($image, $opened_tab);
1383
1384
    echo '<div class="panelHeader"><h3>';
1385
    list($ext) = mimetype($image, false);
1386
    $class    = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1387
    $class    = 'select mediafile mf_'.$class;
1388
    $tabTitle = '<strong><a href="'.ml($image).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.$image.'</a>'.'</strong>';
1389
    if($opened_tab === 'view' && $rev) {
1390
        printf($lang['media_viewold'], $tabTitle, dformat($rev));
0 ignored issues
show
Documentation introduced by
$rev is of type boolean, but the function expects a integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1391
    } else {
1392
        printf($lang['media_'.$opened_tab], $tabTitle);
1393
    }
1394
1395
    echo '</h3></div>'.NL;
1396
1397
    echo '<div class="panelContent">'.NL;
1398
1399
    if($opened_tab == 'view') {
1400
        media_tab_view($image, $ns, null, $rev);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1364 can also be of type false; however, media_tab_view() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
Documentation introduced by
$rev is of type boolean, but the function expects a string|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1401
1402
    } elseif($opened_tab == 'edit' && !$removed) {
1403
        media_tab_edit($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1364 can also be of type false; however, media_tab_edit() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1404
1405
    } elseif($opened_tab == 'history' && $conf['mediarevisions']) {
1406
        media_tab_history($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1364 can also be of type false; however, media_tab_history() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1407
    }
1408
1409
    echo '</div>'.NL;
1410
}
1411
1412
/**
1413
 * prints the namespace tree in the mediamanager popup
1414
 *
1415
 * Only allowed in mediamanager.php
1416
 *
1417
 * @author Andreas Gohr <[email protected]>
1418
 */
1419
function tpl_mediaTree() {
1420
    global $NS;
1421
    ptln('<div id="media__tree">');
1422
    media_nstree($NS);
1423
    ptln('</div>');
1424
}
1425
1426
/**
1427
 * Print a dropdown menu with all DokuWiki actions
1428
 *
1429
 * Note: this will not use any pretty URLs
1430
 *
1431
 * @author Andreas Gohr <[email protected]>
1432
 *
1433
 * @param string $empty empty option label
1434
 * @param string $button submit button label
1435
 */
1436
function tpl_actiondropdown($empty = '', $button = '&gt;') {
1437
    $menu = new \dokuwiki\Menu\MobileMenu();
1438
    echo $menu->getDropdown($empty, $button);
1439
}
1440
1441
/**
1442
 * Print a informational line about the used license
1443
 *
1444
 * @author Andreas Gohr <[email protected]>
1445
 * @param  string $img     print image? (|button|badge)
1446
 * @param  bool   $imgonly skip the textual description?
1447
 * @param  bool   $return  when true don't print, but return HTML
1448
 * @param  bool   $wrap    wrap in div with class="license"?
1449
 * @return string
1450
 */
1451
function tpl_license($img = 'badge', $imgonly = false, $return = false, $wrap = true) {
1452
    global $license;
1453
    global $conf;
1454
    global $lang;
1455
    if(!$conf['license']) return '';
1456
    if(!is_array($license[$conf['license']])) return '';
1457
    $lic    = $license[$conf['license']];
1458
    $target = ($conf['target']['extern']) ? ' target="'.$conf['target']['extern'].'"' : '';
1459
1460
    $out = '';
1461
    if($wrap) $out .= '<div class="license">';
1462
    if($img) {
1463
        $src = license_img($img);
1464
        if($src) {
1465
            $out .= '<a href="'.$lic['url'].'" rel="license"'.$target;
1466
            $out .= '><img src="'.DOKU_BASE.$src.'" alt="'.$lic['name'].'" /></a>';
1467
            if(!$imgonly) $out .= ' ';
1468
        }
1469
    }
1470
    if(!$imgonly) {
1471
        $out .= $lang['license'].' ';
1472
        $out .= '<bdi><a href="'.$lic['url'].'" rel="license" class="urlextern"'.$target;
1473
        $out .= '>'.$lic['name'].'</a></bdi>';
1474
    }
1475
    if($wrap) $out .= '</div>';
1476
1477
    if($return) return $out;
1478
    echo $out;
1479
    return '';
1480
}
1481
1482
/**
1483
 * Includes the rendered HTML of a given page
1484
 *
1485
 * This function is useful to populate sidebars or similar features in a
1486
 * template
1487
 *
1488
 * @param string $pageid The page name you want to include
1489
 * @param bool $print Should the content be printed or returned only
1490
 * @param bool $propagate Search higher namespaces, too?
1491
 * @param bool $useacl Include the page only if the ACLs check out?
1492
 * @return bool|null|string
1493
 */
1494
function tpl_include_page($pageid, $print = true, $propagate = false, $useacl = true) {
1495
    if($propagate) {
1496
        $pageid = page_findnearest($pageid, $useacl);
1497
    } elseif($useacl && auth_quickaclcheck($pageid) == AUTH_NONE) {
1498
        return false;
1499
    }
1500
    if(!$pageid) return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression $pageid of type false|string is loosely compared to false; 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...
1501
1502
    global $TOC;
1503
    $oldtoc = $TOC;
1504
    $html   = p_wiki_xhtml($pageid, '', false);
1505
    $TOC    = $oldtoc;
1506
1507
    if($print) echo $html;
1508
    return $html;
1509
}
1510
1511
/**
1512
 * Display the subscribe form
1513
 *
1514
 * @author Adrian Lang <[email protected]>
1515
 */
1516
function tpl_subscribe() {
1517
    global $INFO;
1518
    global $ID;
1519
    global $lang;
1520
    global $conf;
1521
    $stime_days = $conf['subscribe_time'] / 60 / 60 / 24;
1522
1523
    echo p_locale_xhtml('subscr_form');
1524
    echo '<h2>'.$lang['subscr_m_current_header'].'</h2>';
1525
    echo '<div class="level2">';
1526
    if($INFO['subscribed'] === false) {
1527
        echo '<p>'.$lang['subscr_m_not_subscribed'].'</p>';
1528
    } else {
1529
        echo '<ul>';
1530
        foreach($INFO['subscribed'] as $sub) {
1531
            echo '<li><div class="li">';
1532
            if($sub['target'] !== $ID) {
1533
                echo '<code class="ns">'.hsc(prettyprint_id($sub['target'])).'</code>';
1534
            } else {
1535
                echo '<code class="page">'.hsc(prettyprint_id($sub['target'])).'</code>';
1536
            }
1537
            $sstl = sprintf($lang['subscr_style_'.$sub['style']], $stime_days);
1538
            if(!$sstl) $sstl = hsc($sub['style']);
1539
            echo ' ('.$sstl.') ';
1540
1541
            echo '<a href="'.wl(
1542
                $ID,
1543
                array(
1544
                     'do'        => 'subscribe',
1545
                     'sub_target'=> $sub['target'],
1546
                     'sub_style' => $sub['style'],
1547
                     'sub_action'=> 'unsubscribe',
1548
                     'sectok'    => getSecurityToken()
1549
                )
1550
            ).
1551
                '" class="unsubscribe">'.$lang['subscr_m_unsubscribe'].
1552
                '</a></div></li>';
1553
        }
1554
        echo '</ul>';
1555
    }
1556
    echo '</div>';
1557
1558
    // Add new subscription form
1559
    echo '<h2>'.$lang['subscr_m_new_header'].'</h2>';
1560
    echo '<div class="level2">';
1561
    $ns      = getNS($ID).':';
1562
    $targets = array(
1563
        $ID => '<code class="page">'.prettyprint_id($ID).'</code>',
1564
        $ns => '<code class="ns">'.prettyprint_id($ns).'</code>',
1565
    );
1566
    $styles  = array(
1567
        'every'  => $lang['subscr_style_every'],
1568
        'digest' => sprintf($lang['subscr_style_digest'], $stime_days),
1569
        'list'   => sprintf($lang['subscr_style_list'], $stime_days),
1570
    );
1571
1572
    $form = new Doku_Form(array('id' => 'subscribe__form'));
1573
    $form->startFieldset($lang['subscr_m_subscribe']);
1574
    $form->addRadioSet('sub_target', $targets);
1575
    $form->startFieldset($lang['subscr_m_receive']);
1576
    $form->addRadioSet('sub_style', $styles);
1577
    $form->addHidden('sub_action', 'subscribe');
1578
    $form->addHidden('do', 'subscribe');
1579
    $form->addHidden('id', $ID);
1580
    $form->endFieldset();
1581
    $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe']));
1582
    html_form('SUBSCRIBE', $form);
1583
    echo '</div>';
1584
}
1585
1586
/**
1587
 * Tries to send already created content right to the browser
1588
 *
1589
 * Wraps around ob_flush() and flush()
1590
 *
1591
 * @author Andreas Gohr <[email protected]>
1592
 */
1593
function tpl_flush() {
1594
    ob_flush();
1595
    flush();
1596
}
1597
1598
/**
1599
 * Tries to find a ressource file in the given locations.
1600
 *
1601
 * If a given location starts with a colon it is assumed to be a media
1602
 * file, otherwise it is assumed to be relative to the current template
1603
 *
1604
 * @param  string[] $search       locations to look at
1605
 * @param  bool     $abs           if to use absolute URL
1606
 * @param  array   &$imginfo   filled with getimagesize()
1607
 * @return string
1608
 *
1609
 * @author Andreas  Gohr <[email protected]>
1610
 */
1611
function tpl_getMediaFile($search, $abs = false, &$imginfo = null) {
1612
    $img     = '';
1613
    $file    = '';
1614
    $ismedia = false;
1615
    // loop through candidates until a match was found:
1616
    foreach($search as $img) {
1617
        if(substr($img, 0, 1) == ':') {
1618
            $file    = mediaFN($img);
1619
            $ismedia = true;
1620
        } else {
1621
            $file    = tpl_incdir().$img;
1622
            $ismedia = false;
1623
        }
1624
1625
        if(file_exists($file)) break;
1626
    }
1627
1628
    // fetch image data if requested
1629
    if(!is_null($imginfo)) {
1630
        $imginfo = getimagesize($file);
1631
    }
1632
1633
    // build URL
1634
    if($ismedia) {
1635
        $url = ml($img, '', true, '', $abs);
1636
    } else {
1637
        $url = tpl_basedir().$img;
1638
        if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL));
1639
    }
1640
1641
    return $url;
1642
}
1643
1644
/**
1645
 * PHP include a file
1646
 *
1647
 * either from the conf directory if it exists, otherwise use
1648
 * file in the template's root directory.
1649
 *
1650
 * The function honours config cascade settings and looks for the given
1651
 * file next to the ´main´ config files, in the order protected, local,
1652
 * default.
1653
 *
1654
 * Note: no escaping or sanity checking is done here. Never pass user input
1655
 * to this function!
1656
 *
1657
 * @author Anika Henke <[email protected]>
1658
 * @author Andreas Gohr <[email protected]>
1659
 *
1660
 * @param string $file
1661
 */
1662
function tpl_includeFile($file) {
1663
    global $config_cascade;
1664
    foreach(array('protected', 'local', 'default') as $config_group) {
1665
        if(empty($config_cascade['main'][$config_group])) continue;
1666
        foreach($config_cascade['main'][$config_group] as $conf_file) {
1667
            $dir = dirname($conf_file);
1668
            if(file_exists("$dir/$file")) {
1669
                include("$dir/$file");
1670
                return;
1671
            }
1672
        }
1673
    }
1674
1675
    // still here? try the template dir
1676
    $file = tpl_incdir().$file;
1677
    if(file_exists($file)) {
1678
        include($file);
1679
    }
1680
}
1681
1682
/**
1683
 * Returns <link> tag for various icon types (favicon|mobile|generic)
1684
 *
1685
 * @author Anika Henke <[email protected]>
1686
 *
1687
 * @param  array $types - list of icon types to display (favicon|mobile|generic)
1688
 * @return string
1689
 */
1690
function tpl_favicon($types = array('favicon')) {
1691
1692
    $return = '';
1693
1694
    foreach($types as $type) {
1695
        switch($type) {
1696
            case 'favicon':
1697
                $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico');
1698
                $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1699
                break;
1700
            case 'mobile':
1701
                $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.png');
1702
                $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1703
                break;
1704
            case 'generic':
1705
                // ideal world solution, which doesn't work in any browser yet
1706
                $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg');
1707
                $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL;
1708
                break;
1709
        }
1710
    }
1711
1712
    return $return;
1713
}
1714
1715
/**
1716
 * Prints full-screen media manager
1717
 *
1718
 * @author Kate Arzamastseva <[email protected]>
1719
 */
1720
function tpl_media() {
1721
    global $NS, $IMG, $JUMPTO, $REV, $lang, $fullscreen, $INPUT;
1722
    $fullscreen = true;
1723
    require_once DOKU_INC.'lib/exe/mediamanager.php';
1724
1725
    $rev   = '';
1726
    $image = cleanID($INPUT->str('image'));
1727
    if(isset($IMG)) $image = $IMG;
1728
    if(isset($JUMPTO)) $image = $JUMPTO;
1729
    if(isset($REV) && !$JUMPTO) $rev = $REV;
1730
1731
    echo '<div id="mediamanager__page">'.NL;
1732
    echo '<h1>'.$lang['btn_media'].'</h1>'.NL;
1733
    html_msgarea();
1734
1735
    echo '<div class="panel namespaces">'.NL;
1736
    echo '<h2>'.$lang['namespaces'].'</h2>'.NL;
1737
    echo '<div class="panelHeader">';
1738
    echo $lang['media_namespaces'];
1739
    echo '</div>'.NL;
1740
1741
    echo '<div class="panelContent" id="media__tree">'.NL;
1742
    media_nstree($NS);
1743
    echo '</div>'.NL;
1744
    echo '</div>'.NL;
1745
1746
    echo '<div class="panel filelist">'.NL;
1747
    tpl_mediaFileList();
1748
    echo '</div>'.NL;
1749
1750
    echo '<div class="panel file">'.NL;
1751
    echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL;
1752
    tpl_mediaFileDetails($image, $rev);
1753
    echo '</div>'.NL;
1754
1755
    echo '</div>'.NL;
1756
}
1757
1758
/**
1759
 * Return useful layout classes
1760
 *
1761
 * @author Anika Henke <[email protected]>
1762
 *
1763
 * @return string
1764
 */
1765
function tpl_classes() {
1766
    global $ACT, $conf, $ID, $INFO;
1767
    /** @var Input $INPUT */
1768
    global $INPUT;
1769
1770
    $classes = array(
1771
        'dokuwiki',
1772
        'mode_'.$ACT,
1773
        'tpl_'.$conf['template'],
1774
        $INPUT->server->bool('REMOTE_USER') ? 'loggedIn' : '',
1775
        $INFO['exists'] ? '' : 'notFound',
1776
        ($ID == $conf['start']) ? 'home' : '',
1777
    );
1778
    return join(' ', $classes);
1779
}
1780
1781
/**
1782
 * Create event for tools menues
1783
 *
1784
 * @author Anika Henke <[email protected]>
1785
 * @param string $toolsname name of menu
1786
 * @param array $items
1787
 * @param string $view e.g. 'main', 'detail', ...
1788
 */
1789
function tpl_toolsevent($toolsname, $items, $view = 'main') {
1790
    $data = array(
1791
        'view' => $view,
1792
        'items' => $items
1793
    );
1794
1795
    $hook = 'TEMPLATE_' . strtoupper($toolsname) . '_DISPLAY';
1796
    $evt = new Doku_Event($hook, $data);
1797
    if($evt->advise_before()) {
1798
        foreach($evt->data['items'] as $k => $html) echo $html;
1799
    }
1800
    $evt->advise_after();
1801
}
1802
1803
//Setup VIM: ex: et ts=4 :
1804
1805