0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-12-22 16:31:53 +00:00

[3.1.0] Continue building up validation functions

- Remove incorrect parsing of value aliases
- Implement most allowed and value alias checks
- Add assertIsBool, assertIsArray and assertIsLookup to ValidatorAtom
- Publish string types in VarParser

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1647 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2008-04-04 21:33:37 +00:00
parent 6b21a841c4
commit 0ee090bc7b
15 changed files with 247 additions and 15 deletions

View File

@ -3,6 +3,9 @@
class HTMLPurifier_ConfigSchema_InterchangeBuilder class HTMLPurifier_ConfigSchema_InterchangeBuilder
{ {
/**
* Used for processing DEFAULT, nothing else.
*/
protected $varParser; protected $varParser;
public function __construct($varParser = null) { public function __construct($varParser = null) {
@ -70,18 +73,7 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
} }
if (isset($hash['VALUE-ALIASES'])) { if (isset($hash['VALUE-ALIASES'])) {
$value_aliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES')); $directive->valueAliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES'));
// :TODO: Build corresponding test in Validator.php
try {
foreach ($value_aliases as $alias => $real) {
// might want to allow users to use a different var parser
// in this case
$directive->valueAliases[$this->varParser->parse($alias, $directive->type, $directive->typeAllowsNull)] =
$this->varParser->parse($real, $directive->type, $directive->typeAllowsNull);
}
} catch (HTMLPurifier_VarParserException $e) {
throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in $alias => $real in VALUE-ALIASES in directive hash '$id'");
}
} }
if (isset($hash['ALIASES'])) { if (isset($hash['ALIASES'])) {

View File

@ -79,16 +79,67 @@ class HTMLPurifier_ConfigSchema_Validator
$this->validateId($d->id); $this->validateId($d->id);
$this->with($d, 'description') $this->with($d, 'description')
->assertNotEmpty(); ->assertNotEmpty();
// BEGIN - handled by InterchangeBuilder
$this->with($d, 'type') $this->with($d, 'type')
->assertNotEmpty(); // handled by InterchangeBuilder ->assertNotEmpty();
// Much stricter default check, since we're using the base implementation. $this->with($d, 'typeAllowsNull')
// handled by InterchangeBuilder ->assertIsBool();
try { try {
// This also tests validity of $d->type
$this->parser->parse($d->default, $d->type, $d->typeAllowsNull); $this->parser->parse($d->default, $d->type, $d->typeAllowsNull);
} catch (HTMLPurifier_VarParserException $e) { } catch (HTMLPurifier_VarParserException $e) {
$this->error('default', 'had error: ' . $e->getMessage()); $this->error('default', 'had error: ' . $e->getMessage());
} }
// END - handled by InterchangeBuilder
if (!is_null($d->allowed) || !empty($d->valueAliases)) {
// allowed and valueAliases require that we be dealing with
// strings, so check for that early.
if (!isset(HTMLPurifier_VarParser::$stringTypes[$d->type])) {
$this->error('type', 'must be a string type when used with allowed or value aliases');
}
}
$this->validateDirectiveAllowed($d);
$this->validateDirectiveValueAliases($d);
array_pop($this->context);
}
public function validateDirectiveAllowed($d) {
if (is_null($d->allowed)) return;
$this->with($d, 'allowed')
->assertNotEmpty()
->assertIsLookup(); // handled by InterchangeBuilder
$this->context[] = 'allowed';
foreach ($d->allowed as $val => $x) {
if (!is_string($val)) $this->error("value $val", 'must be a string');
}
array_pop($this->context);
}
public function validateDirectiveValueAliases($d) {
if (is_null($d->valueAliases)) return;
$this->with($d, 'valueAliases')
->assertIsArray(); // handled by InterchangeBuilder
$this->context[] = 'valueAliases';
foreach ($d->valueAliases as $alias => $real) {
if (!is_string($alias)) $this->error("alias $alias", 'must be a string');
if (!is_string($real)) $this->error("alias target $real from alias '$alias'", 'must be a string');
if ($alias === $real) {
$this->error("alias '$alias'", "must not be an alias to itself");
}
}
if (!is_null($d->allowed)) {
foreach ($d->valueAliases as $alias => $real) {
if (isset($d->allowed[$alias])) {
$this->error("alias '$alias'", 'must not be an allowed value');
} elseif (!isset($d->allowed[$real])) {
$this->error("alias '$alias'", 'must be an alias to an allowed value');
}
}
}
array_pop($this->context); array_pop($this->context);
} }

View File

@ -23,6 +23,16 @@ class HTMLPurifier_ConfigSchema_ValidatorAtom
return $this; return $this;
} }
public function assertIsBool() {
if (!is_bool($this->contents)) $this->error('must be a boolean');
return $this;
}
public function assertIsArray() {
if (!is_array($this->contents)) $this->error('must be an array');
return $this;
}
public function assertNotNull() { public function assertNotNull() {
if ($this->contents === null) $this->error('must not be null'); if ($this->contents === null) $this->error('must not be null');
return $this; return $this;
@ -39,6 +49,14 @@ class HTMLPurifier_ConfigSchema_ValidatorAtom
return $this; return $this;
} }
public function assertIsLookup() {
$this->assertIsArray();
foreach ($this->contents as $v) {
if ($v !== true) $this->error('must be a lookup array');
}
return $this;
}
protected function error($msg) { protected function error($msg) {
throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg); throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg);
} }

View File

@ -24,6 +24,17 @@ class HTMLPurifier_VarParser
'mixed' => true 'mixed' => true
); );
/**
* Lookup table of types that are string, and can have aliases or
* allowed value lists.
*/
static public $stringTypes = array(
'string' => true,
'istring' => true,
'text' => true,
'itext' => true,
);
/** /**
* Validate a variable according to type. Throws * Validate a variable according to type. Throws
* HTMLPurifier_VarParserException if invalid. * HTMLPurifier_VarParserException if invalid.

View File

@ -0,0 +1,10 @@
ERROR: Value 3 in allowed in directive 'Ns.Dir' must be a string
----
Ns
DESCRIPTION: Generic namespace.
----
ID: Ns.Dir
TYPE: string
DESCRIPTION: Description
DEFAULT: 'asdf'
ALLOWED: 'asdf', 3

View File

@ -0,0 +1,10 @@
ERROR: Allowed in directive 'Ns.Dir' must not be empty
----
Ns
DESCRIPTION: Generic namespace.
----
ID: Ns.Dir
TYPE: string
DESCRIPTION: Description
DEFAULT: 'asdf'
ALLOWED:

View File

@ -0,0 +1,10 @@
ERROR: Type in directive 'Ns.Dir' must be a string type when used with allowed or value aliases
----
Ns
DESCRIPTION: Namespace
----
Ns.Dir
DESCRIPTION: Directive
TYPE: int
DEFAULT: 3
ALLOWED: 1, 2, 3

View File

@ -0,0 +1,10 @@
ERROR: Type in directive 'Ns.Dir' must be a string type when used with allowed or value aliases
----
Ns
DESCRIPTION: Namespace
----
Ns.Dir
DESCRIPTION: Directive
TYPE: int
DEFAULT: 3
VALUE-ALIASES: 2 => 3

View File

@ -0,0 +1,10 @@
ERROR: Alias 3 in valueAliases in directive 'Ns.Dir' must be a string
----
Ns
DESCRIPTION: Namespace
----
Ns.Dir
DESCRIPTION: Directive
TYPE: string
DEFAULT: 'a'
VALUE-ALIASES: 3 => 'a'

View File

@ -0,0 +1,11 @@
ERROR: Alias 'b' in valueAliases in directive 'Ns.Dir' must not be an allowed value
----
Ns
DESCRIPTION: Namespace
----
Ns.Dir
DESCRIPTION: Directive
TYPE: string
DEFAULT: 'a'
ALLOWED: 'a', 'b', 'c'
VALUE-ALIASES: 'b' => 'c'

View File

@ -0,0 +1,10 @@
ERROR: Alias 'bar' in valueAliases in directive 'Ns.Dir' must not be an alias to itself
----
Ns
DESCRIPTION: Namespace
----
Ns.Dir
DESCRIPTION: Directive
TYPE: string
DEFAULT: 'foo'
VALUE-ALIASES: 'bar' => 'bar'

View File

@ -0,0 +1,11 @@
ERROR: Alias 'c' in valueAliases in directive 'Ns.Dir' must be an alias to an allowed value
----
Ns
DESCRIPTION: Namespace
----
Ns.Dir
DESCRIPTION: Directive
TYPE: string
DEFAULT: 'a'
ALLOWED: 'a', 'b'
VALUE-ALIASES: 'c' => 'd'

View File

@ -0,0 +1,10 @@
ERROR: Alias target 3 from alias 'b' in valueAliases in directive 'Ns.Dir' must be a string
----
Ns
DESCRIPTION: Namespace
----
Ns.Dir
DESCRIPTION: Directive
TYPE: string
DEFAULT: 'a'
VALUE-ALIASES: 'b' => 3

View File

@ -55,4 +55,36 @@ class HTMLPurifier_ConfigSchema_ValidatorAtomTest extends UnitTestCase
$this->makeAtom('')->assertNotEmpty(); $this->makeAtom('')->assertNotEmpty();
} }
public function testAssertIsBool() {
$this->makeAtom(false)->assertIsBool();
}
public function testAssertIsBoolFail() {
$this->expectValidationException("Property in context must be a boolean");
$this->makeAtom('0')->assertIsBool();
}
public function testAssertIsArray() {
$this->makeAtom(array())->assertIsArray();
}
public function testAssertIsArrayFail() {
$this->expectValidationException("Property in context must be an array");
$this->makeAtom('asdf')->assertIsArray();
}
public function testAssertIsLookup() {
$this->makeAtom(array('foo' => true))->assertIsLookup();
}
public function testAssertIsLookupFail() {
$this->expectValidationException("Property in context must be a lookup array");
$this->makeAtom(array('foo' => 4))->assertIsLookup();
}
public function testAssertIsLookupFailIsArray() {
$this->expectValidationException("Property in context must be an array");
$this->makeAtom('asdf')->assertIsLookup();
}
} }

View File

@ -72,6 +72,42 @@ class HTMLPurifier_ConfigSchema_ValidatorTest extends UnitTestCase
$this->validator->validate($this->interchange); $this->validator->validate($this->interchange);
} }
public function testDirectiveTypeAllowsNullIsBool() {
$this->makeNamespace('Ns');
$d = $this->makeDirective('Ns', 'Dir');
$d->default = 0;
$d->type = 'int';
$d->description = 'Description';
$d->typeAllowsNull = 'yes';
$this->expectValidationException("TypeAllowsNull in directive 'Ns.Dir' must be a boolean");
$this->validator->validate($this->interchange);
}
public function testDirectiveValueAliasesIsArray() {
$this->makeNamespace('Ns');
$d = $this->makeDirective('Ns', 'Dir');
$d->default = 'a';
$d->type = 'string';
$d->description = 'Description';
$d->valueAliases = 2;
$this->expectValidationException("ValueAliases in directive 'Ns.Dir' must be an array");
$this->validator->validate($this->interchange);
}
public function testDirectiveAllowedIsLookup() {
$this->makeNamespace('Ns');
$d = $this->makeDirective('Ns', 'Dir');
$d->default = 'foo';
$d->type = 'string';
$d->description = 'Description';
$d->allowed = array('foo' => 1);
$this->expectValidationException("Allowed in directive 'Ns.Dir' must be a lookup array");
$this->validator->validate($this->interchange);
}
// helper functions // helper functions
protected function makeNamespace($n) { protected function makeNamespace($n) {