Completed
Push — master ( e6517f...a40909 )
by Andreas
07:57
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
if(!defined('DOKU_INC')) die('meh.');
10
if(!defined('NL')) define('NL',"\n");
11
if (!defined('SEC_EDIT_PATTERN')) {
12
    define('SEC_EDIT_PATTERN', '#<!-- EDIT(?<secid>\d+) (?<target>[A-Z_]+) (?:"(?<name>[^"]*)" )?(?:"(?<hid>[^"]*)" )?\[(?<range>\d+-\d*)\] -->#');
13
}
14
15
16
/**
17
 * Convenience function to quickly build a wikilink
18
 *
19
 * @author Andreas Gohr <[email protected]>
20
 * @param string  $id      id of the target page
21
 * @param string  $name    the name of the link, i.e. the text that is displayed
22
 * @param string|array  $search  search string(s) that shall be highlighted in the target page
23
 * @return string the HTML code of the link
24
 */
25
function html_wikilink($id,$name=null,$search=''){
26
    /** @var Doku_Renderer_xhtml $xhtml_renderer */
27
    static $xhtml_renderer = null;
28
    if(is_null($xhtml_renderer)){
29
        $xhtml_renderer = p_get_renderer('xhtml');
30
    }
31
32
    return $xhtml_renderer->internallink($id,$name,$search,true,'navigation');
33
}
34
35
/**
36
 * The loginform
37
 *
38
 * @author   Andreas Gohr <[email protected]>
39
 */
40
function html_login(){
41
    global $lang;
42
    global $conf;
43
    global $ID;
44
    global $INPUT;
45
46
    print p_locale_xhtml('login');
47
    print '<div class="centeralign">'.NL;
48
    $form = new Doku_Form(array('id' => 'dw__login'));
49
    $form->startFieldset($lang['btn_login']);
50
    $form->addHidden('id', $ID);
51
    $form->addHidden('do', 'login');
52
    $form->addElement(form_makeTextField('u', ((!$INPUT->bool('http_credentials')) ? $INPUT->str('u') : ''), $lang['user'], 'focus__this', 'block'));
53
    $form->addElement(form_makePasswordField('p', $lang['pass'], '', 'block'));
54
    if($conf['rememberme']) {
55
        $form->addElement(form_makeCheckboxField('r', '1', $lang['remember'], 'remember__me', 'simple'));
56
    }
57
    $form->addElement(form_makeButton('submit', '', $lang['btn_login']));
58
    $form->endFieldset();
59
60
    if(actionOK('register')){
61
        $form->addElement('<p>'.$lang['reghere'].': '.tpl_actionlink('register','','','',true).'</p>');
0 ignored issues
show
Deprecated Code introduced by
The function tpl_actionlink() has been deprecated with message: 2017-09-01 see devel:menus

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

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

Loading history...
62
    }
63
64
    if (actionOK('resendpwd')) {
65
        $form->addElement('<p>'.$lang['pwdforget'].': '.tpl_actionlink('resendpwd','','','',true).'</p>');
0 ignored issues
show
Deprecated Code introduced by
The function tpl_actionlink() has been deprecated with message: 2017-09-01 see devel:menus

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

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

Loading history...
66
    }
67
68
    html_form('login', $form);
69
    print '</div>'.NL;
70
}
71
72
73
/**
74
 * Denied page content
75
 *
76
 * @return string html
77
 */
78
function html_denied() {
79
    print p_locale_xhtml('denied');
80
81
    if(empty($_SERVER['REMOTE_USER'])){
82
        html_login();
83
    }
84
}
85
86
/**
87
 * inserts section edit buttons if wanted or removes the markers
88
 *
89
 * @author Andreas Gohr <[email protected]>
90
 *
91
 * @param string $text
92
 * @param bool   $show show section edit buttons?
93
 * @return string
94
 */
95
function html_secedit($text,$show=true){
96
    global $INFO;
97
98
    if(!$INFO['writable'] || !$show || $INFO['rev']){
99
        return preg_replace(SEC_EDIT_PATTERN,'',$text);
100
    }
101
102
    return preg_replace_callback(SEC_EDIT_PATTERN,
103
                'html_secedit_button', $text);
104
}
105
106
/**
107
 * prepares section edit button data for event triggering
108
 * used as a callback in html_secedit
109
 *
110
 * @author Andreas Gohr <[email protected]>
111
 *
112
 * @param array $matches matches with regexp
113
 * @return string
114
 * @triggers HTML_SECEDIT_BUTTON
115
 */
116
function html_secedit_button($matches){
117
    $data = array('secid'  => $matches['secid'],
118
        'target' => strtolower($matches['target']),
119
        'range'  => $matches['range']);
120
121
    if (!empty($matches['hid'])) {
122
        $data['hid'] = strtolower($matches['hid']);
123
    }
124
125
    if (!empty($matches['name'])) {
126
        $data['name'] = $matches['name'];
127
    }
128
129
    return trigger_event('HTML_SECEDIT_BUTTON', $data,
130
                         'html_secedit_get_button');
131
}
132
133
/**
134
 * prints a section editing button
135
 * used as default action form HTML_SECEDIT_BUTTON
136
 *
137
 * @author Adrian Lang <[email protected]>
138
 *
139
 * @param array $data name, section id and target
140
 * @return string html
141
 */
142
function html_secedit_get_button($data) {
143
    global $ID;
144
    global $INFO;
145
146
    if (!isset($data['name']) || $data['name'] === '') return '';
147
148
    $name = $data['name'];
149
    unset($data['name']);
150
151
    $secid = $data['secid'];
152
    unset($data['secid']);
153
154
    return "<div class='secedit editbutton_" . $data['target'] .
155
                       " editbutton_" . $secid . "'>" .
156
           html_btn('secedit', $ID, '',
157
                    array_merge(array('do'  => 'edit',
158
                                      'rev' => $INFO['lastmod'],
159
                                      'summary' => '['.$name.'] '), $data),
160
                    'post', $name) . '</div>';
161
}
162
163
/**
164
 * Just the back to top button (in its own form)
165
 *
166
 * @author Andreas Gohr <[email protected]>
167
 *
168
 * @return string html
169
 */
170
function html_topbtn(){
171
    global $lang;
172
173
    $ret  = '<a class="nolink" href="#dokuwiki__top"><button class="button" onclick="window.scrollTo(0, 0)" title="'.$lang['btn_top'].'">'.$lang['btn_top'].'</button></a>';
174
175
    return $ret;
176
}
177
178
/**
179
 * Displays a button (using its own form)
180
 * If tooltip exists, the access key tooltip is replaced.
181
 *
182
 * @author Andreas Gohr <[email protected]>
183
 *
184
 * @param string         $name
185
 * @param string         $id
186
 * @param string         $akey   access key
187
 * @param string[] $params key-value pairs added as hidden inputs
188
 * @param string         $method
189
 * @param string         $tooltip
190
 * @param bool|string    $label  label text, false: lookup btn_$name in localization
191
 * @param string         $svg (optional) svg code, inserted into the button
192
 * @return string
193
 */
194
function html_btn($name, $id, $akey, $params, $method='get', $tooltip='', $label=false, $svg=null){
195
    global $conf;
196
    global $lang;
197
198
    if (!$label)
199
        $label = $lang['btn_'.$name];
200
201
    $ret = '';
202
203
    //filter id (without urlencoding)
204
    $id = idfilter($id,false);
205
206
    //make nice URLs even for buttons
207
    if($conf['userewrite'] == 2){
208
        $script = DOKU_BASE.DOKU_SCRIPT.'/'.$id;
209
    }elseif($conf['userewrite']){
210
        $script = DOKU_BASE.$id;
211
    }else{
212
        $script = DOKU_BASE.DOKU_SCRIPT;
213
        $params['id'] = $id;
214
    }
215
216
    $ret .= '<form class="button btn_'.$name.'" method="'.$method.'" action="'.$script.'"><div class="no">';
217
218
    if(is_array($params)){
219
        foreach($params as $key => $val) {
220
            $ret .= '<input type="hidden" name="'.$key.'" ';
221
            $ret .= 'value="'.hsc($val).'" />';
222
        }
223
    }
224
225
    if ($tooltip!='') {
226
        $tip = hsc($tooltip);
227
    }else{
228
        $tip = hsc($label);
229
    }
230
231
    $ret .= '<button type="submit" ';
232
    if($akey){
233
        $tip .= ' ['.strtoupper($akey).']';
234
        $ret .= 'accesskey="'.$akey.'" ';
235
    }
236
    $ret .= 'title="'.$tip.'">';
237
    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...
238
        $ret .= '<span>' . hsc($label) . '</span>';
239
        $ret .= inlineSVG($svg);
240
    } else {
241
        $ret .= hsc($label);
242
    }
243
    $ret .= '</button>';
244
    $ret .= '</div></form>';
245
246
    return $ret;
247
}
248
/**
249
 * show a revision warning
250
 *
251
 * @author Szymon Olewniczak <[email protected]>
252
 */
253
function html_showrev() {
254
    print p_locale_xhtml('showrev');
255
}
256
257
/**
258
 * Show a wiki page
259
 *
260
 * @author Andreas Gohr <[email protected]>
261
 *
262
 * @param null|string $txt wiki text or null for showing $ID
263
 */
264
function html_show($txt=null){
265
    global $ID;
266
    global $REV;
267
    global $HIGH;
268
    global $INFO;
269
    global $DATE_AT;
270
    //disable section editing for old revisions or in preview
271
    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...
272
        $secedit = false;
273
    }else{
274
        $secedit = true;
275
    }
276
277
    if (!is_null($txt)){
278
        //PreviewHeader
279
        echo '<br id="scroll__here" />';
280
        echo p_locale_xhtml('preview');
281
        echo '<div class="preview"><div class="pad">';
282
        $html = html_secedit(p_render('xhtml',p_get_instructions($txt),$info),$secedit);
283
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
284
        echo $html;
285
        echo '<div class="clearer"></div>';
286
        echo '</div></div>';
287
288
    }else{
289
        if ($REV||$DATE_AT){
290
            $data = array('rev' => &$REV, 'date_at' => &$DATE_AT);
291
            trigger_event('HTML_SHOWREV_OUTPUT', $data, 'html_showrev');
292
        }
293
        $html = p_wiki_xhtml($ID,$REV,true,$DATE_AT);
294
        $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...
295
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
296
        $html = html_hilight($html,$HIGH);
297
        echo $html;
298
    }
299
}
300
301
/**
302
 * ask the user about how to handle an exisiting draft
303
 *
304
 * @author Andreas Gohr <[email protected]>
305
 */
306
function html_draft(){
307
    global $INFO;
308
    global $ID;
309
    global $lang;
310
    $draft = unserialize(io_readFile($INFO['draft'],false));
311
    $text  = cleanText(con($draft['prefix'],$draft['text'],$draft['suffix'],true));
312
313
    print p_locale_xhtml('draft');
314
    $form = new Doku_Form(array('id' => 'dw__editform'));
315
    $form->addHidden('id', $ID);
316
    $form->addHidden('date', $draft['date']);
317
    $form->addElement(form_makeWikiText($text, array('readonly'=>'readonly')));
318
    $form->addElement(form_makeOpenTag('div', array('id'=>'draft__status')));
319
    $form->addElement($lang['draftdate'].' '. dformat(filemtime($INFO['draft'])));
320
    $form->addElement(form_makeCloseTag('div'));
321
    $form->addElement(form_makeButton('submit', 'recover', $lang['btn_recover'], array('tabindex'=>'1')));
322
    $form->addElement(form_makeButton('submit', 'draftdel', $lang['btn_draftdel'], array('tabindex'=>'2')));
323
    $form->addElement(form_makeButton('submit', 'show', $lang['btn_cancel'], array('tabindex'=>'3')));
324
    html_form('draft', $form);
325
}
326
327
/**
328
 * Highlights searchqueries in HTML code
329
 *
330
 * @author Andreas Gohr <[email protected]>
331
 * @author Harry Fuecks <[email protected]>
332
 *
333
 * @param string $html
334
 * @param array|string $phrases
335
 * @return string html
336
 */
337
function html_hilight($html,$phrases){
338
    $phrases = (array) $phrases;
339
    $phrases = array_map('preg_quote_cb', $phrases);
340
    $phrases = array_map('ft_snippet_re_preprocess', $phrases);
341
    $phrases = array_filter($phrases);
342
    $regex = join('|',$phrases);
343
344
    if ($regex === '') return $html;
345
    if (!utf8_check($regex)) return $html;
346
    $html = @preg_replace_callback("/((<[^>]*)|$regex)/ui",'html_hilight_callback',$html);
347
    return $html;
348
}
349
350
/**
351
 * Callback used by html_hilight()
352
 *
353
 * @author Harry Fuecks <[email protected]>
354
 *
355
 * @param array $m matches
356
 * @return string html
357
 */
358
function html_hilight_callback($m) {
359
    $hlight = unslash($m[0]);
360
    if ( !isset($m[2])) {
361
        $hlight = '<span class="search_hit">'.$hlight.'</span>';
362
    }
363
    return $hlight;
364
}
365
366
/**
367
 * Run a search and display the result
368
 *
369
 * @author Andreas Gohr <[email protected]>
370
 */
371
function html_search(){
372
    global $QUERY, $ID;
373
    global $lang;
374
375
    $intro = p_locale_xhtml('searchpage');
376
    // allow use of placeholder in search intro
377
    $pagecreateinfo = (auth_quickaclcheck($ID) >= AUTH_CREATE) ? $lang['searchcreatepage'] : '';
378
    $intro = str_replace(
379
        array('@QUERY@', '@SEARCH@', '@CREATEPAGEINFO@'),
380
        array(hsc(rawurlencode($QUERY)), hsc($QUERY), $pagecreateinfo),
381
        $intro
382
    );
383
    echo $intro;
384
385
    //do quick pagesearch
386
    $data = ft_pageLookup($QUERY,true,useHeading('navigation'));
387
    if(count($data)){
388
        print '<div class="search_quickresult">';
389
        print '<h3>'.$lang['quickhits'].':</h3>';
390
        print '<ul class="search_quickhits">';
391
        foreach($data as $id => $title){
392
            print '<li> ';
393
            if (useHeading('navigation')) {
394
                $name = $title;
395
            }else{
396
                $ns = getNS($id);
397
                if($ns){
0 ignored issues
show
Bug Best Practice introduced by
The expression $ns of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
398
                    $name = shorten(noNS($id), ' ('.$ns.')',30);
399
                }else{
400
                    $name = $id;
401
                }
402
            }
403
            print html_wikilink(':'.$id,$name);
404
            print '</li> ';
405
        }
406
        print '</ul> ';
407
        //clear float (see http://www.complexspiral.com/publications/containing-floats/)
408
        print '<div class="clearer"></div>';
409
        print '</div>';
410
    }
411
412
    //do fulltext search
413
    $regex = array();
414
    $data = ft_pageSearch($QUERY,$regex);
415
    if(count($data)){
416
        print '<dl class="search_results">';
417
        $num = 1;
418
        foreach($data as $id => $cnt){
419
            print '<dt>';
420
            print html_wikilink(':'.$id,useHeading('navigation')?null:$id,$regex);
421
            if($cnt !== 0){
422
                print ': '.$cnt.' '.$lang['hits'].'';
423
            }
424
            print '</dt>';
425
            if($cnt !== 0){
426
                if($num < FT_SNIPPET_NUMBER){ // create snippets for the first number of matches only
427
                    print '<dd>'.ft_snippet($id,$regex).'</dd>';
428
                }
429
                $num++;
430
            }
431
        }
432
        print '</dl>';
433
    }else{
434
        print '<div class="nothing">'.$lang['nothingfound'].'</div>';
435
    }
436
}
437
438
/**
439
 * Display error on locked pages
440
 *
441
 * @author Andreas Gohr <[email protected]>
442
 */
443
function html_locked(){
444
    global $ID;
445
    global $conf;
446
    global $lang;
447
    global $INFO;
448
449
    $locktime = filemtime(wikiLockFN($ID));
450
    $expire = dformat($locktime + $conf['locktime']);
451
    $min    = round(($conf['locktime'] - (time() - $locktime) )/60);
452
453
    print p_locale_xhtml('locked');
454
    print '<ul>';
455
    print '<li><div class="li"><strong>'.$lang['lockedby'].'</strong> '.editorinfo($INFO['locked']).'</div></li>';
456
    print '<li><div class="li"><strong>'.$lang['lockexpire'].'</strong> '.$expire.' ('.$min.' min)</div></li>';
457
    print '</ul>';
458
}
459
460
/**
461
 * list old revisions
462
 *
463
 * @author Andreas Gohr <[email protected]>
464
 * @author Ben Coburn <[email protected]>
465
 * @author Kate Arzamastseva <[email protected]>
466
 *
467
 * @param int $first skip the first n changelog lines
468
 * @param bool|string $media_id id of media, or false for current page
469
 */
470
function html_revisions($first=0, $media_id = false){
471
    global $ID;
472
    global $INFO;
473
    global $conf;
474
    global $lang;
475
    $id = $ID;
476
    if ($media_id) {
477
        $id = $media_id;
478
        $changelog = new MediaChangeLog($id);
479
    } else {
480
        $changelog = new PageChangeLog($id);
481
    }
482
483
    /* we need to get one additional log entry to be able to
484
     * decide if this is the last page or is there another one.
485
     * see html_recent()
486
     */
487
488
    $revisions = $changelog->getRevisions($first, $conf['recent']+1);
489
490
    if(count($revisions)==0 && $first!=0){
491
        $first=0;
492
        $revisions = $changelog->getRevisions($first, $conf['recent']+1);
493
    }
494
    $hasNext = false;
495
    if (count($revisions)>$conf['recent']) {
496
        $hasNext = true;
497
        array_pop($revisions); // remove extra log entry
498
    }
499
500
    if (!$media_id) print p_locale_xhtml('revisions');
501
502
    $params = array('id' => 'page__revisions', 'class' => 'changes');
503
    if($media_id) {
504
        $params['action'] = media_managerURL(array('image' => $media_id), '&');
505
    }
506
507
    if(!$media_id) {
508
        $exists = $INFO['exists'];
509
        $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
510
        if(!$display_name) {
511
            $display_name = $id;
512
        }
513
    } else {
514
        $exists = file_exists(mediaFN($id));
515
        $display_name = $id;
516
    }
517
518
    $form = new Doku_Form($params);
519
    $form->addElement(form_makeOpenTag('ul'));
520
521
    if($exists && $first == 0) {
522
        $minor = false;
523
        if($media_id) {
524
            $date = dformat(@filemtime(mediaFN($id)));
525
            $href = media_managerURL(array('image' => $id, 'tab_details' => 'view'), '&');
526
527
            $changelog->setChunkSize(1024);
528
            $revinfo = $changelog->getRevisionInfo(@filemtime(fullpath(mediaFN($id))));
529
530
            $summary = $revinfo['sum'];
531
            if($revinfo['user']) {
532
                $editor = $revinfo['user'];
533
            } else {
534
                $editor = $revinfo['ip'];
535
            }
536
            $sizechange = $revinfo['sizechange'];
537
        } else {
538
            $date = dformat($INFO['lastmod']);
539
            if(isset($INFO['meta']) && isset($INFO['meta']['last_change'])) {
540
                if($INFO['meta']['last_change']['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
541
                    $minor = true;
542
                }
543
                if(isset($INFO['meta']['last_change']['sizechange'])) {
544
                    $sizechange = $INFO['meta']['last_change']['sizechange'];
545
                } else {
546
                    $sizechange = null;
547
                }
548
            }
549
            $pagelog = new PageChangeLog($ID);
550
            $latestrev = $pagelog->getRevisions(-1, 1);
551
            $latestrev = array_pop($latestrev);
552
            $href = wl($id,"rev=$latestrev",false,'&');
553
            $summary = $INFO['sum'];
554
            $editor = $INFO['editor'];
555
        }
556
557
        $form->addElement(form_makeOpenTag('li', array('class' => ($minor ? 'minor' : ''))));
558
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
559
        $form->addElement(form_makeTag('input', array(
560
                        'type' => 'checkbox',
561
                        'name' => 'rev2[]',
562
                        'value' => 'current')));
563
564
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
565
        $form->addElement($date);
566
        $form->addElement(form_makeCloseTag('span'));
567
568
        $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
569
570
        $form->addElement(form_makeOpenTag('a', array(
571
                        'class' => 'wikilink1',
572
                        'href'  => $href)));
573
        $form->addElement($display_name);
574
        $form->addElement(form_makeCloseTag('a'));
575
576
        if ($media_id) $form->addElement(form_makeOpenTag('div'));
577
578
        if($summary) {
579
            $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
580
            if(!$media_id) $form->addElement(' – ');
581
            $form->addElement('<bdi>' . hsc($summary) . '</bdi>');
582
            $form->addElement(form_makeCloseTag('span'));
583
        }
584
585
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
586
        $form->addElement((empty($editor))?('('.$lang['external_edit'].')'):'<bdi>'.editorinfo($editor).'</bdi>');
587
        $form->addElement(form_makeCloseTag('span'));
588
589
        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...
590
591
        $form->addElement('('.$lang['current'].')');
592
593
        if ($media_id) $form->addElement(form_makeCloseTag('div'));
594
595
        $form->addElement(form_makeCloseTag('div'));
596
        $form->addElement(form_makeCloseTag('li'));
597
    }
598
599
    foreach($revisions as $rev) {
600
        $date = dformat($rev);
601
        $info = $changelog->getRevisionInfo($rev);
602
        if($media_id) {
603
            $exists = file_exists(mediaFN($id, $rev));
604
        } else {
605
            $exists = page_exists($id, $rev);
606
        }
607
608
        $class = '';
609
        if($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
610
            $class = 'minor';
611
        }
612
        $form->addElement(form_makeOpenTag('li', array('class' => $class)));
613
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
614
        if($exists){
615
            $form->addElement(form_makeTag('input', array(
616
                            'type' => 'checkbox',
617
                            'name' => 'rev2[]',
618
                            'value' => $rev)));
619
        }else{
620
            $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
621
        }
622
623
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
624
        $form->addElement($date);
625
        $form->addElement(form_makeCloseTag('span'));
626
627
        if($exists){
628
            if (!$media_id) {
629
                $href = wl($id,"rev=$rev,do=diff", false, '&');
630
            } else {
631
                $href = media_managerURL(array('image' => $id, 'rev' => $rev, 'mediado' => 'diff'), '&');
632
            }
633
            $form->addElement(form_makeOpenTag('a', array(
634
                            'class' => 'diff_link',
635
                            'href' => $href)));
636
            $form->addElement(form_makeTag('img', array(
637
                            'src'    => DOKU_BASE.'lib/images/diff.png',
638
                            'width'  => 15,
639
                            'height' => 11,
640
                            'title'  => $lang['diff'],
641
                            'alt'    => $lang['diff'])));
642
            $form->addElement(form_makeCloseTag('a'));
643
644
            if (!$media_id) {
645
                $href = wl($id,"rev=$rev",false,'&');
646
            } else {
647
                $href = media_managerURL(array('image' => $id, 'tab_details' => 'view', 'rev' => $rev), '&');
648
            }
649
            $form->addElement(form_makeOpenTag('a', array(
650
                            'class' => 'wikilink1',
651
                            'href' => $href)));
652
            $form->addElement($display_name);
653
            $form->addElement(form_makeCloseTag('a'));
654
        }else{
655
            $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
656
            $form->addElement($display_name);
657
        }
658
659
        if ($media_id) $form->addElement(form_makeOpenTag('div'));
660
661
        if ($info['sum']) {
662
            $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
663
            if(!$media_id) $form->addElement(' – ');
664
            $form->addElement('<bdi>'.hsc($info['sum']).'</bdi>');
665
            $form->addElement(form_makeCloseTag('span'));
666
        }
667
668
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
669
        if($info['user']){
670
            $form->addElement('<bdi>'.editorinfo($info['user']).'</bdi>');
671
            if(auth_ismanager()){
672
                $form->addElement(' <bdo dir="ltr">('.$info['ip'].')</bdo>');
673
            }
674
        }else{
675
            $form->addElement('<bdo dir="ltr">'.$info['ip'].'</bdo>');
676
        }
677
        $form->addElement(form_makeCloseTag('span'));
678
679
        html_sizechange($info['sizechange'], $form);
680
681
        if ($media_id) $form->addElement(form_makeCloseTag('div'));
682
683
        $form->addElement(form_makeCloseTag('div'));
684
        $form->addElement(form_makeCloseTag('li'));
685
    }
686
    $form->addElement(form_makeCloseTag('ul'));
687
    if (!$media_id) {
688
        $form->addElement(form_makeButton('submit', 'diff', $lang['diff2']));
689
    } else {
690
        $form->addHidden('mediado', 'diff');
691
        $form->addElement(form_makeButton('submit', '', $lang['diff2']));
692
    }
693
    html_form('revisions', $form);
694
695
    print '<div class="pagenav">';
696
    $last = $first + $conf['recent'];
697
    if ($first > 0) {
698
        $first -= $conf['recent'];
699
        if ($first < 0) $first = 0;
700
        print '<div class="pagenav-prev">';
701
        if ($media_id) {
702
            print html_btn('newer',$media_id,"p",media_managerURL(array('first' => $first), '&amp;', false, true));
703
        } else {
704
            print html_btn('newer',$id,"p",array('do' => 'revisions', 'first' => $first));
705
        }
706
        print '</div>';
707
    }
708
    if ($hasNext) {
709
        print '<div class="pagenav-next">';
710
        if ($media_id) {
711
            print html_btn('older',$media_id,"n",media_managerURL(array('first' => $last), '&amp;', false, true));
712
        } else {
713
            print html_btn('older',$id,"n",array('do' => 'revisions', 'first' => $last));
714
        }
715
        print '</div>';
716
    }
717
    print '</div>';
718
719
}
720
721
/**
722
 * display recent changes
723
 *
724
 * @author Andreas Gohr <[email protected]>
725
 * @author Matthias Grimm <[email protected]>
726
 * @author Ben Coburn <[email protected]>
727
 * @author Kate Arzamastseva <[email protected]>
728
 *
729
 * @param int $first
730
 * @param string $show_changes
731
 */
732
function html_recent($first = 0, $show_changes = 'both') {
733
    global $conf;
734
    global $lang;
735
    global $ID;
736
    /* we need to get one additionally log entry to be able to
737
     * decide if this is the last page or is there another one.
738
     * This is the cheapest solution to get this information.
739
     */
740
    $flags = 0;
741
    if($show_changes == 'mediafiles' && $conf['mediarevisions']) {
742
        $flags = RECENTS_MEDIA_CHANGES;
743
    } elseif($show_changes == 'pages') {
744
        $flags = 0;
745
    } elseif($conf['mediarevisions']) {
746
        $show_changes = 'both';
747
        $flags = RECENTS_MEDIA_PAGES_MIXED;
748
    }
749
750
    $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...
751
    if(count($recents) == 0 && $first != 0) {
752
        $first = 0;
753
        $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...
754
    }
755
    $hasNext = false;
756
    if(count($recents) > $conf['recent']) {
757
        $hasNext = true;
758
        array_pop($recents); // remove extra log entry
759
    }
760
761
    print p_locale_xhtml('recent');
762
763
    if(getNS($ID) != '') {
764
        print '<div class="level1"><p>' . sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent')) . '</p></div>';
765
    }
766
767
    $form = new Doku_Form(array('id' => 'dw__recent', 'method' => 'GET', 'class' => 'changes'));
768
    $form->addHidden('sectok', null);
769
    $form->addHidden('do', 'recent');
770
    $form->addHidden('id', $ID);
771
772
    if($conf['mediarevisions']) {
773
        $form->addElement('<div class="changeType">');
774
        $form->addElement(form_makeListboxField(
775
                    'show_changes',
776
                    array(
777
                        'pages'      => $lang['pages_changes'],
778
                        'mediafiles' => $lang['media_changes'],
779
                        'both'       => $lang['both_changes']
780
                    ),
781
                    $show_changes,
782
                    $lang['changes_type'],
783
                    '', '',
784
                    array('class' => 'quickselect')));
785
786
        $form->addElement(form_makeButton('submit', 'recent', $lang['btn_apply']));
787
        $form->addElement('</div>');
788
    }
789
790
    $form->addElement(form_makeOpenTag('ul'));
791
792
    foreach($recents as $recent) {
793
        $date = dformat($recent['date']);
794
795
        $class = '';
796
        if($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
797
            $class = 'minor';
798
        }
799
        $form->addElement(form_makeOpenTag('li', array('class' => $class)));
800
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
801
802
        if(!empty($recent['media'])) {
803
            $form->addElement(media_printicon($recent['id']));
804
        } else {
805
            $icon = DOKU_BASE . 'lib/images/fileicons/file.png';
806
            $form->addElement('<img src="' . $icon . '" alt="' . $recent['id'] . '" class="icon" />');
807
        }
808
809
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
810
        $form->addElement($date);
811
        $form->addElement(form_makeCloseTag('span'));
812
813
        $diff = false;
814
        $href = '';
815
816
        if(!empty($recent['media'])) {
817
            $changelog = new MediaChangeLog($recent['id']);
818
            $revs = $changelog->getRevisions(0, 1);
819
            $diff = (count($revs) && file_exists(mediaFN($recent['id'])));
820
            if($diff) {
821
                $href = media_managerURL(array(
822
                                            'tab_details' => 'history',
823
                                            'mediado' => 'diff',
824
                                            'image' => $recent['id'],
825
                                            'ns' => getNS($recent['id'])
826
                                        ), '&');
827
            }
828
        } else {
829
            $href = wl($recent['id'], "do=diff", false, '&');
830
        }
831
832
        if(!empty($recent['media']) && !$diff) {
833
            $form->addElement('<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />');
834
        } else {
835
            $form->addElement(form_makeOpenTag('a', array('class' => 'diff_link', 'href' => $href)));
836
            $form->addElement(form_makeTag('img', array(
837
                            'src'    => DOKU_BASE . 'lib/images/diff.png',
838
                            'width'  => 15,
839
                            'height' => 11,
840
                            'title'  => $lang['diff'],
841
                            'alt'    => $lang['diff']
842
                        )));
843
            $form->addElement(form_makeCloseTag('a'));
844
        }
845
846
        if(!empty($recent['media'])) {
847
            $href = media_managerURL(array('tab_details' => 'history', 'image' => $recent['id'], 'ns' => getNS($recent['id'])), '&');
848
        } else {
849
            $href = wl($recent['id'], "do=revisions", false, '&');
850
        }
851
        $form->addElement(form_makeOpenTag('a', array(
852
                        'class' => 'revisions_link',
853
                        'href'  => $href)));
854
        $form->addElement(form_makeTag('img', array(
855
                        'src'    => DOKU_BASE . 'lib/images/history.png',
856
                        'width'  => 12,
857
                        'height' => 14,
858
                        'title'  => $lang['btn_revs'],
859
                        'alt'    => $lang['btn_revs']
860
                    )));
861
        $form->addElement(form_makeCloseTag('a'));
862
863
        if(!empty($recent['media'])) {
864
            $href = media_managerURL(array('tab_details' => 'view', 'image' => $recent['id'], 'ns' => getNS($recent['id'])), '&');
865
            $class = file_exists(mediaFN($recent['id'])) ? 'wikilink1' : 'wikilink2';
866
            $form->addElement(form_makeOpenTag('a', array(
867
                        'class' => $class,
868
                        'href'  => $href)));
869
            $form->addElement($recent['id']);
870
            $form->addElement(form_makeCloseTag('a'));
871
        } else {
872
            $form->addElement(html_wikilink(':' . $recent['id'], useHeading('navigation') ? null : $recent['id']));
873
        }
874
        $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
875
        $form->addElement(' – ' . hsc($recent['sum']));
876
        $form->addElement(form_makeCloseTag('span'));
877
878
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
879
        if($recent['user']) {
880
            $form->addElement('<bdi>' . editorinfo($recent['user']) . '</bdi>');
881
            if(auth_ismanager()) {
882
                $form->addElement(' <bdo dir="ltr">(' . $recent['ip'] . ')</bdo>');
883
            }
884
        } else {
885
            $form->addElement('<bdo dir="ltr">' . $recent['ip'] . '</bdo>');
886
        }
887
        $form->addElement(form_makeCloseTag('span'));
888
889
        html_sizechange($recent['sizechange'], $form);
890
891
        $form->addElement(form_makeCloseTag('div'));
892
        $form->addElement(form_makeCloseTag('li'));
893
    }
894
    $form->addElement(form_makeCloseTag('ul'));
895
896
    $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav')));
897
    $last = $first + $conf['recent'];
898
    if($first > 0) {
899
        $first -= $conf['recent'];
900
        if($first < 0) $first = 0;
901
        $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-prev')));
902
        $form->addElement(form_makeOpenTag('button', array(
903
                        'type'      => 'submit',
904
                        'name'      => 'first[' . $first . ']',
905
                        'accesskey' => 'n',
906
                        'title'     => $lang['btn_newer'] . ' [N]',
907
                        'class'     => 'button show'
908
                    )));
909
        $form->addElement($lang['btn_newer']);
910
        $form->addElement(form_makeCloseTag('button'));
911
        $form->addElement(form_makeCloseTag('div'));
912
    }
913
    if($hasNext) {
914
        $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-next')));
915
        $form->addElement(form_makeOpenTag('button', array(
916
                        'type'      => 'submit',
917
                        'name'      => 'first[' . $last . ']',
918
                        'accesskey' => 'p',
919
                        'title'     => $lang['btn_older'] . ' [P]',
920
                        'class'     => 'button show'
921
                    )));
922
        $form->addElement($lang['btn_older']);
923
        $form->addElement(form_makeCloseTag('button'));
924
        $form->addElement(form_makeCloseTag('div'));
925
    }
926
    $form->addElement(form_makeCloseTag('div'));
927
    html_form('recent', $form);
928
}
929
930
/**
931
 * Display page index
932
 *
933
 * @author Andreas Gohr <[email protected]>
934
 *
935
 * @param string $ns
936
 */
937
function html_index($ns){
938
    global $conf;
939
    global $ID;
940
    $ns  = cleanID($ns);
941
    if(empty($ns)){
942
        $ns = getNS($ID);
943
        if($ns === false) $ns ='';
944
    }
945
    $ns  = utf8_encodeFN(str_replace(':','/',$ns));
946
947
    echo p_locale_xhtml('index');
948
    echo '<div id="index__tree" class="index__tree">';
949
950
    $data = array();
951
    search($data,$conf['datadir'],'search_index',array('ns' => $ns));
952
    echo html_buildlist($data,'idx','html_list_index','html_li_index');
953
954
    echo '</div>';
955
}
956
957
/**
958
 * Index item formatter
959
 *
960
 * User function for html_buildlist()
961
 *
962
 * @author Andreas Gohr <[email protected]>
963
 *
964
 * @param array $item
965
 * @return string
966
 */
967
function html_list_index($item){
968
    global $ID, $conf;
969
970
    // prevent searchbots needlessly following links
971
    $nofollow = ($ID != $conf['start'] || $conf['sitemap']) ? ' rel="nofollow"' : '';
972
973
    $ret = '';
974
    $base = ':'.$item['id'];
975
    $base = substr($base,strrpos($base,':')+1);
976
    if($item['type']=='d'){
977
        // FS#2766, no need for search bots to follow namespace links in the index
978
        $ret .= '<a href="'.wl($ID,'idx='.rawurlencode($item['id'])).'" title="' . $item['id'] . '" class="idx_dir"' . $nofollow . '><strong>';
979
        $ret .= $base;
980
        $ret .= '</strong></a>';
981
    }else{
982
        // default is noNSorNS($id), but we want noNS($id) when useheading is off FS#2605
983
        $ret .= html_wikilink(':'.$item['id'], useHeading('navigation') ? null : noNS($item['id']));
984
    }
985
    return $ret;
986
}
987
988
/**
989
 * Index List item
990
 *
991
 * This user function is used in html_buildlist to build the
992
 * <li> tags for namespaces when displaying the page index
993
 * it gives different classes to opened or closed "folders"
994
 *
995
 * @author Andreas Gohr <[email protected]>
996
 *
997
 * @param array $item
998
 * @return string html
999
 */
1000
function html_li_index($item){
1001
    global $INFO;
1002
    global $ACT;
1003
1004
    $class = '';
1005
    $id = '';
1006
1007
    if($item['type'] == "f"){
1008
        // scroll to the current item
1009
        if($item['id'] == $INFO['id'] && $ACT == 'index') {
1010
            $id = ' id="scroll__here"';
1011
            $class = ' bounce';
1012
        }
1013
        return '<li class="level'.$item['level'].$class.'" '.$id.'>';
1014
    }elseif($item['open']){
1015
        return '<li class="open">';
1016
    }else{
1017
        return '<li class="closed">';
1018
    }
1019
}
1020
1021
/**
1022
 * Default List item
1023
 *
1024
 * @author Andreas Gohr <[email protected]>
1025
 *
1026
 * @param array $item
1027
 * @return string html
1028
 */
1029
function html_li_default($item){
1030
    return '<li class="level'.$item['level'].'">';
1031
}
1032
1033
/**
1034
 * Build an unordered list
1035
 *
1036
 * Build an unordered list from the given $data array
1037
 * Each item in the array has to have a 'level' property
1038
 * the item itself gets printed by the given $func user
1039
 * function. The second and optional function is used to
1040
 * print the <li> tag. Both user function need to accept
1041
 * a single item.
1042
 *
1043
 * Both user functions can be given as array to point to
1044
 * a member of an object.
1045
 *
1046
 * @author Andreas Gohr <[email protected]>
1047
 *
1048
 * @param array    $data  array with item arrays
1049
 * @param string   $class class of ul wrapper
1050
 * @param callable $func  callback to print an list item
1051
 * @param callable $lifunc callback to the opening li tag
1052
 * @param bool     $forcewrapper Trigger building a wrapper ul if the first level is
1053
 *                               0 (we have a root object) or 1 (just the root content)
1054
 * @return string html of an unordered list
1055
 */
1056
function html_buildlist($data,$class,$func,$lifunc='html_li_default',$forcewrapper=false){
1057
    if (count($data) === 0) {
1058
        return '';
1059
    }
1060
1061
    $firstElement = reset($data);
1062
    $start_level = $firstElement['level'];
1063
    $level = $start_level;
1064
    $ret   = '';
1065
    $open  = 0;
1066
1067
    foreach ($data as $item){
1068
1069
        if( $item['level'] > $level ){
1070
            //open new list
1071
            for($i=0; $i<($item['level'] - $level); $i++){
1072
                if ($i) $ret .= "<li class=\"clear\">";
1073
                $ret .= "\n<ul class=\"$class\">\n";
1074
                $open++;
1075
            }
1076
            $level = $item['level'];
1077
1078
        }elseif( $item['level'] < $level ){
1079
            //close last item
1080
            $ret .= "</li>\n";
1081
            while( $level > $item['level'] && $open > 0 ){
1082
                //close higher lists
1083
                $ret .= "</ul>\n</li>\n";
1084
                $level--;
1085
                $open--;
1086
            }
1087
        } elseif ($ret !== '') {
1088
            //close previous item
1089
            $ret .= "</li>\n";
1090
        }
1091
1092
        //print item
1093
        $ret .= call_user_func($lifunc,$item);
1094
        $ret .= '<div class="li">';
1095
1096
        $ret .= call_user_func($func,$item);
1097
        $ret .= '</div>';
1098
    }
1099
1100
    //close remaining items and lists
1101
    $ret .= "</li>\n";
1102
    while($open-- > 0) {
1103
        $ret .= "</ul></li>\n";
1104
    }
1105
1106
    if ($forcewrapper || $start_level < 2) {
1107
        // Trigger building a wrapper ul if the first level is
1108
        // 0 (we have a root object) or 1 (just the root content)
1109
        $ret = "\n<ul class=\"$class\">\n".$ret."</ul>\n";
1110
    }
1111
1112
    return $ret;
1113
}
1114
1115
/**
1116
 * display backlinks
1117
 *
1118
 * @author Andreas Gohr <[email protected]>
1119
 * @author Michael Klier <[email protected]>
1120
 */
1121
function html_backlinks(){
1122
    global $ID;
1123
    global $lang;
1124
1125
    print p_locale_xhtml('backlinks');
1126
1127
    $data = ft_backlinks($ID);
1128
1129
    if(!empty($data)) {
1130
        print '<ul class="idx">';
1131
        foreach($data as $blink){
1132
            print '<li><div class="li">';
1133
            print html_wikilink(':'.$blink,useHeading('navigation')?null:$blink);
1134
            print '</div></li>';
1135
        }
1136
        print '</ul>';
1137
    } else {
1138
        print '<div class="level1"><p>' . $lang['nothingfound'] . '</p></div>';
1139
    }
1140
}
1141
1142
/**
1143
 * Get header of diff HTML
1144
 *
1145
 * @param string $l_rev   Left revisions
1146
 * @param string $r_rev   Right revision
1147
 * @param string $id      Page id, if null $ID is used
1148
 * @param bool   $media   If it is for media files
1149
 * @param bool   $inline  Return the header on a single line
1150
 * @return string[] HTML snippets for diff header
1151
 */
1152
function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false) {
1153
    global $lang;
1154
    if ($id === null) {
1155
        global $ID;
1156
        $id = $ID;
1157
    }
1158
    $head_separator = $inline ? ' ' : '<br />';
1159
    $media_or_wikiFN = $media ? 'mediaFN' : 'wikiFN';
1160
    $ml_or_wl = $media ? 'ml' : 'wl';
1161
    $l_minor = $r_minor = '';
1162
1163
    if($media) {
1164
        $changelog = new MediaChangeLog($id);
1165
    } else {
1166
        $changelog = new PageChangeLog($id);
1167
    }
1168
    if(!$l_rev){
1169
        $l_head = '&mdash;';
1170
    }else{
1171
        $l_info   = $changelog->getRevisionInfo($l_rev);
1172
        if($l_info['user']){
1173
            $l_user = '<bdi>'.editorinfo($l_info['user']).'</bdi>';
1174
            if(auth_ismanager()) $l_user .= ' <bdo dir="ltr">('.$l_info['ip'].')</bdo>';
1175
        } else {
1176
            $l_user = '<bdo dir="ltr">'.$l_info['ip'].'</bdo>';
1177
        }
1178
        $l_user  = '<span class="user">'.$l_user.'</span>';
1179
        $l_sum   = ($l_info['sum']) ? '<span class="sum"><bdi>'.hsc($l_info['sum']).'</bdi></span>' : '';
1180
        if ($l_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $l_minor = 'class="minor"';
1181
1182
        $l_head_title = ($media) ? dformat($l_rev) : $id.' ['.dformat($l_rev).']';
1183
        $l_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$l_rev").'">'.
1184
        $l_head_title.'</a></bdi>'.
1185
        $head_separator.$l_user.' '.$l_sum;
1186
    }
1187
1188
    if($r_rev){
1189
        $r_info   = $changelog->getRevisionInfo($r_rev);
1190
        if($r_info['user']){
1191
            $r_user = '<bdi>'.editorinfo($r_info['user']).'</bdi>';
1192
            if(auth_ismanager()) $r_user .= ' <bdo dir="ltr">('.$r_info['ip'].')</bdo>';
1193
        } else {
1194
            $r_user = '<bdo dir="ltr">'.$r_info['ip'].'</bdo>';
1195
        }
1196
        $r_user = '<span class="user">'.$r_user.'</span>';
1197
        $r_sum  = ($r_info['sum']) ? '<span class="sum"><bdi>'.hsc($r_info['sum']).'</bdi></span>' : '';
1198
        if ($r_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
1199
1200
        $r_head_title = ($media) ? dformat($r_rev) : $id.' ['.dformat($r_rev).']';
1201
        $r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$r_rev").'">'.
1202
        $r_head_title.'</a></bdi>'.
1203
        $head_separator.$r_user.' '.$r_sum;
1204
    }elseif($_rev = @filemtime($media_or_wikiFN($id))){
1205
        $_info   = $changelog->getRevisionInfo($_rev);
1206
        if($_info['user']){
1207
            $_user = '<bdi>'.editorinfo($_info['user']).'</bdi>';
1208
            if(auth_ismanager()) $_user .= ' <bdo dir="ltr">('.$_info['ip'].')</bdo>';
1209
        } else {
1210
            $_user = '<bdo dir="ltr">'.$_info['ip'].'</bdo>';
1211
        }
1212
        $_user = '<span class="user">'.$_user.'</span>';
1213
        $_sum  = ($_info['sum']) ? '<span class="sum"><bdi>'.hsc($_info['sum']).'</span></bdi>' : '';
1214
        if ($_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
1215
1216
        $r_head_title = ($media) ? dformat($_rev) : $id.' ['.dformat($_rev).']';
1217
        $r_head  = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id).'">'.
1218
        $r_head_title.'</a></bdi> '.
1219
        '('.$lang['current'].')'.
1220
        $head_separator.$_user.' '.$_sum;
1221
    }else{
1222
        $r_head = '&mdash; ('.$lang['current'].')';
1223
    }
1224
1225
    return array($l_head, $r_head, $l_minor, $r_minor);
1226
}
1227
1228
/**
1229
 * Show diff
1230
 * between current page version and provided $text
1231
 * or between the revisions provided via GET or POST
1232
 *
1233
 * @author Andreas Gohr <[email protected]>
1234
 * @param  string $text  when non-empty: compare with this text with most current version
1235
 * @param  bool   $intro display the intro text
1236
 * @param  string $type  type of the diff (inline or sidebyside)
1237
 */
1238
function html_diff($text = '', $intro = true, $type = null) {
1239
    global $ID;
1240
    global $REV;
1241
    global $lang;
1242
    global $INPUT;
1243
    global $INFO;
1244
    $pagelog = new PageChangeLog($ID);
1245
1246
    /*
1247
     * Determine diff type
1248
     */
1249
    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...
1250
        $type = $INPUT->str('difftype');
1251
        if(empty($type)) {
1252
            $type = get_doku_pref('difftype', $type);
1253
            if(empty($type) && $INFO['ismobile']) {
1254
                $type = 'inline';
1255
            }
1256
        }
1257
    }
1258
    if($type != 'inline') $type = 'sidebyside';
1259
1260
    /*
1261
     * Determine requested revision(s)
1262
     */
1263
    // we're trying to be clever here, revisions to compare can be either
1264
    // given as rev and rev2 parameters, with rev2 being optional. Or in an
1265
    // array in rev2.
1266
    $rev1 = $REV;
1267
1268
    $rev2 = $INPUT->ref('rev2');
1269
    if(is_array($rev2)) {
1270
        $rev1 = (int) $rev2[0];
1271
        $rev2 = (int) $rev2[1];
1272
1273
        if(!$rev1) {
1274
            $rev1 = $rev2;
1275
            unset($rev2);
1276
        }
1277
    } else {
1278
        $rev2 = $INPUT->int('rev2');
1279
    }
1280
1281
    /*
1282
     * Determine left and right revision, its texts and the header
1283
     */
1284
    $r_minor = '';
1285
    $l_minor = '';
1286
1287
    if($text) { // compare text to the most current revision
1288
        $l_rev = '';
1289
        $l_text = rawWiki($ID, '');
1290
        $l_head = '<a class="wikilink1" href="' . wl($ID) . '">' .
1291
            $ID . ' ' . dformat((int) @filemtime(wikiFN($ID))) . '</a> ' .
1292
            $lang['current'];
1293
1294
        $r_rev = '';
1295
        $r_text = cleanText($text);
1296
        $r_head = $lang['yours'];
1297
    } else {
1298
        if($rev1 && isset($rev2) && $rev2) { // two specific revisions wanted
1299
            // make sure order is correct (older on the left)
1300
            if($rev1 < $rev2) {
1301
                $l_rev = $rev1;
1302
                $r_rev = $rev2;
1303
            } else {
1304
                $l_rev = $rev2;
1305
                $r_rev = $rev1;
1306
            }
1307
        } elseif($rev1) { // single revision given, compare to current
1308
            $r_rev = '';
1309
            $l_rev = $rev1;
1310
        } else { // no revision was given, compare previous to current
1311
            $r_rev = '';
1312
            $revs = $pagelog->getRevisions(0, 1);
1313
            $l_rev = $revs[0];
1314
            $REV = $l_rev; // store revision back in $REV
1315
        }
1316
1317
        // when both revisions are empty then the page was created just now
1318
        if(!$l_rev && !$r_rev) {
1319
            $l_text = '';
1320
        } else {
1321
            $l_text = rawWiki($ID, $l_rev);
1322
        }
1323
        $r_text = rawWiki($ID, $r_rev);
1324
1325
        list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev, null, false, $type == 'inline');
1326
    }
1327
1328
    /*
1329
     * Build navigation
1330
     */
1331
    $l_nav = '';
1332
    $r_nav = '';
1333
    if(!$text) {
1334
        list($l_nav, $r_nav) = html_diff_navigation($pagelog, $type, $l_rev, $r_rev);
1335
    }
1336
    /*
1337
     * Create diff object and the formatter
1338
     */
1339
    $diff = new Diff(explode("\n", $l_text), explode("\n", $r_text));
1340
1341
    if($type == 'inline') {
1342
        $diffformatter = new InlineDiffFormatter();
1343
    } else {
1344
        $diffformatter = new TableDiffFormatter();
1345
    }
1346
    /*
1347
     * Display intro
1348
     */
1349
    if($intro) print p_locale_xhtml('diff');
1350
1351
    /*
1352
     * Display type and exact reference
1353
     */
1354
    if(!$text) {
1355
        ptln('<div class="diffoptions group">');
1356
1357
1358
        $form = new Doku_Form(array('action' => wl()));
1359
        $form->addHidden('id', $ID);
1360
        $form->addHidden('rev2[0]', $l_rev);
1361
        $form->addHidden('rev2[1]', $r_rev);
1362
        $form->addHidden('do', 'diff');
1363
        $form->addElement(
1364
             form_makeListboxField(
1365
                 'difftype',
1366
                 array(
1367
                     'sidebyside' => $lang['diff_side'],
1368
                     'inline' => $lang['diff_inline']
1369
                 ),
1370
                 $type,
1371
                 $lang['diff_type'],
1372
                 '', '',
1373
                 array('class' => 'quickselect')
1374
             )
1375
        );
1376
        $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1377
        $form->printForm();
1378
1379
        ptln('<p>');
1380
        // link to exactly this view FS#2835
1381
        echo html_diff_navigationlink($type, 'difflink', $l_rev, $r_rev ? $r_rev : $INFO['currentrev']);
1382
        ptln('</p>');
1383
1384
        ptln('</div>'); // .diffoptions
1385
    }
1386
1387
    /*
1388
     * Display diff view table
1389
     */
1390
    ?>
1391
    <div class="table">
1392
    <table class="diff diff_<?php echo $type ?>">
1393
1394
        <?php
1395
        //navigation and header
1396
        if($type == 'inline') {
1397
            if(!$text) { ?>
1398
                <tr>
1399
                    <td class="diff-lineheader">-</td>
1400
                    <td class="diffnav"><?php echo $l_nav ?></td>
1401
                </tr>
1402
                <tr>
1403
                    <th class="diff-lineheader">-</th>
1404
                    <th <?php echo $l_minor ?>>
1405
                        <?php echo $l_head ?>
1406
                    </th>
1407
                </tr>
1408
            <?php } ?>
1409
            <tr>
1410
                <td class="diff-lineheader">+</td>
1411
                <td class="diffnav"><?php echo $r_nav ?></td>
1412
            </tr>
1413
            <tr>
1414
                <th class="diff-lineheader">+</th>
1415
                <th <?php echo $r_minor ?>>
1416
                    <?php echo $r_head ?>
1417
                </th>
1418
            </tr>
1419
        <?php } else {
1420
            if(!$text) { ?>
1421
                <tr>
1422
                    <td colspan="2" class="diffnav"><?php echo $l_nav ?></td>
1423
                    <td colspan="2" class="diffnav"><?php echo $r_nav ?></td>
1424
                </tr>
1425
            <?php } ?>
1426
            <tr>
1427
                <th colspan="2" <?php echo $l_minor ?>>
1428
                    <?php echo $l_head ?>
1429
                </th>
1430
                <th colspan="2" <?php echo $r_minor ?>>
1431
                    <?php echo $r_head ?>
1432
                </th>
1433
            </tr>
1434
        <?php }
1435
1436
        //diff view
1437
        echo html_insert_softbreaks($diffformatter->format($diff)); ?>
1438
1439
    </table>
1440
    </div>
1441
<?php
1442
}
1443
1444
/**
1445
 * Create html for revision navigation
1446
 *
1447
 * @param PageChangeLog $pagelog changelog object of current page
1448
 * @param string        $type    inline vs sidebyside
1449
 * @param int           $l_rev   left revision timestamp
1450
 * @param int           $r_rev   right revision timestamp
1451
 * @return string[] html of left and right navigation elements
1452
 */
1453
function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) {
1454
    global $INFO, $ID;
1455
1456
    // last timestamp is not in changelog, retrieve timestamp from metadata
1457
    // note: when page is removed, the metadata timestamp is zero
1458
    if(!$r_rev) {
1459
        if(isset($INFO['meta']['last_change']['date'])) {
1460
            $r_rev = $INFO['meta']['last_change']['date'];
1461
        } else {
1462
            $r_rev = 0;
1463
        }
1464
    }
1465
1466
    //retrieve revisions with additional info
1467
    list($l_revs, $r_revs) = $pagelog->getRevisionsAround($l_rev, $r_rev);
1468
    $l_revisions = array();
1469
    if(!$l_rev) {
1470
        $l_revisions[0] = array(0, "", false); //no left revision given, add dummy
1471
    }
1472
    foreach($l_revs as $rev) {
1473
        $info = $pagelog->getRevisionInfo($rev);
1474
        $l_revisions[$rev] = array(
1475
            $rev,
1476
            dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'],
1477
            $r_rev ? $rev >= $r_rev : false //disable?
1478
        );
1479
    }
1480
    $r_revisions = array();
1481
    if(!$r_rev) {
1482
        $r_revisions[0] = array(0, "", false); //no right revision given, add dummy
1483
    }
1484
    foreach($r_revs as $rev) {
1485
        $info = $pagelog->getRevisionInfo($rev);
1486
        $r_revisions[$rev] = array(
1487
            $rev,
1488
            dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'],
1489
            $rev <= $l_rev //disable?
1490
        );
1491
    }
1492
1493
    //determine previous/next revisions
1494
    $l_index = array_search($l_rev, $l_revs);
1495
    $l_prev = $l_revs[$l_index + 1];
1496
    $l_next = $l_revs[$l_index - 1];
1497
    if($r_rev) {
1498
        $r_index = array_search($r_rev, $r_revs);
1499
        $r_prev = $r_revs[$r_index + 1];
1500
        $r_next = $r_revs[$r_index - 1];
1501
    } else {
1502
        //removed page
1503
        if($l_next) {
1504
            $r_prev = $r_revs[0];
1505
        } else {
1506
            $r_prev = null;
1507
        }
1508
        $r_next = null;
1509
    }
1510
1511
    /*
1512
     * Left side:
1513
     */
1514
    $l_nav = '';
1515
    //move back
1516
    if($l_prev) {
1517
        $l_nav .= html_diff_navigationlink($type, 'diffbothprevrev', $l_prev, $r_prev);
1518
        $l_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_prev, $r_rev);
1519
    }
1520
    //dropdown
1521
    $form = new Doku_Form(array('action' => wl()));
1522
    $form->addHidden('id', $ID);
1523
    $form->addHidden('difftype', $type);
1524
    $form->addHidden('rev2[1]', $r_rev);
1525
    $form->addHidden('do', 'diff');
1526
    $form->addElement(
1527
         form_makeListboxField(
1528
             'rev2[0]',
1529
             $l_revisions,
1530
             $l_rev,
1531
             '', '', '',
1532
             array('class' => 'quickselect')
1533
         )
1534
    );
1535
    $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1536
    $l_nav .= $form->getForm();
1537
    //move forward
1538
    if($l_next && ($l_next < $r_rev || !$r_rev)) {
1539
        $l_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_next, $r_rev);
1540
    }
1541
1542
    /*
1543
     * Right side:
1544
     */
1545
    $r_nav = '';
1546
    //move back
1547
    if($l_rev < $r_prev) {
1548
        $r_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_rev, $r_prev);
1549
    }
1550
    //dropdown
1551
    $form = new Doku_Form(array('action' => wl()));
1552
    $form->addHidden('id', $ID);
1553
    $form->addHidden('rev2[0]', $l_rev);
1554
    $form->addHidden('difftype', $type);
1555
    $form->addHidden('do', 'diff');
1556
    $form->addElement(
1557
         form_makeListboxField(
1558
             'rev2[1]',
1559
             $r_revisions,
1560
             $r_rev,
1561
             '', '', '',
1562
             array('class' => 'quickselect')
1563
         )
1564
    );
1565
    $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1566
    $r_nav .= $form->getForm();
1567
    //move forward
1568
    if($r_next) {
1569
        if($pagelog->isCurrentRevision($r_next)) {
1570
            $r_nav .= html_diff_navigationlink($type, 'difflastrev', $l_rev); //last revision is diff with current page
1571
        } else {
1572
            $r_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_rev, $r_next);
1573
        }
1574
        $r_nav .= html_diff_navigationlink($type, 'diffbothnextrev', $l_next, $r_next);
1575
    }
1576
    return array($l_nav, $r_nav);
1577
}
1578
1579
/**
1580
 * Create html link to a diff defined by two revisions
1581
 *
1582
 * @param string $difftype display type
1583
 * @param string $linktype
1584
 * @param int $lrev oldest revision
1585
 * @param int $rrev newest revision or null for diff with current revision
1586
 * @return string html of link to a diff
1587
 */
1588
function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) {
1589
    global $ID, $lang;
1590
    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...
1591
        $urlparam = array(
1592
            'do' => 'diff',
1593
            'rev' => $lrev,
1594
            'difftype' => $difftype,
1595
        );
1596
    } else {
1597
        $urlparam = array(
1598
            'do' => 'diff',
1599
            'rev2[0]' => $lrev,
1600
            'rev2[1]' => $rrev,
1601
            'difftype' => $difftype,
1602
        );
1603
    }
1604
    return  '<a class="' . $linktype . '" href="' . wl($ID, $urlparam) . '" title="' . $lang[$linktype] . '">' .
1605
                '<span>' . $lang[$linktype] . '</span>' .
1606
            '</a>' . "\n";
1607
}
1608
1609
/**
1610
 * Insert soft breaks in diff html
1611
 *
1612
 * @param string $diffhtml
1613
 * @return string
1614
 */
1615
function html_insert_softbreaks($diffhtml) {
1616
    // search the diff html string for both:
1617
    // - html tags, so these can be ignored
1618
    // - long strings of characters without breaking characters
1619
    return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/','html_softbreak_callback',$diffhtml);
1620
}
1621
1622
/**
1623
 * callback which adds softbreaks
1624
 *
1625
 * @param array $match array with first the complete match
1626
 * @return string the replacement
1627
 */
1628
function html_softbreak_callback($match){
1629
    // if match is an html tag, return it intact
1630
    if ($match[0]{0} == '<') return $match[0];
1631
1632
    // its a long string without a breaking character,
1633
    // make certain characters into breaking characters by inserting a
1634
    // breaking character (zero length space, U+200B / #8203) in front them.
1635
    $regex = <<< REGEX
1636
(?(?=                                 # start a conditional expression with a positive look ahead ...
1637
&\#?\\w{1,6};)                        # ... for html entities - we don't want to split them (ok to catch some invalid combinations)
1638
&\#?\\w{1,6};                         # yes pattern - a quicker match for the html entity, since we know we have one
1639
|
1640
[?/,&\#;:]                            # no pattern - any other group of 'special' characters to insert a breaking character after
1641
)+                                    # end conditional expression
1642
REGEX;
1643
1644
    return preg_replace('<'.$regex.'>xu','\0&#8203;',$match[0]);
1645
}
1646
1647
/**
1648
 * show warning on conflict detection
1649
 *
1650
 * @author Andreas Gohr <[email protected]>
1651
 *
1652
 * @param string $text
1653
 * @param string $summary
1654
 */
1655
function html_conflict($text,$summary){
1656
    global $ID;
1657
    global $lang;
1658
1659
    print p_locale_xhtml('conflict');
1660
    $form = new Doku_Form(array('id' => 'dw__editform'));
1661
    $form->addHidden('id', $ID);
1662
    $form->addHidden('wikitext', $text);
1663
    $form->addHidden('summary', $summary);
1664
    $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('accesskey'=>'s')));
1665
    $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel']));
1666
    html_form('conflict', $form);
1667
    print '<br /><br /><br /><br />'.NL;
1668
}
1669
1670
/**
1671
 * Prints the global message array
1672
 *
1673
 * @author Andreas Gohr <[email protected]>
1674
 */
1675
function html_msgarea(){
1676
    global $MSG, $MSG_shown;
1677
    /** @var array $MSG */
1678
    // store if the global $MSG has already been shown and thus HTML output has been started
1679
    $MSG_shown = true;
1680
1681
    if(!isset($MSG)) return;
1682
1683
    $shown = array();
1684
    foreach($MSG as $msg){
1685
        $hash = md5($msg['msg']);
1686
        if(isset($shown[$hash])) continue; // skip double messages
1687
        if(info_msg_allowed($msg)){
1688
            print '<div class="'.$msg['lvl'].'">';
1689
            print $msg['msg'];
1690
            print '</div>';
1691
        }
1692
        $shown[$hash] = 1;
1693
    }
1694
1695
    unset($GLOBALS['MSG']);
1696
}
1697
1698
/**
1699
 * Prints the registration form
1700
 *
1701
 * @author Andreas Gohr <[email protected]>
1702
 */
1703
function html_register(){
1704
    global $lang;
1705
    global $conf;
1706
    global $INPUT;
1707
1708
    $base_attrs = array('size'=>50,'required'=>'required');
1709
    $email_attrs = $base_attrs + array('type'=>'email','class'=>'edit');
1710
1711
    print p_locale_xhtml('register');
1712
    print '<div class="centeralign">'.NL;
1713
    $form = new Doku_Form(array('id' => 'dw__register'));
1714
    $form->startFieldset($lang['btn_register']);
1715
    $form->addHidden('do', 'register');
1716
    $form->addHidden('save', '1');
1717
    $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block', $base_attrs));
1718
    if (!$conf['autopasswd']) {
1719
        $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', $base_attrs));
1720
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', $base_attrs));
1721
    }
1722
    $form->addElement(form_makeTextField('fullname', $INPUT->post->str('fullname'), $lang['fullname'], '', 'block', $base_attrs));
1723
    $form->addElement(form_makeField('email','email', $INPUT->post->str('email'), $lang['email'], '', 'block', $email_attrs));
1724
    $form->addElement(form_makeButton('submit', '', $lang['btn_register']));
1725
    $form->endFieldset();
1726
    html_form('register', $form);
1727
1728
    print '</div>'.NL;
1729
}
1730
1731
/**
1732
 * Print the update profile form
1733
 *
1734
 * @author Christopher Smith <[email protected]>
1735
 * @author Andreas Gohr <[email protected]>
1736
 */
1737
function html_updateprofile(){
1738
    global $lang;
1739
    global $conf;
1740
    global $INPUT;
1741
    global $INFO;
1742
    /** @var DokuWiki_Auth_Plugin $auth */
1743
    global $auth;
1744
1745
    print p_locale_xhtml('updateprofile');
1746
    print '<div class="centeralign">'.NL;
1747
1748
    $fullname = $INPUT->post->str('fullname', $INFO['userinfo']['name'], true);
1749
    $email = $INPUT->post->str('email', $INFO['userinfo']['mail'], true);
1750
    $form = new Doku_Form(array('id' => 'dw__register'));
1751
    $form->startFieldset($lang['profile']);
1752
    $form->addHidden('do', 'profile');
1753
    $form->addHidden('save', '1');
1754
    $form->addElement(form_makeTextField('login', $_SERVER['REMOTE_USER'], $lang['user'], '', 'block', array('size'=>'50', 'disabled'=>'disabled')));
1755
    $attr = array('size'=>'50');
1756
    if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled';
1757
    $form->addElement(form_makeTextField('fullname', $fullname, $lang['fullname'], '', 'block', $attr));
1758
    $attr = array('size'=>'50', 'class'=>'edit');
1759
    if (!$auth->canDo('modMail')) $attr['disabled'] = 'disabled';
1760
    $form->addElement(form_makeField('email','email', $email, $lang['email'], '', 'block', $attr));
1761
    $form->addElement(form_makeTag('br'));
1762
    if ($auth->canDo('modPass')) {
1763
        $form->addElement(form_makePasswordField('newpass', $lang['newpass'], '', 'block', array('size'=>'50')));
1764
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
1765
    }
1766
    if ($conf['profileconfirm']) {
1767
        $form->addElement(form_makeTag('br'));
1768
        $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required')));
1769
    }
1770
    $form->addElement(form_makeButton('submit', '', $lang['btn_save']));
1771
    $form->addElement(form_makeButton('reset', '', $lang['btn_reset']));
1772
1773
    $form->endFieldset();
1774
    html_form('updateprofile', $form);
1775
1776
    if ($auth->canDo('delUser') && actionOK('profile_delete')) {
1777
        $form_profiledelete = new Doku_Form(array('id' => 'dw__profiledelete'));
1778
        $form_profiledelete->startFieldset($lang['profdeleteuser']);
1779
        $form_profiledelete->addHidden('do', 'profile_delete');
1780
        $form_profiledelete->addHidden('delete', '1');
1781
        $form_profiledelete->addElement(form_makeCheckboxField('confirm_delete', '1', $lang['profconfdelete'],'dw__confirmdelete','', array('required' => 'required')));
1782
        if ($conf['profileconfirm']) {
1783
            $form_profiledelete->addElement(form_makeTag('br'));
1784
            $form_profiledelete->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required')));
1785
        }
1786
        $form_profiledelete->addElement(form_makeButton('submit', '', $lang['btn_deleteuser']));
1787
        $form_profiledelete->endFieldset();
1788
1789
        html_form('profiledelete', $form_profiledelete);
1790
    }
1791
1792
    print '</div>'.NL;
1793
}
1794
1795
/**
1796
 * Preprocess edit form data
1797
 *
1798
 * @author   Andreas Gohr <[email protected]>
1799
 *
1800
 * @triggers HTML_EDITFORM_OUTPUT
1801
 */
1802
function html_edit(){
1803
    global $INPUT;
1804
    global $ID;
1805
    global $REV;
1806
    global $DATE;
1807
    global $PRE;
1808
    global $SUF;
1809
    global $INFO;
1810
    global $SUM;
1811
    global $lang;
1812
    global $conf;
1813
    global $TEXT;
1814
1815
    if ($INPUT->has('changecheck')) {
1816
        $check = $INPUT->str('changecheck');
1817
    } elseif(!$INFO['exists']){
1818
        // $TEXT has been loaded from page template
1819
        $check = md5('');
1820
    } else {
1821
        $check = md5($TEXT);
1822
    }
1823
    $mod = md5($TEXT) !== $check;
1824
1825
    $wr = $INFO['writable'] && !$INFO['locked'];
1826
    $include = 'edit';
1827
    if($wr){
1828
        if ($REV) $include = 'editrev';
1829
    }else{
1830
        // check pseudo action 'source'
1831
        if(!actionOK('source')){
1832
            msg('Command disabled: source',-1);
1833
            return;
1834
        }
1835
        $include = 'read';
1836
    }
1837
1838
    global $license;
1839
1840
    $form = new Doku_Form(array('id' => 'dw__editform'));
1841
    $form->addHidden('id', $ID);
1842
    $form->addHidden('rev', $REV);
1843
    $form->addHidden('date', $DATE);
1844
    $form->addHidden('prefix', $PRE . '.');
1845
    $form->addHidden('suffix', $SUF);
1846
    $form->addHidden('changecheck', $check);
1847
1848
    $data = array('form' => $form,
1849
                  'wr'   => $wr,
1850
                  'media_manager' => true,
1851
                  'target' => ($INPUT->has('target') && $wr) ? $INPUT->str('target') : 'section',
1852
                  'intro_locale' => $include);
1853
1854
    if ($data['target'] !== 'section') {
1855
        // Only emit event if page is writable, section edit data is valid and
1856
        // edit target is not section.
1857
        trigger_event('HTML_EDIT_FORMSELECTION', $data, 'html_edit_form', true);
1858
    } else {
1859
        html_edit_form($data);
1860
    }
1861
    if (isset($data['intro_locale'])) {
1862
        echo p_locale_xhtml($data['intro_locale']);
1863
    }
1864
1865
    $form->addHidden('target', $data['target']);
1866
    if ($INPUT->has('hid')) {
1867
        $form->addHidden('hid', $INPUT->str('hid'));
1868
    }
1869
    $form->addElement(form_makeOpenTag('div', array('id'=>'wiki__editbar', 'class'=>'editBar')));
1870
    $form->addElement(form_makeOpenTag('div', array('id'=>'size__ctl')));
1871
    $form->addElement(form_makeCloseTag('div'));
1872
    if ($wr) {
1873
        $form->addElement(form_makeOpenTag('div', array('class'=>'editButtons')));
1874
        $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('id'=>'edbtn__save', 'accesskey'=>'s', 'tabindex'=>'4')));
1875
        $form->addElement(form_makeButton('submit', 'preview', $lang['btn_preview'], array('id'=>'edbtn__preview', 'accesskey'=>'p', 'tabindex'=>'5')));
1876
        $form->addElement(form_makeButton('submit', 'draftdel', $lang['btn_cancel'], array('tabindex'=>'6')));
1877
        $form->addElement(form_makeCloseTag('div'));
1878
        $form->addElement(form_makeOpenTag('div', array('class'=>'summary')));
1879
        $form->addElement(form_makeTextField('summary', $SUM, $lang['summary'], 'edit__summary', 'nowrap', array('size'=>'50', 'tabindex'=>'2')));
1880
        $elem = html_minoredit();
1881
        if ($elem) $form->addElement($elem);
1882
        $form->addElement(form_makeCloseTag('div'));
1883
    }
1884
    $form->addElement(form_makeCloseTag('div'));
1885
    if($wr && $conf['license']){
1886
        $form->addElement(form_makeOpenTag('div', array('class'=>'license')));
1887
        $out  = $lang['licenseok'];
1888
        $out .= ' <a href="'.$license[$conf['license']]['url'].'" rel="license" class="urlextern"';
1889
        if($conf['target']['extern']) $out .= ' target="'.$conf['target']['extern'].'"';
1890
        $out .= '>'.$license[$conf['license']]['name'].'</a>';
1891
        $form->addElement($out);
1892
        $form->addElement(form_makeCloseTag('div'));
1893
    }
1894
1895
    if ($wr) {
1896
        // sets changed to true when previewed
1897
        echo '<script type="text/javascript">/*<![CDATA[*/'. NL;
1898
        echo 'textChanged = ' . ($mod ? 'true' : 'false');
1899
        echo '/*!]]>*/</script>' . NL;
1900
    } ?>
1901
    <div class="editBox" role="application">
1902
1903
    <div class="toolbar group">
1904
        <div id="draft__status" class="draft__status"><?php if(!empty($INFO['draft'])) echo $lang['draftdate'].' '.dformat();?></div>
1905
        <div id="tool__bar" class="tool__bar"><?php if ($wr && $data['media_manager']){?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
1906
            target="_blank"><?php echo $lang['mediaselect'] ?></a><?php }?></div>
1907
    </div>
1908
    <?php
1909
1910
    html_form('edit', $form);
1911
    print '</div>'.NL;
1912
}
1913
1914
/**
1915
 * Display the default edit form
1916
 *
1917
 * Is the default action for HTML_EDIT_FORMSELECTION.
1918
 *
1919
 * @param mixed[] $param
1920
 */
1921
function html_edit_form($param) {
1922
    global $TEXT;
1923
1924
    if ($param['target'] !== 'section') {
1925
        msg('No editor for edit target ' . hsc($param['target']) . ' found.', -1);
1926
    }
1927
1928
    $attr = array('tabindex'=>'1');
1929
    if (!$param['wr']) $attr['readonly'] = 'readonly';
1930
1931
    $param['form']->addElement(form_makeWikiText($TEXT, $attr));
1932
}
1933
1934
/**
1935
 * Adds a checkbox for minor edits for logged in users
1936
 *
1937
 * @author Andreas Gohr <[email protected]>
1938
 *
1939
 * @return array|bool
1940
 */
1941
function html_minoredit(){
1942
    global $conf;
1943
    global $lang;
1944
    global $INPUT;
1945
    // minor edits are for logged in users only
1946
    if(!$conf['useacl'] || !$_SERVER['REMOTE_USER']){
1947
        return false;
1948
    }
1949
1950
    $p = array();
1951
    $p['tabindex'] = 3;
1952
    if($INPUT->bool('minor')) $p['checked']='checked';
1953
    return form_makeCheckboxField('minor', '1', $lang['minoredit'], 'minoredit', 'nowrap', $p);
1954
}
1955
1956
/**
1957
 * prints some debug info
1958
 *
1959
 * @author Andreas Gohr <[email protected]>
1960
 */
1961
function html_debug(){
1962
    global $conf;
1963
    global $lang;
1964
    /** @var DokuWiki_Auth_Plugin $auth */
1965
    global $auth;
1966
    global $INFO;
1967
1968
    //remove sensitive data
1969
    $cnf = $conf;
1970
    debug_guard($cnf);
1971
    $nfo = $INFO;
1972
    debug_guard($nfo);
1973
    $ses = $_SESSION;
1974
    debug_guard($ses);
1975
1976
    print '<html><body>';
1977
1978
    print '<p>When reporting bugs please send all the following ';
1979
    print 'output as a mail to [email protected] ';
1980
    print 'The best way to do this is to save this page in your browser</p>';
1981
1982
    print '<b>$INFO:</b><pre>';
1983
    print_r($nfo);
1984
    print '</pre>';
1985
1986
    print '<b>$_SERVER:</b><pre>';
1987
    print_r($_SERVER);
1988
    print '</pre>';
1989
1990
    print '<b>$conf:</b><pre>';
1991
    print_r($cnf);
1992
    print '</pre>';
1993
1994
    print '<b>DOKU_BASE:</b><pre>';
1995
    print DOKU_BASE;
1996
    print '</pre>';
1997
1998
    print '<b>abs DOKU_BASE:</b><pre>';
1999
    print DOKU_URL;
2000
    print '</pre>';
2001
2002
    print '<b>rel DOKU_BASE:</b><pre>';
2003
    print dirname($_SERVER['PHP_SELF']).'/';
2004
    print '</pre>';
2005
2006
    print '<b>PHP Version:</b><pre>';
2007
    print phpversion();
2008
    print '</pre>';
2009
2010
    print '<b>locale:</b><pre>';
2011
    print setlocale(LC_ALL,0);
2012
    print '</pre>';
2013
2014
    print '<b>encoding:</b><pre>';
2015
    print $lang['encoding'];
2016
    print '</pre>';
2017
2018
    if($auth){
2019
        print '<b>Auth backend capabilities:</b><pre>';
2020
        foreach ($auth->getCapabilities() as $cando){
2021
            print '   '.str_pad($cando,16) . ' => ' . (int)$auth->canDo($cando) . NL;
2022
        }
2023
        print '</pre>';
2024
    }
2025
2026
    print '<b>$_SESSION:</b><pre>';
2027
    print_r($ses);
2028
    print '</pre>';
2029
2030
    print '<b>Environment:</b><pre>';
2031
    print_r($_ENV);
2032
    print '</pre>';
2033
2034
    print '<b>PHP settings:</b><pre>';
2035
    $inis = ini_get_all();
2036
    print_r($inis);
2037
    print '</pre>';
2038
2039
    if (function_exists('apache_get_version')) {
2040
        $apache = array();
2041
        $apache['version'] = apache_get_version();
2042
2043
        if (function_exists('apache_get_modules')) {
2044
            $apache['modules'] = apache_get_modules();
2045
        }
2046
        print '<b>Apache</b><pre>';
2047
        print_r($apache);
2048
        print '</pre>';
2049
    }
2050
2051
    print '</body></html>';
2052
}
2053
2054
/**
2055
 * Form to request a new password for an existing account
2056
 *
2057
 * @author Benoit Chesneau <[email protected]>
2058
 * @author Andreas Gohr <[email protected]>
2059
 */
2060
function html_resendpwd() {
2061
    global $lang;
2062
    global $conf;
2063
    global $INPUT;
2064
2065
    $token = preg_replace('/[^a-f0-9]+/','',$INPUT->str('pwauth'));
2066
2067
    if(!$conf['autopasswd'] && $token){
2068
        print p_locale_xhtml('resetpwd');
2069
        print '<div class="centeralign">'.NL;
2070
        $form = new Doku_Form(array('id' => 'dw__resendpwd'));
2071
        $form->startFieldset($lang['btn_resendpwd']);
2072
        $form->addHidden('token', $token);
2073
        $form->addHidden('do', 'resendpwd');
2074
2075
        $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', array('size'=>'50')));
2076
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
2077
2078
        $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
2079
        $form->endFieldset();
2080
        html_form('resendpwd', $form);
2081
        print '</div>'.NL;
2082
    }else{
2083
        print p_locale_xhtml('resendpwd');
2084
        print '<div class="centeralign">'.NL;
2085
        $form = new Doku_Form(array('id' => 'dw__resendpwd'));
2086
        $form->startFieldset($lang['resendpwd']);
2087
        $form->addHidden('do', 'resendpwd');
2088
        $form->addHidden('save', '1');
2089
        $form->addElement(form_makeTag('br'));
2090
        $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block'));
2091
        $form->addElement(form_makeTag('br'));
2092
        $form->addElement(form_makeTag('br'));
2093
        $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
2094
        $form->endFieldset();
2095
        html_form('resendpwd', $form);
2096
        print '</div>'.NL;
2097
    }
2098
}
2099
2100
/**
2101
 * Return the TOC rendered to XHTML
2102
 *
2103
 * @author Andreas Gohr <[email protected]>
2104
 *
2105
 * @param array $toc
2106
 * @return string html
2107
 */
2108
function html_TOC($toc){
2109
    if(!count($toc)) return '';
2110
    global $lang;
2111
    $out  = '<!-- TOC START -->'.DOKU_LF;
2112
    $out .= '<div id="dw__toc" class="dw__toc">'.DOKU_LF;
2113
    $out .= '<h3 class="toggle">';
2114
    $out .= $lang['toc'];
2115
    $out .= '</h3>'.DOKU_LF;
2116
    $out .= '<div>'.DOKU_LF;
2117
    $out .= html_buildlist($toc,'toc','html_list_toc','html_li_default',true);
2118
    $out .= '</div>'.DOKU_LF.'</div>'.DOKU_LF;
2119
    $out .= '<!-- TOC END -->'.DOKU_LF;
2120
    return $out;
2121
}
2122
2123
/**
2124
 * Callback for html_buildlist
2125
 *
2126
 * @param array $item
2127
 * @return string html
2128
 */
2129
function html_list_toc($item){
2130
    if(isset($item['hid'])){
2131
        $link = '#'.$item['hid'];
2132
    }else{
2133
        $link = $item['link'];
2134
    }
2135
2136
    return '<a href="'.$link.'">'.hsc($item['title']).'</a>';
2137
}
2138
2139
/**
2140
 * Helper function to build TOC items
2141
 *
2142
 * Returns an array ready to be added to a TOC array
2143
 *
2144
 * @param string $link  - where to link (if $hash set to '#' it's a local anchor)
2145
 * @param string $text  - what to display in the TOC
2146
 * @param int    $level - nesting level
2147
 * @param string $hash  - is prepended to the given $link, set blank if you want full links
2148
 * @return array the toc item
2149
 */
2150
function html_mktocitem($link, $text, $level, $hash='#'){
2151
    return  array( 'link'  => $hash.$link,
2152
            'title' => $text,
2153
            'type'  => 'ul',
2154
            'level' => $level);
2155
}
2156
2157
/**
2158
 * Output a Doku_Form object.
2159
 * Triggers an event with the form name: HTML_{$name}FORM_OUTPUT
2160
 *
2161
 * @author Tom N Harris <[email protected]>
2162
 *
2163
 * @param string     $name The name of the form
2164
 * @param Doku_Form  $form The form
2165
 */
2166
function html_form($name, &$form) {
2167
    // Safety check in case the caller forgets.
2168
    $form->endFieldset();
2169
    trigger_event('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false);
2170
}
2171
2172
/**
2173
 * Form print function.
2174
 * Just calls printForm() on the data object.
2175
 *
2176
 * @param Doku_Form $data The form
2177
 */
2178
function html_form_output($data) {
2179
    $data->printForm();
2180
}
2181
2182
/**
2183
 * Embed a flash object in HTML
2184
 *
2185
 * This will create the needed HTML to embed a flash movie in a cross browser
2186
 * compatble way using valid XHTML
2187
 *
2188
 * The parameters $params, $flashvars and $atts need to be associative arrays.
2189
 * No escaping needs to be done for them. The alternative content *has* to be
2190
 * escaped because it is used as is. If no alternative content is given
2191
 * $lang['noflash'] is used.
2192
 *
2193
 * @author Andreas Gohr <[email protected]>
2194
 * @link   http://latrine.dgx.cz/how-to-correctly-insert-a-flash-into-xhtml
2195
 *
2196
 * @param string $swf      - the SWF movie to embed
2197
 * @param int $width       - width of the flash movie in pixels
2198
 * @param int $height      - height of the flash movie in pixels
2199
 * @param array $params    - additional parameters (<param>)
2200
 * @param array $flashvars - parameters to be passed in the flashvar parameter
2201
 * @param array $atts      - additional attributes for the <object> tag
2202
 * @param string $alt      - alternative content (is NOT automatically escaped!)
2203
 * @return string         - the XHTML markup
2204
 */
2205
function html_flashobject($swf,$width,$height,$params=null,$flashvars=null,$atts=null,$alt=''){
2206
    global $lang;
2207
2208
    $out = '';
2209
2210
    // prepare the object attributes
2211
    if(is_null($atts)) $atts = array();
2212
    $atts['width']  = (int) $width;
2213
    $atts['height'] = (int) $height;
2214
    if(!$atts['width'])  $atts['width']  = 425;
2215
    if(!$atts['height']) $atts['height'] = 350;
2216
2217
    // add object attributes for standard compliant browsers
2218
    $std = $atts;
2219
    $std['type'] = 'application/x-shockwave-flash';
2220
    $std['data'] = $swf;
2221
2222
    // add object attributes for IE
2223
    $ie  = $atts;
2224
    $ie['classid'] = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
2225
2226
    // open object (with conditional comments)
2227
    $out .= '<!--[if !IE]> -->'.NL;
2228
    $out .= '<object '.buildAttributes($std).'>'.NL;
2229
    $out .= '<!-- <![endif]-->'.NL;
2230
    $out .= '<!--[if IE]>'.NL;
2231
    $out .= '<object '.buildAttributes($ie).'>'.NL;
2232
    $out .= '    <param name="movie" value="'.hsc($swf).'" />'.NL;
2233
    $out .= '<!--><!-- -->'.NL;
2234
2235
    // print params
2236
    if(is_array($params)) foreach($params as $key => $val){
2237
        $out .= '  <param name="'.hsc($key).'" value="'.hsc($val).'" />'.NL;
2238
    }
2239
2240
    // add flashvars
2241
    if(is_array($flashvars)){
2242
        $out .= '  <param name="FlashVars" value="'.buildURLparams($flashvars).'" />'.NL;
2243
    }
2244
2245
    // alternative content
2246
    if($alt){
2247
        $out .= $alt.NL;
2248
    }else{
2249
        $out .= $lang['noflash'].NL;
2250
    }
2251
2252
    // finish
2253
    $out .= '</object>'.NL;
2254
    $out .= '<!-- <![endif]-->'.NL;
2255
2256
    return $out;
2257
}
2258
2259
/**
2260
 * Prints HTML code for the given tab structure
2261
 *
2262
 * @param array  $tabs        tab structure
2263
 * @param string $current_tab the current tab id
2264
 */
2265
function html_tabs($tabs, $current_tab = null) {
2266
    echo '<ul class="tabs">'.NL;
2267
2268
    foreach($tabs as $id => $tab) {
2269
        html_tab($tab['href'], $tab['caption'], $id === $current_tab);
2270
    }
2271
2272
    echo '</ul>'.NL;
2273
}
2274
2275
/**
2276
 * Prints a single tab
2277
 *
2278
 * @author Kate Arzamastseva <[email protected]>
2279
 * @author Adrian Lang <[email protected]>
2280
 *
2281
 * @param string $href - tab href
2282
 * @param string $caption - tab caption
2283
 * @param boolean $selected - is tab selected
2284
 */
2285
2286
function html_tab($href, $caption, $selected=false) {
2287
    $tab = '<li>';
2288
    if ($selected) {
2289
        $tab .= '<strong>';
2290
    } else {
2291
        $tab .= '<a href="' . hsc($href) . '">';
2292
    }
2293
    $tab .= hsc($caption)
2294
         .  '</' . ($selected ? 'strong' : 'a') . '>'
2295
         .  '</li>'.NL;
2296
    echo $tab;
2297
}
2298
2299
/**
2300
 * Display size change
2301
 *
2302
 * @param int $sizechange - size of change in Bytes
2303
 * @param Doku_Form $form - form to add elements to
2304
 */
2305
2306
function html_sizechange($sizechange, Doku_Form $form) {
2307
    if(isset($sizechange)) {
2308
        $class = 'sizechange';
2309
        $value = filesize_h(abs($sizechange));
2310
        if($sizechange > 0) {
2311
            $class .= ' positive';
2312
            $value = '+' . $value;
2313
        } elseif($sizechange < 0) {
2314
            $class .= ' negative';
2315
            $value = '-' . $value;
2316
        } else {
2317
            $value = '±' . $value;
2318
        }
2319
        $form->addElement(form_makeOpenTag('span', array('class' => $class)));
2320
        $form->addElement($value);
2321
        $form->addElement(form_makeCloseTag('span'));
2322
    }
2323
}
2324