Failed Conditions
Push — phpunit8 ( c85f64...01c53a )
by Andreas
225:58 queued 223:01
created

template.php ➔ tpl_userinfo()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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

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...
486
    if($data === false) {
487
        return false;
488
    } elseif(!is_array($data)) {
489
        $out = sprintf($data, 'button');
490
    } else {
491
        /**
492
         * @var string $accesskey
493
         * @var string $id
494
         * @var string $method
495
         * @var array  $params
496
         */
497
        extract($data);
498
        if($id === '#dokuwiki__top') {
499
            $out = html_topbtn();
500
        } else {
501
            $out = html_btn($type, $id, $accesskey, $params, $method);
502
        }
503
    }
504
    if($return) return $out;
505
    echo $out;
506
    return true;
507
}
508
509
/**
510
 * Like the action buttons but links
511
 *
512
 * @author Adrian Lang <[email protected]>
513
 * @see    tpl_get_action
514
 *
515
 * @param string $type    action command
516
 * @param string $pre     prefix of link
517
 * @param string $suf     suffix of link
518
 * @param string $inner   innerHML of link
519
 * @param bool   $return  if true it returns html, otherwise prints
520
 * @return bool|string html or false if no data, true if printed
521
 * @deprecated 2017-09-01 see devel:menus
522
 */
523
function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = false) {
524
    dbg_deprecated('see devel:menus');
525
    global $lang;
526
    $data = tpl_get_action($type);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_get_action() has been deprecated with message: 2017-09-01 see devel:menus

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...
527
    if($data === false) {
528
        return false;
529
    } elseif(!is_array($data)) {
530
        $out = sprintf($data, 'link');
531
    } else {
532
        /**
533
         * @var string $accesskey
534
         * @var string $id
535
         * @var string $method
536
         * @var bool   $nofollow
537
         * @var array  $params
538
         * @var string $replacement
539
         */
540
        extract($data);
541
        if(strpos($id, '#') === 0) {
542
            $linktarget = $id;
543
        } else {
544
            $linktarget = wl($id, $params);
545
        }
546
        $caption = $lang['btn_'.$type];
547
        if(strpos($caption, '%s')){
548
            $caption = sprintf($caption, $replacement);
549
        }
550
        $akey    = $addTitle = '';
551
        if($accesskey) {
552
            $akey     = 'accesskey="'.$accesskey.'" ';
553
            $addTitle = ' ['.strtoupper($accesskey).']';
554
        }
555
        $rel = $nofollow ? 'rel="nofollow" ' : '';
556
        $out = tpl_link(
557
            $linktarget, $pre.(($inner) ? $inner : $caption).$suf,
558
            'class="action '.$type.'" '.
559
                $akey.$rel.
560
                'title="'.hsc($caption).$addTitle.'"', true
561
        );
562
    }
563
    if($return) return $out;
564
    echo $out;
565
    return true;
566
}
567
568
/**
569
 * Check the actions and get data for buttons and links
570
 *
571
 * @author Andreas Gohr <[email protected]>
572
 * @author Matthias Grimm <[email protected]>
573
 * @author Adrian Lang <[email protected]>
574
 *
575
 * @param string $type
576
 * @return array|bool|string
577
 * @deprecated 2017-09-01 see devel:menus
578
 */
579
function tpl_get_action($type) {
580
    dbg_deprecated('see devel:menus');
581
    if($type == 'history') $type = 'revisions';
582
    if($type == 'subscription') $type = 'subscribe';
583
    if($type == 'img_backto') $type = 'imgBackto';
584
585
    $class = '\\dokuwiki\\Menu\\Item\\' . ucfirst($type);
586
    if(class_exists($class)) {
587
        try {
588
            /** @var \dokuwiki\Menu\Item\AbstractItem $item */
589
            $item = new $class;
590
            $data = $item->getLegacyData();
591
            $unknown = false;
592
        } catch(\RuntimeException $ignored) {
593
            return false;
594
        }
595
    } else {
596
        global $ID;
597
        $data = array(
598
            'accesskey' => null,
599
            'type' => $type,
600
            'id' => $ID,
601
            'method' => 'get',
602
            'params' => array('do' => $type),
603
            'nofollow' => true,
604
            'replacement' => '',
605
        );
606
        $unknown = true;
607
    }
608
609
    $evt = new Event('TPL_ACTION_GET', $data);
610
    if($evt->advise_before()) {
611
        //handle unknown types
612
        if($unknown) {
613
            $data = '[unknown %s type]';
614
        }
615
    }
616
    $evt->advise_after();
617
    unset($evt);
618
619
    return $data;
620
}
621
622
/**
623
 * Wrapper around tpl_button() and tpl_actionlink()
624
 *
625
 * @author Anika Henke <[email protected]>
626
 *
627
 * @param string        $type action command
628
 * @param bool          $link link or form button?
629
 * @param string|bool   $wrapper HTML element wrapper
630
 * @param bool          $return return or print
631
 * @param string        $pre prefix for links
632
 * @param string        $suf suffix for links
633
 * @param string        $inner inner HTML for links
634
 * @return bool|string
635
 * @deprecated 2017-09-01 see devel:menus
636
 */
637
function tpl_action($type, $link = false, $wrapper = false, $return = false, $pre = '', $suf = '', $inner = '') {
638
    dbg_deprecated('see devel:menus');
639
    $out = '';
640
    if($link) {
641
        $out .= tpl_actionlink($type, $pre, $suf, $inner, true);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_actionlink() has been deprecated with message: 2017-09-01 see devel:menus

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...
642
    } else {
643
        $out .= tpl_button($type, true);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_button() has been deprecated with message: 2017-09-01 see devel:menus

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...
644
    }
645
    if($out && $wrapper) $out = "<$wrapper>$out</$wrapper>";
646
647
    if($return) return $out;
648
    print $out;
649
    return $out ? true : false;
650
}
651
652
/**
653
 * Print the search form
654
 *
655
 * If the first parameter is given a div with the ID 'qsearch_out' will
656
 * be added which instructs the ajax pagequicksearch to kick in and place
657
 * its output into this div. The second parameter controls the propritary
658
 * attribute autocomplete. If set to false this attribute will be set with an
659
 * value of "off" to instruct the browser to disable it's own built in
660
 * autocompletion feature (MSIE and Firefox)
661
 *
662
 * @author Andreas Gohr <[email protected]>
663
 *
664
 * @param bool $ajax
665
 * @param bool $autocomplete
666
 * @return bool
667
 */
668
function tpl_searchform($ajax = true, $autocomplete = true) {
669
    global $lang;
670
    global $ACT;
671
    global $QUERY;
672
    global $ID;
673
674
    // don't print the search form if search action has been disabled
675
    if(!actionOK('search')) return false;
676
677
    $searchForm = new dokuwiki\Form\Form([
678
        'action' => wl(),
679
        'method' => 'get',
680
        'role' => 'search',
681
        'class' => 'search',
682
        'id' => 'dw__search',
683
    ], true);
684
    $searchForm->addTagOpen('div')->addClass('no');
685
    $searchForm->setHiddenField('do', 'search');
686
    $searchForm->setHiddenField('id', $ID);
687
    $searchForm->addTextInput('q')
688
        ->addClass('edit')
689
        ->attrs([
690
            'title' => '[F]',
691
            'accesskey' => 'f',
692
            'placeholder' => $lang['btn_search'],
693
            'autocomplete' => $autocomplete ? 'on' : 'off',
694
        ])
695
        ->id('qsearch__in')
696
        ->val($ACT === 'search' ? $QUERY : '')
697
        ->useInput(false)
698
    ;
699
    $searchForm->addButton('', $lang['btn_search'])->attrs([
700
        'type' => 'submit',
701
        'title' => $lang['btn_search'],
702
    ]);
703
    if ($ajax) {
704
        $searchForm->addTagOpen('div')->id('qsearch__out')->addClass('ajax_qsearch JSpopup');
705
        $searchForm->addTagClose('div');
706
    }
707
    $searchForm->addTagClose('div');
708
709
    echo $searchForm->toHTML('QuickSearch');
710
711
    return true;
712
}
713
714
/**
715
 * Print the breadcrumbs trace
716
 *
717
 * @author Andreas Gohr <[email protected]>
718
 *
719
 * @param string $sep Separator between entries
720
 * @param bool   $return return or print
721
 * @return bool|string
722
 */
723
function tpl_breadcrumbs($sep = null, $return = false) {
724
    global $lang;
725
    global $conf;
726
727
    //check if enabled
728
    if(!$conf['breadcrumbs']) return false;
729
730
    //set default
731
    if(is_null($sep)) $sep = '•';
732
733
    $out='';
734
735
    $crumbs = breadcrumbs(); //setup crumb trace
736
737
    $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
738
739
    //render crumbs, highlight the last one
740
    $out .= '<span class="bchead">'.$lang['breadcrumb'].'</span>';
741
    $last = count($crumbs);
742
    $i    = 0;
743
    foreach($crumbs as $id => $name) {
744
        $i++;
745
        $out .= $crumbs_sep;
746
        if($i == $last) $out .= '<span class="curid">';
747
        $out .= '<bdi>' . tpl_link(wl($id), hsc($name), 'class="breadcrumbs" title="'.$id.'"', true) .  '</bdi>';
748
        if($i == $last) $out .= '</span>';
749
    }
750
    if($return) return $out;
751
    print $out;
752
    return $out ? true : false;
753
}
754
755
/**
756
 * Hierarchical breadcrumbs
757
 *
758
 * This code was suggested as replacement for the usual breadcrumbs.
759
 * It only makes sense with a deep site structure.
760
 *
761
 * @author Andreas Gohr <[email protected]>
762
 * @author Nigel McNie <[email protected]>
763
 * @author Sean Coates <[email protected]>
764
 * @author <[email protected]>
765
 * @todo   May behave strangely in RTL languages
766
 *
767
 * @param string $sep Separator between entries
768
 * @param bool   $return return or print
769
 * @return bool|string
770
 */
771
function tpl_youarehere($sep = null, $return = false) {
772
    global $conf;
773
    global $ID;
774
    global $lang;
775
776
    // check if enabled
777
    if(!$conf['youarehere']) return false;
778
779
    //set default
780
    if(is_null($sep)) $sep = ' » ';
781
782
    $out = '';
783
784
    $parts = explode(':', $ID);
785
    $count = count($parts);
786
787
    $out .= '<span class="bchead">'.$lang['youarehere'].' </span>';
788
789
    // always print the startpage
790
    $out .= '<span class="home">' . tpl_pagelink(':'.$conf['start'], null, true) . '</span>';
791
792
    // print intermediate namespace links
793
    $part = '';
794
    for($i = 0; $i < $count - 1; $i++) {
795
        $part .= $parts[$i].':';
796
        $page = $part;
797
        if($page == $conf['start']) continue; // Skip startpage
798
799
        // output
800
        $out .= $sep . tpl_pagelink($page, null, true);
801
    }
802
803
    // print current page, skipping start page, skipping for namespace index
804
    resolve_pageid('', $page, $exists);
805
    if (isset($page) && $page == $part.$parts[$i]) {
806
        if($return) return $out;
807
        print $out;
808
        return true;
809
    }
810
    $page = $part.$parts[$i];
811
    if($page == $conf['start']) {
812
        if($return) return $out;
813
        print $out;
814
        return true;
815
    }
816
    $out .= $sep;
817
    $out .= tpl_pagelink($page, null, true);
818
    if($return) return $out;
819
    print $out;
820
    return $out ? true : false;
821
}
822
823
/**
824
 * Print info if the user is logged in
825
 * and show full name in that case
826
 *
827
 * Could be enhanced with a profile link in future?
828
 *
829
 * @author Andreas Gohr <[email protected]>
830
 *
831
 * @return bool
832
 */
833
function tpl_userinfo() {
834
    global $lang;
835
    /** @var Input $INPUT */
836
    global $INPUT;
837
838
    if($INPUT->server->str('REMOTE_USER')) {
839
        print $lang['loggedinas'].' '.userlink();
840
        return true;
841
    }
842
    return false;
843
}
844
845
/**
846
 * Print some info about the current page
847
 *
848
 * @author Andreas Gohr <[email protected]>
849
 *
850
 * @param bool $ret return content instead of printing it
851
 * @return bool|string
852
 */
853
function tpl_pageinfo($ret = false) {
854
    global $conf;
855
    global $lang;
856
    global $INFO;
857
    global $ID;
858
859
    // return if we are not allowed to view the page
860
    if(!auth_quickaclcheck($ID)) {
861
        return false;
862
    }
863
864
    // prepare date and path
865
    $fn = $INFO['filepath'];
866
    if(!$conf['fullpath']) {
867
        if($INFO['rev']) {
868
            $fn = str_replace($conf['olddir'].'/', '', $fn);
869
        } else {
870
            $fn = str_replace($conf['datadir'].'/', '', $fn);
871
        }
872
    }
873
    $fn   = utf8_decodeFN($fn);
874
    $date = dformat($INFO['lastmod']);
875
876
    // print it
877
    if($INFO['exists']) {
878
        $out = '';
879
        $out .= '<bdi>'.$fn.'</bdi>';
880
        $out .= ' · ';
881
        $out .= $lang['lastmod'];
882
        $out .= ' ';
883
        $out .= $date;
884
        if($INFO['editor']) {
885
            $out .= ' '.$lang['by'].' ';
886
            $out .= '<bdi>'.editorinfo($INFO['editor']).'</bdi>';
887
        } else {
888
            $out .= ' ('.$lang['external_edit'].')';
889
        }
890
        if($INFO['locked']) {
891
            $out .= ' · ';
892
            $out .= $lang['lockedby'];
893
            $out .= ' ';
894
            $out .= '<bdi>'.editorinfo($INFO['locked']).'</bdi>';
895
        }
896
        if($ret) {
897
            return $out;
898
        } else {
899
            echo $out;
900
            return true;
901
        }
902
    }
903
    return false;
904
}
905
906
/**
907
 * Prints or returns the name of the given page (current one if none given).
908
 *
909
 * If useheading is enabled this will use the first headline else
910
 * the given ID is used.
911
 *
912
 * @author Andreas Gohr <[email protected]>
913
 *
914
 * @param string $id page id
915
 * @param bool   $ret return content instead of printing
916
 * @return bool|string
917
 */
918
function tpl_pagetitle($id = null, $ret = false) {
919
    global $ACT, $INPUT, $conf, $lang;
920
921
    if(is_null($id)) {
922
        global $ID;
923
        $id = $ID;
924
    }
925
926
    $name = $id;
927
    if(useHeading('navigation')) {
928
        $first_heading = p_get_first_heading($id);
929
        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...
930
    }
931
932
    // default page title is the page name, modify with the current action
933
    switch ($ACT) {
934
        // admin functions
935
        case 'admin' :
936
            $page_title = $lang['btn_admin'];
937
            // try to get the plugin name
938
            /** @var $plugin AdminPlugin */
939
            if ($plugin = plugin_getRequestAdminPlugin()){
940
                $plugin_title = $plugin->getMenuText($conf['lang']);
941
                $page_title = $plugin_title ? $plugin_title : $plugin->getPluginName();
942
            }
943
            break;
944
945
        // user functions
946
        case 'login' :
947
        case 'profile' :
948
        case 'register' :
949
        case 'resendpwd' :
950
            $page_title = $lang['btn_'.$ACT];
951
            break;
952
953
         // wiki functions
954
        case 'search' :
955
        case 'index' :
956
            $page_title = $lang['btn_'.$ACT];
957
            break;
958
959
        // page functions
960
        case 'edit' :
961
        case 'preview' :
962
            $page_title = "✎ ".$name;
963
            break;
964
965
        case 'revisions' :
966
            $page_title = $name . ' - ' . $lang['btn_revs'];
967
            break;
968
969
        case 'backlink' :
970
        case 'recent' :
971
        case 'subscribe' :
972
            $page_title = $name . ' - ' . $lang['btn_'.$ACT];
973
            break;
974
975
        default : // SHOW and anything else not included
976
            $page_title = $name;
977
    }
978
979
    if($ret) {
980
        return hsc($page_title);
981
    } else {
982
        print hsc($page_title);
983
        return true;
984
    }
985
}
986
987
/**
988
 * Returns the requested EXIF/IPTC tag from the current image
989
 *
990
 * If $tags is an array all given tags are tried until a
991
 * value is found. If no value is found $alt is returned.
992
 *
993
 * Which texts are known is defined in the functions _exifTagNames
994
 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
995
 * to the names of the latter one)
996
 *
997
 * Only allowed in: detail.php
998
 *
999
 * @author Andreas Gohr <[email protected]>
1000
 *
1001
 * @param array|string $tags tag or array of tags to try
1002
 * @param string       $alt  alternative output if no data was found
1003
 * @param null|string  $src  the image src, uses global $SRC if not given
1004
 * @return string
1005
 */
1006
function tpl_img_getTag($tags, $alt = '', $src = null) {
1007
    // Init Exif Reader
1008
    global $SRC;
1009
1010
    if(is_null($src)) $src = $SRC;
1011
    if(is_null($src)) return $alt;
1012
1013
    static $meta = null;
1014
    if(is_null($meta)) $meta = new JpegMeta($src);
1015
    if($meta === false) return $alt;
1016
    $info = cleanText($meta->getField($tags));
1017
    $meta = null; // garbage collect and close any file handles. See #3404
1018
    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...
1019
    return $info;
1020
}
1021
1022
/**
1023
 * Returns a description list of the metatags of the current image
1024
 *
1025
 * @return string html of description list
1026
 */
1027
function tpl_img_meta() {
1028
    global $lang;
1029
1030
    $tags = tpl_get_img_meta();
1031
1032
    echo '<dl>';
1033
    foreach($tags as $tag) {
1034
        $label = $lang[$tag['langkey']];
1035
        if(!$label) $label = $tag['langkey'] . ':';
1036
1037
        echo '<dt>'.$label.'</dt><dd>';
1038
        if ($tag['type'] == 'date') {
1039
            echo dformat($tag['value']);
1040
        } else {
1041
            echo hsc($tag['value']);
1042
        }
1043
        echo '</dd>';
1044
    }
1045
    echo '</dl>';
1046
}
1047
1048
/**
1049
 * Returns metadata as configured in mediameta config file, ready for creating html
1050
 *
1051
 * @return array with arrays containing the entries:
1052
 *   - string langkey  key to lookup in the $lang var, if not found printed as is
1053
 *   - string type     type of value
1054
 *   - string value    tag value (unescaped)
1055
 */
1056
function tpl_get_img_meta() {
1057
1058
    $config_files = getConfigFiles('mediameta');
1059
    foreach ($config_files as $config_file) {
1060
        if(file_exists($config_file)) {
1061
            include($config_file);
1062
        }
1063
    }
1064
    /** @var array $fields the included array with metadata */
1065
1066
    $tags = array();
1067
    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...
1068
        $t = array();
1069
        if (!empty($tag[0])) {
1070
            $t = array($tag[0]);
1071
        }
1072
        if(isset($tag[3]) && is_array($tag[3])) {
1073
            $t = array_merge($t,$tag[3]);
1074
        }
1075
        $value = tpl_img_getTag($t);
1076
        if ($value) {
1077
            $tags[] = array('langkey' => $tag[1], 'type' => $tag[2], 'value' => $value);
1078
        }
1079
    }
1080
    return $tags;
1081
}
1082
1083
/**
1084
 * Prints the image with a link to the full sized version
1085
 *
1086
 * Only allowed in: detail.php
1087
 *
1088
 * @triggers TPL_IMG_DISPLAY
1089
 * @param $maxwidth  int - maximal width of the image
1090
 * @param $maxheight int - maximal height of the image
1091
 * @param $link bool     - link to the orginal size?
1092
 * @param $params array  - additional image attributes
1093
 * @return bool Result of TPL_IMG_DISPLAY
1094
 */
1095
function tpl_img($maxwidth = 0, $maxheight = 0, $link = true, $params = null) {
1096
    global $IMG;
1097
    /** @var Input $INPUT */
1098
    global $INPUT;
1099
    global $REV;
1100
    $w = (int) tpl_img_getTag('File.Width');
1101
    $h = (int) tpl_img_getTag('File.Height');
1102
1103
    //resize to given max values
1104
    $ratio = 1;
1105
    if($w >= $h) {
1106
        if($maxwidth && $w >= $maxwidth) {
1107
            $ratio = $maxwidth / $w;
1108
        } elseif($maxheight && $h > $maxheight) {
1109
            $ratio = $maxheight / $h;
1110
        }
1111
    } else {
1112
        if($maxheight && $h >= $maxheight) {
1113
            $ratio = $maxheight / $h;
1114
        } elseif($maxwidth && $w > $maxwidth) {
1115
            $ratio = $maxwidth / $w;
1116
        }
1117
    }
1118
    if($ratio) {
1119
        $w = floor($ratio * $w);
1120
        $h = floor($ratio * $h);
1121
    }
1122
1123
    //prepare URLs
1124
    $url = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV), true, '&');
1125
    $src = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV, 'w'=> $w, 'h'=> $h), true, '&');
1126
1127
    //prepare attributes
1128
    $alt = tpl_img_getTag('Simple.Title');
1129
    if(is_null($params)) {
1130
        $p = array();
1131
    } else {
1132
        $p = $params;
1133
    }
1134
    if($w) $p['width'] = $w;
1135
    if($h) $p['height'] = $h;
1136
    $p['class'] = 'img_detail';
1137
    if($alt) {
1138
        $p['alt']   = $alt;
1139
        $p['title'] = $alt;
1140
    } else {
1141
        $p['alt'] = '';
1142
    }
1143
    $p['src'] = $src;
1144
1145
    $data = array('url'=> ($link ? $url : null), 'params'=> $p);
1146
    return Event::createAndTrigger('TPL_IMG_DISPLAY', $data, '_tpl_img_action', true);
1147
}
1148
1149
/**
1150
 * Default action for TPL_IMG_DISPLAY
1151
 *
1152
 * @param array $data
1153
 * @return bool
1154
 */
1155
function _tpl_img_action($data) {
1156
    global $lang;
1157
    $p = buildAttributes($data['params']);
1158
1159
    if($data['url']) print '<a href="'.hsc($data['url']).'" title="'.$lang['mediaview'].'">';
1160
    print '<img '.$p.'/>';
1161
    if($data['url']) print '</a>';
1162
    return true;
1163
}
1164
1165
/**
1166
 * This function inserts a small gif which in reality is the indexer function.
1167
 *
1168
 * Should be called somewhere at the very end of the main.php
1169
 * template
1170
 *
1171
 * @return bool
1172
 */
1173
function tpl_indexerWebBug() {
1174
    global $ID;
1175
1176
    $p           = array();
1177
    $p['src']    = DOKU_BASE.'lib/exe/taskrunner.php?id='.rawurlencode($ID).
1178
        '&'.time();
1179
    $p['width']  = 2; //no more 1x1 px image because we live in times of ad blockers...
1180
    $p['height'] = 1;
1181
    $p['alt']    = '';
1182
    $att         = buildAttributes($p);
1183
    print "<img $att />";
1184
    return true;
1185
}
1186
1187
/**
1188
 * tpl_getConf($id)
1189
 *
1190
 * use this function to access template configuration variables
1191
 *
1192
 * @param string $id      name of the value to access
1193
 * @param mixed  $notset  what to return if the setting is not available
1194
 * @return mixed
1195
 */
1196
function tpl_getConf($id, $notset=false) {
1197
    global $conf;
1198
    static $tpl_configloaded = false;
1199
1200
    $tpl = $conf['template'];
1201
1202
    if(!$tpl_configloaded) {
1203
        $tconf = tpl_loadConfig();
1204
        if($tconf !== false) {
1205
            foreach($tconf as $key => $value) {
1206
                if(isset($conf['tpl'][$tpl][$key])) continue;
1207
                $conf['tpl'][$tpl][$key] = $value;
1208
            }
1209
            $tpl_configloaded = true;
1210
        }
1211
    }
1212
1213
    if(isset($conf['tpl'][$tpl][$id])){
1214
        return $conf['tpl'][$tpl][$id];
1215
    }
1216
1217
    return $notset;
1218
}
1219
1220
/**
1221
 * tpl_loadConfig()
1222
 *
1223
 * reads all template configuration variables
1224
 * this function is automatically called by tpl_getConf()
1225
 *
1226
 * @return array
1227
 */
1228
function tpl_loadConfig() {
1229
1230
    $file = tpl_incdir().'/conf/default.php';
1231
    $conf = array();
1232
1233
    if(!file_exists($file)) return false;
1234
1235
    // load default config file
1236
    include($file);
1237
1238
    return $conf;
1239
}
1240
1241
// language methods
1242
/**
1243
 * tpl_getLang($id)
1244
 *
1245
 * use this function to access template language variables
1246
 *
1247
 * @param string $id key of language string
1248
 * @return string
1249
 */
1250
function tpl_getLang($id) {
1251
    static $lang = array();
1252
1253
    if(count($lang) === 0) {
1254
        global $conf, $config_cascade; // definitely don't invoke "global $lang"
1255
1256
        $path = tpl_incdir() . 'lang/';
1257
1258
        $lang = array();
1259
1260
        // don't include once
1261
        @include($path . 'en/lang.php');
1262
        foreach($config_cascade['lang']['template'] as $config_file) {
1263
            if(file_exists($config_file . $conf['template'] . '/en/lang.php')) {
1264
                include($config_file . $conf['template'] . '/en/lang.php');
1265
            }
1266
        }
1267
1268
        if($conf['lang'] != 'en') {
1269
            @include($path . $conf['lang'] . '/lang.php');
1270
            foreach($config_cascade['lang']['template'] as $config_file) {
1271
                if(file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
1272
                    include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
1273
                }
1274
            }
1275
        }
1276
    }
1277
    return isset($lang[$id]) ? $lang[$id] : '';
1278
}
1279
1280
/**
1281
 * Retrieve a language dependent file and pass to xhtml renderer for display
1282
 * template equivalent of p_locale_xhtml()
1283
 *
1284
 * @param   string $id id of language dependent wiki page
1285
 * @return  string     parsed contents of the wiki page in xhtml format
1286
 */
1287
function tpl_locale_xhtml($id) {
1288
    return p_cached_output(tpl_localeFN($id));
1289
}
1290
1291
/**
1292
 * Prepends appropriate path for a language dependent filename
1293
 *
1294
 * @param string $id id of localized text
1295
 * @return string wiki text
1296
 */
1297
function tpl_localeFN($id) {
1298
    $path = tpl_incdir().'lang/';
1299
    global $conf;
1300
    $file = DOKU_CONF.'template_lang/'.$conf['template'].'/'.$conf['lang'].'/'.$id.'.txt';
1301
    if (!file_exists($file)){
1302
        $file = $path.$conf['lang'].'/'.$id.'.txt';
1303
        if(!file_exists($file)){
1304
            //fall back to english
1305
            $file = $path.'en/'.$id.'.txt';
1306
        }
1307
    }
1308
    return $file;
1309
}
1310
1311
/**
1312
 * prints the "main content" in the mediamanager popup
1313
 *
1314
 * Depending on the user's actions this may be a list of
1315
 * files in a namespace, the meta editing dialog or
1316
 * a message of referencing pages
1317
 *
1318
 * Only allowed in mediamanager.php
1319
 *
1320
 * @triggers MEDIAMANAGER_CONTENT_OUTPUT
1321
 * @param bool $fromajax - set true when calling this function via ajax
1322
 * @param string $sort
1323
 *
1324
 * @author Andreas Gohr <[email protected]>
1325
 */
1326
function tpl_mediaContent($fromajax = false, $sort='natural') {
1327
    global $IMG;
1328
    global $AUTH;
1329
    global $INUSE;
1330
    global $NS;
1331
    global $JUMPTO;
1332
    /** @var Input $INPUT */
1333
    global $INPUT;
1334
1335
    $do = $INPUT->extract('do')->str('do');
1336
    if(in_array($do, array('save', 'cancel'))) $do = '';
1337
1338
    if(!$do) {
1339
        if($INPUT->bool('edit')) {
1340
            $do = 'metaform';
1341
        } elseif(is_array($INUSE)) {
1342
            $do = 'filesinuse';
1343
        } else {
1344
            $do = 'filelist';
1345
        }
1346
    }
1347
1348
    // output the content pane, wrapped in an event.
1349
    if(!$fromajax) ptln('<div id="media__content">');
1350
    $data = array('do' => $do);
1351
    $evt  = new Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
1352
    if($evt->advise_before()) {
1353
        $do = $data['do'];
1354
        if($do == 'filesinuse') {
1355
            media_filesinuse($INUSE, $IMG);
1356
        } elseif($do == 'filelist') {
1357
            media_filelist($NS, $AUTH, $JUMPTO,false,$sort);
1358
        } elseif($do == 'searchlist') {
1359
            media_searchlist($INPUT->str('q'), $NS, $AUTH);
1360
        } else {
1361
            msg('Unknown action '.hsc($do), -1);
1362
        }
1363
    }
1364
    $evt->advise_after();
1365
    unset($evt);
1366
    if(!$fromajax) ptln('</div>');
1367
1368
}
1369
1370
/**
1371
 * Prints the central column in full-screen media manager
1372
 * Depending on the opened tab this may be a list of
1373
 * files in a namespace, upload form or search form
1374
 *
1375
 * @author Kate Arzamastseva <[email protected]>
1376
 */
1377
function tpl_mediaFileList() {
1378
    global $AUTH;
1379
    global $NS;
1380
    global $JUMPTO;
1381
    global $lang;
1382
    /** @var Input $INPUT */
1383
    global $INPUT;
1384
1385
    $opened_tab = $INPUT->str('tab_files');
1386
    if(!$opened_tab || !in_array($opened_tab, array('files', 'upload', 'search'))) $opened_tab = 'files';
1387
    if($INPUT->str('mediado') == 'update') $opened_tab = 'upload';
1388
1389
    echo '<h2 class="a11y">'.$lang['mediaselect'].'</h2>'.NL;
1390
1391
    media_tabs_files($opened_tab);
1392
1393
    echo '<div class="panelHeader">'.NL;
1394
    echo '<h3>';
1395
    $tabTitle = ($NS) ? $NS : '['.$lang['mediaroot'].']';
1396
    printf($lang['media_'.$opened_tab], '<strong>'.hsc($tabTitle).'</strong>');
1397
    echo '</h3>'.NL;
1398
    if($opened_tab === 'search' || $opened_tab === 'files') {
1399
        media_tab_files_options();
1400
    }
1401
    echo '</div>'.NL;
1402
1403
    echo '<div class="panelContent">'.NL;
1404
    if($opened_tab == 'files') {
1405
        media_tab_files($NS, $AUTH, $JUMPTO);
1406
    } elseif($opened_tab == 'upload') {
1407
        media_tab_upload($NS, $AUTH, $JUMPTO);
1408
    } elseif($opened_tab == 'search') {
1409
        media_tab_search($NS, $AUTH);
1410
    }
1411
    echo '</div>'.NL;
1412
}
1413
1414
/**
1415
 * Prints the third column in full-screen media manager
1416
 * Depending on the opened tab this may be details of the
1417
 * selected file, the meta editing dialog or
1418
 * list of file revisions
1419
 *
1420
 * @author Kate Arzamastseva <[email protected]>
1421
 *
1422
 * @param string $image
1423
 * @param boolean $rev
1424
 */
1425
function tpl_mediaFileDetails($image, $rev) {
1426
    global $conf, $DEL, $lang;
1427
    /** @var Input $INPUT */
1428
    global $INPUT;
1429
1430
    $removed = (
1431
        !file_exists(mediaFN($image)) &&
1432
        file_exists(mediaMetaFN($image, '.changes')) &&
1433
        $conf['mediarevisions']
1434
    );
1435
    if(!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return;
1436
    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...
1437
    $ns = getNS($image);
1438
    $do = $INPUT->str('mediado');
1439
1440
    $opened_tab = $INPUT->str('tab_details');
1441
1442
    $tab_array = array('view');
1443
    list(, $mime) = mimetype($image);
1444
    if($mime == 'image/jpeg') {
1445
        $tab_array[] = 'edit';
1446
    }
1447
    if($conf['mediarevisions']) {
1448
        $tab_array[] = 'history';
1449
    }
1450
1451
    if(!$opened_tab || !in_array($opened_tab, $tab_array)) $opened_tab = 'view';
1452
    if($INPUT->bool('edit')) $opened_tab = 'edit';
1453
    if($do == 'restore') $opened_tab = 'view';
1454
1455
    media_tabs_details($image, $opened_tab);
1456
1457
    echo '<div class="panelHeader"><h3>';
1458
    list($ext) = mimetype($image, false);
1459
    $class    = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1460
    $class    = 'select mediafile mf_'.$class;
1461
    $attributes = $rev ? ['rev' => $rev] : [];
1462
    $tabTitle = '<strong><a href="'.ml($image, $attributes).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.
1463
        $image.'</a>'.'</strong>';
1464
    if($opened_tab === 'view' && $rev) {
1465
        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...
1466
    } else {
1467
        printf($lang['media_'.$opened_tab], $tabTitle);
1468
    }
1469
1470
    echo '</h3></div>'.NL;
1471
1472
    echo '<div class="panelContent">'.NL;
1473
1474
    if($opened_tab == 'view') {
1475
        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 1437 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...
1476
1477
    } elseif($opened_tab == 'edit' && !$removed) {
1478
        media_tab_edit($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1437 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...
1479
1480
    } elseif($opened_tab == 'history' && $conf['mediarevisions']) {
1481
        media_tab_history($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1437 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...
1482
    }
1483
1484
    echo '</div>'.NL;
1485
}
1486
1487
/**
1488
 * prints the namespace tree in the mediamanager popup
1489
 *
1490
 * Only allowed in mediamanager.php
1491
 *
1492
 * @author Andreas Gohr <[email protected]>
1493
 */
1494
function tpl_mediaTree() {
1495
    global $NS;
1496
    ptln('<div id="media__tree">');
1497
    media_nstree($NS);
1498
    ptln('</div>');
1499
}
1500
1501
/**
1502
 * Print a dropdown menu with all DokuWiki actions
1503
 *
1504
 * Note: this will not use any pretty URLs
1505
 *
1506
 * @author Andreas Gohr <[email protected]>
1507
 *
1508
 * @param string $empty empty option label
1509
 * @param string $button submit button label
1510
 * @deprecated 2017-09-01 see devel:menus
1511
 */
1512
function tpl_actiondropdown($empty = '', $button = '&gt;') {
1513
    dbg_deprecated('see devel:menus');
1514
    $menu = new \dokuwiki\Menu\MobileMenu();
1515
    echo $menu->getDropdown($empty, $button);
1516
}
1517
1518
/**
1519
 * Print a informational line about the used license
1520
 *
1521
 * @author Andreas Gohr <[email protected]>
1522
 * @param  string $img     print image? (|button|badge)
1523
 * @param  bool   $imgonly skip the textual description?
1524
 * @param  bool   $return  when true don't print, but return HTML
1525
 * @param  bool   $wrap    wrap in div with class="license"?
1526
 * @return string
1527
 */
1528
function tpl_license($img = 'badge', $imgonly = false, $return = false, $wrap = true) {
1529
    global $license;
1530
    global $conf;
1531
    global $lang;
1532
    if(!$conf['license']) return '';
1533
    if(!is_array($license[$conf['license']])) return '';
1534
    $lic    = $license[$conf['license']];
1535
    $target = ($conf['target']['extern']) ? ' target="'.$conf['target']['extern'].'"' : '';
1536
1537
    $out = '';
1538
    if($wrap) $out .= '<div class="license">';
1539
    if($img) {
1540
        $src = license_img($img);
1541
        if($src) {
1542
            $out .= '<a href="'.$lic['url'].'" rel="license"'.$target;
1543
            $out .= '><img src="'.DOKU_BASE.$src.'" alt="'.$lic['name'].'" /></a>';
1544
            if(!$imgonly) $out .= ' ';
1545
        }
1546
    }
1547
    if(!$imgonly) {
1548
        $out .= $lang['license'].' ';
1549
        $out .= '<bdi><a href="'.$lic['url'].'" rel="license" class="urlextern"'.$target;
1550
        $out .= '>'.$lic['name'].'</a></bdi>';
1551
    }
1552
    if($wrap) $out .= '</div>';
1553
1554
    if($return) return $out;
1555
    echo $out;
1556
    return '';
1557
}
1558
1559
/**
1560
 * Includes the rendered HTML of a given page
1561
 *
1562
 * This function is useful to populate sidebars or similar features in a
1563
 * template
1564
 *
1565
 * @param string $pageid The page name you want to include
1566
 * @param bool $print Should the content be printed or returned only
1567
 * @param bool $propagate Search higher namespaces, too?
1568
 * @param bool $useacl Include the page only if the ACLs check out?
1569
 * @return bool|null|string
1570
 */
1571
function tpl_include_page($pageid, $print = true, $propagate = false, $useacl = true) {
1572
    if($propagate) {
1573
        $pageid = page_findnearest($pageid, $useacl);
1574
    } elseif($useacl && auth_quickaclcheck($pageid) == AUTH_NONE) {
1575
        return false;
1576
    }
1577
    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...
1578
1579
    global $TOC;
1580
    $oldtoc = $TOC;
1581
    $html   = p_wiki_xhtml($pageid, '', false);
1582
    $TOC    = $oldtoc;
1583
1584
    if($print) echo $html;
1585
    return $html;
1586
}
1587
1588
/**
1589
 * Display the subscribe form
1590
 *
1591
 * @author Adrian Lang <[email protected]>
1592
 * @deprecated 2020-07-23
1593
 */
1594
function tpl_subscribe() {
1595
    dbg_deprecated(\dokuwiki\Ui\Subscribe::class .'::show()');
1596
    (new \dokuwiki\Ui\Subscribe)->show();
1597
}
1598
1599
/**
1600
 * Tries to send already created content right to the browser
1601
 *
1602
 * Wraps around ob_flush() and flush()
1603
 *
1604
 * @author Andreas Gohr <[email protected]>
1605
 */
1606
function tpl_flush() {
1607
    if( ob_get_level() > 0 ) ob_flush();
1608
    flush();
1609
}
1610
1611
/**
1612
 * Tries to find a ressource file in the given locations.
1613
 *
1614
 * If a given location starts with a colon it is assumed to be a media
1615
 * file, otherwise it is assumed to be relative to the current template
1616
 *
1617
 * @param  string[] $search       locations to look at
1618
 * @param  bool     $abs          if to use absolute URL
1619
 * @param  array    &$imginfo     filled with getimagesize()
1620
 * @param  bool     $fallback     use fallback image if target isn't found or return 'false' if potential
1621
 *                                false result is required
1622
 * @return string
1623
 *
1624
 * @author Andreas  Gohr <[email protected]>
1625
 */
1626
function tpl_getMediaFile($search, $abs = false, &$imginfo = null, $fallback = true) {
1627
    $img     = '';
1628
    $file    = '';
1629
    $ismedia = false;
1630
    // loop through candidates until a match was found:
1631
    foreach($search as $img) {
1632
        if(substr($img, 0, 1) == ':') {
1633
            $file    = mediaFN($img);
1634
            $ismedia = true;
1635
        } else {
1636
            $file    = tpl_incdir().$img;
1637
            $ismedia = false;
1638
        }
1639
1640
        if(file_exists($file)) break;
1641
    }
1642
1643
    // manage non existing target
1644
    if (!file_exists($file)) {
1645
        // give result for fallback image
1646
        if ($fallback === true) {
1647
            $file = DOKU_INC . 'lib/images/blank.gif';
1648
            // stop process if false result is required (if $fallback is false)
1649
        } else {
1650
            return false;
1651
        }
1652
    }
1653
1654
    // fetch image data if requested
1655
    if(!is_null($imginfo)) {
1656
        $imginfo = getimagesize($file);
1657
    }
1658
1659
    // build URL
1660
    if($ismedia) {
1661
        $url = ml($img, '', true, '', $abs);
1662
    } else {
1663
        $url = tpl_basedir().$img;
1664
        if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL));
1665
    }
1666
1667
    return $url;
1668
}
1669
1670
/**
1671
 * PHP include a file
1672
 *
1673
 * either from the conf directory if it exists, otherwise use
1674
 * file in the template's root directory.
1675
 *
1676
 * The function honours config cascade settings and looks for the given
1677
 * file next to the ´main´ config files, in the order protected, local,
1678
 * default.
1679
 *
1680
 * Note: no escaping or sanity checking is done here. Never pass user input
1681
 * to this function!
1682
 *
1683
 * @author Anika Henke <[email protected]>
1684
 * @author Andreas Gohr <[email protected]>
1685
 *
1686
 * @param string $file
1687
 */
1688
function tpl_includeFile($file) {
1689
    global $config_cascade;
1690
    foreach(array('protected', 'local', 'default') as $config_group) {
1691
        if(empty($config_cascade['main'][$config_group])) continue;
1692
        foreach($config_cascade['main'][$config_group] as $conf_file) {
1693
            $dir = dirname($conf_file);
1694
            if(file_exists("$dir/$file")) {
1695
                include("$dir/$file");
1696
                return;
1697
            }
1698
        }
1699
    }
1700
1701
    // still here? try the template dir
1702
    $file = tpl_incdir().$file;
1703
    if(file_exists($file)) {
1704
        include($file);
1705
    }
1706
}
1707
1708
/**
1709
 * Returns <link> tag for various icon types (favicon|mobile|generic)
1710
 *
1711
 * @author Anika Henke <[email protected]>
1712
 *
1713
 * @param  array $types - list of icon types to display (favicon|mobile|generic)
1714
 * @return string
1715
 */
1716
function tpl_favicon($types = array('favicon')) {
1717
1718
    $return = '';
1719
1720
    foreach($types as $type) {
1721
        switch($type) {
1722
            case 'favicon':
1723
                $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico');
1724
                $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1725
                break;
1726
            case 'mobile':
1727
                $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.png');
1728
                $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1729
                break;
1730
            case 'generic':
1731
                // ideal world solution, which doesn't work in any browser yet
1732
                $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg');
1733
                $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL;
1734
                break;
1735
        }
1736
    }
1737
1738
    return $return;
1739
}
1740
1741
/**
1742
 * Prints full-screen media manager
1743
 *
1744
 * @author Kate Arzamastseva <[email protected]>
1745
 */
1746
function tpl_media() {
1747
    global $NS, $IMG, $JUMPTO, $REV, $lang, $fullscreen, $INPUT;
1748
    $fullscreen = true;
1749
    require_once DOKU_INC.'lib/exe/mediamanager.php';
1750
1751
    $rev   = '';
1752
    $image = cleanID($INPUT->str('image'));
1753
    if(isset($IMG)) $image = $IMG;
1754
    if(isset($JUMPTO)) $image = $JUMPTO;
1755
    if(isset($REV) && !$JUMPTO) $rev = $REV;
1756
1757
    echo '<div id="mediamanager__page">'.NL;
1758
    echo '<h1>'.$lang['btn_media'].'</h1>'.NL;
1759
    html_msgarea();
1760
1761
    echo '<div class="panel namespaces">'.NL;
1762
    echo '<h2>'.$lang['namespaces'].'</h2>'.NL;
1763
    echo '<div class="panelHeader">';
1764
    echo $lang['media_namespaces'];
1765
    echo '</div>'.NL;
1766
1767
    echo '<div class="panelContent" id="media__tree">'.NL;
1768
    media_nstree($NS);
1769
    echo '</div>'.NL;
1770
    echo '</div>'.NL;
1771
1772
    echo '<div class="panel filelist">'.NL;
1773
    tpl_mediaFileList();
1774
    echo '</div>'.NL;
1775
1776
    echo '<div class="panel file">'.NL;
1777
    echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL;
1778
    tpl_mediaFileDetails($image, $rev);
1779
    echo '</div>'.NL;
1780
1781
    echo '</div>'.NL;
1782
}
1783
1784
/**
1785
 * Return useful layout classes
1786
 *
1787
 * @author Anika Henke <[email protected]>
1788
 *
1789
 * @return string
1790
 */
1791
function tpl_classes() {
1792
    global $ACT, $conf, $ID, $INFO;
1793
    /** @var Input $INPUT */
1794
    global $INPUT;
1795
1796
    $classes = array(
1797
        'dokuwiki',
1798
        'mode_'.$ACT,
1799
        'tpl_'.$conf['template'],
1800
        $INPUT->server->bool('REMOTE_USER') ? 'loggedIn' : '',
1801
        (isset($INFO) && $INFO['exists']) ? '' : 'notFound',
1802
        ($ID == $conf['start']) ? 'home' : '',
1803
    );
1804
    return join(' ', $classes);
1805
}
1806
1807
/**
1808
 * Create event for tools menues
1809
 *
1810
 * @author Anika Henke <[email protected]>
1811
 * @param string $toolsname name of menu
1812
 * @param array $items
1813
 * @param string $view e.g. 'main', 'detail', ...
1814
 * @deprecated 2017-09-01 see devel:menus
1815
 */
1816
function tpl_toolsevent($toolsname, $items, $view = 'main') {
1817
    dbg_deprecated('see devel:menus');
1818
    $data = array(
1819
        'view' => $view,
1820
        'items' => $items
1821
    );
1822
1823
    $hook = 'TEMPLATE_' . strtoupper($toolsname) . '_DISPLAY';
1824
    $evt = new Event($hook, $data);
1825
    if($evt->advise_before()) {
1826
        foreach($evt->data['items'] as $k => $html) echo $html;
1827
    }
1828
    $evt->advise_after();
1829
}
1830
1831
//Setup VIM: ex: et ts=4 :
1832
1833