Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

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

   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          if (is_string($list)) {
 261              $list = func_get_args();
 262          }
 263          $ret = array();
 264          foreach ($list as $value) {
 265              if (is_null($value)) {
 266                  continue;
 267              }
 268              $ret[$value] = true;
 269          }
 270          return $ret;
 271      }
 272  
 273      /**

 274       * Lazy load construction of the module after determining whether

 275       * or not it's needed, and also when a finalized configuration object

 276       * is available.

 277       * @param HTMLPurifier_Config $config

 278       */
 279      public function setup($config)
 280      {
 281      }
 282  }
 283  
 284  // vim: et sw=4 sts=4