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