File indexing completed on 2024-12-22 05:36:18

0001 <?php
0002 
0003 /**
0004  * Validates Color as defined by CSS.
0005  */
0006 class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
0007 {
0008 
0009     /**
0010      * @type HTMLPurifier_AttrDef_CSS_AlphaValue
0011      */
0012     protected $alpha;
0013 
0014     public function __construct()
0015     {
0016         $this->alpha = new HTMLPurifier_AttrDef_CSS_AlphaValue();
0017     }
0018 
0019     /**
0020      * @param string $color
0021      * @param HTMLPurifier_Config $config
0022      * @param HTMLPurifier_Context $context
0023      * @return bool|string
0024      */
0025     public function validate($color, $config, $context)
0026     {
0027         static $colors = null;
0028         if ($colors === null) {
0029             $colors = $config->get('Core.ColorKeywords');
0030         }
0031 
0032         $color = trim($color);
0033         if ($color === '') {
0034             return false;
0035         }
0036 
0037         $lower = strtolower($color);
0038         if (isset($colors[$lower])) {
0039             return $colors[$lower];
0040         }
0041 
0042         if (preg_match('#(rgb|rgba|hsl|hsla)\(#', $color, $matches) === 1) {
0043             $length = strlen($color);
0044             if (strpos($color, ')') !== $length - 1) {
0045                 return false;
0046             }
0047 
0048             // get used function : rgb, rgba, hsl or hsla
0049             $function = $matches[1];
0050 
0051             $parameters_size = 3;
0052             $alpha_channel = false;
0053             if (substr($function, -1) === 'a') {
0054                 $parameters_size = 4;
0055                 $alpha_channel = true;
0056             }
0057 
0058             /*
0059              * Allowed types for values :
0060              * parameter_position => [type => max_value]
0061              */
0062             $allowed_types = array(
0063                 1 => array('percentage' => 100, 'integer' => 255),
0064                 2 => array('percentage' => 100, 'integer' => 255),
0065                 3 => array('percentage' => 100, 'integer' => 255),
0066             );
0067             $allow_different_types = false;
0068 
0069             if (strpos($function, 'hsl') !== false) {
0070                 $allowed_types = array(
0071                     1 => array('integer' => 360),
0072                     2 => array('percentage' => 100),
0073                     3 => array('percentage' => 100),
0074                 );
0075                 $allow_different_types = true;
0076             }
0077 
0078             $values = trim(str_replace($function, '', $color), ' ()');
0079 
0080             $parts = explode(',', $values);
0081             if (count($parts) !== $parameters_size) {
0082                 return false;
0083             }
0084 
0085             $type = false;
0086             $new_parts = array();
0087             $i = 0;
0088 
0089             foreach ($parts as $part) {
0090                 $i++;
0091                 $part = trim($part);
0092 
0093                 if ($part === '') {
0094                     return false;
0095                 }
0096 
0097                 // different check for alpha channel
0098                 if ($alpha_channel === true && $i === count($parts)) {
0099                     $result = $this->alpha->validate($part, $config, $context);
0100 
0101                     if ($result === false) {
0102                         return false;
0103                     }
0104 
0105                     $new_parts[] = (string)$result;
0106                     continue;
0107                 }
0108 
0109                 if (substr($part, -1) === '%') {
0110                     $current_type = 'percentage';
0111                 } else {
0112                     $current_type = 'integer';
0113                 }
0114 
0115                 if (!array_key_exists($current_type, $allowed_types[$i])) {
0116                     return false;
0117                 }
0118 
0119                 if (!$type) {
0120                     $type = $current_type;
0121                 }
0122 
0123                 if ($allow_different_types === false && $type != $current_type) {
0124                     return false;
0125                 }
0126 
0127                 $max_value = $allowed_types[$i][$current_type];
0128 
0129                 if ($current_type == 'integer') {
0130                     // Return value between range 0 -> $max_value
0131                     $new_parts[] = (int)max(min($part, $max_value), 0);
0132                 } elseif ($current_type == 'percentage') {
0133                     $new_parts[] = (float)max(min(rtrim($part, '%'), $max_value), 0) . '%';
0134                 }
0135             }
0136 
0137             $new_values = implode(',', $new_parts);
0138 
0139             $color = $function . '(' . $new_values . ')';
0140         } else {
0141             // hexadecimal handling
0142             if ($color[0] === '#') {
0143                 $hex = substr($color, 1);
0144             } else {
0145                 $hex = $color;
0146                 $color = '#' . $color;
0147             }
0148             $length = strlen($hex);
0149             if ($length !== 3 && $length !== 6) {
0150                 return false;
0151             }
0152             if (!ctype_xdigit($hex)) {
0153                 return false;
0154             }
0155         }
0156         return $color;
0157     }
0158 
0159 }
0160 
0161 // vim: et sw=4 sts=4