Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  
   3  /**
   4   * Validates Color as defined by CSS.
   5   */
   6  class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
   7  {
   8  
   9      /**
  10       * @type HTMLPurifier_AttrDef_CSS_AlphaValue
  11       */
  12      protected $alpha;
  13  
  14      public function __construct()
  15      {
  16          $this->alpha = new HTMLPurifier_AttrDef_CSS_AlphaValue();
  17      }
  18  
  19      /**
  20       * @param string $color
  21       * @param HTMLPurifier_Config $config
  22       * @param HTMLPurifier_Context $context
  23       * @return bool|string
  24       */
  25      public function validate($color, $config, $context)
  26      {
  27          static $colors = null;
  28          if ($colors === null) {
  29              $colors = $config->get('Core.ColorKeywords');
  30          }
  31  
  32          $color = trim($color);
  33          if ($color === '') {
  34              return false;
  35          }
  36  
  37          $lower = strtolower($color);
  38          if (isset($colors[$lower])) {
  39              return $colors[$lower];
  40          }
  41  
  42          if (preg_match('#(rgb|rgba|hsl|hsla)\(#', $color, $matches) === 1) {
  43              $length = strlen($color);
  44              if (strpos($color, ')') !== $length - 1) {
  45                  return false;
  46              }
  47  
  48              // get used function : rgb, rgba, hsl or hsla
  49              $function = $matches[1];
  50  
  51              $parameters_size = 3;
  52              $alpha_channel = false;
  53              if (substr($function, -1) === 'a') {
  54                  $parameters_size = 4;
  55                  $alpha_channel = true;
  56              }
  57  
  58              /*
  59               * Allowed types for values :
  60               * parameter_position => [type => max_value]
  61               */
  62              $allowed_types = array(
  63                  1 => array('percentage' => 100, 'integer' => 255),
  64                  2 => array('percentage' => 100, 'integer' => 255),
  65                  3 => array('percentage' => 100, 'integer' => 255),
  66              );
  67              $allow_different_types = false;
  68  
  69              if (strpos($function, 'hsl') !== false) {
  70                  $allowed_types = array(
  71                      1 => array('integer' => 360),
  72                      2 => array('percentage' => 100),
  73                      3 => array('percentage' => 100),
  74                  );
  75                  $allow_different_types = true;
  76              }
  77  
  78              $values = trim(str_replace($function, '', $color), ' ()');
  79  
  80              $parts = explode(',', $values);
  81              if (count($parts) !== $parameters_size) {
  82                  return false;
  83              }
  84  
  85              $type = false;
  86              $new_parts = array();
  87              $i = 0;
  88  
  89              foreach ($parts as $part) {
  90                  $i++;
  91                  $part = trim($part);
  92  
  93                  if ($part === '') {
  94                      return false;
  95                  }
  96  
  97                  // different check for alpha channel
  98                  if ($alpha_channel === true && $i === count($parts)) {
  99                      $result = $this->alpha->validate($part, $config, $context);
 100  
 101                      if ($result === false) {
 102                          return false;
 103                      }
 104  
 105                      $new_parts[] = (string)$result;
 106                      continue;
 107                  }
 108  
 109                  if (substr($part, -1) === '%') {
 110                      $current_type = 'percentage';
 111                  } else {
 112                      $current_type = 'integer';
 113                  }
 114  
 115                  if (!array_key_exists($current_type, $allowed_types[$i])) {
 116                      return false;
 117                  }
 118  
 119                  if (!$type) {
 120                      $type = $current_type;
 121                  }
 122  
 123                  if ($allow_different_types === false && $type != $current_type) {
 124                      return false;
 125                  }
 126  
 127                  $max_value = $allowed_types[$i][$current_type];
 128  
 129                  if ($current_type == 'integer') {
 130                      // Return value between range 0 -> $max_value
 131                      $new_parts[] = (int)max(min($part, $max_value), 0);
 132                  } elseif ($current_type == 'percentage') {
 133                      $new_parts[] = (float)max(min(rtrim($part, '%'), $max_value), 0) . '%';
 134                  }
 135              }
 136  
 137              $new_values = implode(',', $new_parts);
 138  
 139              $color = $function . '(' . $new_values . ')';
 140          } else {
 141              // hexadecimal handling
 142              if ($color[0] === '#') {
 143                  $hex = substr($color, 1);
 144              } else {
 145                  $hex = $color;
 146                  $color = '#' . $color;
 147              }
 148              $length = strlen($hex);
 149              if ($length !== 3 && $length !== 6) {
 150                  return false;
 151              }
 152              if (!ctype_xdigit($hex)) {
 153                  return false;
 154              }
 155          }
 156          return $color;
 157      }
 158  
 159  }
 160  
 161  // vim: et sw=4 sts=4