Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402]

   1  <?php
   2  
   3  /**
   4   * Represents an XHTML 1.1 module, with information on elements, tags
   5   * and attributes.
   6   * @note Even though this is technically XHTML 1.1, it is also used for
   7   *       regular HTML parsing. We are using modulization as a convenient
   8   *       way to represent the internals of HTMLDefinition, and our
   9   *       implementation is by no means conforming and does not directly
  10   *       use the normative DTDs or XML schemas.
  11   * @note The public variables in a module should almost directly
  12   *       correspond to the variables in HTMLPurifier_HTMLDefinition.
  13   *       However, the prefix info carries no special meaning in these
  14   *       objects (include it anyway if that's the correspondence though).
  15   * @todo Consider making some member functions protected
  16   */
  17  
  18  class HTMLPurifier_HTMLModule
  19  {
  20  
  21      // -- Overloadable ----------------------------------------------------
  22  
  23      /**
  24       * Short unique string identifier of the module.
  25       * @type string
  26       */
  27      public $name;
  28  
  29      /**
  30       * Informally, a list of elements this module changes.
  31       * Not used in any significant way.
  32       * @type array
  33       */
  34      public $elements = array();
  35  
  36      /**
  37       * Associative array of element names to element definitions.
  38       * Some definitions may be incomplete, to be merged in later
  39       * with the full definition.
  40       * @type array
  41       */
  42      public $info = array();
  43  
  44      /**
  45       * Associative array of content set names to content set additions.
  46       * This is commonly used to, say, add an A element to the Inline
  47       * content set. This corresponds to an internal variable $content_sets
  48       * and NOT info_content_sets member variable of HTMLDefinition.
  49       * @type array
  50       */
  51      public $content_sets = array();
  52  
  53      /**
  54       * Associative array of attribute collection names to attribute
  55       * collection additions. More rarely used for adding attributes to
  56       * the global collections. Example is the StyleAttribute module adding
  57       * the style attribute to the Core. Corresponds to HTMLDefinition's
  58       * attr_collections->info, since the object's data is only info,
  59       * with extra behavior associated with it.
  60       * @type array
  61       */
  62      public $attr_collections = array();
  63  
  64      /**
  65       * Associative array of deprecated tag name to HTMLPurifier_TagTransform.
  66       * @type array
  67       */
  68      public $info_tag_transform = array();
  69  
  70      /**
  71       * List of HTMLPurifier_AttrTransform to be performed before validation.
  72       * @type array
  73       */
  74      public $info_attr_transform_pre = array();
  75  
  76      /**
  77       * List of HTMLPurifier_AttrTransform to be performed after validation.
  78       * @type array
  79       */
  80      public $info_attr_transform_post = array();
  81  
  82      /**
  83       * List of HTMLPurifier_Injector to be performed during well-formedness fixing.
  84       * An injector will only be invoked if all of it's pre-requisites are met;
  85       * if an injector fails setup, there will be no error; it will simply be
  86       * silently disabled.
  87       * @type array
  88       */
  89      public $info_injector = array();
  90  
  91      /**
  92       * Boolean flag that indicates whether or not getChildDef is implemented.
  93       * For optimization reasons: may save a call to a function. Be sure
  94       * to set it if you do implement getChildDef(), otherwise it will have
  95       * no effect!
  96       * @type bool
  97       */
  98      public $defines_child_def = false;
  99  
 100      /**
 101       * Boolean flag whether or not this module is safe. If it is not safe, all
 102       * of its members are unsafe. Modules are safe by default (this might be
 103       * slightly dangerous, but it doesn't make much sense to force HTML Purifier,
 104       * which is based off of safe HTML, to explicitly say, "This is safe," even
 105       * though there are modules which are "unsafe")
 106       *
 107       * @type bool
 108       * @note Previously, safety could be applied at an element level granularity.
 109       *       We've removed this ability, so in order to add "unsafe" elements
 110       *       or attributes, a dedicated module with this property set to false
 111       *       must be used.
 112       */
 113      public $safe = true;
 114  
 115      /**
 116       * Retrieves a proper HTMLPurifier_ChildDef subclass based on
 117       * content_model and content_model_type member variables of
 118       * the HTMLPurifier_ElementDef class. There is a similar function
 119       * in HTMLPurifier_HTMLDefinition.
 120       * @param HTMLPurifier_ElementDef $def
 121       * @return HTMLPurifier_ChildDef subclass
 122       */
 123      public function getChildDef($def)
 124      {
 125          return false;
 126      }
 127  
 128      // -- Convenience -----------------------------------------------------
 129  
 130      /**
 131       * Convenience function that sets up a new element
 132       * @param string $element Name of element to add
 133       * @param string|bool $type What content set should element be registered to?
 134       *              Set as false to skip this step.
 135       * @param string|HTMLPurifier_ChildDef $contents Allowed children in form of:
 136       *              "$content_model_type: $content_model"
 137       * @param array|string $attr_includes What attribute collections to register to
 138       *              element?
 139       * @param array $attr What unique attributes does the element define?
 140       * @see HTMLPurifier_ElementDef:: for in-depth descriptions of these parameters.
 141       * @return HTMLPurifier_ElementDef Created element definition object, so you
 142       *         can set advanced parameters
 143       */
 144      public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array())
 145      {
 146          $this->elements[] = $element;
 147          // parse content_model
 148          list($content_model_type, $content_model) = $this->parseContents($contents);
 149          // merge in attribute inclusions
 150          $this->mergeInAttrIncludes($attr, $attr_includes);
 151          // add element to content sets
 152          if ($type) {
 153              $this->addElementToContentSet($element, $type);
 154          }
 155          // create element
 156          $this->info[$element] = HTMLPurifier_ElementDef::create(
 157              $content_model,
 158              $content_model_type,
 159              $attr
 160          );
 161          // literal object $contents means direct child manipulation
 162          if (!is_string($contents)) {
 163              $this->info[$element]->child = $contents;
 164          }
 165          return $this->info[$element];
 166      }
 167  
 168      /**
 169       * Convenience function that creates a totally blank, non-standalone
 170       * element.
 171       * @param string $element Name of element to create
 172       * @return HTMLPurifier_ElementDef Created element
 173       */
 174      public function addBlankElement($element)
 175      {
 176          if (!isset($this->info[$element])) {
 177              $this->elements[] = $element;
 178              $this->info[$element] = new HTMLPurifier_ElementDef();
 179              $this->info[$element]->standalone = false;
 180          } else {
 181              trigger_error("Definition for $element already exists in module, cannot redefine");
 182          }
 183          return $this->info[$element];
 184      }
 185  
 186      /**
 187       * Convenience function that registers an element to a content set
 188       * @param string $element Element to register
 189       * @param string $type Name content set (warning: case sensitive, usually upper-case
 190       *        first letter)
 191       */
 192      public function addElementToContentSet($element, $type)
 193      {
 194          if (!isset($this->content_sets[$type])) {
 195              $this->content_sets[$type] = '';
 196          } else {
 197              $this->content_sets[$type] .= ' | ';
 198          }
 199          $this->content_sets[$type] .= $element;
 200      }
 201  
 202      /**
 203       * Convenience function that transforms single-string contents
 204       * into separate content model and content model type
 205       * @param string $contents Allowed children in form of:
 206       *                  "$content_model_type: $content_model"
 207       * @return array
 208       * @note If contents is an object, an array of two nulls will be
 209       *       returned, and the callee needs to take the original $contents
 210       *       and use it directly.
 211       */
 212      public function parseContents($contents)
 213      {
 214          if (!is_string($contents)) {
 215              return array(null, null);
 216          } // defer
 217          switch ($contents) {
 218              // check for shorthand content model forms
 219              case 'Empty':
 220                  return array('empty', '');
 221              case 'Inline':
 222                  return array('optional', 'Inline | #PCDATA');
 223              case 'Flow':
 224                  return array('optional', 'Flow | #PCDATA');
 225          }
 226          list($content_model_type, $content_model) = explode(':', $contents);
 227          $content_model_type = strtolower(trim($content_model_type));
 228          $content_model = trim($content_model);
 229          return array($content_model_type, $content_model);
 230      }
 231  
 232      /**
 233       * Convenience function that merges a list of attribute includes into
 234       * an attribute array.
 235       * @param array $attr Reference to attr array to modify
 236       * @param array $attr_includes Array of includes / string include to merge in
 237       */
 238      public function mergeInAttrIncludes(&$attr, $attr_includes)
 239      {
 240          if (!is_array($attr_includes)) {
 241              if (empty($attr_includes)) {
 242                  $attr_includes = array();
 243              } else {
 244                  $attr_includes = array($attr_includes);
 245              }
 246          }
 247          $attr[0] = $attr_includes;
 248      }
 249  
 250      /**
 251       * Convenience function that generates a lookup table with boolean
 252       * true as value.
 253       * @param string $list List of values to turn into a lookup
 254       * @note You can also pass an arbitrary number of arguments in
 255       *       place of the regular argument
 256       * @return array array equivalent of list
 257       */
 258      public function makeLookup($list)
 259      {
 260          $args = func_get_args();
 261          if (is_string($list)) {
 262              $list = $args;
 263          }
 264          $ret = array();
 265          foreach ($list as $value) {
 266              if (is_null($value)) {
 267                  continue;
 268              }
 269              $ret[$value] = true;
 270          }
 271          return $ret;
 272      }
 273  
 274      /**
 275       * Lazy load construction of the module after determining whether
 276       * or not it's needed, and also when a finalized configuration object
 277       * is available.
 278       * @param HTMLPurifier_Config $config
 279       */
 280      public function setup($config)
 281      {
 282      }
 283  }
 284  
 285  // vim: et sw=4 sts=4