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.
   1  <?php
   2  
   3  /**

   4   * Validates the attributes of a token. Doesn't manage required attributes

   5   * very well. The only reason we factored this out was because RemoveForeignElements

   6   * also needed it besides ValidateAttributes.

   7   */
   8  class HTMLPurifier_AttrValidator
   9  {
  10  
  11      /**

  12       * Validates the attributes of a token, mutating it as necessary.

  13       * that has valid tokens

  14       * @param HTMLPurifier_Token $token Token to validate.

  15       * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config

  16       * @param HTMLPurifier_Context $context Instance of HTMLPurifier_Context

  17       */
  18      public function validateToken($token, $config, $context)
  19      {
  20          $definition = $config->getHTMLDefinition();
  21          $e =& $context->get('ErrorCollector', true);
  22  
  23          // initialize IDAccumulator if necessary

  24          $ok =& $context->get('IDAccumulator', true);
  25          if (!$ok) {
  26              $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
  27              $context->register('IDAccumulator', $id_accumulator);
  28          }
  29  
  30          // initialize CurrentToken if necessary

  31          $current_token =& $context->get('CurrentToken', true);
  32          if (!$current_token) {
  33              $context->register('CurrentToken', $token);
  34          }
  35  
  36          if (!$token instanceof HTMLPurifier_Token_Start &&
  37              !$token instanceof HTMLPurifier_Token_Empty
  38          ) {
  39              return;
  40          }
  41  
  42          // create alias to global definition array, see also $defs

  43          // DEFINITION CALL

  44          $d_defs = $definition->info_global_attr;
  45  
  46          // don't update token until the very end, to ensure an atomic update

  47          $attr = $token->attr;
  48  
  49          // do global transformations (pre)

  50          // nothing currently utilizes this

  51          foreach ($definition->info_attr_transform_pre as $transform) {
  52              $attr = $transform->transform($o = $attr, $config, $context);
  53              if ($e) {
  54                  if ($attr != $o) {
  55                      $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
  56                  }
  57              }
  58          }
  59  
  60          // do local transformations only applicable to this element (pre)

  61          // ex. <p align="right"> to <p style="text-align:right;">

  62          foreach ($definition->info[$token->name]->attr_transform_pre as $transform) {
  63              $attr = $transform->transform($o = $attr, $config, $context);
  64              if ($e) {
  65                  if ($attr != $o) {
  66                      $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
  67                  }
  68              }
  69          }
  70  
  71          // create alias to this element's attribute definition array, see

  72          // also $d_defs (global attribute definition array)

  73          // DEFINITION CALL

  74          $defs = $definition->info[$token->name]->attr;
  75  
  76          $attr_key = false;
  77          $context->register('CurrentAttr', $attr_key);
  78  
  79          // iterate through all the attribute keypairs

  80          // Watch out for name collisions: $key has previously been used

  81          foreach ($attr as $attr_key => $value) {
  82  
  83              // call the definition

  84              if (isset($defs[$attr_key])) {
  85                  // there is a local definition defined

  86                  if ($defs[$attr_key] === false) {
  87                      // We've explicitly been told not to allow this element.

  88                      // This is usually when there's a global definition

  89                      // that must be overridden.

  90                      // Theoretically speaking, we could have a

  91                      // AttrDef_DenyAll, but this is faster!

  92                      $result = false;
  93                  } else {
  94                      // validate according to the element's definition

  95                      $result = $defs[$attr_key]->validate(
  96                          $value,
  97                          $config,
  98                          $context
  99                      );
 100                  }
 101              } elseif (isset($d_defs[$attr_key])) {
 102                  // there is a global definition defined, validate according

 103                  // to the global definition

 104                  $result = $d_defs[$attr_key]->validate(
 105                      $value,
 106                      $config,
 107                      $context
 108                  );
 109              } else {
 110                  // system never heard of the attribute? DELETE!

 111                  $result = false;
 112              }
 113  
 114              // put the results into effect

 115              if ($result === false || $result === null) {
 116                  // this is a generic error message that should replaced

 117                  // with more specific ones when possible

 118                  if ($e) {
 119                      $e->send(E_ERROR, 'AttrValidator: Attribute removed');
 120                  }
 121  
 122                  // remove the attribute

 123                  unset($attr[$attr_key]);
 124              } elseif (is_string($result)) {
 125                  // generally, if a substitution is happening, there

 126                  // was some sort of implicit correction going on. We'll

 127                  // delegate it to the attribute classes to say exactly what.

 128  
 129                  // simple substitution

 130                  $attr[$attr_key] = $result;
 131              } else {
 132                  // nothing happens

 133              }
 134  
 135              // we'd also want slightly more complicated substitution

 136              // involving an array as the return value,

 137              // although we're not sure how colliding attributes would

 138              // resolve (certain ones would be completely overriden,

 139              // others would prepend themselves).

 140          }
 141  
 142          $context->destroy('CurrentAttr');
 143  
 144          // post transforms

 145  
 146          // global (error reporting untested)

 147          foreach ($definition->info_attr_transform_post as $transform) {
 148              $attr = $transform->transform($o = $attr, $config, $context);
 149              if ($e) {
 150                  if ($attr != $o) {
 151                      $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
 152                  }
 153              }
 154          }
 155  
 156          // local (error reporting untested)

 157          foreach ($definition->info[$token->name]->attr_transform_post as $transform) {
 158              $attr = $transform->transform($o = $attr, $config, $context);
 159              if ($e) {
 160                  if ($attr != $o) {
 161                      $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
 162                  }
 163              }
 164          }
 165  
 166          $token->attr = $attr;
 167  
 168          // destroy CurrentToken if we made it ourselves

 169          if (!$current_token) {
 170              $context->destroy('CurrentToken');
 171          }
 172  
 173      }
 174  
 175  
 176  }
 177  
 178  // vim: et sw=4 sts=4