Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  
   3  class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
   4  {
   5  
   6      /**
   7       * @type HTMLPurifier_HTMLDefinition, for easy access
   8       */
   9      protected $def;
  10  
  11      /**
  12       * @param HTMLPurifier_Config $config
  13       * @return string
  14       */
  15      public function render($config)
  16      {
  17          $ret = '';
  18          $this->config =& $config;
  19  
  20          $this->def = $config->getHTMLDefinition();
  21  
  22          $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer'));
  23  
  24          $ret .= $this->renderDoctype();
  25          $ret .= $this->renderEnvironment();
  26          $ret .= $this->renderContentSets();
  27          $ret .= $this->renderInfo();
  28  
  29          $ret .= $this->end('div');
  30  
  31          return $ret;
  32      }
  33  
  34      /**
  35       * Renders the Doctype table
  36       * @return string
  37       */
  38      protected function renderDoctype()
  39      {
  40          $doctype = $this->def->doctype;
  41          $ret = '';
  42          $ret .= $this->start('table');
  43          $ret .= $this->element('caption', 'Doctype');
  44          $ret .= $this->row('Name', $doctype->name);
  45          $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No');
  46          $ret .= $this->row('Default Modules', implode(', ', $doctype->modules));
  47          $ret .= $this->row('Default Tidy Modules', implode(', ', $doctype->tidyModules));
  48          $ret .= $this->end('table');
  49          return $ret;
  50      }
  51  
  52  
  53      /**
  54       * Renders environment table, which is miscellaneous info
  55       * @return string
  56       */
  57      protected function renderEnvironment()
  58      {
  59          $def = $this->def;
  60  
  61          $ret = '';
  62  
  63          $ret .= $this->start('table');
  64          $ret .= $this->element('caption', 'Environment');
  65  
  66          $ret .= $this->row('Parent of fragment', $def->info_parent);
  67          $ret .= $this->renderChildren($def->info_parent_def->child);
  68          $ret .= $this->row('Block wrap name', $def->info_block_wrapper);
  69  
  70          $ret .= $this->start('tr');
  71          $ret .= $this->element('th', 'Global attributes');
  72          $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0);
  73          $ret .= $this->end('tr');
  74  
  75          $ret .= $this->start('tr');
  76          $ret .= $this->element('th', 'Tag transforms');
  77          $list = array();
  78          foreach ($def->info_tag_transform as $old => $new) {
  79              $new = $this->getClass($new, 'TagTransform_');
  80              $list[] = "<$old> with $new";
  81          }
  82          $ret .= $this->element('td', $this->listify($list));
  83          $ret .= $this->end('tr');
  84  
  85          $ret .= $this->start('tr');
  86          $ret .= $this->element('th', 'Pre-AttrTransform');
  87          $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre));
  88          $ret .= $this->end('tr');
  89  
  90          $ret .= $this->start('tr');
  91          $ret .= $this->element('th', 'Post-AttrTransform');
  92          $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post));
  93          $ret .= $this->end('tr');
  94  
  95          $ret .= $this->end('table');
  96          return $ret;
  97      }
  98  
  99      /**
 100       * Renders the Content Sets table
 101       * @return string
 102       */
 103      protected function renderContentSets()
 104      {
 105          $ret = '';
 106          $ret .= $this->start('table');
 107          $ret .= $this->element('caption', 'Content Sets');
 108          foreach ($this->def->info_content_sets as $name => $lookup) {
 109              $ret .= $this->heavyHeader($name);
 110              $ret .= $this->start('tr');
 111              $ret .= $this->element('td', $this->listifyTagLookup($lookup));
 112              $ret .= $this->end('tr');
 113          }
 114          $ret .= $this->end('table');
 115          return $ret;
 116      }
 117  
 118      /**
 119       * Renders the Elements ($info) table
 120       * @return string
 121       */
 122      protected function renderInfo()
 123      {
 124          $ret = '';
 125          $ret .= $this->start('table');
 126          $ret .= $this->element('caption', 'Elements ($info)');
 127          ksort($this->def->info);
 128          $ret .= $this->heavyHeader('Allowed tags', 2);
 129          $ret .= $this->start('tr');
 130          $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2));
 131          $ret .= $this->end('tr');
 132          foreach ($this->def->info as $name => $def) {
 133              $ret .= $this->start('tr');
 134              $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2));
 135              $ret .= $this->end('tr');
 136              $ret .= $this->start('tr');
 137              $ret .= $this->element('th', 'Inline content');
 138              $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No');
 139              $ret .= $this->end('tr');
 140              if (!empty($def->excludes)) {
 141                  $ret .= $this->start('tr');
 142                  $ret .= $this->element('th', 'Excludes');
 143                  $ret .= $this->element('td', $this->listifyTagLookup($def->excludes));
 144                  $ret .= $this->end('tr');
 145              }
 146              if (!empty($def->attr_transform_pre)) {
 147                  $ret .= $this->start('tr');
 148                  $ret .= $this->element('th', 'Pre-AttrTransform');
 149                  $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre));
 150                  $ret .= $this->end('tr');
 151              }
 152              if (!empty($def->attr_transform_post)) {
 153                  $ret .= $this->start('tr');
 154                  $ret .= $this->element('th', 'Post-AttrTransform');
 155                  $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post));
 156                  $ret .= $this->end('tr');
 157              }
 158              if (!empty($def->auto_close)) {
 159                  $ret .= $this->start('tr');
 160                  $ret .= $this->element('th', 'Auto closed by');
 161                  $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close));
 162                  $ret .= $this->end('tr');
 163              }
 164              $ret .= $this->start('tr');
 165              $ret .= $this->element('th', 'Allowed attributes');
 166              $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0);
 167              $ret .= $this->end('tr');
 168  
 169              if (!empty($def->required_attr)) {
 170                  $ret .= $this->row('Required attributes', $this->listify($def->required_attr));
 171              }
 172  
 173              $ret .= $this->renderChildren($def->child);
 174          }
 175          $ret .= $this->end('table');
 176          return $ret;
 177      }
 178  
 179      /**
 180       * Renders a row describing the allowed children of an element
 181       * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element
 182       * @return string
 183       */
 184      protected function renderChildren($def)
 185      {
 186          $context = new HTMLPurifier_Context();
 187          $ret = '';
 188          $ret .= $this->start('tr');
 189          $elements = array();
 190          $attr = array();
 191          if (isset($def->elements)) {
 192              if ($def->type == 'strictblockquote') {
 193                  $def->validateChildren(array(), $this->config, $context);
 194              }
 195              $elements = $def->elements;
 196          }
 197          if ($def->type == 'chameleon') {
 198              $attr['rowspan'] = 2;
 199          } elseif ($def->type == 'empty') {
 200              $elements = array();
 201          } elseif ($def->type == 'table') {
 202              $elements = array_flip(
 203                  array(
 204                      'col',
 205                      'caption',
 206                      'colgroup',
 207                      'thead',
 208                      'tfoot',
 209                      'tbody',
 210                      'tr'
 211                  )
 212              );
 213          }
 214          $ret .= $this->element('th', 'Allowed children', $attr);
 215  
 216          if ($def->type == 'chameleon') {
 217  
 218              $ret .= $this->element(
 219                  'td',
 220                  '<em>Block</em>: ' .
 221                  $this->escape($this->listifyTagLookup($def->block->elements)),
 222                  null,
 223                  0
 224              );
 225              $ret .= $this->end('tr');
 226              $ret .= $this->start('tr');
 227              $ret .= $this->element(
 228                  'td',
 229                  '<em>Inline</em>: ' .
 230                  $this->escape($this->listifyTagLookup($def->inline->elements)),
 231                  null,
 232                  0
 233              );
 234  
 235          } elseif ($def->type == 'custom') {
 236  
 237              $ret .= $this->element(
 238                  'td',
 239                  '<em>' . ucfirst($def->type) . '</em>: ' .
 240                  $def->dtd_regex
 241              );
 242  
 243          } else {
 244              $ret .= $this->element(
 245                  'td',
 246                  '<em>' . ucfirst($def->type) . '</em>: ' .
 247                  $this->escape($this->listifyTagLookup($elements)),
 248                  null,
 249                  0
 250              );
 251          }
 252          $ret .= $this->end('tr');
 253          return $ret;
 254      }
 255  
 256      /**
 257       * Listifies a tag lookup table.
 258       * @param array $array Tag lookup array in form of array('tagname' => true)
 259       * @return string
 260       */
 261      protected function listifyTagLookup($array)
 262      {
 263          ksort($array);
 264          $list = array();
 265          foreach ($array as $name => $discard) {
 266              if ($name !== '#PCDATA' && !isset($this->def->info[$name])) {
 267                  continue;
 268              }
 269              $list[] = $name;
 270          }
 271          return $this->listify($list);
 272      }
 273  
 274      /**
 275       * Listifies a list of objects by retrieving class names and internal state
 276       * @param array $array List of objects
 277       * @return string
 278       * @todo Also add information about internal state
 279       */
 280      protected function listifyObjectList($array)
 281      {
 282          ksort($array);
 283          $list = array();
 284          foreach ($array as $obj) {
 285              $list[] = $this->getClass($obj, 'AttrTransform_');
 286          }
 287          return $this->listify($list);
 288      }
 289  
 290      /**
 291       * Listifies a hash of attributes to AttrDef classes
 292       * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef)
 293       * @return string
 294       */
 295      protected function listifyAttr($array)
 296      {
 297          ksort($array);
 298          $list = array();
 299          foreach ($array as $name => $obj) {
 300              if ($obj === false) {
 301                  continue;
 302              }
 303              $list[] = "$name&nbsp;=&nbsp;<i>" . $this->getClass($obj, 'AttrDef_') . '</i>';
 304          }
 305          return $this->listify($list);
 306      }
 307  
 308      /**
 309       * Creates a heavy header row
 310       * @param string $text
 311       * @param int $num
 312       * @return string
 313       */
 314      protected function heavyHeader($text, $num = 1)
 315      {
 316          $ret = '';
 317          $ret .= $this->start('tr');
 318          $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy'));
 319          $ret .= $this->end('tr');
 320          return $ret;
 321      }
 322  }
 323  
 324  // vim: et sw=4 sts=4