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