diff options
Diffstat (limited to 'library/HTMLPurifier/AttrDef/CSS')
19 files changed, 0 insertions, 1633 deletions
diff --git a/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php deleted file mode 100644 index af2b83dff..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php +++ /dev/null @@ -1,34 +0,0 @@ -<?php - -class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number -{ - - public function __construct() - { - parent::__construct(false); // opacity is non-negative, but we will clamp it - } - - /** - * @param string $number - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return string - */ - public function validate($number, $config, $context) - { - $result = parent::validate($number, $config, $context); - if ($result === false) { - return $result; - } - $float = (float)$result; - if ($float < 0.0) { - $result = '0'; - } - if ($float > 1.0) { - $result = '1'; - } - return $result; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Background.php b/library/HTMLPurifier/AttrDef/CSS/Background.php deleted file mode 100644 index 7f1ea3b0f..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Background.php +++ /dev/null @@ -1,111 +0,0 @@ -<?php - -/** - * Validates shorthand CSS property background. - * @warning Does not support url tokens that have internal spaces. - */ -class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef -{ - - /** - * Local copy of component validators. - * @type HTMLPurifier_AttrDef[] - * @note See HTMLPurifier_AttrDef_Font::$info for a similar impl. - */ - protected $info; - - /** - * @param HTMLPurifier_Config $config - */ - public function __construct($config) - { - $def = $config->getCSSDefinition(); - $this->info['background-color'] = $def->info['background-color']; - $this->info['background-image'] = $def->info['background-image']; - $this->info['background-repeat'] = $def->info['background-repeat']; - $this->info['background-attachment'] = $def->info['background-attachment']; - $this->info['background-position'] = $def->info['background-position']; - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - // regular pre-processing - $string = $this->parseCDATA($string); - if ($string === '') { - return false; - } - - // munge rgb() decl if necessary - $string = $this->mungeRgb($string); - - // assumes URI doesn't have spaces in it - $bits = explode(' ', $string); // bits to process - - $caught = array(); - $caught['color'] = false; - $caught['image'] = false; - $caught['repeat'] = false; - $caught['attachment'] = false; - $caught['position'] = false; - - $i = 0; // number of catches - - foreach ($bits as $bit) { - if ($bit === '') { - continue; - } - foreach ($caught as $key => $status) { - if ($key != 'position') { - if ($status !== false) { - continue; - } - $r = $this->info['background-' . $key]->validate($bit, $config, $context); - } else { - $r = $bit; - } - if ($r === false) { - continue; - } - if ($key == 'position') { - if ($caught[$key] === false) { - $caught[$key] = ''; - } - $caught[$key] .= $r . ' '; - } else { - $caught[$key] = $r; - } - $i++; - break; - } - } - - if (!$i) { - return false; - } - if ($caught['position'] !== false) { - $caught['position'] = $this->info['background-position']-> - validate($caught['position'], $config, $context); - } - - $ret = array(); - foreach ($caught as $value) { - if ($value === false) { - continue; - } - $ret[] = $value; - } - - if (empty($ret)) { - return false; - } - return implode(' ', $ret); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php deleted file mode 100644 index 4580ef5a9..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php +++ /dev/null @@ -1,157 +0,0 @@ -<?php - -/* W3C says: - [ // adjective and number must be in correct order, even if - // you could switch them without introducing ambiguity. - // some browsers support that syntax - [ - <percentage> | <length> | left | center | right - ] - [ - <percentage> | <length> | top | center | bottom - ]? - ] | - [ // this signifies that the vertical and horizontal adjectives - // can be arbitrarily ordered, however, there can only be two, - // one of each, or none at all - [ - left | center | right - ] || - [ - top | center | bottom - ] - ] - top, left = 0% - center, (none) = 50% - bottom, right = 100% -*/ - -/* QuirksMode says: - keyword + length/percentage must be ordered correctly, as per W3C - - Internet Explorer and Opera, however, support arbitrary ordering. We - should fix it up. - - Minor issue though, not strictly necessary. -*/ - -// control freaks may appreciate the ability to convert these to -// percentages or something, but it's not necessary - -/** - * Validates the value of background-position. - */ -class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef -{ - - /** - * @type HTMLPurifier_AttrDef_CSS_Length - */ - protected $length; - - /** - * @type HTMLPurifier_AttrDef_CSS_Percentage - */ - protected $percentage; - - public function __construct() - { - $this->length = new HTMLPurifier_AttrDef_CSS_Length(); - $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage(); - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - $string = $this->parseCDATA($string); - $bits = explode(' ', $string); - - $keywords = array(); - $keywords['h'] = false; // left, right - $keywords['v'] = false; // top, bottom - $keywords['ch'] = false; // center (first word) - $keywords['cv'] = false; // center (second word) - $measures = array(); - - $i = 0; - - $lookup = array( - 'top' => 'v', - 'bottom' => 'v', - 'left' => 'h', - 'right' => 'h', - 'center' => 'c' - ); - - foreach ($bits as $bit) { - if ($bit === '') { - continue; - } - - // test for keyword - $lbit = ctype_lower($bit) ? $bit : strtolower($bit); - if (isset($lookup[$lbit])) { - $status = $lookup[$lbit]; - if ($status == 'c') { - if ($i == 0) { - $status = 'ch'; - } else { - $status = 'cv'; - } - } - $keywords[$status] = $lbit; - $i++; - } - - // test for length - $r = $this->length->validate($bit, $config, $context); - if ($r !== false) { - $measures[] = $r; - $i++; - } - - // test for percentage - $r = $this->percentage->validate($bit, $config, $context); - if ($r !== false) { - $measures[] = $r; - $i++; - } - } - - if (!$i) { - return false; - } // no valid values were caught - - $ret = array(); - - // first keyword - if ($keywords['h']) { - $ret[] = $keywords['h']; - } elseif ($keywords['ch']) { - $ret[] = $keywords['ch']; - $keywords['cv'] = false; // prevent re-use: center = center center - } elseif (count($measures)) { - $ret[] = array_shift($measures); - } - - if ($keywords['v']) { - $ret[] = $keywords['v']; - } elseif ($keywords['cv']) { - $ret[] = $keywords['cv']; - } elseif (count($measures)) { - $ret[] = array_shift($measures); - } - - if (empty($ret)) { - return false; - } - return implode(' ', $ret); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Border.php b/library/HTMLPurifier/AttrDef/CSS/Border.php deleted file mode 100644 index 16243ba1e..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Border.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php - -/** - * Validates the border property as defined by CSS. - */ -class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef -{ - - /** - * Local copy of properties this property is shorthand for. - * @type HTMLPurifier_AttrDef[] - */ - protected $info = array(); - - /** - * @param HTMLPurifier_Config $config - */ - public function __construct($config) - { - $def = $config->getCSSDefinition(); - $this->info['border-width'] = $def->info['border-width']; - $this->info['border-style'] = $def->info['border-style']; - $this->info['border-top-color'] = $def->info['border-top-color']; - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - $string = $this->parseCDATA($string); - $string = $this->mungeRgb($string); - $bits = explode(' ', $string); - $done = array(); // segments we've finished - $ret = ''; // return value - foreach ($bits as $bit) { - foreach ($this->info as $propname => $validator) { - if (isset($done[$propname])) { - continue; - } - $r = $validator->validate($bit, $config, $context); - if ($r !== false) { - $ret .= $r . ' '; - $done[$propname] = true; - break; - } - } - } - return rtrim($ret); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Color.php b/library/HTMLPurifier/AttrDef/CSS/Color.php deleted file mode 100644 index 16d2a6b98..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Color.php +++ /dev/null @@ -1,105 +0,0 @@ -<?php - -/** - * Validates Color as defined by CSS. - */ -class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef -{ - - /** - * @param string $color - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($color, $config, $context) - { - static $colors = null; - if ($colors === null) { - $colors = $config->get('Core.ColorKeywords'); - } - - $color = trim($color); - if ($color === '') { - return false; - } - - $lower = strtolower($color); - if (isset($colors[$lower])) { - return $colors[$lower]; - } - - if (strpos($color, 'rgb(') !== false) { - // rgb literal handling - $length = strlen($color); - if (strpos($color, ')') !== $length - 1) { - return false; - } - $triad = substr($color, 4, $length - 4 - 1); - $parts = explode(',', $triad); - if (count($parts) !== 3) { - return false; - } - $type = false; // to ensure that they're all the same type - $new_parts = array(); - foreach ($parts as $part) { - $part = trim($part); - if ($part === '') { - return false; - } - $length = strlen($part); - if ($part[$length - 1] === '%') { - // handle percents - if (!$type) { - $type = 'percentage'; - } elseif ($type !== 'percentage') { - return false; - } - $num = (float)substr($part, 0, $length - 1); - if ($num < 0) { - $num = 0; - } - if ($num > 100) { - $num = 100; - } - $new_parts[] = "$num%"; - } else { - // handle integers - if (!$type) { - $type = 'integer'; - } elseif ($type !== 'integer') { - return false; - } - $num = (int)$part; - if ($num < 0) { - $num = 0; - } - if ($num > 255) { - $num = 255; - } - $new_parts[] = (string)$num; - } - } - $new_triad = implode(',', $new_parts); - $color = "rgb($new_triad)"; - } else { - // hexadecimal handling - if ($color[0] === '#') { - $hex = substr($color, 1); - } else { - $hex = $color; - $color = '#' . $color; - } - $length = strlen($hex); - if ($length !== 3 && $length !== 6) { - return false; - } - if (!ctype_xdigit($hex)) { - return false; - } - } - return $color; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Composite.php b/library/HTMLPurifier/AttrDef/CSS/Composite.php deleted file mode 100644 index 9c1750554..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Composite.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php - -/** - * Allows multiple validators to attempt to validate attribute. - * - * Composite is just what it sounds like: a composite of many validators. - * This means that multiple HTMLPurifier_AttrDef objects will have a whack - * at the string. If one of them passes, that's what is returned. This is - * especially useful for CSS values, which often are a choice between - * an enumerated set of predefined values or a flexible data type. - */ -class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef -{ - - /** - * List of objects that may process strings. - * @type HTMLPurifier_AttrDef[] - * @todo Make protected - */ - public $defs; - - /** - * @param HTMLPurifier_AttrDef[] $defs List of HTMLPurifier_AttrDef objects - */ - public function __construct($defs) - { - $this->defs = $defs; - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - foreach ($this->defs as $i => $def) { - $result = $this->defs[$i]->validate($string, $config, $context); - if ($result !== false) { - return $result; - } - } - return false; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php deleted file mode 100644 index 9d77cc9aa..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php - -/** - * Decorator which enables CSS properties to be disabled for specific elements. - */ -class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef -{ - /** - * @type HTMLPurifier_AttrDef - */ - public $def; - /** - * @type string - */ - public $element; - - /** - * @param HTMLPurifier_AttrDef $def Definition to wrap - * @param string $element Element to deny - */ - public function __construct($def, $element) - { - $this->def = $def; - $this->element = $element; - } - - /** - * Checks if CurrentToken is set and equal to $this->element - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - $token = $context->get('CurrentToken', true); - if ($token && $token->name == $this->element) { - return false; - } - return $this->def->validate($string, $config, $context); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Filter.php b/library/HTMLPurifier/AttrDef/CSS/Filter.php deleted file mode 100644 index bde4c3301..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Filter.php +++ /dev/null @@ -1,77 +0,0 @@ -<?php - -/** - * Microsoft's proprietary filter: CSS property - * @note Currently supports the alpha filter. In the future, this will - * probably need an extensible framework - */ -class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef -{ - /** - * @type HTMLPurifier_AttrDef_Integer - */ - protected $intValidator; - - public function __construct() - { - $this->intValidator = new HTMLPurifier_AttrDef_Integer(); - } - - /** - * @param string $value - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($value, $config, $context) - { - $value = $this->parseCDATA($value); - if ($value === 'none') { - return $value; - } - // if we looped this we could support multiple filters - $function_length = strcspn($value, '('); - $function = trim(substr($value, 0, $function_length)); - if ($function !== 'alpha' && - $function !== 'Alpha' && - $function !== 'progid:DXImageTransform.Microsoft.Alpha' - ) { - return false; - } - $cursor = $function_length + 1; - $parameters_length = strcspn($value, ')', $cursor); - $parameters = substr($value, $cursor, $parameters_length); - $params = explode(',', $parameters); - $ret_params = array(); - $lookup = array(); - foreach ($params as $param) { - list($key, $value) = explode('=', $param); - $key = trim($key); - $value = trim($value); - if (isset($lookup[$key])) { - continue; - } - if ($key !== 'opacity') { - continue; - } - $value = $this->intValidator->validate($value, $config, $context); - if ($value === false) { - continue; - } - $int = (int)$value; - if ($int > 100) { - $value = '100'; - } - if ($int < 0) { - $value = '0'; - } - $ret_params[] = "$key=$value"; - $lookup[$key] = true; - } - $ret_parameters = implode(',', $ret_params); - $ret_function = "$function($ret_parameters)"; - return $ret_function; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Font.php b/library/HTMLPurifier/AttrDef/CSS/Font.php deleted file mode 100644 index 579b97ef1..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Font.php +++ /dev/null @@ -1,176 +0,0 @@ -<?php - -/** - * Validates shorthand CSS property font. - */ -class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef -{ - - /** - * Local copy of validators - * @type HTMLPurifier_AttrDef[] - * @note If we moved specific CSS property definitions to their own - * classes instead of having them be assembled at run time by - * CSSDefinition, this wouldn't be necessary. We'd instantiate - * our own copies. - */ - protected $info = array(); - - /** - * @param HTMLPurifier_Config $config - */ - public function __construct($config) - { - $def = $config->getCSSDefinition(); - $this->info['font-style'] = $def->info['font-style']; - $this->info['font-variant'] = $def->info['font-variant']; - $this->info['font-weight'] = $def->info['font-weight']; - $this->info['font-size'] = $def->info['font-size']; - $this->info['line-height'] = $def->info['line-height']; - $this->info['font-family'] = $def->info['font-family']; - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - static $system_fonts = array( - 'caption' => true, - 'icon' => true, - 'menu' => true, - 'message-box' => true, - 'small-caption' => true, - 'status-bar' => true - ); - - // regular pre-processing - $string = $this->parseCDATA($string); - if ($string === '') { - return false; - } - - // check if it's one of the keywords - $lowercase_string = strtolower($string); - if (isset($system_fonts[$lowercase_string])) { - return $lowercase_string; - } - - $bits = explode(' ', $string); // bits to process - $stage = 0; // this indicates what we're looking for - $caught = array(); // which stage 0 properties have we caught? - $stage_1 = array('font-style', 'font-variant', 'font-weight'); - $final = ''; // output - - for ($i = 0, $size = count($bits); $i < $size; $i++) { - if ($bits[$i] === '') { - continue; - } - switch ($stage) { - case 0: // attempting to catch font-style, font-variant or font-weight - foreach ($stage_1 as $validator_name) { - if (isset($caught[$validator_name])) { - continue; - } - $r = $this->info[$validator_name]->validate( - $bits[$i], - $config, - $context - ); - if ($r !== false) { - $final .= $r . ' '; - $caught[$validator_name] = true; - break; - } - } - // all three caught, continue on - if (count($caught) >= 3) { - $stage = 1; - } - if ($r !== false) { - break; - } - case 1: // attempting to catch font-size and perhaps line-height - $found_slash = false; - if (strpos($bits[$i], '/') !== false) { - list($font_size, $line_height) = - explode('/', $bits[$i]); - if ($line_height === '') { - // ooh, there's a space after the slash! - $line_height = false; - $found_slash = true; - } - } else { - $font_size = $bits[$i]; - $line_height = false; - } - $r = $this->info['font-size']->validate( - $font_size, - $config, - $context - ); - if ($r !== false) { - $final .= $r; - // attempt to catch line-height - if ($line_height === false) { - // we need to scroll forward - for ($j = $i + 1; $j < $size; $j++) { - if ($bits[$j] === '') { - continue; - } - if ($bits[$j] === '/') { - if ($found_slash) { - return false; - } else { - $found_slash = true; - continue; - } - } - $line_height = $bits[$j]; - break; - } - } else { - // slash already found - $found_slash = true; - $j = $i; - } - if ($found_slash) { - $i = $j; - $r = $this->info['line-height']->validate( - $line_height, - $config, - $context - ); - if ($r !== false) { - $final .= '/' . $r; - } - } - $final .= ' '; - $stage = 2; - break; - } - return false; - case 2: // attempting to catch font-family - $font_family = - implode(' ', array_slice($bits, $i, $size - $i)); - $r = $this->info['font-family']->validate( - $font_family, - $config, - $context - ); - if ($r !== false) { - $final .= $r . ' '; - // processing completed successfully - return rtrim($final); - } - return false; - } - } - return false; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/FontFamily.php b/library/HTMLPurifier/AttrDef/CSS/FontFamily.php deleted file mode 100644 index 74e24c881..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/FontFamily.php +++ /dev/null @@ -1,219 +0,0 @@ -<?php - -/** - * Validates a font family list according to CSS spec - */ -class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef -{ - - protected $mask = null; - - public function __construct() - { - $this->mask = '_- '; - for ($c = 'a'; $c <= 'z'; $c++) { - $this->mask .= $c; - } - for ($c = 'A'; $c <= 'Z'; $c++) { - $this->mask .= $c; - } - for ($c = '0'; $c <= '9'; $c++) { - $this->mask .= $c; - } // cast-y, but should be fine - // special bytes used by UTF-8 - for ($i = 0x80; $i <= 0xFF; $i++) { - // We don't bother excluding invalid bytes in this range, - // because the our restriction of well-formed UTF-8 will - // prevent these from ever occurring. - $this->mask .= chr($i); - } - - /* - PHP's internal strcspn implementation is - O(length of string * length of mask), making it inefficient - for large masks. However, it's still faster than - preg_match 8) - for (p = s1;;) { - spanp = s2; - do { - if (*spanp == c || p == s1_end) { - return p - s1; - } - } while (spanp++ < (s2_end - 1)); - c = *++p; - } - */ - // possible optimization: invert the mask. - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - static $generic_names = array( - 'serif' => true, - 'sans-serif' => true, - 'monospace' => true, - 'fantasy' => true, - 'cursive' => true - ); - $allowed_fonts = $config->get('CSS.AllowedFonts'); - - // assume that no font names contain commas in them - $fonts = explode(',', $string); - $final = ''; - foreach ($fonts as $font) { - $font = trim($font); - if ($font === '') { - continue; - } - // match a generic name - if (isset($generic_names[$font])) { - if ($allowed_fonts === null || isset($allowed_fonts[$font])) { - $final .= $font . ', '; - } - continue; - } - // match a quoted name - if ($font[0] === '"' || $font[0] === "'") { - $length = strlen($font); - if ($length <= 2) { - continue; - } - $quote = $font[0]; - if ($font[$length - 1] !== $quote) { - continue; - } - $font = substr($font, 1, $length - 2); - } - - $font = $this->expandCSSEscape($font); - - // $font is a pure representation of the font name - - if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) { - continue; - } - - if (ctype_alnum($font) && $font !== '') { - // very simple font, allow it in unharmed - $final .= $font . ', '; - continue; - } - - // bugger out on whitespace. form feed (0C) really - // shouldn't show up regardless - $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font); - - // Here, there are various classes of characters which need - // to be treated differently: - // - Alphanumeric characters are essentially safe. We - // handled these above. - // - Spaces require quoting, though most parsers will do - // the right thing if there aren't any characters that - // can be misinterpreted - // - Dashes rarely occur, but they fairly unproblematic - // for parsing/rendering purposes. - // The above characters cover the majority of Western font - // names. - // - Arbitrary Unicode characters not in ASCII. Because - // most parsers give little thought to Unicode, treatment - // of these codepoints is basically uniform, even for - // punctuation-like codepoints. These characters can - // show up in non-Western pages and are supported by most - // major browsers, for example: "MS 明朝" is a - // legitimate font-name - // <http://ja.wikipedia.org/wiki/MS_明朝>. See - // the CSS3 spec for more examples: - // <http://www.w3.org/TR/2011/WD-css3-fonts-20110324/localizedfamilynames.png> - // You can see live samples of these on the Internet: - // <http://www.google.co.jp/search?q=font-family+MS+明朝|ゴシック> - // However, most of these fonts have ASCII equivalents: - // for example, 'MS Mincho', and it's considered - // professional to use ASCII font names instead of - // Unicode font names. Thanks Takeshi Terada for - // providing this information. - // The following characters, to my knowledge, have not been - // used to name font names. - // - Single quote. While theoretically you might find a - // font name that has a single quote in its name (serving - // as an apostrophe, e.g. Dave's Scribble), I haven't - // been able to find any actual examples of this. - // Internet Explorer's cssText translation (which I - // believe is invoked by innerHTML) normalizes any - // quoting to single quotes, and fails to escape single - // quotes. (Note that this is not IE's behavior for all - // CSS properties, just some sort of special casing for - // font-family). So a single quote *cannot* be used - // safely in the font-family context if there will be an - // innerHTML/cssText translation. Note that Firefox 3.x - // does this too. - // - Double quote. In IE, these get normalized to - // single-quotes, no matter what the encoding. (Fun - // fact, in IE8, the 'content' CSS property gained - // support, where they special cased to preserve encoded - // double quotes, but still translate unadorned double - // quotes into single quotes.) So, because their - // fixpoint behavior is identical to single quotes, they - // cannot be allowed either. Firefox 3.x displays - // single-quote style behavior. - // - Backslashes are reduced by one (so \\ -> \) every - // iteration, so they cannot be used safely. This shows - // up in IE7, IE8 and FF3 - // - Semicolons, commas and backticks are handled properly. - // - The rest of the ASCII punctuation is handled properly. - // We haven't checked what browsers do to unadorned - // versions, but this is not important as long as the - // browser doesn't /remove/ surrounding quotes (as IE does - // for HTML). - // - // With these results in hand, we conclude that there are - // various levels of safety: - // - Paranoid: alphanumeric, spaces and dashes(?) - // - International: Paranoid + non-ASCII Unicode - // - Edgy: Everything except quotes, backslashes - // - NoJS: Standards compliance, e.g. sod IE. Note that - // with some judicious character escaping (since certain - // types of escaping doesn't work) this is theoretically - // OK as long as innerHTML/cssText is not called. - // We believe that international is a reasonable default - // (that we will implement now), and once we do more - // extensive research, we may feel comfortable with dropping - // it down to edgy. - - // Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of - // str(c)spn assumes that the string was already well formed - // Unicode (which of course it is). - if (strspn($font, $this->mask) !== strlen($font)) { - continue; - } - - // Historical: - // In the absence of innerHTML/cssText, these ugly - // transforms don't pose a security risk (as \\ and \" - // might--these escapes are not supported by most browsers). - // We could try to be clever and use single-quote wrapping - // when there is a double quote present, but I have choosen - // not to implement that. (NOTE: you can reduce the amount - // of escapes by one depending on what quoting style you use) - // $font = str_replace('\\', '\\5C ', $font); - // $font = str_replace('"', '\\22 ', $font); - // $font = str_replace("'", '\\27 ', $font); - - // font possibly with spaces, requires quoting - $final .= "'$font', "; - } - $final = rtrim($final, ', '); - if ($final === '') { - return false; - } - return $final; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Ident.php b/library/HTMLPurifier/AttrDef/CSS/Ident.php deleted file mode 100644 index 973002c17..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Ident.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -/** - * Validates based on {ident} CSS grammar production - */ -class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef -{ - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - $string = trim($string); - - // early abort: '' and '0' (strings that convert to false) are invalid - if (!$string) { - return false; - } - - $pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/'; - if (!preg_match($pattern, $string)) { - return false; - } - return $string; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php b/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php deleted file mode 100644 index ffc989fe8..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php - -/** - * Decorator which enables !important to be used in CSS values. - */ -class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef -{ - /** - * @type HTMLPurifier_AttrDef - */ - public $def; - /** - * @type bool - */ - public $allow; - - /** - * @param HTMLPurifier_AttrDef $def Definition to wrap - * @param bool $allow Whether or not to allow !important - */ - public function __construct($def, $allow = false) - { - $this->def = $def; - $this->allow = $allow; - } - - /** - * Intercepts and removes !important if necessary - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - // test for ! and important tokens - $string = trim($string); - $is_important = false; - // :TODO: optimization: test directly for !important and ! important - if (strlen($string) >= 9 && substr($string, -9) === 'important') { - $temp = rtrim(substr($string, 0, -9)); - // use a temp, because we might want to restore important - if (strlen($temp) >= 1 && substr($temp, -1) === '!') { - $string = rtrim(substr($temp, 0, -1)); - $is_important = true; - } - } - $string = $this->def->validate($string, $config, $context); - if ($this->allow && $is_important) { - $string .= ' !important'; - } - return $string; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Length.php b/library/HTMLPurifier/AttrDef/CSS/Length.php deleted file mode 100644 index f12453a04..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Length.php +++ /dev/null @@ -1,77 +0,0 @@ -<?php - -/** - * Represents a Length as defined by CSS. - */ -class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef -{ - - /** - * @type HTMLPurifier_Length|string - */ - protected $min; - - /** - * @type HTMLPurifier_Length|string - */ - protected $max; - - /** - * @param HTMLPurifier_Length|string $min Minimum length, or null for no bound. String is also acceptable. - * @param HTMLPurifier_Length|string $max Maximum length, or null for no bound. String is also acceptable. - */ - public function __construct($min = null, $max = null) - { - $this->min = $min !== null ? HTMLPurifier_Length::make($min) : null; - $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - $string = $this->parseCDATA($string); - - // Optimizations - if ($string === '') { - return false; - } - if ($string === '0') { - return '0'; - } - if (strlen($string) === 1) { - return false; - } - - $length = HTMLPurifier_Length::make($string); - if (!$length->isValid()) { - return false; - } - - if ($this->min) { - $c = $length->compareTo($this->min); - if ($c === false) { - return false; - } - if ($c < 0) { - return false; - } - } - if ($this->max) { - $c = $length->compareTo($this->max); - if ($c === false) { - return false; - } - if ($c > 0) { - return false; - } - } - return $length->toString(); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/ListStyle.php b/library/HTMLPurifier/AttrDef/CSS/ListStyle.php deleted file mode 100644 index e74d42654..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/ListStyle.php +++ /dev/null @@ -1,112 +0,0 @@ -<?php - -/** - * Validates shorthand CSS property list-style. - * @warning Does not support url tokens that have internal spaces. - */ -class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef -{ - - /** - * Local copy of validators. - * @type HTMLPurifier_AttrDef[] - * @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl. - */ - protected $info; - - /** - * @param HTMLPurifier_Config $config - */ - public function __construct($config) - { - $def = $config->getCSSDefinition(); - $this->info['list-style-type'] = $def->info['list-style-type']; - $this->info['list-style-position'] = $def->info['list-style-position']; - $this->info['list-style-image'] = $def->info['list-style-image']; - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - // regular pre-processing - $string = $this->parseCDATA($string); - if ($string === '') { - return false; - } - - // assumes URI doesn't have spaces in it - $bits = explode(' ', strtolower($string)); // bits to process - - $caught = array(); - $caught['type'] = false; - $caught['position'] = false; - $caught['image'] = false; - - $i = 0; // number of catches - $none = false; - - foreach ($bits as $bit) { - if ($i >= 3) { - return; - } // optimization bit - if ($bit === '') { - continue; - } - foreach ($caught as $key => $status) { - if ($status !== false) { - continue; - } - $r = $this->info['list-style-' . $key]->validate($bit, $config, $context); - if ($r === false) { - continue; - } - if ($r === 'none') { - if ($none) { - continue; - } else { - $none = true; - } - if ($key == 'image') { - continue; - } - } - $caught[$key] = $r; - $i++; - break; - } - } - - if (!$i) { - return false; - } - - $ret = array(); - - // construct type - if ($caught['type']) { - $ret[] = $caught['type']; - } - - // construct image - if ($caught['image']) { - $ret[] = $caught['image']; - } - - // construct position - if ($caught['position']) { - $ret[] = $caught['position']; - } - - if (empty($ret)) { - return false; - } - return implode(' ', $ret); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Multiple.php b/library/HTMLPurifier/AttrDef/CSS/Multiple.php deleted file mode 100644 index 9f266cdd1..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Multiple.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php - -/** - * Framework class for strings that involve multiple values. - * - * Certain CSS properties such as border-width and margin allow multiple - * lengths to be specified. This class can take a vanilla border-width - * definition and multiply it, usually into a max of four. - * - * @note Even though the CSS specification isn't clear about it, inherit - * can only be used alone: it will never manifest as part of a multi - * shorthand declaration. Thus, this class does not allow inherit. - */ -class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef -{ - /** - * Instance of component definition to defer validation to. - * @type HTMLPurifier_AttrDef - * @todo Make protected - */ - public $single; - - /** - * Max number of values allowed. - * @todo Make protected - */ - public $max; - - /** - * @param HTMLPurifier_AttrDef $single HTMLPurifier_AttrDef to multiply - * @param int $max Max number of values allowed (usually four) - */ - public function __construct($single, $max = 4) - { - $this->single = $single; - $this->max = $max; - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - $string = $this->parseCDATA($string); - if ($string === '') { - return false; - } - $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n - $length = count($parts); - $final = ''; - for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) { - if (ctype_space($parts[$i])) { - continue; - } - $result = $this->single->validate($parts[$i], $config, $context); - if ($result !== false) { - $final .= $result . ' '; - $num++; - } - } - if ($final === '') { - return false; - } - return rtrim($final); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Number.php b/library/HTMLPurifier/AttrDef/CSS/Number.php deleted file mode 100644 index 8edc159e7..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Number.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php - -/** - * Validates a number as defined by the CSS spec. - */ -class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef -{ - - /** - * Indicates whether or not only positive values are allowed. - * @type bool - */ - protected $non_negative = false; - - /** - * @param bool $non_negative indicates whether negatives are forbidden - */ - public function __construct($non_negative = false) - { - $this->non_negative = $non_negative; - } - - /** - * @param string $number - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return string|bool - * @warning Some contexts do not pass $config, $context. These - * variables should not be used without checking HTMLPurifier_Length - */ - public function validate($number, $config, $context) - { - $number = $this->parseCDATA($number); - - if ($number === '') { - return false; - } - if ($number === '0') { - return '0'; - } - - $sign = ''; - switch ($number[0]) { - case '-': - if ($this->non_negative) { - return false; - } - $sign = '-'; - case '+': - $number = substr($number, 1); - } - - if (ctype_digit($number)) { - $number = ltrim($number, '0'); - return $number ? $sign . $number : '0'; - } - - // Period is the only non-numeric character allowed - if (strpos($number, '.') === false) { - return false; - } - - list($left, $right) = explode('.', $number, 2); - - if ($left === '' && $right === '') { - return false; - } - if ($left !== '' && !ctype_digit($left)) { - return false; - } - - $left = ltrim($left, '0'); - $right = rtrim($right, '0'); - - if ($right === '') { - return $left ? $sign . $left : '0'; - } elseif (!ctype_digit($right)) { - return false; - } - return $sign . $left . '.' . $right; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Percentage.php b/library/HTMLPurifier/AttrDef/CSS/Percentage.php deleted file mode 100644 index f0f25c50a..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Percentage.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php - -/** - * Validates a Percentage as defined by the CSS spec. - */ -class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef -{ - - /** - * Instance to defer number validation to. - * @type HTMLPurifier_AttrDef_CSS_Number - */ - protected $number_def; - - /** - * @param bool $non_negative Whether to forbid negative values - */ - public function __construct($non_negative = false) - { - $this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); - } - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - $string = $this->parseCDATA($string); - - if ($string === '') { - return false; - } - $length = strlen($string); - if ($length === 1) { - return false; - } - if ($string[$length - 1] !== '%') { - return false; - } - - $number = substr($string, 0, $length - 1); - $number = $this->number_def->validate($number, $config, $context); - - if ($number === false) { - return false; - } - return "$number%"; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php deleted file mode 100644 index 5fd4b7f7b..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php - -/** - * Validates the value for the CSS property text-decoration - * @note This class could be generalized into a version that acts sort of - * like Enum except you can compound the allowed values. - */ -class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef -{ - - /** - * @param string $string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($string, $config, $context) - { - static $allowed_values = array( - 'line-through' => true, - 'overline' => true, - 'underline' => true, - ); - - $string = strtolower($this->parseCDATA($string)); - - if ($string === 'none') { - return $string; - } - - $parts = explode(' ', $string); - $final = ''; - foreach ($parts as $part) { - if (isset($allowed_values[$part])) { - $final .= $part . ' '; - } - } - $final = rtrim($final); - if ($final === '') { - return false; - } - return $final; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/URI.php b/library/HTMLPurifier/AttrDef/CSS/URI.php deleted file mode 100644 index f9434230e..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/URI.php +++ /dev/null @@ -1,74 +0,0 @@ -<?php - -/** - * Validates a URI in CSS syntax, which uses url('http://example.com') - * @note While theoretically speaking a URI in a CSS document could - * be non-embedded, as of CSS2 there is no such usage so we're - * generalizing it. This may need to be changed in the future. - * @warning Since HTMLPurifier_AttrDef_CSS blindly uses semicolons as - * the separator, you cannot put a literal semicolon in - * in the URI. Try percent encoding it, in that case. - */ -class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI -{ - - public function __construct() - { - parent::__construct(true); // always embedded - } - - /** - * @param string $uri_string - * @param HTMLPurifier_Config $config - * @param HTMLPurifier_Context $context - * @return bool|string - */ - public function validate($uri_string, $config, $context) - { - // parse the URI out of the string and then pass it onto - // the parent object - - $uri_string = $this->parseCDATA($uri_string); - if (strpos($uri_string, 'url(') !== 0) { - return false; - } - $uri_string = substr($uri_string, 4); - $new_length = strlen($uri_string) - 1; - if ($uri_string[$new_length] != ')') { - return false; - } - $uri = trim(substr($uri_string, 0, $new_length)); - - if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) { - $quote = $uri[0]; - $new_length = strlen($uri) - 1; - if ($uri[$new_length] !== $quote) { - return false; - } - $uri = substr($uri, 1, $new_length - 1); - } - - $uri = $this->expandCSSEscape($uri); - - $result = parent::validate($uri, $config, $context); - - if ($result === false) { - return false; - } - - // extra sanity check; should have been done by URI - $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result); - - // suspicious characters are ()'; we're going to percent encode - // them for safety. - $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result); - - // there's an extra bug where ampersands lose their escaping on - // an innerHTML cycle, so a very unlucky query parameter could - // then change the meaning of the URL. Unfortunately, there's - // not much we can do about that... - return "url(\"$result\")"; - } -} - -// vim: et sw=4 sts=4 |