[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> html.php (source)

   1  <?php
   2  
   3  /**
   4   * HTML output functions
   5   *
   6   * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
   7   * @author     Andreas Gohr <andi@splitbrain.org>
   8   */
   9  
  10  use dokuwiki\Ui\MediaRevisions;
  11  use dokuwiki\Form\Form;
  12  use dokuwiki\Action\Denied;
  13  use dokuwiki\Action\Locked;
  14  use dokuwiki\ChangeLog\PageChangeLog;
  15  use dokuwiki\Extension\AuthPlugin;
  16  use dokuwiki\Extension\Event;
  17  use dokuwiki\Search\FulltextSearch;
  18  use dokuwiki\Utf8;
  19  use dokuwiki\Ui\Backlinks;
  20  use dokuwiki\Ui\Editor;
  21  use dokuwiki\Ui\Index;
  22  use dokuwiki\Ui\Login;
  23  use dokuwiki\Ui\PageConflict;
  24  use dokuwiki\Ui\PageDiff;
  25  use dokuwiki\Ui\PageDraft;
  26  use dokuwiki\Ui\PageRevisions;
  27  use dokuwiki\Ui\PageView;
  28  use dokuwiki\Ui\Recent;
  29  use dokuwiki\Ui\UserProfile;
  30  use dokuwiki\Ui\UserRegister;
  31  use dokuwiki\Ui\UserResendPwd;
  32  use dokuwiki\Utf8\Clean;
  33  
  34  if (!defined('SEC_EDIT_PATTERN')) {
  35      define('SEC_EDIT_PATTERN', '#<!-- EDIT({.*?}) -->#');
  36  }
  37  
  38  
  39  /**
  40   * Convenience function to quickly build a wikilink
  41   *
  42   * @author Andreas Gohr <andi@splitbrain.org>
  43   * @param string  $id      id of the target page
  44   * @param string  $name    the name of the link, i.e. the text that is displayed
  45   * @param string|array  $search  search string(s) that shall be highlighted in the target page
  46   * @return string the HTML code of the link
  47   */
  48  function html_wikilink($id, $name = null, $search = '')
  49  {
  50      /** @var Doku_Renderer_xhtml $xhtml_renderer */
  51      static $xhtml_renderer = null;
  52      if (is_null($xhtml_renderer)) {
  53          $xhtml_renderer = p_get_renderer('xhtml');
  54      }
  55  
  56      return $xhtml_renderer->internallink($id, $name, $search, true, 'navigation');
  57  }
  58  
  59  /**
  60   * The loginform
  61   *
  62   * @author   Andreas Gohr <andi@splitbrain.org>
  63   *
  64   * @param bool $svg Whether to show svg icons in the register and resendpwd links or not
  65   * @deprecated 2020-07-18
  66   */
  67  function html_login($svg = false)
  68  {
  69      dbg_deprecated(Login::class . '::show()');
  70      (new Login($svg))->show();
  71  }
  72  
  73  
  74  /**
  75   * Denied page content
  76   *
  77   * @deprecated 2020-07-18 not called anymore, see inc/Action/Denied::tplContent()
  78   */
  79  function html_denied()
  80  {
  81      dbg_deprecated(Denied::class . '::showBanner()');
  82      (new Denied())->showBanner();
  83  }
  84  
  85  /**
  86   * inserts section edit buttons if wanted or removes the markers
  87   *
  88   * @author Andreas Gohr <andi@splitbrain.org>
  89   *
  90   * @param string $text
  91   * @param bool   $show show section edit buttons?
  92   * @return string
  93   */
  94  function html_secedit($text, $show = true)
  95  {
  96      global $INFO;
  97  
  98      if ((isset($INFO) && !$INFO['writable']) || !$show || (isset($INFO) && $INFO['rev'])) {
  99          return preg_replace(SEC_EDIT_PATTERN, '', $text);
 100      }
 101  
 102      return preg_replace_callback(
 103          SEC_EDIT_PATTERN,
 104          html_secedit_button(...),
 105          $text
 106      );
 107  }
 108  
 109  /**
 110   * prepares section edit button data for event triggering
 111   * used as a callback in html_secedit
 112   *
 113   * @author Andreas Gohr <andi@splitbrain.org>
 114   *
 115   * @param array $matches matches with regexp
 116   * @return string
 117   * @triggers HTML_SECEDIT_BUTTON
 118   */
 119  function html_secedit_button($matches)
 120  {
 121      $json = htmlspecialchars_decode($matches[1], ENT_QUOTES);
 122  
 123      try {
 124          $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
 125      } catch (JsonException) {
 126          return '';
 127      }
 128      $data['target'] = strtolower($data['target']);
 129      $data['hid'] = strtolower($data['hid'] ?? '');
 130  
 131      return Event::createAndTrigger(
 132          'HTML_SECEDIT_BUTTON',
 133          $data,
 134          'html_secedit_get_button'
 135      );
 136  }
 137  
 138  /**
 139   * prints a section editing button
 140   * used as default action form HTML_SECEDIT_BUTTON
 141   *
 142   * @author Adrian Lang <lang@cosmocode.de>
 143   *
 144   * @param array $data name, section id and target
 145   * @return string html
 146   */
 147  function html_secedit_get_button($data)
 148  {
 149      global $ID;
 150      global $INFO;
 151  
 152      if (!isset($data['name']) || $data['name'] === '') return '';
 153  
 154      $name = $data['name'];
 155      unset($data['name']);
 156  
 157      $secid = $data['secid'];
 158      unset($data['secid']);
 159  
 160      $params = array_merge(
 161          ['do'  => 'edit', 'rev' => $INFO['lastmod'], 'summary' => '[' . $name . '] '],
 162          $data
 163      );
 164  
 165      $html = '<div class="secedit editbutton_' . $data['target'] . ' editbutton_' . $secid . '">';
 166      $html .= html_btn('secedit', $ID, '', $params, 'post', $name);
 167      $html .= '</div>';
 168      return $html;
 169  }
 170  
 171  /**
 172   * Just the back to top button (in its own form)
 173   *
 174   * @author Andreas Gohr <andi@splitbrain.org>
 175   *
 176   * @return string html
 177   */
 178  function html_topbtn()
 179  {
 180      global $lang;
 181  
 182      return '<a class="nolink" href="#dokuwiki__top">'
 183          . '<button class="button" onclick="window.scrollTo(0, 0)" title="' . $lang['btn_top'] . '">'
 184          . $lang['btn_top']
 185          . '</button></a>';
 186  }
 187  
 188  /**
 189   * Displays a button (using its own form)
 190   * If tooltip exists, the access key tooltip is replaced.
 191   *
 192   * @author Andreas Gohr <andi@splitbrain.org>
 193   *
 194   * @param string         $name
 195   * @param string         $id
 196   * @param string         $akey   access key
 197   * @param string[]       $params key-value pairs added as hidden inputs
 198   * @param string         $method
 199   * @param string         $tooltip
 200   * @param bool|string    $label  label text, false: lookup btn_$name in localization
 201   * @param string         $svg (optional) svg code, inserted into the button
 202   * @return string
 203   */
 204  function html_btn($name, $id, $akey, $params, $method = 'get', $tooltip = '', $label = false, $svg = null)
 205  {
 206      global $conf;
 207      global $lang;
 208  
 209      if (!$label)
 210          $label = $lang['btn_' . $name];
 211  
 212      //filter id (without urlencoding)
 213      $id = idfilter($id, false);
 214  
 215      //make nice URLs even for buttons
 216      if ($conf['userewrite'] == 2) {
 217          $script = DOKU_BASE . DOKU_SCRIPT . '/' . $id;
 218      } elseif ($conf['userewrite']) {
 219          $script = DOKU_BASE . $id;
 220      } else {
 221          $script = DOKU_BASE . DOKU_SCRIPT;
 222          $params['id'] = $id;
 223      }
 224  
 225      $html = '<form class="button btn_' . $name . '" method="' . $method . '" action="' . $script . '"><div class="no">';
 226  
 227      if (is_array($params)) {
 228          foreach ($params as $key => $val) {
 229              $html .= '<input type="hidden" name="' . $key . '" value="' . hsc($val) . '" />';
 230          }
 231      }
 232  
 233      $tip = empty($tooltip) ? hsc($label) : hsc($tooltip);
 234  
 235      $html .= '<button type="submit" ';
 236      if ($akey) {
 237          $tip  .= ' [' . strtoupper($akey) . ']';
 238          $html .= 'accesskey="' . $akey . '" ';
 239      }
 240      $html .= 'title="' . $tip . '">';
 241      if ($svg) {
 242          $html .= '<span>' . hsc($label) . '</span>' . inlineSVG($svg);
 243      } else {
 244          $html .= hsc($label);
 245      }
 246      $html .= '</button>';
 247      $html .= '</div></form>';
 248  
 249      return $html;
 250  }
 251  /**
 252   * show a revision warning
 253   *
 254   * @author Szymon Olewniczak <dokuwiki@imz.re>
 255   * @deprecated 2020-07-18
 256   */
 257  function html_showrev()
 258  {
 259      dbg_deprecated(PageView::class . '::showrev()');
 260  }
 261  
 262  /**
 263   * Show a wiki page
 264   *
 265   * @author Andreas Gohr <andi@splitbrain.org>
 266   *
 267   * @param null|string $txt wiki text or null for showing $ID
 268   * @deprecated 2020-07-18
 269   */
 270  function html_show($txt = null)
 271  {
 272      dbg_deprecated(PageView::class . '::show()');
 273      (new PageView($txt))->show();
 274  }
 275  
 276  /**
 277   * ask the user about how to handle an exisiting draft
 278   *
 279   * @author Andreas Gohr <andi@splitbrain.org>
 280   * @deprecated 2020-07-18
 281   */
 282  function html_draft()
 283  {
 284      dbg_deprecated(PageDraft::class . '::show()');
 285      (new PageDraft())->show();
 286  }
 287  
 288  /**
 289   * Highlights searchqueries in HTML code
 290   *
 291   * @author Andreas Gohr <andi@splitbrain.org>
 292   * @author Harry Fuecks <hfuecks@gmail.com>
 293   *
 294   * @param string $html
 295   * @param array|string $phrases
 296   * @return string html
 297   */
 298  function html_hilight($html, $phrases)
 299  {
 300      $FulltextSearch = new FulltextSearch();
 301      $phrases = (array) $phrases;
 302      $phrases = array_map(preg_quote_cb(...), $phrases);
 303      $phrases = array_map($FulltextSearch->snippetRePreprocess(...), $phrases);
 304      $phrases = array_filter($phrases);
 305  
 306      $regex = implode('|', $phrases);
 307  
 308      if ($regex === '') return $html;
 309      if (!Clean::isUtf8($regex)) return $html;
 310  
 311      return @preg_replace_callback("/((<[^>]*)|$regex)/ui", function ($match) {
 312          $hlight = unslash($match[0]);
 313          if (!isset($match[2])) {
 314              $hlight = '<span class="search_hit">' . $hlight . '</span>';
 315          }
 316          return $hlight;
 317      }, $html);
 318  }
 319  
 320  /**
 321   * Display error on locked pages
 322   *
 323   * @author Andreas Gohr <andi@splitbrain.org>
 324   * @deprecated 2020-07-18 not called anymore, see inc/Action/Locked::tplContent()
 325   */
 326  function html_locked()
 327  {
 328      dbg_deprecated(Locked::class . '::showBanner()');
 329      (new Locked())->showBanner();
 330  }
 331  
 332  /**
 333   * list old revisions
 334   *
 335   * @author Andreas Gohr <andi@splitbrain.org>
 336   * @author Ben Coburn <btcoburn@silicodon.net>
 337   * @author Kate Arzamastseva <pshns@ukr.net>
 338   *
 339   * @param int $first skip the first n changelog lines
 340   * @param string $media_id id of media, or empty for current page
 341   * @deprecated 2020-07-18
 342   */
 343  function html_revisions($first = -1, $media_id = '')
 344  {
 345      dbg_deprecated(PageRevisions::class . '::show()');
 346      if ($media_id) {
 347          (new MediaRevisions($media_id))->show($first);
 348      } else {
 349          global $INFO;
 350          (new PageRevisions($INFO['id']))->show($first);
 351      }
 352  }
 353  
 354  /**
 355   * display recent changes
 356   *
 357   * @author Andreas Gohr <andi@splitbrain.org>
 358   * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
 359   * @author Ben Coburn <btcoburn@silicodon.net>
 360   * @author Kate Arzamastseva <pshns@ukr.net>
 361   *
 362   * @param int $first
 363   * @param string $show_changes
 364   * @deprecated 2020-07-18
 365   */
 366  function html_recent($first = 0, $show_changes = 'both')
 367  {
 368      dbg_deprecated(Recent::class . '::show()');
 369      (new Recent($first, $show_changes))->show();
 370  }
 371  
 372  /**
 373   * Display page index
 374   *
 375   * @author Andreas Gohr <andi@splitbrain.org>
 376   *
 377   * @param string $ns
 378   * @deprecated 2020-07-18
 379   */
 380  function html_index($ns)
 381  {
 382      dbg_deprecated(Index::class . '::show()');
 383      (new Index($ns))->show();
 384  }
 385  
 386  /**
 387   * Index tree item formatter for html_buildlist()
 388   *
 389   * User function for html_buildlist()
 390   *
 391   * @author Andreas Gohr <andi@splitbrain.org>
 392   *
 393   * @param array $item
 394   * @return string
 395   * @deprecated 2020-07-18
 396   */
 397  function html_list_index($item)
 398  {
 399      dbg_deprecated(Index::class . '::formatListItem()');
 400      return (new Index())->formatListItem($item);
 401  }
 402  
 403  /**
 404   * Index list item formatter for html_buildlist()
 405   *
 406   * This user function is used in html_buildlist to build the
 407   * <li> tags for namespaces when displaying the page index
 408   * it gives different classes to opened or closed "folders"
 409   *
 410   * @author Andreas Gohr <andi@splitbrain.org>
 411   *
 412   * @param array $item
 413   * @return string html
 414   * @deprecated 2020-07-18
 415   */
 416  function html_li_index($item)
 417  {
 418      dbg_deprecated(Index::class . '::tagListItem()');
 419      return (new Index())->tagListItem($item);
 420  }
 421  
 422  /**
 423   * Default list item formatter for html_buildlist()
 424   *
 425   * @author Andreas Gohr <andi@splitbrain.org>
 426   *
 427   * @param array $item
 428   * @return string html
 429   * @deprecated 2020-07-18
 430   */
 431  function html_li_default($item)
 432  {
 433      return '<li class="level' . $item['level'] . '">';
 434  }
 435  
 436  /**
 437   * Build an unordered list
 438   *
 439   * Build an unordered list from the given $data array
 440   * Each item in the array has to have a 'level' property
 441   * the item itself gets printed by the given $func user
 442   * function. The second and optional function is used to
 443   * print the <li> tag. Both user function need to accept
 444   * a single item.
 445   *
 446   * Both user functions can be given as array to point to
 447   * a member of an object.
 448   *
 449   * @author Andreas Gohr <andi@splitbrain.org>
 450   *
 451   * @param array    $data  array with item arrays
 452   * @param string   $class class of ul wrapper
 453   * @param callable $func  callback to print an list item
 454   * @param callable $lifunc (optional) callback to the opening li tag
 455   * @param bool     $forcewrapper (optional) Trigger building a wrapper ul if the first level is
 456   *                               0 (we have a root object) or 1 (just the root content)
 457   * @return string html of an unordered list
 458   */
 459  function html_buildlist($data, $class, $func, $lifunc = null, $forcewrapper = false)
 460  {
 461      if ($data === []) {
 462          return '';
 463      }
 464  
 465      $firstElement = reset($data);
 466      $start_level = $firstElement['level'];
 467      $level = $start_level;
 468      $html  = '';
 469      $open  = 0;
 470  
 471      // set callback function to build the <li> tag, formerly defined as html_li_default()
 472      if (!is_callable($lifunc)) {
 473          $lifunc = static fn($item) => '<li class="level' . $item['level'] . '">';
 474      }
 475  
 476      foreach ($data as $item) {
 477          if ($item['level'] > $level) {
 478              //open new list
 479              for ($i = 0; $i < ($item['level'] - $level); $i++) {
 480                  if ($i) $html .= '<li class="clear">';
 481                  $html .= "\n" . '<ul class="' . $class . '">' . "\n";
 482                  $open++;
 483              }
 484              $level = $item['level'];
 485          } elseif ($item['level'] < $level) {
 486              //close last item
 487              $html .= '</li>' . "\n";
 488              while ($level > $item['level'] && $open > 0) {
 489                  //close higher lists
 490                  $html .= '</ul>' . "\n" . '</li>' . "\n";
 491                  $level--;
 492                  $open--;
 493              }
 494          } elseif ($html !== '') {
 495              //close previous item
 496              $html .= '</li>' . "\n";
 497          }
 498  
 499          //print item
 500          $html .= call_user_func($lifunc, $item);
 501          $html .= '<div class="li">';
 502  
 503          $html .= call_user_func($func, $item);
 504          $html .= '</div>';
 505      }
 506  
 507      //close remaining items and lists
 508      $html .= '</li>' . "\n";
 509      while ($open-- > 0) {
 510          $html .= '</ul></li>' . "\n";
 511      }
 512  
 513      if ($forcewrapper || $start_level < 2) {
 514          // Trigger building a wrapper ul if the first level is
 515          // 0 (we have a root object) or 1 (just the root content)
 516          $html = "\n" . '<ul class="' . $class . '">' . "\n" . $html . '</ul>' . "\n";
 517      }
 518  
 519      return $html;
 520  }
 521  
 522  /**
 523   * display backlinks
 524   *
 525   * @author Andreas Gohr <andi@splitbrain.org>
 526   * @author Michael Klier <chi@chimeric.de>
 527   * @deprecated 2020-07-18
 528   */
 529  function html_backlinks()
 530  {
 531      dbg_deprecated(Backlinks::class . '::show()');
 532      (new Backlinks())->show();
 533  }
 534  
 535  /**
 536   * Get header of diff HTML
 537   *
 538   * @param string $l_rev   Left revisions
 539   * @param string $r_rev   Right revision
 540   * @param string $id      Page id, if null $ID is used
 541   * @param bool   $media   If it is for media files
 542   * @param bool   $inline  Return the header on a single line
 543   * @return string[] HTML snippets for diff header
 544   * @deprecated 2020-07-18
 545   */
 546  function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false)
 547  {
 548      dbg_deprecated('see ' . PageDiff::class . '::buildDiffHead()');
 549      return ['', '', '', ''];
 550  }
 551  
 552  /**
 553   * Show diff
 554   * between current page version and provided $text
 555   * or between the revisions provided via GET or POST
 556   *
 557   * @author Andreas Gohr <andi@splitbrain.org>
 558   * @param  string $text  when non-empty: compare with this text with most current version
 559   * @param  bool   $intro display the intro text
 560   * @param  string $type  type of the diff (inline or sidebyside)
 561   * @deprecated 2020-07-18
 562   */
 563  function html_diff($text = '', $intro = true, $type = null)
 564  {
 565      dbg_deprecated(PageDiff::class . '::show()');
 566      global $INFO;
 567      (new PageDiff($INFO['id']))->compareWith($text)->preference([
 568          'showIntro' => $intro,
 569          'difftype'  => $type,
 570      ])->show();
 571  }
 572  
 573  /**
 574   * Create html for revision navigation
 575   *
 576   * @param PageChangeLog $pagelog changelog object of current page
 577   * @param string        $type    inline vs sidebyside
 578   * @param int           $l_rev   left revision timestamp
 579   * @param int           $r_rev   right revision timestamp
 580   * @return string[] html of left and right navigation elements
 581   * @deprecated 2020-07-18
 582   */
 583  function html_diff_navigation($pagelog, $type, $l_rev, $r_rev)
 584  {
 585      dbg_deprecated('see ' . PageDiff::class . '::buildRevisionsNavigation()');
 586      return ['', ''];
 587  }
 588  
 589  /**
 590   * Create html link to a diff defined by two revisions
 591   *
 592   * @param string $difftype display type
 593   * @param string $linktype
 594   * @param int $lrev oldest revision
 595   * @param int $rrev newest revision or null for diff with current revision
 596   * @return string html of link to a diff
 597   * @deprecated 2020-07-18
 598   */
 599  function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null)
 600  {
 601      dbg_deprecated('see ' . PageDiff::class . '::diffViewlink()');
 602      return '';
 603  }
 604  
 605  /**
 606   * Insert soft breaks in diff html
 607   *
 608   * @param string $diffhtml
 609   * @return string
 610   * @deprecated 2020-07-18
 611   */
 612  function html_insert_softbreaks($diffhtml)
 613  {
 614      dbg_deprecated(PageDiff::class . '::insertSoftbreaks()');
 615      return (new PageDiff())->insertSoftbreaks($diffhtml);
 616  }
 617  
 618  /**
 619   * show warning on conflict detection
 620   *
 621   * @author Andreas Gohr <andi@splitbrain.org>
 622   *
 623   * @param string $text
 624   * @param string $summary
 625   * @deprecated 2020-07-18
 626   */
 627  function html_conflict($text, $summary)
 628  {
 629      dbg_deprecated(PageConflict::class . '::show()');
 630      (new PageConflict($text, $summary))->show();
 631  }
 632  
 633  /**
 634   * Prints the global message array
 635   *
 636   * @author Andreas Gohr <andi@splitbrain.org>
 637   */
 638  function html_msgarea()
 639  {
 640      global $MSG, $MSG_shown;
 641      /** @var array $MSG */
 642      // store if the global $MSG has already been shown and thus HTML output has been started
 643      $MSG_shown = true;
 644  
 645      if (!isset($MSG)) return;
 646  
 647      $shown = [];
 648      foreach ($MSG as $msg) {
 649          $hash = md5($msg['msg']);
 650          if (isset($shown[$hash])) continue; // skip double messages
 651          if (info_msg_allowed($msg)) {
 652              echo '<div class="' . $msg['lvl'] . '">';
 653              echo $msg['msg'];
 654              echo '</div>';
 655          }
 656          $shown[$hash] = 1;
 657      }
 658  
 659      unset($GLOBALS['MSG']);
 660  }
 661  
 662  /**
 663   * Prints the registration form
 664   *
 665   * @author Andreas Gohr <andi@splitbrain.org>
 666   * @deprecated 2020-07-18
 667   */
 668  function html_register()
 669  {
 670      dbg_deprecated(UserRegister::class . '::show()');
 671      (new UserRegister())->show();
 672  }
 673  
 674  /**
 675   * Print the update profile form
 676   *
 677   * @author Christopher Smith <chris@jalakai.co.uk>
 678   * @author Andreas Gohr <andi@splitbrain.org>
 679   * @deprecated 2020-07-18
 680   */
 681  function html_updateprofile()
 682  {
 683      dbg_deprecated(UserProfile::class . '::show()');
 684      (new UserProfile())->show();
 685  }
 686  
 687  /**
 688   * Preprocess edit form data
 689   *
 690   * @author   Andreas Gohr <andi@splitbrain.org>
 691   *
 692   * @deprecated 2020-07-18
 693   */
 694  function html_edit()
 695  {
 696      dbg_deprecated(Editor::class . '::show()');
 697      (new Editor())->show();
 698  }
 699  
 700  /**
 701   * Display the default edit form
 702   *
 703   * Is the default action for HTML_EDIT_FORMSELECTION.
 704   *
 705   * @param array $param
 706   * @deprecated 2020-07-18
 707   */
 708  function html_edit_form($param)
 709  {
 710      dbg_deprecated(Editor::class . '::addTextarea()');
 711      (new Editor())->addTextarea($param);
 712  }
 713  
 714  /**
 715   * prints some debug info
 716   *
 717   * @author Andreas Gohr <andi@splitbrain.org>
 718   */
 719  function html_debug()
 720  {
 721      global $conf;
 722      global $lang;
 723      /** @var AuthPlugin $auth */
 724      global $auth;
 725      global $INFO;
 726  
 727      //remove sensitive data
 728      $cnf = $conf;
 729      debug_guard($cnf);
 730      $nfo = $INFO;
 731      debug_guard($nfo);
 732      $ses = $_SESSION;
 733      debug_guard($ses);
 734  
 735      echo '<html><body>';
 736  
 737      echo '<p>When reporting bugs please send all the following ';
 738      echo 'output as a mail to andi@splitbrain.org ';
 739      echo 'The best way to do this is to save this page in your browser</p>';
 740  
 741      echo '<b>$INFO:</b><pre>';
 742      print_r($nfo);
 743      echo '</pre>';
 744  
 745      echo '<b>$_SERVER:</b><pre>';
 746      print_r($_SERVER);
 747      echo '</pre>';
 748  
 749      echo '<b>$conf:</b><pre>';
 750      print_r($cnf);
 751      echo '</pre>';
 752  
 753      echo '<b>DOKU_BASE:</b><pre>';
 754      echo DOKU_BASE;
 755      echo '</pre>';
 756  
 757      echo '<b>abs DOKU_BASE:</b><pre>';
 758      echo DOKU_URL;
 759      echo '</pre>';
 760  
 761      echo '<b>rel DOKU_BASE:</b><pre>';
 762      echo dirname($_SERVER['PHP_SELF']) . '/';
 763      echo '</pre>';
 764  
 765      echo '<b>PHP Version:</b><pre>';
 766      echo phpversion();
 767      echo '</pre>';
 768  
 769      echo '<b>locale:</b><pre>';
 770      echo setlocale(LC_ALL, 0);
 771      echo '</pre>';
 772  
 773      echo '<b>encoding:</b><pre>';
 774      echo $lang['encoding'];
 775      echo '</pre>';
 776  
 777      if ($auth instanceof AuthPlugin) {
 778          echo '<b>Auth backend capabilities:</b><pre>';
 779          foreach ($auth->getCapabilities() as $cando) {
 780              echo '   ' . str_pad($cando, 16) . ' => ' . (int)$auth->canDo($cando) . DOKU_LF;
 781          }
 782          echo '</pre>';
 783      }
 784  
 785      echo '<b>$_SESSION:</b><pre>';
 786      print_r($ses);
 787      echo '</pre>';
 788  
 789      echo '<b>Environment:</b><pre>';
 790      print_r($_ENV);
 791      echo '</pre>';
 792  
 793      echo '<b>PHP settings:</b><pre>';
 794      $inis = ini_get_all();
 795      print_r($inis);
 796      echo '</pre>';
 797  
 798      if (function_exists('apache_get_version')) {
 799          $apache = [];
 800          $apache['version'] = apache_get_version();
 801  
 802          if (function_exists('apache_get_modules')) {
 803              $apache['modules'] = apache_get_modules();
 804          }
 805          echo '<b>Apache</b><pre>';
 806          print_r($apache);
 807          echo '</pre>';
 808      }
 809  
 810      echo '</body></html>';
 811  }
 812  
 813  /**
 814   * Form to request a new password for an existing account
 815   *
 816   * @author Benoit Chesneau <benoit@bchesneau.info>
 817   * @author Andreas Gohr <gohr@cosmocode.de>
 818   * @deprecated 2020-07-18
 819   */
 820  function html_resendpwd()
 821  {
 822      dbg_deprecated(UserResendPwd::class . '::show()');
 823      (new UserResendPwd())->show();
 824  }
 825  
 826  /**
 827   * Return the TOC rendered to XHTML
 828   *
 829   * @author Andreas Gohr <andi@splitbrain.org>
 830   *
 831   * @param array $toc
 832   * @return string html
 833   */
 834  function html_TOC($toc)
 835  {
 836      if ($toc === []) return '';
 837      global $lang;
 838      $out  = '<!-- TOC START -->' . DOKU_LF;
 839      $out .= '<div id="dw__toc" class="dw__toc">' . DOKU_LF;
 840      $out .= '<h3 class="toggle">';
 841      $out .= $lang['toc'];
 842      $out .= '</h3>' . DOKU_LF;
 843      $out .= '<div>' . DOKU_LF;
 844      $out .= html_buildlist($toc, 'toc', 'html_list_toc', null, true);
 845      $out .= '</div>' . DOKU_LF . '</div>' . DOKU_LF;
 846      $out .= '<!-- TOC END -->' . DOKU_LF;
 847      return $out;
 848  }
 849  
 850  /**
 851   * Callback for html_buildlist
 852   *
 853   * @param array $item
 854   * @return string html
 855   */
 856  function html_list_toc($item)
 857  {
 858      if (isset($item['hid'])) {
 859          $link = '#' . $item['hid'];
 860      } else {
 861          $link = $item['link'];
 862      }
 863  
 864      return '<a href="' . $link . '">' . hsc($item['title']) . '</a>';
 865  }
 866  
 867  /**
 868   * Helper function to build TOC items
 869   *
 870   * Returns an array ready to be added to a TOC array
 871   *
 872   * @param string $link  - where to link (if $hash set to '#' it's a local anchor)
 873   * @param string $text  - what to display in the TOC
 874   * @param int    $level - nesting level
 875   * @param string $hash  - is prepended to the given $link, set blank if you want full links
 876   * @return array the toc item
 877   */
 878  function html_mktocitem($link, $text, $level, $hash = '#')
 879  {
 880      return  [
 881          'link'  => $hash . $link,
 882          'title' => $text,
 883          'type'  => 'ul',
 884          'level' => $level
 885      ];
 886  }
 887  
 888  /**
 889   * Output a Doku_Form object.
 890   * Triggers an event with the form name: HTML_{$name}FORM_OUTPUT
 891   *
 892   * @author Tom N Harris <tnharris@whoopdedo.org>
 893   *
 894   * @param string     $name The name of the form
 895   * @param Doku_Form  $form The form
 896   * @return void
 897   * @deprecated 2020-07-18
 898   */
 899  function html_form($name, $form)
 900  {
 901      dbg_deprecated('use dokuwiki\Form\Form instead of Doku_Form');
 902      // Safety check in case the caller forgets.
 903      $form->endFieldset();
 904      Event::createAndTrigger('HTML_' . strtoupper($name) . 'FORM_OUTPUT', $form, 'html_form_output', false);
 905  }
 906  
 907  /**
 908   * Form print function.
 909   * Just calls printForm() on the form object.
 910   *
 911   * @param Doku_Form $form The form
 912   * @return void
 913   * @deprecated 2020-07-18
 914   */
 915  function html_form_output($form)
 916  {
 917      dbg_deprecated('use ' . Form::class . '::toHTML()');
 918      $form->printForm();
 919  }
 920  
 921  /**
 922   * Embed a flash object in HTML
 923   *
 924   * This will create the needed HTML to embed a flash movie in a cross browser
 925   * compatble way using valid XHTML
 926   *
 927   * The parameters $params, $flashvars and $atts need to be associative arrays.
 928   * No escaping needs to be done for them. The alternative content *has* to be
 929   * escaped because it is used as is. If no alternative content is given
 930   * $lang['noflash'] is used.
 931   *
 932   * @author Andreas Gohr <andi@splitbrain.org>
 933   * @link   http://latrine.dgx.cz/how-to-correctly-insert-a-flash-into-xhtml
 934   *
 935   * @param string $swf      - the SWF movie to embed
 936   * @param int $width       - width of the flash movie in pixels
 937   * @param int $height      - height of the flash movie in pixels
 938   * @param array $params    - additional parameters (<param>)
 939   * @param array $flashvars - parameters to be passed in the flashvar parameter
 940   * @param array $atts      - additional attributes for the <object> tag
 941   * @param string $alt      - alternative content (is NOT automatically escaped!)
 942   * @return string         - the XHTML markup
 943   */
 944  function html_flashobject($swf, $width, $height, $params = null, $flashvars = null, $atts = null, $alt = '')
 945  {
 946      global $lang;
 947  
 948      $out = '';
 949  
 950      // prepare the object attributes
 951      if (is_null($atts)) $atts = [];
 952      $atts['width']  = (int) $width;
 953      $atts['height'] = (int) $height;
 954      if (!$atts['width'])  $atts['width']  = 425;
 955      if (!$atts['height']) $atts['height'] = 350;
 956  
 957      // add object attributes for standard compliant browsers
 958      $std = $atts;
 959      $std['type'] = 'application/x-shockwave-flash';
 960      $std['data'] = $swf;
 961  
 962      // add object attributes for IE
 963      $ie  = $atts;
 964      $ie['classid'] = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
 965  
 966      // open object (with conditional comments)
 967      $out .= '<!--[if !IE]> -->' . NL;
 968      $out .= '<object ' . buildAttributes($std) . '>' . NL;
 969      $out .= '<!-- <![endif]-->' . NL;
 970      $out .= '<!--[if IE]>' . NL;
 971      $out .= '<object ' . buildAttributes($ie) . '>' . NL;
 972      $out .= '    <param name="movie" value="' . hsc($swf) . '" />' . NL;
 973      $out .= '<!--><!-- -->' . NL;
 974  
 975      // print params
 976      if (is_array($params)) foreach ($params as $key => $val) {
 977          $out .= '  <param name="' . hsc($key) . '" value="' . hsc($val) . '" />' . NL;
 978      }
 979  
 980      // add flashvars
 981      if (is_array($flashvars)) {
 982          $out .= '  <param name="FlashVars" value="' . buildURLparams($flashvars) . '" />' . NL;
 983      }
 984  
 985      // alternative content
 986      if ($alt) {
 987          $out .= $alt . NL;
 988      } else {
 989          $out .= $lang['noflash'] . NL;
 990      }
 991  
 992      // finish
 993      $out .= '</object>' . NL;
 994      $out .= '<!-- <![endif]-->' . NL;
 995  
 996      return $out;
 997  }
 998  
 999  /**
1000   * Prints HTML code for the given tab structure
1001   *
1002   * @param array  $tabs        tab structure
1003   * @param string $current_tab the current tab id
1004   * @return void
1005   */
1006  function html_tabs($tabs, $current_tab = null)
1007  {
1008      echo '<ul class="tabs">' . NL;
1009  
1010      foreach ($tabs as $id => $tab) {
1011          html_tab($tab['href'], $tab['caption'], $id === $current_tab);
1012      }
1013  
1014      echo '</ul>' . NL;
1015  }
1016  
1017  /**
1018   * Prints a single tab
1019   *
1020   * @author Kate Arzamastseva <pshns@ukr.net>
1021   * @author Adrian Lang <mail@adrianlang.de>
1022   *
1023   * @param string $href - tab href
1024   * @param string $caption - tab caption
1025   * @param boolean $selected - is tab selected
1026   * @return void
1027   */
1028  
1029  function html_tab($href, $caption, $selected = false)
1030  {
1031      $tab = '<li>';
1032      if ($selected) {
1033          $tab .= '<strong>';
1034      } else {
1035          $tab .= '<a href="' . hsc($href) . '">';
1036      }
1037      $tab .= hsc($caption)
1038           .  '</' . ($selected ? 'strong' : 'a') . '>'
1039           .  '</li>' . NL;
1040      echo $tab;
1041  }
1042  
1043  /**
1044   * Display size change
1045   *
1046   * @param int $sizechange - size of change in Bytes
1047   * @param Doku_Form $form - (optional) form to add elements to
1048   * @return void|string
1049   */
1050  function html_sizechange($sizechange, $form = null)
1051  {
1052      if (isset($sizechange)) {
1053          $class = 'sizechange';
1054          $value = filesize_h(abs($sizechange));
1055          if ($sizechange > 0) {
1056              $class .= ' positive';
1057              $value = '+' . $value;
1058          } elseif ($sizechange < 0) {
1059              $class .= ' negative';
1060              $value = '-' . $value;
1061          } else {
1062              $value = '±' . $value;
1063          }
1064          if (!isset($form)) {
1065              return '<span class="' . $class . '">' . $value . '</span>';
1066          } else { // Doku_Form
1067              $form->addElement(form_makeOpenTag('span', ['class' => $class]));
1068              $form->addElement($value);
1069              $form->addElement(form_makeCloseTag('span'));
1070          }
1071      }
1072  }