0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-09-19 18:55:19 +00:00
+ PHP4 reference/foreach cruft in Injector removed
. Unit tests for Injector improved
. Some todo stuff updated

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1462 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2007-12-05 01:26:28 +00:00
parent 7ddd9d0afe
commit b5546ff6f0
6 changed files with 44 additions and 24 deletions

2
NEWS
View File

@ -15,7 +15,9 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
to it. to it.
+ Visibility declarations added + Visibility declarations added
+ Constructor methods renamed to __construct() + Constructor methods renamed to __construct()
+ PHP4 reference/foreach cruft removed (in progress)
! CSS properties are no case-insensitive ! CSS properties are no case-insensitive
. Unit tests for Injector improved
2.1.3, released 2007-11-05 2.1.3, released 2007-11-05
! tests/multitest.php allows you to test multiple versions by running ! tests/multitest.php allows you to test multiple versions by running

3
TODO
View File

@ -11,6 +11,9 @@ If no interest is expressed for a feature that may required a considerable
amount of effort to implement, it may get endlessly delayed. Do not be amount of effort to implement, it may get endlessly delayed. Do not be
afraid to cast your vote for the next feature to be implemented! afraid to cast your vote for the next feature to be implemented!
3.0 release [Go PHP5!]
- Convert all &$context calls to $context, as PHP5 passes objects by value
3.1 release [Error'ed] 3.1 release [Error'ed]
# Error logging for filtering/cleanup procedures # Error logging for filtering/cleanup procedures
- XSS-attempt detection - XSS-attempt detection

View File

@ -134,6 +134,7 @@ class HTMLPurifier
*/ */
public function purify($html, $config = null) { public function purify($html, $config = null) {
// todo: make the config merge in, instead of replace
$config = $config ? HTMLPurifier_Config::create($config) : $this->config; $config = $config ? HTMLPurifier_Config::create($config) : $this->config;
// implementation is partially environment dependant, partially // implementation is partially environment dependant, partially

View File

@ -8,7 +8,7 @@
* @todo Allow injectors to request a re-run on their output. This * @todo Allow injectors to request a re-run on their output. This
* would help if an operation is recursive. * would help if an operation is recursive.
*/ */
class HTMLPurifier_Injector abstract class HTMLPurifier_Injector
{ {
/** /**

View File

@ -39,7 +39,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
$result = array(); $result = array();
$generator = new HTMLPurifier_Generator(); $generator = new HTMLPurifier_Generator();
$escape_invalid_tags = $config->get('Core', 'EscapeInvalidTags'); $escape_invalid_tags = $config->get('Core', 'EscapeInvalidTags');
$e =& $context->get('ErrorCollector', true); $e = $context->get('ErrorCollector', true);
// member variables // member variables
$this->currentNesting = array(); $this->currentNesting = array();
@ -81,23 +81,22 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// give the injectors references to the definition and context // give the injectors references to the definition and context
// variables for performance reasons // variables for performance reasons
foreach ($this->injectors as $i => $x) { foreach ($this->injectors as $i => $injector) {
$error = $this->injectors[$i]->prepare($config, $context); $error = $injector->prepare($config, $context);
if (!$error) continue; if (!$error) continue;
list($injector) = array_splice($this->injectors, $i, 1); array_splice($this->injectors, $i, 1); // rm the injector
$name = $injector->name; trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING);
trigger_error("Cannot enable $name injector because $error is not allowed", E_USER_WARNING);
} }
// warning: most foreach loops follow the convention $i => $x. // warning: most foreach loops follow the convention $i => $injector.
// be sure, for PHP4 compatibility, to only perform write operations // Don't define these as loop-wide variables, please!
// directly referencing the object using $i: $x is only safe for reads
// -- end INJECTOR -- // -- end INJECTOR --
$token = false; $token = false;
$context->register('CurrentToken', $token); $context->register('CurrentToken', $token);
// isset is in loop because $tokens size changes during loop exec
for ($this->inputIndex = 0; isset($tokens[$this->inputIndex]); $this->inputIndex++) { for ($this->inputIndex = 0; isset($tokens[$this->inputIndex]); $this->inputIndex++) {
// if all goes well, this token will be passed through unharmed // if all goes well, this token will be passed through unharmed
@ -105,16 +104,16 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
//printTokens($tokens, $this->inputIndex); //printTokens($tokens, $this->inputIndex);
foreach ($this->injectors as $i => $x) { foreach ($this->injectors as $injector) {
if ($x->skip > 0) $this->injectors[$i]->skip--; if ($injector->skip > 0) $injector->skip--;
} }
// quick-check: if it's not a tag, no need to process // quick-check: if it's not a tag, no need to process
if (empty( $token->is_tag )) { if (empty( $token->is_tag )) {
if ($token->type === 'text') { if ($token->type === 'text') {
// injector handler code; duplicated for performance reasons // injector handler code; duplicated for performance reasons
foreach ($this->injectors as $i => $x) { foreach ($this->injectors as $i => $injector) {
if (!$x->skip) $this->injectors[$i]->handleText($token); if (!$injector->skip) $injector->handleText($token);
if (is_array($token)) { if (is_array($token)) {
$this->currentInjector = $i; $this->currentInjector = $i;
break; break;
@ -171,8 +170,8 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// injector handler code; duplicated for performance reasons // injector handler code; duplicated for performance reasons
if ($ok) { if ($ok) {
foreach ($this->injectors as $i => $x) { foreach ($this->injectors as $i => $injector) {
if (!$x->skip) $this->injectors[$i]->handleElement($token); if (!$injector->skip) $injector->handleElement($token);
if (is_array($token)) { if (is_array($token)) {
$this->currentInjector = $i; $this->currentInjector = $i;
break; break;
@ -202,8 +201,8 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
$current_parent = array_pop($this->currentNesting); $current_parent = array_pop($this->currentNesting);
if ($current_parent->name == $token->name) { if ($current_parent->name == $token->name) {
$result[] = $token; $result[] = $token;
foreach ($this->injectors as $i => $x) { foreach ($this->injectors as $i => $injector) {
$this->injectors[$i]->notifyEnd($token); $injector->notifyEnd($token);
} }
continue; continue;
} }
@ -242,12 +241,13 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// okay, we found it, close all the skipped tags // okay, we found it, close all the skipped tags
// note that skipped tags contains the element we need closed // note that skipped tags contains the element we need closed
for ($i = count($skipped_tags) - 1; $i >= 0; $i--) { for ($i = count($skipped_tags) - 1; $i >= 0; $i--) {
// please don't redefine $i!
if ($i && $e && !isset($skipped_tags[$i]->armor['MakeWellFormed_TagClosedError'])) { if ($i && $e && !isset($skipped_tags[$i]->armor['MakeWellFormed_TagClosedError'])) {
$e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$i]); $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$i]);
} }
$result[] = $new_token = new HTMLPurifier_Token_End($skipped_tags[$i]->name); $result[] = $new_token = new HTMLPurifier_Token_End($skipped_tags[$i]->name);
foreach ($this->injectors as $j => $x) { // $j, not $i!!! foreach ($this->injectors as $injector) {
$this->injectors[$j]->notifyEnd($new_token); $injector->notifyEnd($new_token);
} }
} }
@ -263,12 +263,13 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// not using $skipped_tags since it would invariably be all of them // not using $skipped_tags since it would invariably be all of them
if (!empty($this->currentNesting)) { if (!empty($this->currentNesting)) {
for ($i = count($this->currentNesting) - 1; $i >= 0; $i--) { for ($i = count($this->currentNesting) - 1; $i >= 0; $i--) {
// please don't redefine $i!
if ($e && !isset($this->currentNesting[$i]->armor['MakeWellFormed_TagClosedError'])) { if ($e && !isset($this->currentNesting[$i]->armor['MakeWellFormed_TagClosedError'])) {
$e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $this->currentNesting[$i]); $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $this->currentNesting[$i]);
} }
$result[] = $new_token = new HTMLPurifier_Token_End($this->currentNesting[$i]->name); $result[] = $new_token = new HTMLPurifier_Token_End($this->currentNesting[$i]->name);
foreach ($this->injectors as $j => $x) { // $j, not $i!!! foreach ($this->injectors as $injector) {
$this->injectors[$j]->notifyEnd($new_token); $injector->notifyEnd($new_token);
} }
} }
} }

View File

@ -26,6 +26,19 @@ class HTMLPurifier_Strategy_MakeWellFormed_InjectorTest extends HTMLPurifier_Str
$this->assertResult('<i><b>asdf</b>', '<i><b>asdf</b></i>'); $this->assertResult('<i><b>asdf</b>', '<i><b>asdf</b></i>');
} }
function testErrorRequiredElementNotAllowed() {
$this->config->set('HTML', 'Allowed', '');
$this->expectError('Cannot enable AutoParagraph injector because p is not allowed');
$this->expectError('Cannot enable Linkify injector because a is not allowed');
$this->assertResult('Foobar');
}
function testErrorRequiredAttributeNotAllowed() {
$this->config->set('HTML', 'Allowed', 'a,p');
$this->expectError('Cannot enable Linkify injector because a.href is not allowed');
$this->assertResult('<p>http://example.com</p>');
}
function testOnlyAutoParagraph() { function testOnlyAutoParagraph() {
$this->assertResult( $this->assertResult(
'Foobar', 'Foobar',