Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  
   3  /**
   4   * Validates shorthand CSS property font.
   5   */
   6  class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
   7  {
   8  
   9      /**
  10       * Local copy of validators
  11       * @type HTMLPurifier_AttrDef[]
  12       * @note If we moved specific CSS property definitions to their own
  13       *       classes instead of having them be assembled at run time by
  14       *       CSSDefinition, this wouldn't be necessary.  We'd instantiate
  15       *       our own copies.
  16       */
  17      protected $info = array();
  18  
  19      /**
  20       * @param HTMLPurifier_Config $config
  21       */
  22      public function __construct($config)
  23      {
  24          $def = $config->getCSSDefinition();
  25          $this->info['font-style'] = $def->info['font-style'];
  26          $this->info['font-variant'] = $def->info['font-variant'];
  27          $this->info['font-weight'] = $def->info['font-weight'];
  28          $this->info['font-size'] = $def->info['font-size'];
  29          $this->info['line-height'] = $def->info['line-height'];
  30          $this->info['font-family'] = $def->info['font-family'];
  31      }
  32  
  33      /**
  34       * @param string $string
  35       * @param HTMLPurifier_Config $config
  36       * @param HTMLPurifier_Context $context
  37       * @return bool|string
  38       */
  39      public function validate($string, $config, $context)
  40      {
  41          static $system_fonts = array(
  42              'caption' => true,
  43              'icon' => true,
  44              'menu' => true,
  45              'message-box' => true,
  46              'small-caption' => true,
  47              'status-bar' => true
  48          );
  49  
  50          // regular pre-processing
  51          $string = $this->parseCDATA($string);
  52          if ($string === '') {
  53              return false;
  54          }
  55  
  56          // check if it's one of the keywords
  57          $lowercase_string = strtolower($string);
  58          if (isset($system_fonts[$lowercase_string])) {
  59              return $lowercase_string;
  60          }
  61  
  62          $bits = explode(' ', $string); // bits to process
  63          $stage = 0; // this indicates what we're looking for
  64          $caught = array(); // which stage 0 properties have we caught?
  65          $stage_1 = array('font-style', 'font-variant', 'font-weight');
  66          $final = ''; // output
  67  
  68          for ($i = 0, $size = count($bits); $i < $size; $i++) {
  69              if ($bits[$i] === '') {
  70                  continue;
  71              }
  72              switch ($stage) {
  73                  case 0: // attempting to catch font-style, font-variant or font-weight
  74                      foreach ($stage_1 as $validator_name) {
  75                          if (isset($caught[$validator_name])) {
  76                              continue;
  77                          }
  78                          $r = $this->info[$validator_name]->validate(
  79                              $bits[$i],
  80                              $config,
  81                              $context
  82                          );
  83                          if ($r !== false) {
  84                              $final .= $r . ' ';
  85                              $caught[$validator_name] = true;
  86                              break;
  87                          }
  88                      }
  89                      // all three caught, continue on
  90                      if (count($caught) >= 3) {
  91                          $stage = 1;
  92                      }
  93                      if ($r !== false) {
  94                          break;
  95                      }
  96                  case 1: // attempting to catch font-size and perhaps line-height
  97                      $found_slash = false;
  98                      if (strpos($bits[$i], '/') !== false) {
  99                          list($font_size, $line_height) =
 100                              explode('/', $bits[$i]);
 101                          if ($line_height === '') {
 102                              // ooh, there's a space after the slash!
 103                              $line_height = false;
 104                              $found_slash = true;
 105                          }
 106                      } else {
 107                          $font_size = $bits[$i];
 108                          $line_height = false;
 109                      }
 110                      $r = $this->info['font-size']->validate(
 111                          $font_size,
 112                          $config,
 113                          $context
 114                      );
 115                      if ($r !== false) {
 116                          $final .= $r;
 117                          // attempt to catch line-height
 118                          if ($line_height === false) {
 119                              // we need to scroll forward
 120                              for ($j = $i + 1; $j < $size; $j++) {
 121                                  if ($bits[$j] === '') {
 122                                      continue;
 123                                  }
 124                                  if ($bits[$j] === '/') {
 125                                      if ($found_slash) {
 126                                          return false;
 127                                      } else {
 128                                          $found_slash = true;
 129                                          continue;
 130                                      }
 131                                  }
 132                                  $line_height = $bits[$j];
 133                                  break;
 134                              }
 135                          } else {
 136                              // slash already found
 137                              $found_slash = true;
 138                              $j = $i;
 139                          }
 140                          if ($found_slash) {
 141                              $i = $j;
 142                              $r = $this->info['line-height']->validate(
 143                                  $line_height,
 144                                  $config,
 145                                  $context
 146                              );
 147                              if ($r !== false) {
 148                                  $final .= '/' . $r;
 149                              }
 150                          }
 151                          $final .= ' ';
 152                          $stage = 2;
 153                          break;
 154                      }
 155                      return false;
 156                  case 2: // attempting to catch font-family
 157                      $font_family =
 158                          implode(' ', array_slice($bits, $i, $size - $i));
 159                      $r = $this->info['font-family']->validate(
 160                          $font_family,
 161                          $config,
 162                          $context
 163                      );
 164                      if ($r !== false) {
 165                          $final .= $r . ' ';
 166                          // processing completed successfully
 167                          return rtrim($final);
 168                      }
 169                      return false;
 170              }
 171          }
 172          return false;
 173      }
 174  }
 175  
 176  // vim: et sw=4 sts=4