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
title
Description
Body
title
Description
Body
title
Description
Body
title
Body