mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-03-11 17:18:44 +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
|
maintenance/generate-schema-cache.php generates the schema.ser file, which
|
||||||
is now instantiated. Support for userland schema changes coming soon!
|
is now instantiated. Support for userland schema changes coming soon!
|
||||||
! Extra utility classes for testing and non-library operations can
|
! 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
|
You may find a use for these in your own project, but right now they
|
||||||
are highly experimental and volatile.
|
are highly experimental and volatile.
|
||||||
! Integration with PHPT allows for automated smoketests
|
! Integration with PHPT allows for automated smoketests
|
||||||
|
@ -200,3 +200,4 @@ require 'HTMLPurifier/URIScheme/https.php';
|
|||||||
require 'HTMLPurifier/URIScheme/mailto.php';
|
require 'HTMLPurifier/URIScheme/mailto.php';
|
||||||
require 'HTMLPurifier/URIScheme/news.php';
|
require 'HTMLPurifier/URIScheme/news.php';
|
||||||
require 'HTMLPurifier/URIScheme/nntp.php';
|
require 'HTMLPurifier/URIScheme/nntp.php';
|
||||||
|
require 'HTMLPurifier/VarParser/Flexible.php';
|
||||||
|
@ -75,7 +75,7 @@ class HTMLPurifier_Config
|
|||||||
public function __construct(&$definition) {
|
public function __construct(&$definition) {
|
||||||
$this->conf = $definition->defaults; // set up, copy in defaults
|
$this->conf = $definition->defaults; // set up, copy in defaults
|
||||||
$this->def = $definition; // keep a copy around for checking
|
$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() {
|
public function __construct() {
|
||||||
$this->parser = new HTMLPurifier_VarParser();
|
$this->parser = new HTMLPurifier_VarParser_Flexible();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,23 +8,6 @@
|
|||||||
class HTMLPurifier_ConfigSchema_Interchange
|
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)
|
* Array of Namespace ID => array(namespace info)
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@ class HTMLPurifier_ConfigSchema_Validator_ParseType extends HTMLPurifier_ConfigS
|
|||||||
|
|
||||||
public function validate(&$arr, $interchange) {
|
public function validate(&$arr, $interchange) {
|
||||||
$r = explode('/', $arr['TYPE'], 2);
|
$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']);
|
$this->error('Invalid type ' . $r[0] . ' for configuration directive ' . $arr['ID']);
|
||||||
}
|
}
|
||||||
$arr['_TYPE'] = $r[0];
|
$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
|
* Parses string representations into their corresponding native PHP
|
||||||
* variable type.
|
* variable type.
|
||||||
*/
|
*/
|
||||||
class HTMLPurifier_VarParser
|
abstract class HTMLPurifier_VarParser
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup table of allowed types.
|
* Lookup table of allowed types.
|
||||||
*/
|
*/
|
||||||
public $types = array(
|
static public $types = array(
|
||||||
'string' => true,
|
'string' => true,
|
||||||
'istring' => true,
|
'istring' => true,
|
||||||
'text' => true,
|
'text' => true,
|
||||||
@ -25,100 +25,15 @@ class HTMLPurifier_VarParser
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate a variable according to type. Throws exception if invalid.
|
* Validate a variable according to type. Throws
|
||||||
* It may return NULL as a valid type.
|
* 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) {
|
abstract 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
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
|
<?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() {
|
function testValidate() {
|
||||||
|
|
||||||
$this->assertValid('foobar', 'string');
|
$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…
x
Reference in New Issue
Block a user