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

[1.2.0] Allow configuration directives to permit null values. ConfigDoc updated accordingly.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@521 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2006-11-12 02:59:36 +00:00
parent ad934540da
commit 926b94bdd3
7 changed files with 99 additions and 16 deletions

1
NEWS
View File

@ -22,6 +22,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
. Refactored unit tests to minimize duplication
. XSS attack sheet updated
. configdoc.xml now has xml:space attached to default value nodes
. Allow configuration directives to permit null values
1.1.3, unknown projected release date
(bugfix release, may be dropped if no major bugs are found before features)

View File

@ -110,9 +110,12 @@ foreach($schema->info as $namespace_name => $namespace_info) {
$dom_constraints = $dom_document->createElement('constraints');
$dom_directive->appendChild($dom_constraints);
$dom_constraints->appendChild(
$dom_document->createElement('type', $info->type)
);
$dom_type = $dom_document->createElement('type', $info->type);
if ($info->allow_null) {
$dom_type->setAttribute('allow-null', 'yes');
}
$dom_constraints->appendChild($dom_type);
if ($info->allowed !== true) {
$dom_allowed = $dom_document->createElement('allowed');
$dom_constraints->appendChild($dom_allowed);
@ -128,6 +131,8 @@ foreach($schema->info as $namespace_name => $namespace_info) {
$default = $raw_default ? 'true' : 'false';
} elseif (is_string($raw_default)) {
$default = "\"$raw_default\"";
} elseif (is_null($raw_default)) {
$default = 'null';
} else {
$default = print_r(
$schema->defaults[$namespace_name][$name], true

View File

@ -69,7 +69,7 @@
<xsl:apply-templates />
</xsl:template>
<xsl:template match="directive/name">
<h3 id="{../@id}"><xsl:value-of select="." /></h3>
<h3 id="{../@id}"><xsl:value-of select="../@id" /></h3>
</xsl:template>
<xsl:template match="directive/constraints">
<table class="constraints">
@ -99,6 +99,9 @@
<xsl:variable name="type" select="text()" />
<xsl:attribute name="class">type type-<xsl:value-of select="$type" /></xsl:attribute>
<xsl:value-of select="$typeLookup/types/type[@id=$type]/text()" />
<xsl:if test="@allow-null='yes'">
(or null)
</xsl:if>
</td>
</tr>
</xsl:template>

View File

@ -80,8 +80,11 @@ class HTMLPurifier_Config
E_USER_WARNING);
return;
}
$value = $this->def->validate($value,
$this->def->info[$namespace][$key]->type);
$value = $this->def->validate(
$value,
$this->def->info[$namespace][$key]->type,
$this->def->info[$namespace][$key]->allow_null
);
if (is_string($value)) {
// resolve value alias if defined
if (isset($this->def->info[$namespace][$key]->aliases[$value])) {
@ -95,7 +98,7 @@ class HTMLPurifier_Config
}
}
}
if ($value === null) {
if ($this->def->isError($value)) {
trigger_error('Value is of invalid type', E_USER_WARNING);
return;
}

View File

@ -1,5 +1,7 @@
<?php
require_once 'HTMLPurifier/Error.php';
/**
* Configuration definition, defines directives and their defaults.
* @todo The ability to define things multiple times is confusing and should
@ -111,12 +113,19 @@ class HTMLPurifier_ConfigSchema {
return;
}
} else {
// process modifiers
$type_values = explode('/', $type, 2);
$type = $type_values[0];
$modifier = isset($type_values[1]) ? $type_values[1] : false;
$allow_null = ($modifier === 'null');
if (!isset($def->types[$type])) {
trigger_error('Invalid type for configuration directive',
E_USER_ERROR);
return;
}
if ($def->validate($default, $type) === null) {
$default = $def->validate($default, $type, $allow_null);
if ($def->isError($default)) {
trigger_error('Default value does not match directive type',
E_USER_ERROR);
return;
@ -124,6 +133,7 @@ class HTMLPurifier_ConfigSchema {
$def->info[$namespace][$name] =
new HTMLPurifier_ConfigEntity_Directive();
$def->info[$namespace][$name]->type = $type;
$def->info[$namespace][$name]->allow_null = $allow_null;
$def->defaults[$namespace][$name] = $default;
}
$backtrace = debug_backtrace();
@ -212,36 +222,37 @@ class HTMLPurifier_ConfigSchema {
/**
* Validate a variable according to type. Return null if invalid.
*/
function validate($var, $type) {
function validate($var, $type, $allow_null = false) {
if (!isset($this->types[$type])) {
trigger_error('Invalid type', E_USER_ERROR);
return;
}
if ($allow_null && $var === null) return null;
switch ($type) {
case 'mixed':
return $var;
case 'istring':
case 'string':
if (!is_string($var)) return;
if (!is_string($var)) break;
if ($type === 'istring') $var = strtolower($var);
return $var;
case 'int':
if (is_string($var) && ctype_digit($var)) $var = (int) $var;
elseif (!is_int($var)) return;
elseif (!is_int($var)) break;
return $var;
case 'float':
if (is_string($var) && is_numeric($var)) $var = (float) $var;
elseif (!is_float($var)) return;
elseif (!is_float($var)) break;
return $var;
case 'bool':
if (is_int($var) && ($var === 0 || $var === 1)) {
$var = (bool) $var;
} elseif (!is_bool($var)) return;
} elseif (!is_bool($var)) break;
return $var;
case 'list':
case 'hash':
case 'lookup':
if (!is_array($var)) return;
if (!is_array($var)) break;
$keys = array_keys($var);
if ($keys === array_keys($keys)) {
if ($type == 'list') return $var;
@ -251,7 +262,7 @@ class HTMLPurifier_ConfigSchema {
$new[$key] = true;
}
return $new;
} else return;
} else break;
}
if ($type === 'lookup') {
foreach ($var as $key => $value) {
@ -260,8 +271,13 @@ class HTMLPurifier_ConfigSchema {
}
return $var;
}
$error = new HTMLPurifier_Error();
return $error;
}
/**
* Takes an absolute path and munges it into a more manageable relative path
*/
function mungeFilename($filename) {
$offset = strrpos($filename, 'HTMLPurifier');
$filename = substr($filename, $offset);
@ -269,6 +285,14 @@ class HTMLPurifier_ConfigSchema {
return $filename;
}
/**
* Checks if var is an HTMLPurifier_Error object
*/
function isError($var) {
if (!is_object($var)) return false;
if (!is_a($var, 'HTMLPurifier_Error')) return false;
return true;
}
}
/**
@ -318,6 +342,13 @@ class HTMLPurifier_ConfigEntity_Directive extends HTMLPurifier_ConfigEntity
* - mixed (anything goes)
*/
var $type = 'mixed';
/**
* Is null allowed? Has no affect for mixed type.
* @bool
*/
var $allow_null = false;
/**
* Plaintext descriptions of the configuration entity is. Organized by
* file and line number, so multiple descriptions are allowed.

View File

@ -0,0 +1,8 @@
<?php
/**
* Return object from functions that signifies error when null doesn't cut it
*/
class HTMLPurifier_Error {}
?>

View File

@ -231,6 +231,17 @@ class HTMLPurifier_ConfigSchemaTest extends UnitTestCase
$this->swallowErrors();
// define a directive that allows null
HTMLPurifier_ConfigSchema::define(
'Core', 'Foobaz', null, 'string/null',
'Nulls are allowed if you add on /null, cool huh?'
);
$this->assertNoErrors();
$this->swallowErrors();
// define a directive with bad characters
HTMLPurifier_ConfigSchema::define(
'Core', 'Core.Attr', 10, 'int',
@ -258,7 +269,11 @@ class HTMLPurifier_ConfigSchemaTest extends UnitTestCase
}
function assertInvalid($var, $type) {
$this->assertIdentical($this->our_copy->validate($var, $type), null);
$this->assertTrue(
$this->our_copy->isError(
$this->our_copy->validate($var, $type)
)
);
}
function testValidate() {
@ -271,6 +286,7 @@ class HTMLPurifier_ConfigSchemaTest extends UnitTestCase
$this->assertValid(0, 'bool', false);
$this->assertValid(1, 'bool', true);
$this->assertInvalid(34, 'bool');
$this->assertInvalid(null, 'bool');
$this->assertValid(array('1', '2', '3'), 'list');
$this->assertValid(array('1' => true, '2' => true), 'lookup');
$this->assertValid(array('1', '2'), 'lookup', array('1' => true, '2' => true));
@ -281,6 +297,22 @@ class HTMLPurifier_ConfigSchemaTest extends UnitTestCase
}
function testValidate_null() {
$this->assertTrue(
$this->our_copy->isError(
$this->our_copy->validate(null, 'string', false)
)
);
$this->assertFalse(
$this->our_copy->isError(
$this->our_copy->validate(null, 'string', true)
)
);
}
function assertMungeFilename($oldname, $newname) {
$this->assertIdentical(
$this->our_copy->mungeFilename($oldname),