From 3a1d505b3dd639d453b7e8a5c4dd876d870609cf Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" <edwardzyang@thewritingpot.com> Date: Wed, 27 Jun 2007 02:03:15 +0000 Subject: [PATCH] [2.0.1] Implement haphazard error collection for AttrValidator. - Error collector / Language can take arrays and listify them - AttrValidator takes token by reference - Formatted errors now have their severity <strong> - 100 test-cases! W00t! git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1250 48356398-32a2-884e-a903-53898d9a118a --- NEWS | 4 +- art/100cases.png | Bin 0 -> 2732 bytes library/HTMLPurifier/AttrValidator.php | 65 +++++++++++++----- library/HTMLPurifier/ErrorCollector.php | 7 +- library/HTMLPurifier/Language.php | 62 +++++++++++++---- library/HTMLPurifier/Language/messages/en.php | 12 +++- .../Strategy/RemoveForeignElements.php | 2 +- .../Strategy/ValidateAttributes.php | 6 +- .../HTMLPurifier/AttrValidator_ErrorsTest.php | 50 ++++++++++++++ tests/HTMLPurifier/ErrorCollectorTest.php | 8 +-- tests/HTMLPurifier/LanguageTest.php | 32 ++++++++- tests/test_files.php | 1 + 12 files changed, 205 insertions(+), 44 deletions(-) create mode 100644 art/100cases.png create mode 100644 tests/HTMLPurifier/AttrValidator_ErrorsTest.php diff --git a/NEWS b/NEWS index c7788e04..7d89e7dc 100644 --- a/NEWS +++ b/NEWS @@ -18,8 +18,8 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier ! Newlines normalized internally, and then converted back to the value of PHP_EOL. If this is not desired, set your newline format using %Output.Newline. -! Beta error collection, messages are implemented for Lexer and - RemoveForeignElements +! Beta error collection, messages are implemented for the most generic + cases involving Lexing or Strategies - Clean up special case code for <script> tags - Reorder includes for DefinitionCache decorators, fixes a possible missing class error diff --git a/art/100cases.png b/art/100cases.png new file mode 100644 index 0000000000000000000000000000000000000000..03103a07e5b19dca4547b9637b10508479722b99 GIT binary patch literal 2732 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 U|A63+=_lac9c#0ipWL7Q8<vzev;Y7A literal 0 HcmV?d00001 diff --git a/library/HTMLPurifier/AttrValidator.php b/library/HTMLPurifier/AttrValidator.php index 6b8ec243..b0e79adc 100644 --- a/library/HTMLPurifier/AttrValidator.php +++ b/library/HTMLPurifier/AttrValidator.php @@ -1,12 +1,31 @@ <?php +/** + * Validates the attributes of a token. Doesn't manage required attributes + * very well. The only reason we factored this out was because RemoveForeignElements + * also needed it besides ValidateAttributes. + */ class HTMLPurifier_AttrValidator { - - function validateToken($token, &$config, &$context) { + /** + * Validates the attributes of a token, returning a modified token + * that has valid tokens + * @param $token Reference to token to validate. We require a reference + * because the operation this class performs on the token are + * not atomic, so the context CurrentToken to be updated + * throughout + * @param $config Instance of HTMLPurifier_Config + * @param $context Instance of HTMLPurifier_Context + */ + function validateToken(&$token, &$config, &$context) { $definition = $config->getHTMLDefinition(); + $e =& $context->get('ErrorCollector', true); + + // initialize CurrentToken if necessary + $current_token =& $context->get('CurrentToken', true); + if (!$current_token) $context->register('CurrentToken', $token); if ($token->type !== 'start' && $token->type !== 'empty') return $token; @@ -14,21 +33,21 @@ class HTMLPurifier_AttrValidator // DEFINITION CALL $d_defs = $definition->info_global_attr; - // copy out attributes for easy manipulation - $attr = $token->attr; + // reference attributes for easy manipulation + $attr =& $token->attr; // do global transformations (pre) // nothing currently utilizes this foreach ($definition->info_attr_transform_pre as $transform) { - $attr = $transform->transform($attr, $config, $context); + $attr = $transform->transform($o = $attr, $config, $context); + if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); } // do local transformations only applicable to this element (pre) // ex. <p align="right"> to <p style="text-align:right;"> - foreach ($definition->info[$token->name]->attr_transform_pre - as $transform - ) { - $attr = $transform->transform($attr, $config, $context); + foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); } // create alias to this element's attribute definition array, see @@ -36,6 +55,9 @@ class HTMLPurifier_AttrValidator // DEFINITION CALL $defs = $definition->info[$token->name]->attr; + $attr_key = false; + $context->register('CurrentAttr', $attr_key); + // iterate through all the attribute keypairs // Watch out for name collisions: $key has previously been used foreach ($attr as $attr_key => $value) { @@ -69,9 +91,17 @@ class HTMLPurifier_AttrValidator // put the results into effect if ($result === false || $result === null) { + // this is a generic error message that should replaced + // with more specific ones when possible + if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed'); + // remove the attribute unset($attr[$attr_key]); } elseif (is_string($result)) { + // generally, if a substitution is happening, there + // was some sort of implicit correction going on. We'll + // delegate it to the attribute classes to say exactly what. + // simple substitution $attr[$attr_key] = $result; } @@ -83,21 +113,24 @@ class HTMLPurifier_AttrValidator // others would prepend themselves). } + $context->destroy('CurrentAttr'); + // post transforms - // ex. <x lang="fr"> to <x lang="fr" xml:lang="fr"> + // global (error reporting untested) foreach ($definition->info_attr_transform_post as $transform) { - $attr = $transform->transform($attr, $config, $context); + $attr = $transform->transform($o = $attr, $config, $context); + if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); } - // ex. <bdo> to <bdo dir="ltr"> + // local (error reporting untested) foreach ($definition->info[$token->name]->attr_transform_post as $transform) { - $attr = $transform->transform($attr, $config, $context); + $attr = $transform->transform($o = $attr, $config, $context); + if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); } - // commit changes - $token->attr = $attr; - return $token; + // destroy CurrentToken if we made it ourselves + if (!$current_token) $context->destroy('CurrentToken'); } diff --git a/library/HTMLPurifier/ErrorCollector.php b/library/HTMLPurifier/ErrorCollector.php index a66209c8..c0254ffc 100644 --- a/library/HTMLPurifier/ErrorCollector.php +++ b/library/HTMLPurifier/ErrorCollector.php @@ -26,9 +26,10 @@ class HTMLPurifier_ErrorCollector * @param $severity int Error severity, PHP error style (don't use E_USER_) * @param $msg string Error message text */ - function send($severity, $msg, $args = array()) { + function send($severity, $msg) { - if (!is_array($args)) { + $args = array(); + if (func_num_args() > 2) { $args = func_get_args(); array_shift($args); unset($args[0]); @@ -94,7 +95,7 @@ class HTMLPurifier_ErrorCollector foreach ($errors as $error) { list($line, $severity, $msg) = $error; $string = ''; - $string .= $this->locale->getErrorName($severity) . ': '; + $string .= '<strong>' . $this->locale->getErrorName($severity) . '</strong>: '; $string .= $this->generator->escape($msg); if ($line) { // have javascript link generation that causes diff --git a/library/HTMLPurifier/Language.php b/library/HTMLPurifier/Language.php index c89592ad..ea1a99c9 100644 --- a/library/HTMLPurifier/Language.php +++ b/library/HTMLPurifier/Language.php @@ -78,6 +78,25 @@ class HTMLPurifier_Language return $this->errorNames[$int]; } + /** + * Converts an array list into a string readable representation + */ + function listify($array) { + $sep = $this->getMessage('Item separator'); + $sep_last = $this->getMessage('Item separator last'); + $ret = ''; + for ($i = 0, $c = count($array); $i < $c; $i++) { + if ($i == 0) { + } elseif ($i + 1 < $c) { + $ret .= $sep; + } else { + $ret .= $sep_last; + } + $ret .= $array[$i]; + } + return $ret; + } + /** * Formats a localised message with passed parameters * @param $key string identifier of message @@ -94,22 +113,35 @@ class HTMLPurifier_Language $generator = false; foreach ($args as $i => $value) { if (is_object($value)) { - // complicated stuff - if (!$generator) $generator = $this->context->get('Generator'); - // assuming it's a token - if (isset($value->name)) $subst['$'.$i.'.Name'] = $value->name; - if (isset($value->data)) $subst['$'.$i.'.Data'] = $value->data; - $subst['$'.$i.'.Compact'] = - $subst['$'.$i.'.Serialized'] = $generator->generateFromToken($value); - // a more complex algorithm for compact representation - // could be introduced for all types of tokens. This - // may need to be factored out into a dedicated class - if (!empty($value->attr)) { - $stripped_token = $value->copy(); - $stripped_token->attr = array(); - $subst['$'.$i.'.Compact'] = $generator->generateFromToken($stripped_token); + if (is_a($value, 'HTMLPurifier_Token')) { + // factor this out some time + if (!$generator) $generator = $this->context->get('Generator'); + if (isset($value->name)) $subst['$'.$i.'.Name'] = $value->name; + if (isset($value->data)) $subst['$'.$i.'.Data'] = $value->data; + $subst['$'.$i.'.Compact'] = + $subst['$'.$i.'.Serialized'] = $generator->generateFromToken($value); + // a more complex algorithm for compact representation + // could be introduced for all types of tokens. This + // may need to be factored out into a dedicated class + if (!empty($value->attr)) { + $stripped_token = $value->copy(); + $stripped_token->attr = array(); + $subst['$'.$i.'.Compact'] = $generator->generateFromToken($stripped_token); + } + $subst['$'.$i.'.Line'] = $value->line ? $value->line : 'unknown'; + } + continue; + } elseif (is_array($value)) { + $keys = array_keys($value); + if (array_keys($keys) === $keys) { + // list + $subst['$'.$i] = $this->listify($value); + } else { + // associative array + // no $i implementation yet, sorry + $subst['$'.$i.'.Keys'] = $this->listify($keys); + $subst['$'.$i.'.Values'] = $this->listify(array_values($value)); } - $subst['$'.$i.'.Line'] = $value->line ? $value->line : 'unknown'; continue; } $subst['$' . $i] = $value; diff --git a/library/HTMLPurifier/Language/messages/en.php b/library/HTMLPurifier/Language/messages/en.php index 00e6b5dc..56969cf0 100644 --- a/library/HTMLPurifier/Language/messages/en.php +++ b/library/HTMLPurifier/Language/messages/en.php @@ -5,7 +5,14 @@ $fallback = false; $messages = array( 'HTMLPurifier' => 'HTML Purifier', -'LanguageFactoryTest: Pizza' => 'Pizza', // for unit testing purposes + +// for unit testing purposes +'LanguageFactoryTest: Pizza' => 'Pizza', +'LanguageTest: List' => '$1', +'LanguageTest: Hash' => '$1.Keys; $1.Values', + +'Item separator' => ', ', +'Item separator last' => ' and ', // non-Harvard style 'ErrorCollector: No errors' => 'No errors detected. However, because error reporting is still incomplete, there may have been errors that the error collector was not notified of; please inspect the output HTML carefully.', 'ErrorCollector: At line' => ' at line $line', @@ -37,6 +44,9 @@ $messages = array( 'Strategy_FixNesting: Node reorganized' => 'Contents of $CurrentToken.Compact node reorganized to enforce its content model', 'Strategy_FixNesting: Node contents removed' => 'Contents of $CurrentToken.Compact node removed', +'AttrValidator: Attributes transformed' => 'Attributes on $CurrentToken.Compact transformed from $1.Keys to $2.Keys', +'AttrValidator: Attribute removed' => '$CurrentAttr.Name attribute on $CurrentToken.Compact removed', + ); $errorNames = array( diff --git a/library/HTMLPurifier/Strategy/RemoveForeignElements.php b/library/HTMLPurifier/Strategy/RemoveForeignElements.php index 591b3faa..993789d7 100644 --- a/library/HTMLPurifier/Strategy/RemoveForeignElements.php +++ b/library/HTMLPurifier/Strategy/RemoveForeignElements.php @@ -91,7 +91,7 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy $definition->info[$token->name]->required_attr && ($token->name != 'img' || $remove_invalid_img) // ensure config option still works ) { - $token = $attr_validator->validateToken($token, $config, $context); + $attr_validator->validateToken($token, $config, $context); $ok = true; foreach ($definition->info[$token->name]->required_attr as $name) { if (!isset($token->attr[$name])) { diff --git a/library/HTMLPurifier/Strategy/ValidateAttributes.php b/library/HTMLPurifier/Strategy/ValidateAttributes.php index 1c9e09b3..c9d0ef7c 100644 --- a/library/HTMLPurifier/Strategy/ValidateAttributes.php +++ b/library/HTMLPurifier/Strategy/ValidateAttributes.php @@ -27,6 +27,9 @@ class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy // setup validator $validator = new HTMLPurifier_AttrValidator(); + $token = false; + $context->register('CurrentToken', $token); + foreach ($tokens as $key => $token) { // only process tokens that have attributes, @@ -36,7 +39,8 @@ class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy // skip tokens that are armored if (!empty($token->armor['ValidateAttributes'])) continue; - $tokens[$key] = $validator->validateToken($token, $config, $context); + // note that we have no facilities here for removing tokens + $validator->validateToken($token, $config, $context); } $context->destroy('IDAccumulator'); diff --git a/tests/HTMLPurifier/AttrValidator_ErrorsTest.php b/tests/HTMLPurifier/AttrValidator_ErrorsTest.php new file mode 100644 index 00000000..841d0523 --- /dev/null +++ b/tests/HTMLPurifier/AttrValidator_ErrorsTest.php @@ -0,0 +1,50 @@ +<?php + +require_once 'HTMLPurifier/ErrorsHarness.php'; +require_once 'HTMLPurifier/AttrValidator.php'; + +class HTMLPurifier_AttrValidator_ErrorsTest extends HTMLPurifier_ErrorsHarness +{ + + function invoke($input) { + $validator = new HTMLPurifier_AttrValidator(); + $validator->validateToken($input, $this->config, $this->context); + } + + function testAttributesTransformedGlobalPre() { + $this->config->set('HTML', 'DefinitionID', + 'HTMLPurifier_AttrValidator_ErrorsTest::testAttributesTransformedGlobalPre'); + $def =& $this->config->getHTMLDefinition(true); + generate_mock_once('HTMLPurifier_AttrTransform'); + $transform = new HTMLPurifier_AttrTransformMock(); + $input = array('original' => 'value'); + $output = array('class' => 'value'); // must be valid + $transform->setReturnValue('transform', $output, array($input, new AnythingExpectation(), new AnythingExpectation())); + $def->info_attr_transform_pre[] = $transform; + $this->expectErrorCollection(E_NOTICE, 'AttrValidator: Attributes transformed', $input, $output); + $token = new HTMLPurifier_Token_Start('span', $input, 1); + $this->invoke($token); + } + + function testAttributesTransformedLocalPre() { + $this->config->set('HTML', 'TidyLevel', 'heavy'); + $input = array('align' => 'right'); + $output = array('style' => 'text-align:right;'); + $this->expectErrorCollection(E_NOTICE, 'AttrValidator: Attributes transformed', $input, $output); + $token = new HTMLPurifier_Token_Start('p', $input, 1); + $this->invoke($token); + } + + // to lazy to check for global post and global pre + + function testAttributeRemoved() { + $this->expectErrorCollection(E_ERROR, 'AttrValidator: Attribute removed'); + $this->expectContext('CurrentAttr', 'foobar'); + $token = new HTMLPurifier_Token_Start('p', array('foobar' => 'right'), 1); + $this->expectContext('CurrentToken', $token); + $this->invoke($token); + } + +} + +?> \ No newline at end of file diff --git a/tests/HTMLPurifier/ErrorCollectorTest.php b/tests/HTMLPurifier/ErrorCollectorTest.php index 1338819b..cbc6e0ff 100644 --- a/tests/HTMLPurifier/ErrorCollectorTest.php +++ b/tests/HTMLPurifier/ErrorCollectorTest.php @@ -45,8 +45,8 @@ class HTMLPurifier_ErrorCollectorTest extends UnitTestCase $this->assertIdentical($collector->getRaw(), $result); $formatted_result = - '<ul><li>Warning: Message 2 at line 3</li>'. - '<li>Error: Message 1 at line 23</li></ul>'; + '<ul><li><strong>Warning</strong>: Message 2 at line 3</li>'. + '<li><strong>Error</strong>: Message 1 at line 23</li></ul>'; $config = HTMLPurifier_Config::create(array('Core.MaintainLineNumbers' => true)); @@ -91,8 +91,8 @@ class HTMLPurifier_ErrorCollectorTest extends UnitTestCase $this->assertIdentical($collector->getRaw(), $result); $formatted_result = - '<ul><li>Error: Message 1</li>'. - '<li>Error: Message 2</li></ul>'; + '<ul><li><strong>Error</strong>: Message 1</li>'. + '<li><strong>Error</strong>: Message 2</li></ul>'; $config = HTMLPurifier_Config::createDefault(); $this->assertIdentical($collector->getHTMLFormatted($config), $formatted_result); } diff --git a/tests/HTMLPurifier/LanguageTest.php b/tests/HTMLPurifier/LanguageTest.php index 5bf04b05..dd56fe3c 100644 --- a/tests/HTMLPurifier/LanguageTest.php +++ b/tests/HTMLPurifier/LanguageTest.php @@ -7,6 +7,13 @@ class HTMLPurifier_LanguageTest extends UnitTestCase var $lang; + function generateEnLanguage() { + $factory = HTMLPurifier_LanguageFactory::instance(); + $config = HTMLPurifier_Config::create(array('Core.Language' => 'en')); + $context = new HTMLPurifier_Context(); + return $factory->create($config, $context); + } + function test_getMessage() { $config = HTMLPurifier_Config::createDefault(); $context = new HTMLPurifier_Context(); @@ -26,7 +33,7 @@ class HTMLPurifier_LanguageTest extends UnitTestCase $this->assertIdentical($lang->formatMessage('LanguageTest: Error', array(1=>'fatal', 32)), 'Error is fatal on line 32'); } - function test_formatMessage_complexParameter() { + function test_formatMessage_tokenParameter() { $config = HTMLPurifier_Config::createDefault(); $context = new HTMLPurifier_Context(); $generator = new HTMLPurifier_Generator(); // replace with mock if this gets icky @@ -43,6 +50,29 @@ class HTMLPurifier_LanguageTest extends UnitTestCase 'Data Token: data>, data>, data>, 23'); } + function test_listify() { + $lang = $this->generateEnLanguage(); + $this->assertEqual($lang->listify(array('Item')), 'Item'); + $this->assertEqual($lang->listify(array('Item', 'Item2')), 'Item and Item2'); + $this->assertEqual($lang->listify(array('Item', 'Item2', 'Item3')), 'Item, Item2 and Item3'); + } + + function test_formatMessage_arrayParameter() { + $lang = $this->generateEnLanguage(); + + $array = array('Item1', 'Item2', 'Item3'); + $this->assertIdentical( + $lang->formatMessage('LanguageTest: List', array(1=>$array)), + 'Item1, Item2 and Item3' + ); + + $array = array('Key1' => 'Value1', 'Key2' => 'Value2'); + $this->assertIdentical( + $lang->formatMessage('LanguageTest: Hash', array(1=>$array)), + 'Key1 and Key2; Value1 and Value2' + ); + } + } ?> \ No newline at end of file diff --git a/tests/test_files.php b/tests/test_files.php index b0ee2389..0c503527 100644 --- a/tests/test_files.php +++ b/tests/test_files.php @@ -52,6 +52,7 @@ $test_files[] = 'HTMLPurifier/AttrTransform/LangTest.php'; $test_files[] = 'HTMLPurifier/AttrTransform/LengthTest.php'; $test_files[] = 'HTMLPurifier/AttrTransform/NameTest.php'; $test_files[] = 'HTMLPurifier/AttrTypesTest.php'; +$test_files[] = 'HTMLPurifier/AttrValidator_ErrorsTest.php'; $test_files[] = 'HTMLPurifier/ChildDef/ChameleonTest.php'; $test_files[] = 'HTMLPurifier/ChildDef/CustomTest.php'; $test_files[] = 'HTMLPurifier/ChildDef/OptionalTest.php';