Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

   1  <?php
   2  
   3  /**

   4   * Structure that stores an HTML element definition. Used by

   5   * HTMLPurifier_HTMLDefinition and HTMLPurifier_HTMLModule.

   6   * @note This class is inspected by HTMLPurifier_Printer_HTMLDefinition.

   7   *       Please update that class too.

   8   * @warning If you add new properties to this class, you MUST update

   9   *          the mergeIn() method.

  10   */
  11  class HTMLPurifier_ElementDef
  12  {
  13      /**

  14       * Does the definition work by itself, or is it created solely

  15       * for the purpose of merging into another definition?

  16       * @type bool

  17       */
  18      public $standalone = true;
  19  
  20      /**

  21       * Associative array of attribute name to HTMLPurifier_AttrDef.

  22       * @type array

  23       * @note Before being processed by HTMLPurifier_AttrCollections

  24       *       when modules are finalized during

  25       *       HTMLPurifier_HTMLDefinition->setup(), this array may also

  26       *       contain an array at index 0 that indicates which attribute

  27       *       collections to load into the full array. It may also

  28       *       contain string indentifiers in lieu of HTMLPurifier_AttrDef,

  29       *       see HTMLPurifier_AttrTypes on how they are expanded during

  30       *       HTMLPurifier_HTMLDefinition->setup() processing.

  31       */
  32      public $attr = array();
  33  
  34      // XXX: Design note: currently, it's not possible to override

  35      // previously defined AttrTransforms without messing around with

  36      // the final generated config. This is by design; a previous version

  37      // used an associated list of attr_transform, but it was extremely

  38      // easy to accidentally override other attribute transforms by

  39      // forgetting to specify an index (and just using 0.)  While we

  40      // could check this by checking the index number and complaining,

  41      // there is a second problem which is that it is not at all easy to

  42      // tell when something is getting overridden. Combine this with a

  43      // codebase where this isn't really being used, and it's perfect for

  44      // nuking.

  45  
  46      /**

  47       * List of tags HTMLPurifier_AttrTransform to be done before validation.

  48       * @type array

  49       */
  50      public $attr_transform_pre = array();
  51  
  52      /**

  53       * List of tags HTMLPurifier_AttrTransform to be done after validation.

  54       * @type array

  55       */
  56      public $attr_transform_post = array();
  57  
  58      /**

  59       * HTMLPurifier_ChildDef of this tag.

  60       * @type HTMLPurifier_ChildDef

  61       */
  62      public $child;
  63  
  64      /**

  65       * Abstract string representation of internal ChildDef rules.

  66       * @see HTMLPurifier_ContentSets for how this is parsed and then transformed

  67       * into an HTMLPurifier_ChildDef.

  68       * @warning This is a temporary variable that is not available after

  69       *      being processed by HTMLDefinition

  70       * @type string

  71       */
  72      public $content_model;
  73  
  74      /**

  75       * Value of $child->type, used to determine which ChildDef to use,

  76       * used in combination with $content_model.

  77       * @warning This must be lowercase

  78       * @warning This is a temporary variable that is not available after

  79       *      being processed by HTMLDefinition

  80       * @type string

  81       */
  82      public $content_model_type;
  83  
  84      /**

  85       * Does the element have a content model (#PCDATA | Inline)*? This

  86       * is important for chameleon ins and del processing in

  87       * HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't

  88       * have to worry about this one.

  89       * @type bool

  90       */
  91      public $descendants_are_inline = false;
  92  
  93      /**

  94       * List of the names of required attributes this element has.

  95       * Dynamically populated by HTMLPurifier_HTMLDefinition::getElement()

  96       * @type array

  97       */
  98      public $required_attr = array();
  99  
 100      /**

 101       * Lookup table of tags excluded from all descendants of this tag.

 102       * @type array

 103       * @note SGML permits exclusions for all descendants, but this is

 104       *       not possible with DTDs or XML Schemas. W3C has elected to

 105       *       use complicated compositions of content_models to simulate

 106       *       exclusion for children, but we go the simpler, SGML-style

 107       *       route of flat-out exclusions, which correctly apply to

 108       *       all descendants and not just children. Note that the XHTML

 109       *       Modularization Abstract Modules are blithely unaware of such

 110       *       distinctions.

 111       */
 112      public $excludes = array();
 113  
 114      /**

 115       * This tag is explicitly auto-closed by the following tags.

 116       * @type array

 117       */
 118      public $autoclose = array();
 119  
 120      /**

 121       * If a foreign element is found in this element, test if it is

 122       * allowed by this sub-element; if it is, instead of closing the

 123       * current element, place it inside this element.

 124       * @type string

 125       */
 126      public $wrap;
 127  
 128      /**

 129       * Whether or not this is a formatting element affected by the

 130       * "Active Formatting Elements" algorithm.

 131       * @type bool

 132       */
 133      public $formatting;
 134  
 135      /**

 136       * Low-level factory constructor for creating new standalone element defs

 137       */
 138      public static function create($content_model, $content_model_type, $attr)
 139      {
 140          $def = new HTMLPurifier_ElementDef();
 141          $def->content_model = $content_model;
 142          $def->content_model_type = $content_model_type;
 143          $def->attr = $attr;
 144          return $def;
 145      }
 146  
 147      /**

 148       * Merges the values of another element definition into this one.

 149       * Values from the new element def take precedence if a value is

 150       * not mergeable.

 151       * @param HTMLPurifier_ElementDef $def

 152       */
 153      public function mergeIn($def)
 154      {
 155          // later keys takes precedence

 156          foreach ($def->attr as $k => $v) {
 157              if ($k === 0) {
 158                  // merge in the includes

 159                  // sorry, no way to override an include

 160                  foreach ($v as $v2) {
 161                      $this->attr[0][] = $v2;
 162                  }
 163                  continue;
 164              }
 165              if ($v === false) {
 166                  if (isset($this->attr[$k])) {
 167                      unset($this->attr[$k]);
 168                  }
 169                  continue;
 170              }
 171              $this->attr[$k] = $v;
 172          }
 173          $this->_mergeAssocArray($this->excludes, $def->excludes);
 174          $this->attr_transform_pre = array_merge($this->attr_transform_pre, $def->attr_transform_pre);
 175          $this->attr_transform_post = array_merge($this->attr_transform_post, $def->attr_transform_post);
 176  
 177          if (!empty($def->content_model)) {
 178              $this->content_model =
 179                  str_replace("#SUPER", $this->content_model, $def->content_model);
 180              $this->child = false;
 181          }
 182          if (!empty($def->content_model_type)) {
 183              $this->content_model_type = $def->content_model_type;
 184              $this->child = false;
 185          }
 186          if (!is_null($def->child)) {
 187              $this->child = $def->child;
 188          }
 189          if (!is_null($def->formatting)) {
 190              $this->formatting = $def->formatting;
 191          }
 192          if ($def->descendants_are_inline) {
 193              $this->descendants_are_inline = $def->descendants_are_inline;
 194          }
 195      }
 196  
 197      /**

 198       * Merges one array into another, removes values which equal false

 199       * @param $a1 Array by reference that is merged into

 200       * @param $a2 Array that merges into $a1

 201       */
 202      private function _mergeAssocArray(&$a1, $a2)
 203      {
 204          foreach ($a2 as $k => $v) {
 205              if ($v === false) {
 206                  if (isset($a1[$k])) {
 207                      unset($a1[$k]);
 208                  }
 209                  continue;
 210              }
 211              $a1[$k] = $v;
 212          }
 213      }
 214  }
 215  
 216  // vim: et sw=4 sts=4