Failed Conditions
Push — psr2 ( 9ddafc...b78f68 )
by Andreas
11:21 queued 07:11
created

html.php ➔ html_btn()   B

Complexity

Conditions 9
Paths 96

Size

Total Lines 54
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 36
nc 96
nop 8
dl 0
loc 54
rs 7.255
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * HTML output functions
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
use dokuwiki\ChangeLog\MediaChangeLog;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, MediaChangeLog.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use dokuwiki\ChangeLog\PageChangeLog;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, PageChangeLog.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
11
12
if (!defined('SEC_EDIT_PATTERN')) {
13
    define('SEC_EDIT_PATTERN', '#<!-- EDIT({.*?}) -->#');
14
}
15
16
17
/**
18
 * Convenience function to quickly build a wikilink
19
 *
20
 * @author Andreas Gohr <[email protected]>
21
 * @param string  $id      id of the target page
22
 * @param string  $name    the name of the link, i.e. the text that is displayed
23
 * @param string|array  $search  search string(s) that shall be highlighted in the target page
24
 * @return string the HTML code of the link
25
 */
26
function html_wikilink($id,$name=null,$search=''){
27
    /** @var Doku_Renderer_xhtml $xhtml_renderer */
28
    static $xhtml_renderer = null;
29
    if(is_null($xhtml_renderer)){
30
        $xhtml_renderer = p_get_renderer('xhtml');
31
    }
32
33
    return $xhtml_renderer->internallink($id,$name,$search,true,'navigation');
34
}
35
36
/**
37
 * The loginform
38
 *
39
 * @author   Andreas Gohr <[email protected]>
40
 *
41
 * @param bool $svg Whether to show svg icons in the register and resendpwd links or not
42
 */
43
function html_login($svg = false){
44
    global $lang;
45
    global $conf;
46
    global $ID;
47
    global $INPUT;
48
49
    print p_locale_xhtml('login');
50
    print '<div class="centeralign">'.NL;
51
    $form = new Doku_Form(array('id' => 'dw__login'));
52
    $form->startFieldset($lang['btn_login']);
53
    $form->addHidden('id', $ID);
54
    $form->addHidden('do', 'login');
55
    $form->addElement(form_makeTextField(
56
        'u',
57
        ((!$INPUT->bool('http_credentials')) ? $INPUT->str('u') : ''),
58
        $lang['user'],
59
        'focus__this',
60
        'block')
61
    );
62
    $form->addElement(form_makePasswordField('p', $lang['pass'], '', 'block'));
63
    if($conf['rememberme']) {
64
        $form->addElement(form_makeCheckboxField('r', '1', $lang['remember'], 'remember__me', 'simple'));
65
    }
66
    $form->addElement(form_makeButton('submit', '', $lang['btn_login']));
67
    $form->endFieldset();
68
69
    if(actionOK('register')){
70
        $registerLink = (new \dokuwiki\Menu\Item\Register())->asHtmlLink('', $svg);
71
        $form->addElement('<p>'.$lang['reghere'].': '. $registerLink .'</p>');
72
    }
73
74
    if (actionOK('resendpwd')) {
75
        $resendPwLink = (new \dokuwiki\Menu\Item\Resendpwd())->asHtmlLink('', $svg);
76
        $form->addElement('<p>'.$lang['pwdforget'].': '. $resendPwLink .'</p>');
77
    }
78
79
    html_form('login', $form);
80
    print '</div>'.NL;
81
}
82
83
84
/**
85
 * Denied page content
86
 *
87
 * @return string html
88
 */
89
function html_denied() {
90
    print p_locale_xhtml('denied');
91
92
    if(empty($_SERVER['REMOTE_USER'])){
93
        html_login();
94
    }
95
}
96
97
/**
98
 * inserts section edit buttons if wanted or removes the markers
99
 *
100
 * @author Andreas Gohr <[email protected]>
101
 *
102
 * @param string $text
103
 * @param bool   $show show section edit buttons?
104
 * @return string
105
 */
106
function html_secedit($text,$show=true){
107
    global $INFO;
108
109
    if(!$INFO['writable'] || !$show || $INFO['rev']){
110
        return preg_replace(SEC_EDIT_PATTERN,'',$text);
111
    }
112
113
    return preg_replace_callback(SEC_EDIT_PATTERN,
114
                'html_secedit_button', $text);
115
}
116
117
/**
118
 * prepares section edit button data for event triggering
119
 * used as a callback in html_secedit
120
 *
121
 * @author Andreas Gohr <[email protected]>
122
 *
123
 * @param array $matches matches with regexp
124
 * @return string
125
 * @triggers HTML_SECEDIT_BUTTON
126
 */
127
function html_secedit_button($matches){
128
    $json = htmlspecialchars_decode($matches[1], ENT_QUOTES);
129
    $data = json_decode($json, true);
130
    if ($data == NULL) {
131
        return;
132
    }
133
    $data ['target'] = strtolower($data['target']);
134
    $data ['hid'] = strtolower($data['hid']);
135
136
    return trigger_event('HTML_SECEDIT_BUTTON', $data,
137
                         'html_secedit_get_button');
138
}
139
140
/**
141
 * prints a section editing button
142
 * used as default action form HTML_SECEDIT_BUTTON
143
 *
144
 * @author Adrian Lang <[email protected]>
145
 *
146
 * @param array $data name, section id and target
147
 * @return string html
148
 */
149
function html_secedit_get_button($data) {
150
    global $ID;
151
    global $INFO;
152
153
    if (!isset($data['name']) || $data['name'] === '') return '';
154
155
    $name = $data['name'];
156
    unset($data['name']);
157
158
    $secid = $data['secid'];
159
    unset($data['secid']);
160
161
    return "<div class='secedit editbutton_" . $data['target'] .
162
                       " editbutton_" . $secid . "'>" .
163
           html_btn('secedit', $ID, '',
164
                    array_merge(array('do'  => 'edit',
165
                                      'rev' => $INFO['lastmod'],
166
                                      'summary' => '['.$name.'] '), $data),
167
                    'post', $name) . '</div>';
168
}
169
170
/**
171
 * Just the back to top button (in its own form)
172
 *
173
 * @author Andreas Gohr <[email protected]>
174
 *
175
 * @return string html
176
 */
177
function html_topbtn(){
178
    global $lang;
179
180
    $ret = '<a class="nolink" href="#dokuwiki__top">' .
181
        '<button class="button" onclick="window.scrollTo(0, 0)" title="' . $lang['btn_top'] . '">' .
182
        $lang['btn_top'] .
183
        '</button></a>';
184
185
    return $ret;
186
}
187
188
/**
189
 * Displays a button (using its own form)
190
 * If tooltip exists, the access key tooltip is replaced.
191
 *
192
 * @author Andreas Gohr <[email protected]>
193
 *
194
 * @param string         $name
195
 * @param string         $id
196
 * @param string         $akey   access key
197
 * @param string[] $params key-value pairs added as hidden inputs
198
 * @param string         $method
199
 * @param string         $tooltip
200
 * @param bool|string    $label  label text, false: lookup btn_$name in localization
201
 * @param string         $svg (optional) svg code, inserted into the button
202
 * @return string
203
 */
204
function html_btn($name, $id, $akey, $params, $method='get', $tooltip='', $label=false, $svg=null){
205
    global $conf;
206
    global $lang;
207
208
    if (!$label)
209
        $label = $lang['btn_'.$name];
210
211
    $ret = '';
212
213
    //filter id (without urlencoding)
214
    $id = idfilter($id,false);
215
216
    //make nice URLs even for buttons
217
    if($conf['userewrite'] == 2){
218
        $script = DOKU_BASE.DOKU_SCRIPT.'/'.$id;
219
    }elseif($conf['userewrite']){
220
        $script = DOKU_BASE.$id;
221
    }else{
222
        $script = DOKU_BASE.DOKU_SCRIPT;
223
        $params['id'] = $id;
224
    }
225
226
    $ret .= '<form class="button btn_'.$name.'" method="'.$method.'" action="'.$script.'"><div class="no">';
227
228
    if(is_array($params)){
229
        foreach($params as $key => $val) {
230
            $ret .= '<input type="hidden" name="'.$key.'" ';
231
            $ret .= 'value="'.hsc($val).'" />';
232
        }
233
    }
234
235
    if ($tooltip!='') {
236
        $tip = hsc($tooltip);
237
    }else{
238
        $tip = hsc($label);
239
    }
240
241
    $ret .= '<button type="submit" ';
242
    if($akey){
243
        $tip .= ' ['.strtoupper($akey).']';
244
        $ret .= 'accesskey="'.$akey.'" ';
245
    }
246
    $ret .= 'title="'.$tip.'">';
247
    if ($svg) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $svg 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...
248
        $ret .= '<span>' . hsc($label) . '</span>';
249
        $ret .= inlineSVG($svg);
250
    } else {
251
        $ret .= hsc($label);
252
    }
253
    $ret .= '</button>';
254
    $ret .= '</div></form>';
255
256
    return $ret;
257
}
258
/**
259
 * show a revision warning
260
 *
261
 * @author Szymon Olewniczak <[email protected]>
262
 */
263
function html_showrev() {
264
    print p_locale_xhtml('showrev');
265
}
266
267
/**
268
 * Show a wiki page
269
 *
270
 * @author Andreas Gohr <[email protected]>
271
 *
272
 * @param null|string $txt wiki text or null for showing $ID
273
 */
274
function html_show($txt=null){
275
    global $ID;
276
    global $REV;
277
    global $HIGH;
278
    global $INFO;
279
    global $DATE_AT;
280
    //disable section editing for old revisions or in preview
281
    if($txt || $REV){
0 ignored issues
show
Bug Best Practice introduced by
The expression $txt of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
282
        $secedit = false;
283
    }else{
284
        $secedit = true;
285
    }
286
287
    if (!is_null($txt)){
288
        //PreviewHeader
289
        echo '<br id="scroll__here" />';
290
        echo p_locale_xhtml('preview');
291
        echo '<div class="preview"><div class="pad">';
292
        $html = html_secedit(p_render('xhtml',p_get_instructions($txt),$info),$secedit);
293
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
294
        echo $html;
295
        echo '<div class="clearer"></div>';
296
        echo '</div></div>';
297
298
    }else{
299
        if ($REV||$DATE_AT){
300
            $data = array('rev' => &$REV, 'date_at' => &$DATE_AT);
301
            trigger_event('HTML_SHOWREV_OUTPUT', $data, 'html_showrev');
302
        }
303
        $html = p_wiki_xhtml($ID,$REV,true,$DATE_AT);
304
        $html = html_secedit($html,$secedit);
0 ignored issues
show
Bug introduced by
It seems like $html can also be of type boolean or null; however, html_secedit() does only seem to accept string, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
305
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
306
        $html = html_hilight($html,$HIGH);
307
        echo $html;
308
    }
309
}
310
311
/**
312
 * ask the user about how to handle an exisiting draft
313
 *
314
 * @author Andreas Gohr <[email protected]>
315
 */
316
function html_draft(){
317
    global $INFO;
318
    global $ID;
319
    global $lang;
320
    $draft = new \dokuwiki\Draft($ID, $INFO['client']);
321
    $text  = $draft->getDraftText();
322
323
    print p_locale_xhtml('draft');
324
    html_diff($text, false);
325
    $form = new Doku_Form(array('id' => 'dw__editform'));
326
    $form->addHidden('id', $ID);
327
    $form->addHidden('date', $draft->getDraftDate());
328
    $form->addHidden('wikitext', $text);
329
    $form->addElement(form_makeOpenTag('div', array('id'=>'draft__status')));
330
    $form->addElement($draft->getDraftMessage());
331
    $form->addElement(form_makeCloseTag('div'));
332
    $form->addElement(form_makeButton('submit', 'recover', $lang['btn_recover'], array('tabindex'=>'1')));
333
    $form->addElement(form_makeButton('submit', 'draftdel', $lang['btn_draftdel'], array('tabindex'=>'2')));
334
    $form->addElement(form_makeButton('submit', 'show', $lang['btn_cancel'], array('tabindex'=>'3')));
335
    html_form('draft', $form);
336
}
337
338
/**
339
 * Highlights searchqueries in HTML code
340
 *
341
 * @author Andreas Gohr <[email protected]>
342
 * @author Harry Fuecks <[email protected]>
343
 *
344
 * @param string $html
345
 * @param array|string $phrases
346
 * @return string html
347
 */
348
function html_hilight($html,$phrases){
349
    $phrases = (array) $phrases;
350
    $phrases = array_map('preg_quote_cb', $phrases);
351
    $phrases = array_map('ft_snippet_re_preprocess', $phrases);
352
    $phrases = array_filter($phrases);
353
    $regex = join('|',$phrases);
354
355
    if ($regex === '') return $html;
356
    if (!utf8_check($regex)) return $html;
357
    $html = @preg_replace_callback("/((<[^>]*)|$regex)/ui",'html_hilight_callback',$html);
358
    return $html;
359
}
360
361
/**
362
 * Callback used by html_hilight()
363
 *
364
 * @author Harry Fuecks <[email protected]>
365
 *
366
 * @param array $m matches
367
 * @return string html
368
 */
369
function html_hilight_callback($m) {
370
    $hlight = unslash($m[0]);
371
    if ( !isset($m[2])) {
372
        $hlight = '<span class="search_hit">'.$hlight.'</span>';
373
    }
374
    return $hlight;
375
}
376
377
/**
378
 * Display error on locked pages
379
 *
380
 * @author Andreas Gohr <[email protected]>
381
 */
382
function html_locked(){
383
    global $ID;
384
    global $conf;
385
    global $lang;
386
    global $INFO;
387
388
    $locktime = filemtime(wikiLockFN($ID));
389
    $expire = dformat($locktime + $conf['locktime']);
390
    $min    = round(($conf['locktime'] - (time() - $locktime) )/60);
391
392
    print p_locale_xhtml('locked');
393
    print '<ul>';
394
    print '<li><div class="li"><strong>'.$lang['lockedby'].'</strong> '.editorinfo($INFO['locked']).'</div></li>';
395
    print '<li><div class="li"><strong>'.$lang['lockexpire'].'</strong> '.$expire.' ('.$min.' min)</div></li>';
396
    print '</ul>';
397
}
398
399
/**
400
 * list old revisions
401
 *
402
 * @author Andreas Gohr <[email protected]>
403
 * @author Ben Coburn <[email protected]>
404
 * @author Kate Arzamastseva <[email protected]>
405
 *
406
 * @param int $first skip the first n changelog lines
407
 * @param bool|string $media_id id of media, or false for current page
408
 */
409
function html_revisions($first=0, $media_id = false){
410
    global $ID;
411
    global $INFO;
412
    global $conf;
413
    global $lang;
414
    $id = $ID;
415
    if ($media_id) {
416
        $id = $media_id;
417
        $changelog = new MediaChangeLog($id);
418
    } else {
419
        $changelog = new PageChangeLog($id);
420
    }
421
422
    /* we need to get one additional log entry to be able to
423
     * decide if this is the last page or is there another one.
424
     * see html_recent()
425
     */
426
427
    $revisions = $changelog->getRevisions($first, $conf['recent']+1);
428
429
    if(count($revisions)==0 && $first!=0){
430
        $first=0;
431
        $revisions = $changelog->getRevisions($first, $conf['recent']+1);
432
    }
433
    $hasNext = false;
434
    if (count($revisions)>$conf['recent']) {
435
        $hasNext = true;
436
        array_pop($revisions); // remove extra log entry
437
    }
438
439
    if (!$media_id) print p_locale_xhtml('revisions');
440
441
    $params = array('id' => 'page__revisions', 'class' => 'changes');
442
    if($media_id) {
443
        $params['action'] = media_managerURL(array('image' => $media_id), '&');
444
    }
445
446
    if(!$media_id) {
447
        $exists = $INFO['exists'];
448
        $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
449
        if(!$display_name) {
450
            $display_name = $id;
451
        }
452
    } else {
453
        $exists = file_exists(mediaFN($id));
454
        $display_name = $id;
455
    }
456
457
    $form = new Doku_Form($params);
458
    $form->addElement(form_makeOpenTag('ul'));
459
460
    if($exists && $first == 0) {
461
        $minor = false;
462
        if($media_id) {
463
            $date = dformat(@filemtime(mediaFN($id)));
464
            $href = media_managerURL(array('image' => $id, 'tab_details' => 'view'), '&');
465
466
            $changelog->setChunkSize(1024);
467
            $revinfo = $changelog->getRevisionInfo(@filemtime(fullpath(mediaFN($id))));
468
469
            $summary = $revinfo['sum'];
470
            if($revinfo['user']) {
471
                $editor = $revinfo['user'];
472
            } else {
473
                $editor = $revinfo['ip'];
474
            }
475
            $sizechange = $revinfo['sizechange'];
476
        } else {
477
            $date = dformat($INFO['lastmod']);
478
            if(isset($INFO['meta']) && isset($INFO['meta']['last_change'])) {
479
                if($INFO['meta']['last_change']['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
480
                    $minor = true;
481
                }
482
                if(isset($INFO['meta']['last_change']['sizechange'])) {
483
                    $sizechange = $INFO['meta']['last_change']['sizechange'];
484
                } else {
485
                    $sizechange = null;
486
                }
487
            }
488
            $pagelog = new PageChangeLog($ID);
489
            $latestrev = $pagelog->getRevisions(-1, 1);
490
            $latestrev = array_pop($latestrev);
491
            $href = wl($id,"rev=$latestrev",false,'&');
492
            $summary = $INFO['sum'];
493
            $editor = $INFO['editor'];
494
        }
495
496
        $form->addElement(form_makeOpenTag('li', array('class' => ($minor ? 'minor' : ''))));
497
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
498
        $form->addElement(form_makeTag('input', array(
499
                        'type' => 'checkbox',
500
                        'name' => 'rev2[]',
501
                        'value' => 'current')));
502
503
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
504
        $form->addElement($date);
505
        $form->addElement(form_makeCloseTag('span'));
506
507
        $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
508
509
        $form->addElement(form_makeOpenTag('a', array(
510
                        'class' => 'wikilink1',
511
                        'href'  => $href)));
512
        $form->addElement($display_name);
513
        $form->addElement(form_makeCloseTag('a'));
514
515
        if ($media_id) $form->addElement(form_makeOpenTag('div'));
516
517
        if($summary) {
518
            $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
519
            if(!$media_id) $form->addElement(' – ');
520
            $form->addElement('<bdi>' . hsc($summary) . '</bdi>');
521
            $form->addElement(form_makeCloseTag('span'));
522
        }
523
524
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
525
        $form->addElement((empty($editor))?('('.$lang['external_edit'].')'):'<bdi>'.editorinfo($editor).'</bdi>');
526
        $form->addElement(form_makeCloseTag('span'));
527
528
        html_sizechange($sizechange, $form);
0 ignored issues
show
Bug introduced by
The variable $sizechange does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
529
530
        $form->addElement('('.$lang['current'].')');
531
532
        if ($media_id) $form->addElement(form_makeCloseTag('div'));
533
534
        $form->addElement(form_makeCloseTag('div'));
535
        $form->addElement(form_makeCloseTag('li'));
536
    }
537
538
    foreach($revisions as $rev) {
539
        $date = dformat($rev);
540
        $info = $changelog->getRevisionInfo($rev);
541
        if($media_id) {
542
            $exists = file_exists(mediaFN($id, $rev));
543
        } else {
544
            $exists = page_exists($id, $rev);
545
        }
546
547
        $class = '';
548
        if($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
549
            $class = 'minor';
550
        }
551
        $form->addElement(form_makeOpenTag('li', array('class' => $class)));
552
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
553
        if($exists){
554
            $form->addElement(form_makeTag('input', array(
555
                            'type' => 'checkbox',
556
                            'name' => 'rev2[]',
557
                            'value' => $rev)));
558
        }else{
559
            $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
560
        }
561
562
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
563
        $form->addElement($date);
564
        $form->addElement(form_makeCloseTag('span'));
565
566
        if($exists){
567
            if (!$media_id) {
568
                $href = wl($id,"rev=$rev,do=diff", false, '&');
569
            } else {
570
                $href = media_managerURL(array('image' => $id, 'rev' => $rev, 'mediado' => 'diff'), '&');
571
            }
572
            $form->addElement(form_makeOpenTag('a', array(
573
                            'class' => 'diff_link',
574
                            'href' => $href)));
575
            $form->addElement(form_makeTag('img', array(
576
                            'src'    => DOKU_BASE.'lib/images/diff.png',
577
                            'width'  => 15,
578
                            'height' => 11,
579
                            'title'  => $lang['diff'],
580
                            'alt'    => $lang['diff'])));
581
            $form->addElement(form_makeCloseTag('a'));
582
583
            if (!$media_id) {
584
                $href = wl($id,"rev=$rev",false,'&');
585
            } else {
586
                $href = media_managerURL(array('image' => $id, 'tab_details' => 'view', 'rev' => $rev), '&');
587
            }
588
            $form->addElement(form_makeOpenTag('a', array(
589
                            'class' => 'wikilink1',
590
                            'href' => $href)));
591
            $form->addElement($display_name);
592
            $form->addElement(form_makeCloseTag('a'));
593
        }else{
594
            $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
595
            $form->addElement($display_name);
596
        }
597
598
        if ($media_id) $form->addElement(form_makeOpenTag('div'));
599
600
        if ($info['sum']) {
601
            $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
602
            if(!$media_id) $form->addElement(' – ');
603
            $form->addElement('<bdi>'.hsc($info['sum']).'</bdi>');
604
            $form->addElement(form_makeCloseTag('span'));
605
        }
606
607
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
608
        if($info['user']){
609
            $form->addElement('<bdi>'.editorinfo($info['user']).'</bdi>');
610
            if(auth_ismanager()){
611
                $form->addElement(' <bdo dir="ltr">('.$info['ip'].')</bdo>');
612
            }
613
        }else{
614
            $form->addElement('<bdo dir="ltr">'.$info['ip'].'</bdo>');
615
        }
616
        $form->addElement(form_makeCloseTag('span'));
617
618
        html_sizechange($info['sizechange'], $form);
619
620
        if ($media_id) $form->addElement(form_makeCloseTag('div'));
621
622
        $form->addElement(form_makeCloseTag('div'));
623
        $form->addElement(form_makeCloseTag('li'));
624
    }
625
    $form->addElement(form_makeCloseTag('ul'));
626
    if (!$media_id) {
627
        $form->addElement(form_makeButton('submit', 'diff', $lang['diff2']));
628
    } else {
629
        $form->addHidden('mediado', 'diff');
630
        $form->addElement(form_makeButton('submit', '', $lang['diff2']));
631
    }
632
    html_form('revisions', $form);
633
634
    print '<div class="pagenav">';
635
    $last = $first + $conf['recent'];
636
    if ($first > 0) {
637
        $first -= $conf['recent'];
638
        if ($first < 0) $first = 0;
639
        print '<div class="pagenav-prev">';
640
        if ($media_id) {
641
            print html_btn('newer',$media_id,"p",media_managerURL(array('first' => $first), '&amp;', false, true));
642
        } else {
643
            print html_btn('newer',$id,"p",array('do' => 'revisions', 'first' => $first));
644
        }
645
        print '</div>';
646
    }
647
    if ($hasNext) {
648
        print '<div class="pagenav-next">';
649
        if ($media_id) {
650
            print html_btn('older',$media_id,"n",media_managerURL(array('first' => $last), '&amp;', false, true));
651
        } else {
652
            print html_btn('older',$id,"n",array('do' => 'revisions', 'first' => $last));
653
        }
654
        print '</div>';
655
    }
656
    print '</div>';
657
658
}
659
660
/**
661
 * display recent changes
662
 *
663
 * @author Andreas Gohr <[email protected]>
664
 * @author Matthias Grimm <[email protected]>
665
 * @author Ben Coburn <[email protected]>
666
 * @author Kate Arzamastseva <[email protected]>
667
 *
668
 * @param int $first
669
 * @param string $show_changes
670
 */
671
function html_recent($first = 0, $show_changes = 'both') {
672
    global $conf;
673
    global $lang;
674
    global $ID;
675
    /* we need to get one additionally log entry to be able to
676
     * decide if this is the last page or is there another one.
677
     * This is the cheapest solution to get this information.
678
     */
679
    $flags = 0;
680
    if($show_changes == 'mediafiles' && $conf['mediarevisions']) {
681
        $flags = RECENTS_MEDIA_CHANGES;
682
    } elseif($show_changes == 'pages') {
683
        $flags = 0;
684
    } elseif($conf['mediarevisions']) {
685
        $show_changes = 'both';
686
        $flags = RECENTS_MEDIA_PAGES_MIXED;
687
    }
688
689
    $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, getRecents() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
690
    if(count($recents) == 0 && $first != 0) {
691
        $first = 0;
692
        $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, getRecents() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
693
    }
694
    $hasNext = false;
695
    if(count($recents) > $conf['recent']) {
696
        $hasNext = true;
697
        array_pop($recents); // remove extra log entry
698
    }
699
700
    print p_locale_xhtml('recent');
701
702
    if(getNS($ID) != '') {
703
        print '<div class="level1"><p>' .
704
            sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent')) .
705
            '</p></div>';
706
    }
707
708
    $form = new Doku_Form(array('id' => 'dw__recent', 'method' => 'GET', 'class' => 'changes'));
709
    $form->addHidden('sectok', null);
710
    $form->addHidden('do', 'recent');
711
    $form->addHidden('id', $ID);
712
713
    if($conf['mediarevisions']) {
714
        $form->addElement('<div class="changeType">');
715
        $form->addElement(form_makeListboxField(
716
                    'show_changes',
717
                    array(
718
                        'pages'      => $lang['pages_changes'],
719
                        'mediafiles' => $lang['media_changes'],
720
                        'both'       => $lang['both_changes']
721
                    ),
722
                    $show_changes,
723
                    $lang['changes_type'],
724
                    '', '',
725
                    array('class' => 'quickselect')));
726
727
        $form->addElement(form_makeButton('submit', 'recent', $lang['btn_apply']));
728
        $form->addElement('</div>');
729
    }
730
731
    $form->addElement(form_makeOpenTag('ul'));
732
733
    foreach($recents as $recent) {
734
        $date = dformat($recent['date']);
735
736
        $class = '';
737
        if($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
738
            $class = 'minor';
739
        }
740
        $form->addElement(form_makeOpenTag('li', array('class' => $class)));
741
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
742
743
        if(!empty($recent['media'])) {
744
            $form->addElement(media_printicon($recent['id']));
745
        } else {
746
            $icon = DOKU_BASE . 'lib/images/fileicons/file.png';
747
            $form->addElement('<img src="' . $icon . '" alt="' . $recent['id'] . '" class="icon" />');
748
        }
749
750
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
751
        $form->addElement($date);
752
        $form->addElement(form_makeCloseTag('span'));
753
754
        $diff = false;
755
        $href = '';
756
757
        if(!empty($recent['media'])) {
758
            $changelog = new MediaChangeLog($recent['id']);
759
            $revs = $changelog->getRevisions(0, 1);
760
            $diff = (count($revs) && file_exists(mediaFN($recent['id'])));
761
            if($diff) {
762
                $href = media_managerURL(array(
763
                                            'tab_details' => 'history',
764
                                            'mediado' => 'diff',
765
                                            'image' => $recent['id'],
766
                                            'ns' => getNS($recent['id'])
767
                                        ), '&');
768
            }
769
        } else {
770
            $href = wl($recent['id'], "do=diff", false, '&');
771
        }
772
773
        if(!empty($recent['media']) && !$diff) {
774
            $form->addElement('<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />');
775
        } else {
776
            $form->addElement(form_makeOpenTag('a', array('class' => 'diff_link', 'href' => $href)));
777
            $form->addElement(form_makeTag('img', array(
778
                            'src'    => DOKU_BASE . 'lib/images/diff.png',
779
                            'width'  => 15,
780
                            'height' => 11,
781
                            'title'  => $lang['diff'],
782
                            'alt'    => $lang['diff']
783
                        )));
784
            $form->addElement(form_makeCloseTag('a'));
785
        }
786
787
        if(!empty($recent['media'])) {
788
            $href = media_managerURL(
789
                array(
790
                    'tab_details' => 'history',
791
                    'image' => $recent['id'],
792
                    'ns' => getNS($recent['id'])
793
                ),
794
                '&'
795
            );
796
        } else {
797
            $href = wl($recent['id'], "do=revisions", false, '&');
798
        }
799
        $form->addElement(form_makeOpenTag('a', array(
800
                        'class' => 'revisions_link',
801
                        'href'  => $href)));
802
        $form->addElement(form_makeTag('img', array(
803
                        'src'    => DOKU_BASE . 'lib/images/history.png',
804
                        'width'  => 12,
805
                        'height' => 14,
806
                        'title'  => $lang['btn_revs'],
807
                        'alt'    => $lang['btn_revs']
808
                    )));
809
        $form->addElement(form_makeCloseTag('a'));
810
811
        if(!empty($recent['media'])) {
812
            $href = media_managerURL(
813
                array(
814
                    'tab_details' => 'view',
815
                    'image' => $recent['id'],
816
                    'ns' => getNS($recent['id'])
817
                ),
818
                '&'
819
            );
820
            $class = file_exists(mediaFN($recent['id'])) ? 'wikilink1' : 'wikilink2';
821
            $form->addElement(form_makeOpenTag('a', array(
822
                        'class' => $class,
823
                        'href'  => $href)));
824
            $form->addElement($recent['id']);
825
            $form->addElement(form_makeCloseTag('a'));
826
        } else {
827
            $form->addElement(html_wikilink(':' . $recent['id'], useHeading('navigation') ? null : $recent['id']));
828
        }
829
        $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
830
        $form->addElement(' – ' . hsc($recent['sum']));
831
        $form->addElement(form_makeCloseTag('span'));
832
833
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
834
        if($recent['user']) {
835
            $form->addElement('<bdi>' . editorinfo($recent['user']) . '</bdi>');
836
            if(auth_ismanager()) {
837
                $form->addElement(' <bdo dir="ltr">(' . $recent['ip'] . ')</bdo>');
838
            }
839
        } else {
840
            $form->addElement('<bdo dir="ltr">' . $recent['ip'] . '</bdo>');
841
        }
842
        $form->addElement(form_makeCloseTag('span'));
843
844
        html_sizechange($recent['sizechange'], $form);
845
846
        $form->addElement(form_makeCloseTag('div'));
847
        $form->addElement(form_makeCloseTag('li'));
848
    }
849
    $form->addElement(form_makeCloseTag('ul'));
850
851
    $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav')));
852
    $last = $first + $conf['recent'];
853
    if($first > 0) {
854
        $first -= $conf['recent'];
855
        if($first < 0) $first = 0;
856
        $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-prev')));
857
        $form->addElement(form_makeOpenTag('button', array(
858
                        'type'      => 'submit',
859
                        'name'      => 'first[' . $first . ']',
860
                        'accesskey' => 'n',
861
                        'title'     => $lang['btn_newer'] . ' [N]',
862
                        'class'     => 'button show'
863
                    )));
864
        $form->addElement($lang['btn_newer']);
865
        $form->addElement(form_makeCloseTag('button'));
866
        $form->addElement(form_makeCloseTag('div'));
867
    }
868
    if($hasNext) {
869
        $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-next')));
870
        $form->addElement(form_makeOpenTag('button', array(
871
                        'type'      => 'submit',
872
                        'name'      => 'first[' . $last . ']',
873
                        'accesskey' => 'p',
874
                        'title'     => $lang['btn_older'] . ' [P]',
875
                        'class'     => 'button show'
876
                    )));
877
        $form->addElement($lang['btn_older']);
878
        $form->addElement(form_makeCloseTag('button'));
879
        $form->addElement(form_makeCloseTag('div'));
880
    }
881
    $form->addElement(form_makeCloseTag('div'));
882
    html_form('recent', $form);
883
}
884
885
/**
886
 * Display page index
887
 *
888
 * @author Andreas Gohr <[email protected]>
889
 *
890
 * @param string $ns
891
 */
892
function html_index($ns){
893
    global $conf;
894
    global $ID;
895
    $ns  = cleanID($ns);
896
    if(empty($ns)){
897
        $ns = getNS($ID);
898
        if($ns === false) $ns ='';
899
    }
900
    $ns  = utf8_encodeFN(str_replace(':','/',$ns));
901
902
    echo p_locale_xhtml('index');
903
    echo '<div id="index__tree" class="index__tree">';
904
905
    $data = array();
906
    search($data,$conf['datadir'],'search_index',array('ns' => $ns));
907
    echo html_buildlist($data,'idx','html_list_index','html_li_index');
908
909
    echo '</div>';
910
}
911
912
/**
913
 * Index item formatter
914
 *
915
 * User function for html_buildlist()
916
 *
917
 * @author Andreas Gohr <[email protected]>
918
 *
919
 * @param array $item
920
 * @return string
921
 */
922
function html_list_index($item){
923
    global $ID, $conf;
924
925
    // prevent searchbots needlessly following links
926
    $nofollow = ($ID != $conf['start'] || $conf['sitemap']) ? 'rel="nofollow"' : '';
927
928
    $ret = '';
929
    $base = ':'.$item['id'];
930
    $base = substr($base,strrpos($base,':')+1);
931
    if($item['type']=='d'){
932
        // FS#2766, no need for search bots to follow namespace links in the index
933
        $link = wl($ID, 'idx=' . rawurlencode($item['id']));
934
        $ret .= '<a href="' . $link . '" title="' . $item['id'] . '" class="idx_dir" ' . $nofollow . '><strong>';
935
        $ret .= $base;
936
        $ret .= '</strong></a>';
937
    }else{
938
        // default is noNSorNS($id), but we want noNS($id) when useheading is off FS#2605
939
        $ret .= html_wikilink(':'.$item['id'], useHeading('navigation') ? null : noNS($item['id']));
940
    }
941
    return $ret;
942
}
943
944
/**
945
 * Index List item
946
 *
947
 * This user function is used in html_buildlist to build the
948
 * <li> tags for namespaces when displaying the page index
949
 * it gives different classes to opened or closed "folders"
950
 *
951
 * @author Andreas Gohr <[email protected]>
952
 *
953
 * @param array $item
954
 * @return string html
955
 */
956
function html_li_index($item){
957
    global $INFO;
958
    global $ACT;
959
960
    $class = '';
961
    $id = '';
962
963
    if($item['type'] == "f"){
964
        // scroll to the current item
965
        if($item['id'] == $INFO['id'] && $ACT == 'index') {
966
            $id = ' id="scroll__here"';
967
            $class = ' bounce';
968
        }
969
        return '<li class="level'.$item['level'].$class.'" '.$id.'>';
970
    }elseif($item['open']){
971
        return '<li class="open">';
972
    }else{
973
        return '<li class="closed">';
974
    }
975
}
976
977
/**
978
 * Default List item
979
 *
980
 * @author Andreas Gohr <[email protected]>
981
 *
982
 * @param array $item
983
 * @return string html
984
 */
985
function html_li_default($item){
986
    return '<li class="level'.$item['level'].'">';
987
}
988
989
/**
990
 * Build an unordered list
991
 *
992
 * Build an unordered list from the given $data array
993
 * Each item in the array has to have a 'level' property
994
 * the item itself gets printed by the given $func user
995
 * function. The second and optional function is used to
996
 * print the <li> tag. Both user function need to accept
997
 * a single item.
998
 *
999
 * Both user functions can be given as array to point to
1000
 * a member of an object.
1001
 *
1002
 * @author Andreas Gohr <[email protected]>
1003
 *
1004
 * @param array    $data  array with item arrays
1005
 * @param string   $class class of ul wrapper
1006
 * @param callable $func  callback to print an list item
1007
 * @param callable $lifunc callback to the opening li tag
1008
 * @param bool     $forcewrapper Trigger building a wrapper ul if the first level is
1009
 *                               0 (we have a root object) or 1 (just the root content)
1010
 * @return string html of an unordered list
1011
 */
1012
function html_buildlist($data,$class,$func,$lifunc='html_li_default',$forcewrapper=false){
1013
    if (count($data) === 0) {
1014
        return '';
1015
    }
1016
1017
    $firstElement = reset($data);
1018
    $start_level = $firstElement['level'];
1019
    $level = $start_level;
1020
    $ret   = '';
1021
    $open  = 0;
1022
1023
    foreach ($data as $item){
1024
1025
        if( $item['level'] > $level ){
1026
            //open new list
1027
            for($i=0; $i<($item['level'] - $level); $i++){
1028
                if ($i) $ret .= "<li class=\"clear\">";
1029
                $ret .= "\n<ul class=\"$class\">\n";
1030
                $open++;
1031
            }
1032
            $level = $item['level'];
1033
1034
        }elseif( $item['level'] < $level ){
1035
            //close last item
1036
            $ret .= "</li>\n";
1037
            while( $level > $item['level'] && $open > 0 ){
1038
                //close higher lists
1039
                $ret .= "</ul>\n</li>\n";
1040
                $level--;
1041
                $open--;
1042
            }
1043
        } elseif ($ret !== '') {
1044
            //close previous item
1045
            $ret .= "</li>\n";
1046
        }
1047
1048
        //print item
1049
        $ret .= call_user_func($lifunc,$item);
1050
        $ret .= '<div class="li">';
1051
1052
        $ret .= call_user_func($func,$item);
1053
        $ret .= '</div>';
1054
    }
1055
1056
    //close remaining items and lists
1057
    $ret .= "</li>\n";
1058
    while($open-- > 0) {
1059
        $ret .= "</ul></li>\n";
1060
    }
1061
1062
    if ($forcewrapper || $start_level < 2) {
1063
        // Trigger building a wrapper ul if the first level is
1064
        // 0 (we have a root object) or 1 (just the root content)
1065
        $ret = "\n<ul class=\"$class\">\n".$ret."</ul>\n";
1066
    }
1067
1068
    return $ret;
1069
}
1070
1071
/**
1072
 * display backlinks
1073
 *
1074
 * @author Andreas Gohr <[email protected]>
1075
 * @author Michael Klier <[email protected]>
1076
 */
1077
function html_backlinks(){
1078
    global $ID;
1079
    global $lang;
1080
1081
    print p_locale_xhtml('backlinks');
1082
1083
    $data = ft_backlinks($ID);
1084
1085
    if(!empty($data)) {
1086
        print '<ul class="idx">';
1087
        foreach($data as $blink){
1088
            print '<li><div class="li">';
1089
            print html_wikilink(':'.$blink,useHeading('navigation')?null:$blink);
1090
            print '</div></li>';
1091
        }
1092
        print '</ul>';
1093
    } else {
1094
        print '<div class="level1"><p>' . $lang['nothingfound'] . '</p></div>';
1095
    }
1096
}
1097
1098
/**
1099
 * Get header of diff HTML
1100
 *
1101
 * @param string $l_rev   Left revisions
1102
 * @param string $r_rev   Right revision
1103
 * @param string $id      Page id, if null $ID is used
1104
 * @param bool   $media   If it is for media files
1105
 * @param bool   $inline  Return the header on a single line
1106
 * @return string[] HTML snippets for diff header
1107
 */
1108
function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false) {
1109
    global $lang;
1110
    if ($id === null) {
1111
        global $ID;
1112
        $id = $ID;
1113
    }
1114
    $head_separator = $inline ? ' ' : '<br />';
1115
    $media_or_wikiFN = $media ? 'mediaFN' : 'wikiFN';
1116
    $ml_or_wl = $media ? 'ml' : 'wl';
1117
    $l_minor = $r_minor = '';
1118
1119
    if($media) {
1120
        $changelog = new MediaChangeLog($id);
1121
    } else {
1122
        $changelog = new PageChangeLog($id);
1123
    }
1124
    if(!$l_rev){
1125
        $l_head = '&mdash;';
1126
    }else{
1127
        $l_info   = $changelog->getRevisionInfo($l_rev);
1128
        if($l_info['user']){
1129
            $l_user = '<bdi>'.editorinfo($l_info['user']).'</bdi>';
1130
            if(auth_ismanager()) $l_user .= ' <bdo dir="ltr">('.$l_info['ip'].')</bdo>';
1131
        } else {
1132
            $l_user = '<bdo dir="ltr">'.$l_info['ip'].'</bdo>';
1133
        }
1134
        $l_user  = '<span class="user">'.$l_user.'</span>';
1135
        $l_sum   = ($l_info['sum']) ? '<span class="sum"><bdi>'.hsc($l_info['sum']).'</bdi></span>' : '';
1136
        if ($l_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $l_minor = 'class="minor"';
1137
1138
        $l_head_title = ($media) ? dformat($l_rev) : $id.' ['.dformat($l_rev).']';
1139
        $l_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$l_rev").'">'.
1140
        $l_head_title.'</a></bdi>'.
1141
        $head_separator.$l_user.' '.$l_sum;
1142
    }
1143
1144
    if($r_rev){
1145
        $r_info   = $changelog->getRevisionInfo($r_rev);
1146
        if($r_info['user']){
1147
            $r_user = '<bdi>'.editorinfo($r_info['user']).'</bdi>';
1148
            if(auth_ismanager()) $r_user .= ' <bdo dir="ltr">('.$r_info['ip'].')</bdo>';
1149
        } else {
1150
            $r_user = '<bdo dir="ltr">'.$r_info['ip'].'</bdo>';
1151
        }
1152
        $r_user = '<span class="user">'.$r_user.'</span>';
1153
        $r_sum  = ($r_info['sum']) ? '<span class="sum"><bdi>'.hsc($r_info['sum']).'</bdi></span>' : '';
1154
        if ($r_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
1155
1156
        $r_head_title = ($media) ? dformat($r_rev) : $id.' ['.dformat($r_rev).']';
1157
        $r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$r_rev").'">'.
1158
        $r_head_title.'</a></bdi>'.
1159
        $head_separator.$r_user.' '.$r_sum;
1160
    }elseif($_rev = @filemtime($media_or_wikiFN($id))){
1161
        $_info   = $changelog->getRevisionInfo($_rev);
1162
        if($_info['user']){
1163
            $_user = '<bdi>'.editorinfo($_info['user']).'</bdi>';
1164
            if(auth_ismanager()) $_user .= ' <bdo dir="ltr">('.$_info['ip'].')</bdo>';
1165
        } else {
1166
            $_user = '<bdo dir="ltr">'.$_info['ip'].'</bdo>';
1167
        }
1168
        $_user = '<span class="user">'.$_user.'</span>';
1169
        $_sum  = ($_info['sum']) ? '<span class="sum"><bdi>'.hsc($_info['sum']).'</span></bdi>' : '';
1170
        if ($_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
1171
1172
        $r_head_title = ($media) ? dformat($_rev) : $id.' ['.dformat($_rev).']';
1173
        $r_head  = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id).'">'.
1174
        $r_head_title.'</a></bdi> '.
1175
        '('.$lang['current'].')'.
1176
        $head_separator.$_user.' '.$_sum;
1177
    }else{
1178
        $r_head = '&mdash; ('.$lang['current'].')';
1179
    }
1180
1181
    return array($l_head, $r_head, $l_minor, $r_minor);
1182
}
1183
1184
/**
1185
 * Show diff
1186
 * between current page version and provided $text
1187
 * or between the revisions provided via GET or POST
1188
 *
1189
 * @author Andreas Gohr <[email protected]>
1190
 * @param  string $text  when non-empty: compare with this text with most current version
1191
 * @param  bool   $intro display the intro text
1192
 * @param  string $type  type of the diff (inline or sidebyside)
1193
 */
1194
function html_diff($text = '', $intro = true, $type = null) {
1195
    global $ID;
1196
    global $REV;
1197
    global $lang;
1198
    global $INPUT;
1199
    global $INFO;
1200
    $pagelog = new PageChangeLog($ID);
1201
1202
    /*
1203
     * Determine diff type
1204
     */
1205
    if(!$type) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1206
        $type = $INPUT->str('difftype');
1207
        if(empty($type)) {
1208
            $type = get_doku_pref('difftype', $type);
1209
            if(empty($type) && $INFO['ismobile']) {
1210
                $type = 'inline';
1211
            }
1212
        }
1213
    }
1214
    if($type != 'inline') $type = 'sidebyside';
1215
1216
    /*
1217
     * Determine requested revision(s)
1218
     */
1219
    // we're trying to be clever here, revisions to compare can be either
1220
    // given as rev and rev2 parameters, with rev2 being optional. Or in an
1221
    // array in rev2.
1222
    $rev1 = $REV;
1223
1224
    $rev2 = $INPUT->ref('rev2');
1225
    if(is_array($rev2)) {
1226
        $rev1 = (int) $rev2[0];
1227
        $rev2 = (int) $rev2[1];
1228
1229
        if(!$rev1) {
1230
            $rev1 = $rev2;
1231
            unset($rev2);
1232
        }
1233
    } else {
1234
        $rev2 = $INPUT->int('rev2');
1235
    }
1236
1237
    /*
1238
     * Determine left and right revision, its texts and the header
1239
     */
1240
    $r_minor = '';
1241
    $l_minor = '';
1242
1243
    if($text) { // compare text to the most current revision
1244
        $l_rev = '';
1245
        $l_text = rawWiki($ID, '');
1246
        $l_head = '<a class="wikilink1" href="' . wl($ID) . '">' .
1247
            $ID . ' ' . dformat((int) @filemtime(wikiFN($ID))) . '</a> ' .
1248
            $lang['current'];
1249
1250
        $r_rev = '';
1251
        $r_text = cleanText($text);
1252
        $r_head = $lang['yours'];
1253
    } else {
1254
        if($rev1 && isset($rev2) && $rev2) { // two specific revisions wanted
1255
            // make sure order is correct (older on the left)
1256
            if($rev1 < $rev2) {
1257
                $l_rev = $rev1;
1258
                $r_rev = $rev2;
1259
            } else {
1260
                $l_rev = $rev2;
1261
                $r_rev = $rev1;
1262
            }
1263
        } elseif($rev1) { // single revision given, compare to current
1264
            $r_rev = '';
1265
            $l_rev = $rev1;
1266
        } else { // no revision was given, compare previous to current
1267
            $r_rev = '';
1268
            $revs = $pagelog->getRevisions(0, 1);
1269
            $l_rev = $revs[0];
1270
            $REV = $l_rev; // store revision back in $REV
1271
        }
1272
1273
        // when both revisions are empty then the page was created just now
1274
        if(!$l_rev && !$r_rev) {
1275
            $l_text = '';
1276
        } else {
1277
            $l_text = rawWiki($ID, $l_rev);
1278
        }
1279
        $r_text = rawWiki($ID, $r_rev);
1280
1281
        list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev, null, false, $type == 'inline');
1282
    }
1283
1284
    /*
1285
     * Build navigation
1286
     */
1287
    $l_nav = '';
1288
    $r_nav = '';
1289
    if(!$text) {
1290
        list($l_nav, $r_nav) = html_diff_navigation($pagelog, $type, $l_rev, $r_rev);
1291
    }
1292
    /*
1293
     * Create diff object and the formatter
1294
     */
1295
    $diff = new Diff(explode("\n", $l_text), explode("\n", $r_text));
1296
1297
    if($type == 'inline') {
1298
        $diffformatter = new InlineDiffFormatter();
1299
    } else {
1300
        $diffformatter = new TableDiffFormatter();
1301
    }
1302
    /*
1303
     * Display intro
1304
     */
1305
    if($intro) print p_locale_xhtml('diff');
1306
1307
    /*
1308
     * Display type and exact reference
1309
     */
1310
    if(!$text) {
1311
        ptln('<div class="diffoptions group">');
1312
1313
1314
        $form = new Doku_Form(array('action' => wl()));
1315
        $form->addHidden('id', $ID);
1316
        $form->addHidden('rev2[0]', $l_rev);
1317
        $form->addHidden('rev2[1]', $r_rev);
1318
        $form->addHidden('do', 'diff');
1319
        $form->addElement(
1320
             form_makeListboxField(
1321
                 'difftype',
1322
                 array(
1323
                     'sidebyside' => $lang['diff_side'],
1324
                     'inline' => $lang['diff_inline']
1325
                 ),
1326
                 $type,
1327
                 $lang['diff_type'],
1328
                 '', '',
1329
                 array('class' => 'quickselect')
1330
             )
1331
        );
1332
        $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1333
        $form->printForm();
1334
1335
        ptln('<p>');
1336
        // link to exactly this view FS#2835
1337
        echo html_diff_navigationlink($type, 'difflink', $l_rev, $r_rev ? $r_rev : $INFO['currentrev']);
1338
        ptln('</p>');
1339
1340
        ptln('</div>'); // .diffoptions
1341
    }
1342
1343
    /*
1344
     * Display diff view table
1345
     */
1346
    ?>
1347
    <div class="table">
1348
    <table class="diff diff_<?php echo $type ?>">
1349
1350
        <?php
1351
        //navigation and header
1352
        if($type == 'inline') {
1353
            if(!$text) { ?>
1354
                <tr>
1355
                    <td class="diff-lineheader">-</td>
1356
                    <td class="diffnav"><?php echo $l_nav ?></td>
1357
                </tr>
1358
                <tr>
1359
                    <th class="diff-lineheader">-</th>
1360
                    <th <?php echo $l_minor ?>>
1361
                        <?php echo $l_head ?>
1362
                    </th>
1363
                </tr>
1364
            <?php } ?>
1365
            <tr>
1366
                <td class="diff-lineheader">+</td>
1367
                <td class="diffnav"><?php echo $r_nav ?></td>
1368
            </tr>
1369
            <tr>
1370
                <th class="diff-lineheader">+</th>
1371
                <th <?php echo $r_minor ?>>
1372
                    <?php echo $r_head ?>
1373
                </th>
1374
            </tr>
1375
        <?php } else {
1376
            if(!$text) { ?>
1377
                <tr>
1378
                    <td colspan="2" class="diffnav"><?php echo $l_nav ?></td>
1379
                    <td colspan="2" class="diffnav"><?php echo $r_nav ?></td>
1380
                </tr>
1381
            <?php } ?>
1382
            <tr>
1383
                <th colspan="2" <?php echo $l_minor ?>>
1384
                    <?php echo $l_head ?>
1385
                </th>
1386
                <th colspan="2" <?php echo $r_minor ?>>
1387
                    <?php echo $r_head ?>
1388
                </th>
1389
            </tr>
1390
        <?php }
1391
1392
        //diff view
1393
        echo html_insert_softbreaks($diffformatter->format($diff)); ?>
1394
1395
    </table>
1396
    </div>
1397
<?php
1398
}
1399
1400
/**
1401
 * Create html for revision navigation
1402
 *
1403
 * @param PageChangeLog $pagelog changelog object of current page
1404
 * @param string        $type    inline vs sidebyside
1405
 * @param int           $l_rev   left revision timestamp
1406
 * @param int           $r_rev   right revision timestamp
1407
 * @return string[] html of left and right navigation elements
1408
 */
1409
function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) {
1410
    global $INFO, $ID;
1411
1412
    // last timestamp is not in changelog, retrieve timestamp from metadata
1413
    // note: when page is removed, the metadata timestamp is zero
1414
    if(!$r_rev) {
1415
        if(isset($INFO['meta']['last_change']['date'])) {
1416
            $r_rev = $INFO['meta']['last_change']['date'];
1417
        } else {
1418
            $r_rev = 0;
1419
        }
1420
    }
1421
1422
    //retrieve revisions with additional info
1423
    list($l_revs, $r_revs) = $pagelog->getRevisionsAround($l_rev, $r_rev);
1424
    $l_revisions = array();
1425
    if(!$l_rev) {
1426
        $l_revisions[0] = array(0, "", false); //no left revision given, add dummy
1427
    }
1428
    foreach($l_revs as $rev) {
1429
        $info = $pagelog->getRevisionInfo($rev);
1430
        $l_revisions[$rev] = array(
1431
            $rev,
1432
            dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'],
1433
            $r_rev ? $rev >= $r_rev : false //disable?
1434
        );
1435
    }
1436
    $r_revisions = array();
1437
    if(!$r_rev) {
1438
        $r_revisions[0] = array(0, "", false); //no right revision given, add dummy
1439
    }
1440
    foreach($r_revs as $rev) {
1441
        $info = $pagelog->getRevisionInfo($rev);
1442
        $r_revisions[$rev] = array(
1443
            $rev,
1444
            dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'],
1445
            $rev <= $l_rev //disable?
1446
        );
1447
    }
1448
1449
    //determine previous/next revisions
1450
    $l_index = array_search($l_rev, $l_revs);
1451
    $l_prev = $l_revs[$l_index + 1];
1452
    $l_next = $l_revs[$l_index - 1];
1453
    if($r_rev) {
1454
        $r_index = array_search($r_rev, $r_revs);
1455
        $r_prev = $r_revs[$r_index + 1];
1456
        $r_next = $r_revs[$r_index - 1];
1457
    } else {
1458
        //removed page
1459
        if($l_next) {
1460
            $r_prev = $r_revs[0];
1461
        } else {
1462
            $r_prev = null;
1463
        }
1464
        $r_next = null;
1465
    }
1466
1467
    /*
1468
     * Left side:
1469
     */
1470
    $l_nav = '';
1471
    //move back
1472
    if($l_prev) {
1473
        $l_nav .= html_diff_navigationlink($type, 'diffbothprevrev', $l_prev, $r_prev);
1474
        $l_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_prev, $r_rev);
1475
    }
1476
    //dropdown
1477
    $form = new Doku_Form(array('action' => wl()));
1478
    $form->addHidden('id', $ID);
1479
    $form->addHidden('difftype', $type);
1480
    $form->addHidden('rev2[1]', $r_rev);
1481
    $form->addHidden('do', 'diff');
1482
    $form->addElement(
1483
         form_makeListboxField(
1484
             'rev2[0]',
1485
             $l_revisions,
1486
             $l_rev,
1487
             '', '', '',
1488
             array('class' => 'quickselect')
1489
         )
1490
    );
1491
    $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1492
    $l_nav .= $form->getForm();
1493
    //move forward
1494
    if($l_next && ($l_next < $r_rev || !$r_rev)) {
1495
        $l_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_next, $r_rev);
1496
    }
1497
1498
    /*
1499
     * Right side:
1500
     */
1501
    $r_nav = '';
1502
    //move back
1503
    if($l_rev < $r_prev) {
1504
        $r_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_rev, $r_prev);
1505
    }
1506
    //dropdown
1507
    $form = new Doku_Form(array('action' => wl()));
1508
    $form->addHidden('id', $ID);
1509
    $form->addHidden('rev2[0]', $l_rev);
1510
    $form->addHidden('difftype', $type);
1511
    $form->addHidden('do', 'diff');
1512
    $form->addElement(
1513
         form_makeListboxField(
1514
             'rev2[1]',
1515
             $r_revisions,
1516
             $r_rev,
1517
             '', '', '',
1518
             array('class' => 'quickselect')
1519
         )
1520
    );
1521
    $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1522
    $r_nav .= $form->getForm();
1523
    //move forward
1524
    if($r_next) {
1525
        if($pagelog->isCurrentRevision($r_next)) {
1526
            $r_nav .= html_diff_navigationlink($type, 'difflastrev', $l_rev); //last revision is diff with current page
1527
        } else {
1528
            $r_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_rev, $r_next);
1529
        }
1530
        $r_nav .= html_diff_navigationlink($type, 'diffbothnextrev', $l_next, $r_next);
1531
    }
1532
    return array($l_nav, $r_nav);
1533
}
1534
1535
/**
1536
 * Create html link to a diff defined by two revisions
1537
 *
1538
 * @param string $difftype display type
1539
 * @param string $linktype
1540
 * @param int $lrev oldest revision
1541
 * @param int $rrev newest revision or null for diff with current revision
1542
 * @return string html of link to a diff
1543
 */
1544
function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) {
1545
    global $ID, $lang;
1546
    if(!$rrev) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rrev of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1547
        $urlparam = array(
1548
            'do' => 'diff',
1549
            'rev' => $lrev,
1550
            'difftype' => $difftype,
1551
        );
1552
    } else {
1553
        $urlparam = array(
1554
            'do' => 'diff',
1555
            'rev2[0]' => $lrev,
1556
            'rev2[1]' => $rrev,
1557
            'difftype' => $difftype,
1558
        );
1559
    }
1560
    return  '<a class="' . $linktype . '" href="' . wl($ID, $urlparam) . '" title="' . $lang[$linktype] . '">' .
1561
                '<span>' . $lang[$linktype] . '</span>' .
1562
            '</a>' . "\n";
1563
}
1564
1565
/**
1566
 * Insert soft breaks in diff html
1567
 *
1568
 * @param string $diffhtml
1569
 * @return string
1570
 */
1571
function html_insert_softbreaks($diffhtml) {
1572
    // search the diff html string for both:
1573
    // - html tags, so these can be ignored
1574
    // - long strings of characters without breaking characters
1575
    return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/','html_softbreak_callback',$diffhtml);
1576
}
1577
1578
/**
1579
 * callback which adds softbreaks
1580
 *
1581
 * @param array $match array with first the complete match
1582
 * @return string the replacement
1583
 */
1584
function html_softbreak_callback($match){
1585
    // if match is an html tag, return it intact
1586
    if ($match[0]{0} == '<') return $match[0];
1587
1588
    // its a long string without a breaking character,
1589
    // make certain characters into breaking characters by inserting a
1590
    // breaking character (zero length space, U+200B / #8203) in front them.
1591
    $regex = <<< REGEX
1592
(?(?=              # start a conditional expression with a positive look ahead ...
1593
&\#?\\w{1,6};)     # ... for html entities - we don't want to split them (ok to catch some invalid combinations)
1594
&\#?\\w{1,6};      # yes pattern - a quicker match for the html entity, since we know we have one
1595
|
1596
[?/,&\#;:]         # no pattern - any other group of 'special' characters to insert a breaking character after
1597
)+                 # end conditional expression
1598
REGEX;
1599
1600
    return preg_replace('<'.$regex.'>xu','\0&#8203;',$match[0]);
1601
}
1602
1603
/**
1604
 * show warning on conflict detection
1605
 *
1606
 * @author Andreas Gohr <[email protected]>
1607
 *
1608
 * @param string $text
1609
 * @param string $summary
1610
 */
1611
function html_conflict($text,$summary){
1612
    global $ID;
1613
    global $lang;
1614
1615
    print p_locale_xhtml('conflict');
1616
    $form = new Doku_Form(array('id' => 'dw__editform'));
1617
    $form->addHidden('id', $ID);
1618
    $form->addHidden('wikitext', $text);
1619
    $form->addHidden('summary', $summary);
1620
    $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('accesskey'=>'s')));
1621
    $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel']));
1622
    html_form('conflict', $form);
1623
    print '<br /><br /><br /><br />'.NL;
1624
}
1625
1626
/**
1627
 * Prints the global message array
1628
 *
1629
 * @author Andreas Gohr <[email protected]>
1630
 */
1631
function html_msgarea(){
1632
    global $MSG, $MSG_shown;
1633
    /** @var array $MSG */
1634
    // store if the global $MSG has already been shown and thus HTML output has been started
1635
    $MSG_shown = true;
1636
1637
    if(!isset($MSG)) return;
1638
1639
    $shown = array();
1640
    foreach($MSG as $msg){
1641
        $hash = md5($msg['msg']);
1642
        if(isset($shown[$hash])) continue; // skip double messages
1643
        if(info_msg_allowed($msg)){
1644
            print '<div class="'.$msg['lvl'].'">';
1645
            print $msg['msg'];
1646
            print '</div>';
1647
        }
1648
        $shown[$hash] = 1;
1649
    }
1650
1651
    unset($GLOBALS['MSG']);
1652
}
1653
1654
/**
1655
 * Prints the registration form
1656
 *
1657
 * @author Andreas Gohr <[email protected]>
1658
 */
1659
function html_register(){
1660
    global $lang;
1661
    global $conf;
1662
    global $INPUT;
1663
1664
    $base_attrs = array('size'=>50,'required'=>'required');
1665
    $email_attrs = $base_attrs + array('type'=>'email','class'=>'edit');
1666
1667
    print p_locale_xhtml('register');
1668
    print '<div class="centeralign">'.NL;
1669
    $form = new Doku_Form(array('id' => 'dw__register'));
1670
    $form->startFieldset($lang['btn_register']);
1671
    $form->addHidden('do', 'register');
1672
    $form->addHidden('save', '1');
1673
    $form->addElement(
1674
        form_makeTextField(
1675
            'login',
1676
            $INPUT->post->str('login'),
1677
            $lang['user'],
1678
            '',
1679
            'block',
1680
            $base_attrs
1681
        )
1682
    );
1683
    if (!$conf['autopasswd']) {
1684
        $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', $base_attrs));
1685
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', $base_attrs));
1686
    }
1687
    $form->addElement(
1688
        form_makeTextField(
1689
            'fullname',
1690
            $INPUT->post->str('fullname'),
1691
            $lang['fullname'],
1692
            '',
1693
            'block',
1694
            $base_attrs
1695
        )
1696
    );
1697
    $form->addElement(
1698
        form_makeField(
1699
            'email',
1700
            'email',
1701
            $INPUT->post->str('email'),
1702
            $lang['email'],
1703
            '',
1704
            'block',
1705
            $email_attrs
1706
        )
1707
    );
1708
    $form->addElement(form_makeButton('submit', '', $lang['btn_register']));
1709
    $form->endFieldset();
1710
    html_form('register', $form);
1711
1712
    print '</div>'.NL;
1713
}
1714
1715
/**
1716
 * Print the update profile form
1717
 *
1718
 * @author Christopher Smith <[email protected]>
1719
 * @author Andreas Gohr <[email protected]>
1720
 */
1721
function html_updateprofile(){
1722
    global $lang;
1723
    global $conf;
1724
    global $INPUT;
1725
    global $INFO;
1726
    /** @var DokuWiki_Auth_Plugin $auth */
1727
    global $auth;
1728
1729
    print p_locale_xhtml('updateprofile');
1730
    print '<div class="centeralign">'.NL;
1731
1732
    $fullname = $INPUT->post->str('fullname', $INFO['userinfo']['name'], true);
1733
    $email = $INPUT->post->str('email', $INFO['userinfo']['mail'], true);
1734
    $form = new Doku_Form(array('id' => 'dw__register'));
1735
    $form->startFieldset($lang['profile']);
1736
    $form->addHidden('do', 'profile');
1737
    $form->addHidden('save', '1');
1738
    $form->addElement(
1739
        form_makeTextField(
1740
            'login',
1741
            $_SERVER['REMOTE_USER'],
1742
            $lang['user'],
1743
            '',
1744
            'block',
1745
            array('size' => '50', 'disabled' => 'disabled')
1746
        )
1747
    );
1748
    $attr = array('size'=>'50');
1749
    if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled';
1750
    $form->addElement(form_makeTextField('fullname', $fullname, $lang['fullname'], '', 'block', $attr));
1751
    $attr = array('size'=>'50', 'class'=>'edit');
1752
    if (!$auth->canDo('modMail')) $attr['disabled'] = 'disabled';
1753
    $form->addElement(form_makeField('email','email', $email, $lang['email'], '', 'block', $attr));
1754
    $form->addElement(form_makeTag('br'));
1755
    if ($auth->canDo('modPass')) {
1756
        $form->addElement(form_makePasswordField('newpass', $lang['newpass'], '', 'block', array('size'=>'50')));
1757
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
1758
    }
1759
    if ($conf['profileconfirm']) {
1760
        $form->addElement(form_makeTag('br'));
1761
        $form->addElement(
1762
            form_makePasswordField(
1763
                'oldpass',
1764
                $lang['oldpass'],
1765
                '',
1766
                'block',
1767
                array('size' => '50', 'required' => 'required')
1768
            )
1769
        );
1770
    }
1771
    $form->addElement(form_makeButton('submit', '', $lang['btn_save']));
1772
    $form->addElement(form_makeButton('reset', '', $lang['btn_reset']));
1773
1774
    $form->endFieldset();
1775
    html_form('updateprofile', $form);
1776
1777
    if ($auth->canDo('delUser') && actionOK('profile_delete')) {
1778
        $form_profiledelete = new Doku_Form(array('id' => 'dw__profiledelete'));
1779
        $form_profiledelete->startFieldset($lang['profdeleteuser']);
1780
        $form_profiledelete->addHidden('do', 'profile_delete');
1781
        $form_profiledelete->addHidden('delete', '1');
1782
        $form_profiledelete->addElement(
1783
            form_makeCheckboxField(
1784
                'confirm_delete',
1785
                '1',
1786
                $lang['profconfdelete'],
1787
                'dw__confirmdelete',
1788
                '',
1789
                array('required' => 'required')
1790
            )
1791
        );
1792
        if ($conf['profileconfirm']) {
1793
            $form_profiledelete->addElement(form_makeTag('br'));
1794
            $form_profiledelete->addElement(
1795
                form_makePasswordField(
1796
                    'oldpass',
1797
                    $lang['oldpass'],
1798
                    '',
1799
                    'block',
1800
                    array('size' => '50', 'required' => 'required')
1801
                )
1802
            );
1803
        }
1804
        $form_profiledelete->addElement(form_makeButton('submit', '', $lang['btn_deleteuser']));
1805
        $form_profiledelete->endFieldset();
1806
1807
        html_form('profiledelete', $form_profiledelete);
1808
    }
1809
1810
    print '</div>'.NL;
1811
}
1812
1813
/**
1814
 * Preprocess edit form data
1815
 *
1816
 * @author   Andreas Gohr <[email protected]>
1817
 *
1818
 * @triggers HTML_EDITFORM_OUTPUT
1819
 */
1820
function html_edit(){
1821
    global $INPUT;
1822
    global $ID;
1823
    global $REV;
1824
    global $DATE;
1825
    global $PRE;
1826
    global $SUF;
1827
    global $INFO;
1828
    global $SUM;
1829
    global $lang;
1830
    global $conf;
1831
    global $TEXT;
1832
1833
    if ($INPUT->has('changecheck')) {
1834
        $check = $INPUT->str('changecheck');
1835
    } elseif(!$INFO['exists']){
1836
        // $TEXT has been loaded from page template
1837
        $check = md5('');
1838
    } else {
1839
        $check = md5($TEXT);
1840
    }
1841
    $mod = md5($TEXT) !== $check;
1842
1843
    $wr = $INFO['writable'] && !$INFO['locked'];
1844
    $include = 'edit';
1845
    if($wr){
1846
        if ($REV) $include = 'editrev';
1847
    }else{
1848
        // check pseudo action 'source'
1849
        if(!actionOK('source')){
1850
            msg('Command disabled: source',-1);
1851
            return;
1852
        }
1853
        $include = 'read';
1854
    }
1855
1856
    global $license;
1857
1858
    $form = new Doku_Form(array('id' => 'dw__editform'));
1859
    $form->addHidden('id', $ID);
1860
    $form->addHidden('rev', $REV);
1861
    $form->addHidden('date', $DATE);
1862
    $form->addHidden('prefix', $PRE . '.');
1863
    $form->addHidden('suffix', $SUF);
1864
    $form->addHidden('changecheck', $check);
1865
1866
    $data = array('form' => $form,
1867
                  'wr'   => $wr,
1868
                  'media_manager' => true,
1869
                  'target' => ($INPUT->has('target') && $wr) ? $INPUT->str('target') : 'section',
1870
                  'intro_locale' => $include);
1871
1872
    if ($data['target'] !== 'section') {
1873
        // Only emit event if page is writable, section edit data is valid and
1874
        // edit target is not section.
1875
        trigger_event('HTML_EDIT_FORMSELECTION', $data, 'html_edit_form', true);
1876
    } else {
1877
        html_edit_form($data);
1878
    }
1879
    if (isset($data['intro_locale'])) {
1880
        echo p_locale_xhtml($data['intro_locale']);
1881
    }
1882
1883
    $form->addHidden('target', $data['target']);
1884
    if ($INPUT->has('hid')) {
1885
        $form->addHidden('hid', $INPUT->str('hid'));
1886
    }
1887
    if ($INPUT->has('codeblockOffset')) {
1888
        $form->addHidden('codeblockOffset', $INPUT->str('codeblockOffset'));
1889
    }
1890
    $form->addElement(form_makeOpenTag('div', array('id'=>'wiki__editbar', 'class'=>'editBar')));
1891
    $form->addElement(form_makeOpenTag('div', array('id'=>'size__ctl')));
1892
    $form->addElement(form_makeCloseTag('div'));
1893
    if ($wr) {
1894
        $form->addElement(form_makeOpenTag('div', array('class'=>'editButtons')));
1895
        $form->addElement(
1896
            form_makeButton(
1897
                'submit',
1898
                'save',
1899
                $lang['btn_save'],
1900
                array('id' => 'edbtn__save', 'accesskey' => 's', 'tabindex' => '4')
1901
            )
1902
        );
1903
        $form->addElement(
1904
            form_makeButton(
1905
                'submit',
1906
                'preview',
1907
                $lang['btn_preview'],
1908
                array('id' => 'edbtn__preview', 'accesskey' => 'p', 'tabindex' => '5')
1909
            )
1910
        );
1911
        $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel'], array('tabindex'=>'6')));
1912
        $form->addElement(form_makeCloseTag('div'));
1913
        $form->addElement(form_makeOpenTag('div', array('class'=>'summary')));
1914
        $form->addElement(
1915
            form_makeTextField(
1916
                'summary',
1917
                $SUM,
1918
                $lang['summary'],
1919
                'edit__summary',
1920
                'nowrap',
1921
                array('size' => '50', 'tabindex' => '2')
1922
            )
1923
        );
1924
        $elem = html_minoredit();
1925
        if ($elem) $form->addElement($elem);
1926
        $form->addElement(form_makeCloseTag('div'));
1927
    }
1928
    $form->addElement(form_makeCloseTag('div'));
1929
    if($wr && $conf['license']){
1930
        $form->addElement(form_makeOpenTag('div', array('class'=>'license')));
1931
        $out  = $lang['licenseok'];
1932
        $out .= ' <a href="'.$license[$conf['license']]['url'].'" rel="license" class="urlextern"';
1933
        if($conf['target']['extern']) $out .= ' target="'.$conf['target']['extern'].'"';
1934
        $out .= '>'.$license[$conf['license']]['name'].'</a>';
1935
        $form->addElement($out);
1936
        $form->addElement(form_makeCloseTag('div'));
1937
    }
1938
1939
    if ($wr) {
1940
        // sets changed to true when previewed
1941
        echo '<script type="text/javascript">/*<![CDATA[*/'. NL;
1942
        echo 'textChanged = ' . ($mod ? 'true' : 'false');
1943
        echo '/*!]]>*/</script>' . NL;
1944
    } ?>
1945
    <div class="editBox" role="application">
1946
1947
    <div class="toolbar group">
1948
        <div id="tool__bar" class="tool__bar"><?php
1949
            if ($wr && $data['media_manager']){
1950
                ?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
1951
                target="_blank"><?php echo $lang['mediaselect'] ?></a><?php
1952
            }?>
1953
        </div>
1954
    </div>
1955
    <div id="draft__status" class="draft__status">
1956
        <?php
1957
        $draft = new \dokuwiki\Draft($ID, $INFO['client']);
1958
        if ($draft->isDraftAvailable()) {
1959
            echo $draft->getDraftMessage();
1960
        }
1961
        ?>
1962
    </div>
1963
    <?php
1964
1965
    html_form('edit', $form);
1966
    print '</div>'.NL;
1967
}
1968
1969
/**
1970
 * Display the default edit form
1971
 *
1972
 * Is the default action for HTML_EDIT_FORMSELECTION.
1973
 *
1974
 * @param mixed[] $param
1975
 */
1976
function html_edit_form($param) {
1977
    global $TEXT;
1978
1979
    if ($param['target'] !== 'section') {
1980
        msg('No editor for edit target ' . hsc($param['target']) . ' found.', -1);
1981
    }
1982
1983
    $attr = array('tabindex'=>'1');
1984
    if (!$param['wr']) $attr['readonly'] = 'readonly';
1985
1986
    $param['form']->addElement(form_makeWikiText($TEXT, $attr));
1987
}
1988
1989
/**
1990
 * Adds a checkbox for minor edits for logged in users
1991
 *
1992
 * @author Andreas Gohr <[email protected]>
1993
 *
1994
 * @return array|bool
1995
 */
1996
function html_minoredit(){
1997
    global $conf;
1998
    global $lang;
1999
    global $INPUT;
2000
    // minor edits are for logged in users only
2001
    if(!$conf['useacl'] || !$_SERVER['REMOTE_USER']){
2002
        return false;
2003
    }
2004
2005
    $p = array();
2006
    $p['tabindex'] = 3;
2007
    if($INPUT->bool('minor')) $p['checked']='checked';
2008
    return form_makeCheckboxField('minor', '1', $lang['minoredit'], 'minoredit', 'nowrap', $p);
2009
}
2010
2011
/**
2012
 * prints some debug info
2013
 *
2014
 * @author Andreas Gohr <[email protected]>
2015
 */
2016
function html_debug(){
2017
    global $conf;
2018
    global $lang;
2019
    /** @var DokuWiki_Auth_Plugin $auth */
2020
    global $auth;
2021
    global $INFO;
2022
2023
    //remove sensitive data
2024
    $cnf = $conf;
2025
    debug_guard($cnf);
2026
    $nfo = $INFO;
2027
    debug_guard($nfo);
2028
    $ses = $_SESSION;
2029
    debug_guard($ses);
2030
2031
    print '<html><body>';
2032
2033
    print '<p>When reporting bugs please send all the following ';
2034
    print 'output as a mail to [email protected] ';
2035
    print 'The best way to do this is to save this page in your browser</p>';
2036
2037
    print '<b>$INFO:</b><pre>';
2038
    print_r($nfo);
2039
    print '</pre>';
2040
2041
    print '<b>$_SERVER:</b><pre>';
2042
    print_r($_SERVER);
2043
    print '</pre>';
2044
2045
    print '<b>$conf:</b><pre>';
2046
    print_r($cnf);
2047
    print '</pre>';
2048
2049
    print '<b>DOKU_BASE:</b><pre>';
2050
    print DOKU_BASE;
2051
    print '</pre>';
2052
2053
    print '<b>abs DOKU_BASE:</b><pre>';
2054
    print DOKU_URL;
2055
    print '</pre>';
2056
2057
    print '<b>rel DOKU_BASE:</b><pre>';
2058
    print dirname($_SERVER['PHP_SELF']).'/';
2059
    print '</pre>';
2060
2061
    print '<b>PHP Version:</b><pre>';
2062
    print phpversion();
2063
    print '</pre>';
2064
2065
    print '<b>locale:</b><pre>';
2066
    print setlocale(LC_ALL,0);
2067
    print '</pre>';
2068
2069
    print '<b>encoding:</b><pre>';
2070
    print $lang['encoding'];
2071
    print '</pre>';
2072
2073
    if($auth){
2074
        print '<b>Auth backend capabilities:</b><pre>';
2075
        foreach ($auth->getCapabilities() as $cando){
2076
            print '   '.str_pad($cando,16) . ' => ' . (int)$auth->canDo($cando) . NL;
2077
        }
2078
        print '</pre>';
2079
    }
2080
2081
    print '<b>$_SESSION:</b><pre>';
2082
    print_r($ses);
2083
    print '</pre>';
2084
2085
    print '<b>Environment:</b><pre>';
2086
    print_r($_ENV);
2087
    print '</pre>';
2088
2089
    print '<b>PHP settings:</b><pre>';
2090
    $inis = ini_get_all();
2091
    print_r($inis);
2092
    print '</pre>';
2093
2094
    if (function_exists('apache_get_version')) {
2095
        $apache = array();
2096
        $apache['version'] = apache_get_version();
2097
2098
        if (function_exists('apache_get_modules')) {
2099
            $apache['modules'] = apache_get_modules();
2100
        }
2101
        print '<b>Apache</b><pre>';
2102
        print_r($apache);
2103
        print '</pre>';
2104
    }
2105
2106
    print '</body></html>';
2107
}
2108
2109
/**
2110
 * Form to request a new password for an existing account
2111
 *
2112
 * @author Benoit Chesneau <[email protected]>
2113
 * @author Andreas Gohr <[email protected]>
2114
 */
2115
function html_resendpwd() {
2116
    global $lang;
2117
    global $conf;
2118
    global $INPUT;
2119
2120
    $token = preg_replace('/[^a-f0-9]+/','',$INPUT->str('pwauth'));
2121
2122
    if(!$conf['autopasswd'] && $token){
2123
        print p_locale_xhtml('resetpwd');
2124
        print '<div class="centeralign">'.NL;
2125
        $form = new Doku_Form(array('id' => 'dw__resendpwd'));
2126
        $form->startFieldset($lang['btn_resendpwd']);
2127
        $form->addHidden('token', $token);
2128
        $form->addHidden('do', 'resendpwd');
2129
2130
        $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', array('size'=>'50')));
2131
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
2132
2133
        $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
2134
        $form->endFieldset();
2135
        html_form('resendpwd', $form);
2136
        print '</div>'.NL;
2137
    }else{
2138
        print p_locale_xhtml('resendpwd');
2139
        print '<div class="centeralign">'.NL;
2140
        $form = new Doku_Form(array('id' => 'dw__resendpwd'));
2141
        $form->startFieldset($lang['resendpwd']);
2142
        $form->addHidden('do', 'resendpwd');
2143
        $form->addHidden('save', '1');
2144
        $form->addElement(form_makeTag('br'));
2145
        $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block'));
2146
        $form->addElement(form_makeTag('br'));
2147
        $form->addElement(form_makeTag('br'));
2148
        $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
2149
        $form->endFieldset();
2150
        html_form('resendpwd', $form);
2151
        print '</div>'.NL;
2152
    }
2153
}
2154
2155
/**
2156
 * Return the TOC rendered to XHTML
2157
 *
2158
 * @author Andreas Gohr <[email protected]>
2159
 *
2160
 * @param array $toc
2161
 * @return string html
2162
 */
2163
function html_TOC($toc){
2164
    if(!count($toc)) return '';
2165
    global $lang;
2166
    $out  = '<!-- TOC START -->'.DOKU_LF;
2167
    $out .= '<div id="dw__toc" class="dw__toc">'.DOKU_LF;
2168
    $out .= '<h3 class="toggle">';
2169
    $out .= $lang['toc'];
2170
    $out .= '</h3>'.DOKU_LF;
2171
    $out .= '<div>'.DOKU_LF;
2172
    $out .= html_buildlist($toc,'toc','html_list_toc','html_li_default',true);
2173
    $out .= '</div>'.DOKU_LF.'</div>'.DOKU_LF;
2174
    $out .= '<!-- TOC END -->'.DOKU_LF;
2175
    return $out;
2176
}
2177
2178
/**
2179
 * Callback for html_buildlist
2180
 *
2181
 * @param array $item
2182
 * @return string html
2183
 */
2184
function html_list_toc($item){
2185
    if(isset($item['hid'])){
2186
        $link = '#'.$item['hid'];
2187
    }else{
2188
        $link = $item['link'];
2189
    }
2190
2191
    return '<a href="'.$link.'">'.hsc($item['title']).'</a>';
2192
}
2193
2194
/**
2195
 * Helper function to build TOC items
2196
 *
2197
 * Returns an array ready to be added to a TOC array
2198
 *
2199
 * @param string $link  - where to link (if $hash set to '#' it's a local anchor)
2200
 * @param string $text  - what to display in the TOC
2201
 * @param int    $level - nesting level
2202
 * @param string $hash  - is prepended to the given $link, set blank if you want full links
2203
 * @return array the toc item
2204
 */
2205
function html_mktocitem($link, $text, $level, $hash='#'){
2206
    return  array( 'link'  => $hash.$link,
2207
            'title' => $text,
2208
            'type'  => 'ul',
2209
            'level' => $level);
2210
}
2211
2212
/**
2213
 * Output a Doku_Form object.
2214
 * Triggers an event with the form name: HTML_{$name}FORM_OUTPUT
2215
 *
2216
 * @author Tom N Harris <[email protected]>
2217
 *
2218
 * @param string     $name The name of the form
2219
 * @param Doku_Form  $form The form
2220
 */
2221
function html_form($name, &$form) {
2222
    // Safety check in case the caller forgets.
2223
    $form->endFieldset();
2224
    trigger_event('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false);
2225
}
2226
2227
/**
2228
 * Form print function.
2229
 * Just calls printForm() on the data object.
2230
 *
2231
 * @param Doku_Form $data The form
2232
 */
2233
function html_form_output($data) {
2234
    $data->printForm();
2235
}
2236
2237
/**
2238
 * Embed a flash object in HTML
2239
 *
2240
 * This will create the needed HTML to embed a flash movie in a cross browser
2241
 * compatble way using valid XHTML
2242
 *
2243
 * The parameters $params, $flashvars and $atts need to be associative arrays.
2244
 * No escaping needs to be done for them. The alternative content *has* to be
2245
 * escaped because it is used as is. If no alternative content is given
2246
 * $lang['noflash'] is used.
2247
 *
2248
 * @author Andreas Gohr <[email protected]>
2249
 * @link   http://latrine.dgx.cz/how-to-correctly-insert-a-flash-into-xhtml
2250
 *
2251
 * @param string $swf      - the SWF movie to embed
2252
 * @param int $width       - width of the flash movie in pixels
2253
 * @param int $height      - height of the flash movie in pixels
2254
 * @param array $params    - additional parameters (<param>)
2255
 * @param array $flashvars - parameters to be passed in the flashvar parameter
2256
 * @param array $atts      - additional attributes for the <object> tag
2257
 * @param string $alt      - alternative content (is NOT automatically escaped!)
2258
 * @return string         - the XHTML markup
2259
 */
2260
function html_flashobject($swf,$width,$height,$params=null,$flashvars=null,$atts=null,$alt=''){
2261
    global $lang;
2262
2263
    $out = '';
2264
2265
    // prepare the object attributes
2266
    if(is_null($atts)) $atts = array();
2267
    $atts['width']  = (int) $width;
2268
    $atts['height'] = (int) $height;
2269
    if(!$atts['width'])  $atts['width']  = 425;
2270
    if(!$atts['height']) $atts['height'] = 350;
2271
2272
    // add object attributes for standard compliant browsers
2273
    $std = $atts;
2274
    $std['type'] = 'application/x-shockwave-flash';
2275
    $std['data'] = $swf;
2276
2277
    // add object attributes for IE
2278
    $ie  = $atts;
2279
    $ie['classid'] = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
2280
2281
    // open object (with conditional comments)
2282
    $out .= '<!--[if !IE]> -->'.NL;
2283
    $out .= '<object '.buildAttributes($std).'>'.NL;
2284
    $out .= '<!-- <![endif]-->'.NL;
2285
    $out .= '<!--[if IE]>'.NL;
2286
    $out .= '<object '.buildAttributes($ie).'>'.NL;
2287
    $out .= '    <param name="movie" value="'.hsc($swf).'" />'.NL;
2288
    $out .= '<!--><!-- -->'.NL;
2289
2290
    // print params
2291
    if(is_array($params)) foreach($params as $key => $val){
2292
        $out .= '  <param name="'.hsc($key).'" value="'.hsc($val).'" />'.NL;
2293
    }
2294
2295
    // add flashvars
2296
    if(is_array($flashvars)){
2297
        $out .= '  <param name="FlashVars" value="'.buildURLparams($flashvars).'" />'.NL;
2298
    }
2299
2300
    // alternative content
2301
    if($alt){
2302
        $out .= $alt.NL;
2303
    }else{
2304
        $out .= $lang['noflash'].NL;
2305
    }
2306
2307
    // finish
2308
    $out .= '</object>'.NL;
2309
    $out .= '<!-- <![endif]-->'.NL;
2310
2311
    return $out;
2312
}
2313
2314
/**
2315
 * Prints HTML code for the given tab structure
2316
 *
2317
 * @param array  $tabs        tab structure
2318
 * @param string $current_tab the current tab id
2319
 */
2320
function html_tabs($tabs, $current_tab = null) {
2321
    echo '<ul class="tabs">'.NL;
2322
2323
    foreach($tabs as $id => $tab) {
2324
        html_tab($tab['href'], $tab['caption'], $id === $current_tab);
2325
    }
2326
2327
    echo '</ul>'.NL;
2328
}
2329
2330
/**
2331
 * Prints a single tab
2332
 *
2333
 * @author Kate Arzamastseva <[email protected]>
2334
 * @author Adrian Lang <[email protected]>
2335
 *
2336
 * @param string $href - tab href
2337
 * @param string $caption - tab caption
2338
 * @param boolean $selected - is tab selected
2339
 */
2340
2341
function html_tab($href, $caption, $selected=false) {
2342
    $tab = '<li>';
2343
    if ($selected) {
2344
        $tab .= '<strong>';
2345
    } else {
2346
        $tab .= '<a href="' . hsc($href) . '">';
2347
    }
2348
    $tab .= hsc($caption)
2349
         .  '</' . ($selected ? 'strong' : 'a') . '>'
2350
         .  '</li>'.NL;
2351
    echo $tab;
2352
}
2353
2354
/**
2355
 * Display size change
2356
 *
2357
 * @param int $sizechange - size of change in Bytes
2358
 * @param Doku_Form $form - form to add elements to
2359
 */
2360
2361
function html_sizechange($sizechange, Doku_Form $form) {
2362
    if(isset($sizechange)) {
2363
        $class = 'sizechange';
2364
        $value = filesize_h(abs($sizechange));
2365
        if($sizechange > 0) {
2366
            $class .= ' positive';
2367
            $value = '+' . $value;
2368
        } elseif($sizechange < 0) {
2369
            $class .= ' negative';
2370
            $value = '-' . $value;
2371
        } else {
2372
            $value = '±' . $value;
2373
        }
2374
        $form->addElement(form_makeOpenTag('span', array('class' => $class)));
2375
        $form->addElement($value);
2376
        $form->addElement(form_makeCloseTag('span'));
2377
    }
2378
}
2379