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

Reorganize VarParser; there may be multiple implementations.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1602 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2008-03-05 03:51:09 +00:00
parent 7480e7b956
commit bd64a8346d
11 changed files with 152 additions and 143 deletions

2
NEWS
View File

@ -22,7 +22,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
maintenance/generate-schema-cache.php generates the schema.ser file, which
is now instantiated. Support for userland schema changes coming soon!
! Extra utility classes for testing and non-library operations can
be found in extras/. Specifically, these are FSTools and ConfigSchema.
be found in extras/. Specifically, these are FSTools and ConfigDoc.
You may find a use for these in your own project, but right now they
are highly experimental and volatile.
! Integration with PHPT allows for automated smoketests

View File

@ -200,3 +200,4 @@ require 'HTMLPurifier/URIScheme/https.php';
require 'HTMLPurifier/URIScheme/mailto.php';
require 'HTMLPurifier/URIScheme/news.php';
require 'HTMLPurifier/URIScheme/nntp.php';
require 'HTMLPurifier/VarParser/Flexible.php';

View File

@ -75,7 +75,7 @@ class HTMLPurifier_Config
public function __construct(&$definition) {
$this->conf = $definition->defaults; // set up, copy in defaults
$this->def = $definition; // keep a copy around for checking
$this->parser = new HTMLPurifier_VarParser();
$this->parser = new HTMLPurifier_VarParser_Flexible();
}
/**

View File

@ -51,7 +51,7 @@ class HTMLPurifier_ConfigSchema {
);
public function __construct() {
$this->parser = new HTMLPurifier_VarParser();
$this->parser = new HTMLPurifier_VarParser_Flexible();
}
/**

View File

@ -8,23 +8,6 @@
class HTMLPurifier_ConfigSchema_Interchange
{
/**
* Hash table of allowed types.
*/
public $types = array(
'string' => 'String',
'istring' => 'Case-insensitive string',
'text' => 'Text',
'itext' => 'Case-insensitive text',
'int' => 'Integer',
'float' => 'Float',
'bool' => 'Boolean',
'lookup' => 'Lookup array',
'list' => 'Array list',
'hash' => 'Associative array',
'mixed' => 'Mixed'
);
/**
* Array of Namespace ID => array(namespace info)
*/

View File

@ -8,7 +8,7 @@ class HTMLPurifier_ConfigSchema_Validator_ParseType extends HTMLPurifier_ConfigS
public function validate(&$arr, $interchange) {
$r = explode('/', $arr['TYPE'], 2);
if (!isset($interchange->types[$r[0]])) {
if (!isset(HTMLPurifier_VarParser::$types[$r[0]])) {
$this->error('Invalid type ' . $r[0] . ' for configuration directive ' . $arr['ID']);
}
$arr['_TYPE'] = $r[0];

File diff suppressed because one or more lines are too long

View File

@ -4,13 +4,13 @@
* Parses string representations into their corresponding native PHP
* variable type.
*/
class HTMLPurifier_VarParser
abstract class HTMLPurifier_VarParser
{
/**
* Lookup table of allowed types.
*/
public $types = array(
static public $types = array(
'string' => true,
'istring' => true,
'text' => true,
@ -25,100 +25,15 @@ class HTMLPurifier_VarParser
);
/**
* Validate a variable according to type. Throws exception if invalid.
* It may return NULL as a valid type.
* Validate a variable according to type. Throws
* HTMLPurifier_VarParserException if invalid.
* It may return NULL as a valid type if $allow_null is true.
*
* @param $var Variable to validate
* @param $type Type of variable, see HTMLPurifier_VarParser->types
* @param $allow_null Whether or not to permit null as a value
* @return Validated and type-coerced variable
*/
public function parse($var, $type, $allow_null = false) {
if (!isset($this->types[$type])) {
throw new HTMLPurifier_VarParserException("Invalid type $type");
}
if ($allow_null && $var === null) return null;
switch ($type) {
// Note: if code "breaks" from the switch, it triggers a generic
// exception to be thrown. Specific errors can be specifically
// done here.
case 'mixed':
//if (is_string($var)) $var = unserialize($var);
return $var;
case 'istring':
case 'string':
case 'text': // no difference, just is longer/multiple line string
case 'itext':
if (!is_string($var)) break;
if ($type === 'istring' || $type === 'itext') $var = strtolower($var);
return $var;
case 'int':
if (is_string($var) && ctype_digit($var)) $var = (int) $var;
elseif (!is_int($var)) break;
return $var;
case 'float':
if (is_string($var) && is_numeric($var)) $var = (float) $var;
elseif (!is_float($var)) break;
return $var;
case 'bool':
if (is_int($var) && ($var === 0 || $var === 1)) {
$var = (bool) $var;
} elseif (is_string($var)) {
if ($var == 'on' || $var == 'true' || $var == '1') {
$var = true;
} elseif ($var == 'off' || $var == 'false' || $var == '0') {
$var = false;
} else {
throw new HTMLPurifier_VarParserException("Unrecognized value '$var' for $type");
}
} elseif (!is_bool($var)) break;
return $var;
case 'list':
case 'hash':
case 'lookup':
if (is_string($var)) {
// special case: technically, this is an array with
// a single empty string item, but having an empty
// array is more intuitive
if ($var == '') return array();
if (strpos($var, "\n") === false && strpos($var, "\r") === false) {
// simplistic string to array method that only works
// for simple lists of tag names or alphanumeric characters
$var = explode(',',$var);
} else {
$var = preg_split('/(,|[\n\r]+)/', $var);
}
// remove spaces
foreach ($var as $i => $j) $var[$i] = trim($j);
if ($type === 'hash') {
// key:value,key2:value2
$nvar = array();
foreach ($var as $keypair) {
$c = explode(':', $keypair, 2);
if (!isset($c[1])) continue;
$nvar[$c[0]] = $c[1];
}
$var = $nvar;
}
}
if (!is_array($var)) break;
$keys = array_keys($var);
if ($keys === array_keys($keys)) {
if ($type == 'list') return $var;
elseif ($type == 'lookup') {
$new = array();
foreach ($var as $key) {
$new[$key] = true;
}
return $new;
} else break;
}
if ($type === 'lookup') {
foreach ($var as $key => $value) {
$var[$key] = true;
}
}
return $var;
default:
// This should not happen!
throw new HTMLPurifier_Exception("Inconsistency in HTMLPurifier_VarParser: $type is not implemented");
}
throw new HTMLPurifier_VarParserException("Invalid input for type $type");
}
abstract public function parse($var, $type, $allow_null = false);
}

View File

@ -0,0 +1,103 @@
<?php
/**
* Performs safe variable parsing based on types which can be used by
* users. This may not be able to represent all possible data inputs,
* however.
*/
class HTMLPurifier_VarParser_Flexible extends HTMLPurifier_VarParser
{
public function parse($var, $type, $allow_null = false) {
if (!isset(HTMLPurifier_VarParser::$types[$type])) {
throw new HTMLPurifier_VarParserException("Invalid type $type");
}
if ($allow_null && $var === null) return null;
switch ($type) {
// Note: if code "breaks" from the switch, it triggers a generic
// exception to be thrown. Specific errors can be specifically
// done here.
case 'mixed':
return $var;
case 'istring':
case 'string':
case 'text': // no difference, just is longer/multiple line string
case 'itext':
if (!is_string($var)) break;
if ($type === 'istring' || $type === 'itext') $var = strtolower($var);
return $var;
case 'int':
if (is_string($var) && ctype_digit($var)) $var = (int) $var;
elseif (!is_int($var)) break;
return $var;
case 'float':
if (is_string($var) && is_numeric($var)) $var = (float) $var;
elseif (!is_float($var)) break;
return $var;
case 'bool':
if (is_int($var) && ($var === 0 || $var === 1)) {
$var = (bool) $var;
} elseif (is_string($var)) {
if ($var == 'on' || $var == 'true' || $var == '1') {
$var = true;
} elseif ($var == 'off' || $var == 'false' || $var == '0') {
$var = false;
} else {
throw new HTMLPurifier_VarParserException("Unrecognized value '$var' for $type");
}
} elseif (!is_bool($var)) break;
return $var;
case 'list':
case 'hash':
case 'lookup':
if (is_string($var)) {
// special case: technically, this is an array with
// a single empty string item, but having an empty
// array is more intuitive
if ($var == '') return array();
if (strpos($var, "\n") === false && strpos($var, "\r") === false) {
// simplistic string to array method that only works
// for simple lists of tag names or alphanumeric characters
$var = explode(',',$var);
} else {
$var = preg_split('/(,|[\n\r]+)/', $var);
}
// remove spaces
foreach ($var as $i => $j) $var[$i] = trim($j);
if ($type === 'hash') {
// key:value,key2:value2
$nvar = array();
foreach ($var as $keypair) {
$c = explode(':', $keypair, 2);
if (!isset($c[1])) continue;
$nvar[$c[0]] = $c[1];
}
$var = $nvar;
}
}
if (!is_array($var)) break;
$keys = array_keys($var);
if ($keys === array_keys($keys)) {
if ($type == 'list') return $var;
elseif ($type == 'lookup') {
$new = array();
foreach ($var as $key) {
$new[$key] = true;
}
return $new;
} else break;
}
if ($type === 'lookup') {
foreach ($var as $key => $value) {
$var[$key] = true;
}
}
return $var;
default:
// This should not happen!
throw new HTMLPurifier_Exception("Inconsistency in HTMLPurifier_VarParser_Flexible: $type is not implemented");
}
throw new HTMLPurifier_VarParserException("Invalid input for type $type");
}
}

View File

@ -1,32 +1,8 @@
<?php
class HTMLPurifier_VarParserTest extends UnitTestCase
class HTMLPurifier_VarParser_FlexibleTest extends HTMLPurifier_VarParserHarness
{
protected $parser;
public function setup() {
$this->parser = new HTMLPurifier_VarParser();
}
function assertValid($var, $type, $ret = null) {
$ret = ($ret === null) ? $var : $ret;
$this->assertIdentical($this->parser->parse($var, $type), $ret);
}
function assertInvalid($var, $type, $msg = null) {
$caught = false;
try {
$this->parser->parse($var, $type);
} catch (HTMLPurifier_VarParserException $e) {
$caught = true;
if ($msg !== null) $this->assertIdentical($e->getMessage(), $msg);
}
if (!$caught) {
$this->fail('Did not catch expected error');
}
}
function testValidate() {
$this->assertValid('foobar', 'string');

View File

@ -0,0 +1,31 @@
<?php
class HTMLPurifier_VarParserHarness extends UnitTestCase
{
protected $parser;
public function setup() {
$class = substr(get_class($this), 0, -4);
$this->parser = new $class();
}
function assertValid($var, $type, $ret = null) {
$ret = ($ret === null) ? $var : $ret;
$this->assertIdentical($this->parser->parse($var, $type), $ret);
}
function assertInvalid($var, $type, $msg = null) {
$caught = false;
try {
$this->parser->parse($var, $type);
} catch (HTMLPurifier_VarParserException $e) {
$caught = true;
if ($msg !== null) $this->assertIdentical($e->getMessage(), $msg);
}
if (!$caught) {
$this->fail('Did not catch expected error');
}
}
}