mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2024-12-22 08:21:52 +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:
parent
7480e7b956
commit
bd64a8346d
2
NEWS
2
NEWS
@ -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
|
||||
|
@ -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';
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,7 +51,7 @@ class HTMLPurifier_ConfigSchema {
|
||||
);
|
||||
|
||||
public function __construct() {
|
||||
$this->parser = new HTMLPurifier_VarParser();
|
||||
$this->parser = new HTMLPurifier_VarParser_Flexible();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
*/
|
||||
|
@ -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
@ -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);
|
||||
|
||||
}
|
||||
|
103
library/HTMLPurifier/VarParser/Flexible.php
Normal file
103
library/HTMLPurifier/VarParser/Flexible.php
Normal 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");
|
||||
}
|
||||
|
||||
}
|
@ -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');
|
31
tests/HTMLPurifier/VarParserHarness.php
Normal file
31
tests/HTMLPurifier/VarParserHarness.php
Normal 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');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user