File indexing completed on 2024-12-22 05:36:18
0001 <?php 0002 0003 /** 0004 * Validates shorthand CSS property font. 0005 */ 0006 class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef 0007 { 0008 0009 /** 0010 * Local copy of validators 0011 * @type HTMLPurifier_AttrDef[] 0012 * @note If we moved specific CSS property definitions to their own 0013 * classes instead of having them be assembled at run time by 0014 * CSSDefinition, this wouldn't be necessary. We'd instantiate 0015 * our own copies. 0016 */ 0017 protected $info = array(); 0018 0019 /** 0020 * @param HTMLPurifier_Config $config 0021 */ 0022 public function __construct($config) 0023 { 0024 $def = $config->getCSSDefinition(); 0025 $this->info['font-style'] = $def->info['font-style']; 0026 $this->info['font-variant'] = $def->info['font-variant']; 0027 $this->info['font-weight'] = $def->info['font-weight']; 0028 $this->info['font-size'] = $def->info['font-size']; 0029 $this->info['line-height'] = $def->info['line-height']; 0030 $this->info['font-family'] = $def->info['font-family']; 0031 } 0032 0033 /** 0034 * @param string $string 0035 * @param HTMLPurifier_Config $config 0036 * @param HTMLPurifier_Context $context 0037 * @return bool|string 0038 */ 0039 public function validate($string, $config, $context) 0040 { 0041 static $system_fonts = array( 0042 'caption' => true, 0043 'icon' => true, 0044 'menu' => true, 0045 'message-box' => true, 0046 'small-caption' => true, 0047 'status-bar' => true 0048 ); 0049 0050 // regular pre-processing 0051 $string = $this->parseCDATA($string); 0052 if ($string === '') { 0053 return false; 0054 } 0055 0056 // check if it's one of the keywords 0057 $lowercase_string = strtolower($string); 0058 if (isset($system_fonts[$lowercase_string])) { 0059 return $lowercase_string; 0060 } 0061 0062 $bits = explode(' ', $string); // bits to process 0063 $stage = 0; // this indicates what we're looking for 0064 $caught = array(); // which stage 0 properties have we caught? 0065 $stage_1 = array('font-style', 'font-variant', 'font-weight'); 0066 $final = ''; // output 0067 0068 for ($i = 0, $size = count($bits); $i < $size; $i++) { 0069 if ($bits[$i] === '') { 0070 continue; 0071 } 0072 switch ($stage) { 0073 case 0: // attempting to catch font-style, font-variant or font-weight 0074 foreach ($stage_1 as $validator_name) { 0075 if (isset($caught[$validator_name])) { 0076 continue; 0077 } 0078 $r = $this->info[$validator_name]->validate( 0079 $bits[$i], 0080 $config, 0081 $context 0082 ); 0083 if ($r !== false) { 0084 $final .= $r . ' '; 0085 $caught[$validator_name] = true; 0086 break; 0087 } 0088 } 0089 // all three caught, continue on 0090 if (count($caught) >= 3) { 0091 $stage = 1; 0092 } 0093 if ($r !== false) { 0094 break; 0095 } 0096 case 1: // attempting to catch font-size and perhaps line-height 0097 $found_slash = false; 0098 if (strpos($bits[$i], '/') !== false) { 0099 list($font_size, $line_height) = 0100 explode('/', $bits[$i]); 0101 if ($line_height === '') { 0102 // ooh, there's a space after the slash! 0103 $line_height = false; 0104 $found_slash = true; 0105 } 0106 } else { 0107 $font_size = $bits[$i]; 0108 $line_height = false; 0109 } 0110 $r = $this->info['font-size']->validate( 0111 $font_size, 0112 $config, 0113 $context 0114 ); 0115 if ($r !== false) { 0116 $final .= $r; 0117 // attempt to catch line-height 0118 if ($line_height === false) { 0119 // we need to scroll forward 0120 for ($j = $i + 1; $j < $size; $j++) { 0121 if ($bits[$j] === '') { 0122 continue; 0123 } 0124 if ($bits[$j] === '/') { 0125 if ($found_slash) { 0126 return false; 0127 } else { 0128 $found_slash = true; 0129 continue; 0130 } 0131 } 0132 $line_height = $bits[$j]; 0133 break; 0134 } 0135 } else { 0136 // slash already found 0137 $found_slash = true; 0138 $j = $i; 0139 } 0140 if ($found_slash) { 0141 $i = $j; 0142 $r = $this->info['line-height']->validate( 0143 $line_height, 0144 $config, 0145 $context 0146 ); 0147 if ($r !== false) { 0148 $final .= '/' . $r; 0149 } 0150 } 0151 $final .= ' '; 0152 $stage = 2; 0153 break; 0154 } 0155 return false; 0156 case 2: // attempting to catch font-family 0157 $font_family = 0158 implode(' ', array_slice($bits, $i, $size - $i)); 0159 $r = $this->info['font-family']->validate( 0160 $font_family, 0161 $config, 0162 $context 0163 ); 0164 if ($r !== false) { 0165 $final .= $r . ' '; 0166 // processing completed successfully 0167 return rtrim($final); 0168 } 0169 return false; 0170 } 0171 } 0172 return false; 0173 } 0174 } 0175 0176 // vim: et sw=4 sts=4