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