0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-09-19 10:45:18 +00:00

[3.0.0] [BACKPORT] More work for hire from Chris

! Experimental support for some proprietary CSS attributes allowed: opacity (and all of the browser-specific equivalents) and scrollbar colors. Enable by setting %CSS.Proprietary to true.
- Colors missing # but in hex form will be corrected
- CSS Number algorithm improved
. New classes:
  + HTMLPurifier_AttrDef_CSS_AlphaValue
  + HTMLPurifier_AttrDef_CSS_Filter

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1473 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2007-12-16 23:16:45 +00:00
parent a840c24796
commit 0f961c6af4
12 changed files with 237 additions and 12 deletions

8
NEWS
View File

@ -22,7 +22,15 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
documents and cleaning their contents up. Requires the CSSTidy library
<http://csstidy.sourceforge.net/>. You can access the blocks with the
'StyleBlocks' Context variable ($purifier->context->get('StyleBlocks'))
! Experimental support for some proprietary CSS attributes allowed:
opacity (and all of the browser-specific equivalents) and scrollbar colors.
Enable by setting %CSS.Proprietary to true.
- Colors missing # but in hex form will be corrected
- CSS Number algorithm improved
. Unit tests for Injector improved
. New classes:
+ HTMLPurifier_AttrDef_CSS_AlphaValue
+ HTMLPurifier_AttrDef_CSS_Filter
2.1.3, released 2007-11-05
! tests/multitest.php allows you to test multiple versions by running

View File

@ -0,0 +1,22 @@
<?php
require_once 'HTMLPurifier/AttrDef.php';
require_once 'HTMLPurifier/AttrDef/CSS/Number.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
}
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;
}
}

View File

@ -39,20 +39,13 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
if ($colors === null) $colors = $config->get('Core', 'ColorKeywords');
$color = trim($color);
if (!$color) return false;
if ($color === '') return false;
$lower = strtolower($color);
if (isset($colors[$lower])) return $colors[$lower];
if ($color[0] === '#') {
// hexadecimal handling
$hex = substr($color, 1);
$length = strlen($hex);
if ($length !== 3 && $length !== 6) return false;
if (!ctype_xdigit($hex)) return false;
} else {
if (strpos($color, 'rgb(') !== false) {
// rgb literal handling
if (strpos($color, 'rgb(')) return false;
$length = strlen($color);
if (strpos($color, ')') !== $length - 1) return false;
$triad = substr($color, 4, $length - 4 - 1);
@ -90,6 +83,17 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
}
$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;

View File

@ -0,0 +1,54 @@
<?php
require_once 'HTMLPurifier/AttrDef.php';
require_once 'HTMLPurifier/AttrDef/Integer.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
{
protected $intValidator;
public function __construct() {
$this->intValidator = new HTMLPurifier_AttrDef_Integer();
}
public function validate($value, $config, &$context) {
$value = $this->parseCDATA($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;
}
}

View File

@ -23,6 +23,7 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
$number = $this->parseCDATA($number);
if ($number === '') return false;
if ($number === '0') return '0';
$sign = '';
switch ($number[0]) {
@ -37,13 +38,16 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
$number = ltrim($number, '0');
return $number ? $sign . $number : '0';
}
if (!strpos($number, '.')) return false;
// Period is the only non-numeric character allowed
if (strpos($number, '.') === false) return false;
list($left, $right) = explode('.', $number, 2);
if (!ctype_digit($left)) return false;
$left = ltrim($left, '0');
if ($left === '' && $right === '') return false;
if ($left !== '' && !ctype_digit($left)) return false;
$left = ltrim($left, '0');
$right = rtrim($right, '0');
if ($right === '') {

View File

@ -2,11 +2,13 @@
require_once 'HTMLPurifier/Definition.php';
require_once 'HTMLPurifier/AttrDef/CSS/AlphaValue.php';
require_once 'HTMLPurifier/AttrDef/CSS/Background.php';
require_once 'HTMLPurifier/AttrDef/CSS/BackgroundPosition.php';
require_once 'HTMLPurifier/AttrDef/CSS/Border.php';
require_once 'HTMLPurifier/AttrDef/CSS/Color.php';
require_once 'HTMLPurifier/AttrDef/CSS/Composite.php';
require_once 'HTMLPurifier/AttrDef/CSS/Filter.php';
require_once 'HTMLPurifier/AttrDef/CSS/Font.php';
require_once 'HTMLPurifier/AttrDef/CSS/FontFamily.php';
require_once 'HTMLPurifier/AttrDef/CSS/Length.php';
@ -26,6 +28,14 @@ HTMLPurifier_ConfigSchema::define(
</p>
');
HTMLPurifier_ConfigSchema::define(
'CSS', 'Proprietary', false, 'bool', '
<p>
Whether or not to allow safe, proprietary CSS values. This directive
has been available since 3.0.0.
</p>
');
/**
* Defines allowed CSS attributes and what their values are.
* @see HTMLPurifier_HTMLDefinition
@ -224,6 +234,29 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
// partial support
$this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(array('nowrap'));
if ($config->get('CSS', 'Proprietary')) {
$this->doSetupProprietary($config);
}
}
protected function doSetupProprietary($config) {
// Internet Explorer only scrollbar colors
$this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
// technically not proprietary, but CSS3, and no one supports it
$this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
$this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
$this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
// only opacity, for now
$this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter();
}
}

View File

@ -0,0 +1,30 @@
<?php
require_once 'HTMLPurifier/AttrDef/CSS/AlphaValue.php';
require_once 'HTMLPurifier/AttrDefHarness.php';
class HTMLPurifier_AttrDef_CSS_AlphaValueTest extends HTMLPurifier_AttrDefHarness
{
function test() {
$this->def = new HTMLPurifier_AttrDef_CSS_AlphaValue();
$this->assertDef('0');
$this->assertDef('1');
$this->assertDef('.2');
// clamping to [0.0, 1,0]
$this->assertDef('1.2', '1');
$this->assertDef('-3', '0');
$this->assertDef('0.0', '0');
$this->assertDef('1.0', '1');
$this->assertDef('000', '0');
$this->assertDef('asdf', false);
}
}

View File

@ -11,6 +11,8 @@ class HTMLPurifier_AttrDef_CSS_ColorTest extends HTMLPurifier_AttrDefHarness
$this->def = new HTMLPurifier_AttrDef_CSS_Color();
$this->assertDef('#F00');
$this->assertDef('#fff');
$this->assertDef('#eeeeee');
$this->assertDef('#808080');
$this->assertDef('rgb(255, 0, 0)', 'rgb(255,0,0)'); // rm spaces
$this->assertDef('rgb(100%,0%,0%)');
@ -27,6 +29,11 @@ class HTMLPurifier_AttrDef_CSS_ColorTest extends HTMLPurifier_AttrDefHarness
// color keywords, of course
$this->assertDef('red', '#FF0000');
// malformed hex declaration
$this->assertDef('808080', '#808080');
$this->assertDef('000000', '#000000');
$this->assertDef('fed', '#fed');
// maybe hex transformations would be another nice feature
// at the very least transform rgb percent to rgb integer

View File

@ -0,0 +1,29 @@
<?php
require_once 'HTMLPurifier/AttrDef/CSS/Filter.php';
require_once 'HTMLPurifier/AttrDefHarness.php';
class HTMLPurifier_AttrDef_CSS_FilterTest extends HTMLPurifier_AttrDefHarness
{
function test() {
$this->def = new HTMLPurifier_AttrDef_CSS_Filter();
$this->assertDef('alpha(opacity=0)');
$this->assertDef('alpha(opacity=100)');
$this->assertDef('alpha(opacity=50)');
$this->assertDef('alpha(opacity=342)', 'alpha(opacity=100)');
$this->assertDef('alpha(opacity=-23)', 'alpha(opacity=0)');
$this->assertDef('alpha ( opacity = 0 )', 'alpha(opacity=0)');
$this->assertDef('alpha(opacity=0,opacity=100)', 'alpha(opacity=0)');
$this->assertDef('progid:DXImageTransform.Microsoft.Alpha(opacity=20)');
$this->assertDef('progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)', false);
}
}

View File

@ -11,10 +11,24 @@ class HTMLPurifier_AttrDef_CSS_NumberTest extends HTMLPurifier_AttrDefHarness
$this->def = new HTMLPurifier_AttrDef_CSS_Number();
$this->assertDef('0');
$this->assertDef('0.0', '0');
$this->assertDef('1.0', '1');
$this->assertDef('34');
$this->assertDef('4.5');
$this->assertDef('.5');
$this->assertDef('0.5', '.5');
$this->assertDef('-56.9');
$this->assertDef('0.', '0');
$this->assertDef('.0', '0');
$this->assertDef('0.0', '0');
$this->assertDef('1.', '1');
$this->assertDef('.1', '.1');
$this->assertDef('1.0', '1');
$this->assertDef('0.1', '.1');
$this->assertDef('000', '0');
$this->assertDef(' 9', '9');
$this->assertDef('+5.0000', '5');

View File

@ -112,5 +112,23 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
}
function testProprietary() {
$this->config->set('CSS', 'Proprietary', true);
$this->def = new HTMLPurifier_AttrDef_CSS();
$this->assertDef('scrollbar-arrow-color:#ff0;');
$this->assertDef('scrollbar-base-color:#ff6347;');
$this->assertDef('scrollbar-darkshadow-color:#ffa500;');
$this->assertDef('scrollbar-face-color:#008080;');
$this->assertDef('scrollbar-highlight-color:#ff69b4;');
$this->assertDef('scrollbar-shadow-color:#f0f;');
$this->assertDef('opacity:.2;');
$this->assertDef('-moz-opacity:.2;');
$this->assertDef('-khtml-opacity:.2;');
$this->assertDef('filter:alpha(opacity=20);');
}
}

View File

@ -7,11 +7,13 @@ if (!defined('HTMLPurifierTest')) exit;
// HTML Purifier main library
$test_files[] = 'HTMLPurifier/AttrCollectionsTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/AlphaValueTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/BackgroundPositionTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/BackgroundTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/BorderTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/ColorTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/CompositeTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/FilterTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/FontFamilyTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/FontTest.php';
$test_files[] = 'HTMLPurifier/AttrDef/CSS/LengthTest.php';