diff --git a/lib/htmlpurifier/HTMLPurifier.php b/lib/htmlpurifier/HTMLPurifier.php index 677c1e39952..e9dfe5f4048 100644 --- a/lib/htmlpurifier/HTMLPurifier.php +++ b/lib/htmlpurifier/HTMLPurifier.php @@ -22,8 +22,8 @@ */ /* - HTML Purifier 2.1.2 - Standards Compliant HTML Filtering - Copyright (C) 2006 Edward Z. Yang + HTML Purifier 2.1.3 - Standards Compliant HTML Filtering + Copyright (C) 2006-2007 Edward Z. Yang This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -43,9 +43,8 @@ // constants are slow, but we'll make one exception define('HTMLPURIFIER_PREFIX', dirname(__FILE__)); -// almost every class has an undocumented dependency to these, so make sure -// they get included -require_once 'HTMLPurifier/ConfigSchema.php'; // important +// every class has an undocumented dependency to these, must be included! +require_once 'HTMLPurifier/ConfigSchema.php'; // fatal errors if not included require_once 'HTMLPurifier/Config.php'; require_once 'HTMLPurifier/Context.php'; @@ -60,16 +59,23 @@ require_once 'HTMLPurifier/LanguageFactory.php'; HTMLPurifier_ConfigSchema::define( 'Core', 'CollectErrors', false, 'bool', ' Whether or not to collect errors found while filtering the document. This -is a useful way to give feedback to your users. CURRENTLY NOT IMPLEMENTED. -This directive has been available since 2.0.0. +is a useful way to give feedback to your users. Warning: +Currently this feature is very patchy and experimental, with lots of +possible error messages not yet implemented. It will not cause any problems, +but it may not help your users either. This directive has been available +since 2.0.0. '); /** - * Main library execution class. + * Facade that coordinates HTML Purifier's subsystems in order to purify HTML. * - * Facade that performs calls to the HTMLPurifier_Lexer, - * HTMLPurifier_Strategy and HTMLPurifier_Generator subsystems in order to - * purify HTML. + * @note There are several points in which configuration can be specified + * for HTML Purifier. The precedence of these (from lowest to + * highest) is as follows: + * -# Instance: new HTMLPurifier($config) + * -# Invocation: purify($html, $config) + * These configurations are entirely independent of each other and + * are *not* merged. * * @todo We need an easier way to inject strategies, it'll probably end * up getting done through config though. @@ -77,15 +83,16 @@ This directive has been available since 2.0.0. class HTMLPurifier { - var $version = '2.1.2'; + var $version = '2.1.3'; var $config; - var $filters; + var $filters = array(); var $strategy, $generator; /** - * Final HTMLPurifier_Context of last run purification. Might be an array. + * Resultant HTMLPurifier_Context of last run purification. Is an array + * of contexts if the last called method was purifyArray(). * @public */ var $context; @@ -150,6 +157,11 @@ class HTMLPurifier $context->register('ErrorCollector', $error_collector); } + // setup id_accumulator context, necessary due to the fact that + // AttrValidator can be called from many places + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + $html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context); for ($i = 0, $size = count($this->filters); $i < $size; $i++) { @@ -198,6 +210,8 @@ class HTMLPurifier /** * Singleton for enforcing just one HTML Purifier in your system + * @param $prototype Optional prototype HTMLPurifier instance to + * overload singleton with. */ function &getInstance($prototype = null) { static $htmlpurifier; diff --git a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI.php b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI.php index 365748c037d..0e9a5f47398 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI.php @@ -102,7 +102,7 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef $result = $uri->validate($config, $context); if (!$result) break; - // chained validation + // chained filtering $uri_def =& $config->getDefinition('URI'); $result = $uri_def->filter($uri, $config, $context); if (!$result) break; diff --git a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php index aaec099a6e4..ababd9eae07 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php @@ -1,7 +1,6 @@ getHTMLDefinition(); $e =& $context->get('ErrorCollector', true); + // initialize IDAccumulator if necessary + $ok =& $context->get('IDAccumulator', true); + if (!$ok) { + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + } + // initialize CurrentToken if necessary $current_token =& $context->get('CurrentToken', true); if (!$current_token) $context->register('CurrentToken', $token); diff --git a/lib/htmlpurifier/HTMLPurifier/ChildDef/Optional.php b/lib/htmlpurifier/HTMLPurifier/ChildDef/Optional.php index 779a7f06b9e..e9f14edf7db 100644 --- a/lib/htmlpurifier/HTMLPurifier/ChildDef/Optional.php +++ b/lib/htmlpurifier/HTMLPurifier/ChildDef/Optional.php @@ -15,7 +15,10 @@ class HTMLPurifier_ChildDef_Optional extends HTMLPurifier_ChildDef_Required var $type = 'optional'; function validateChildren($tokens_of_children, $config, &$context) { $result = parent::validateChildren($tokens_of_children, $config, $context); - if ($result === false) return array(); + if ($result === false) { + if (empty($tokens_of_children)) return true; + else return array(); + } return $result; } } diff --git a/lib/htmlpurifier/HTMLPurifier/Config.php b/lib/htmlpurifier/HTMLPurifier/Config.php index e04a4b0cc51..203542f0aa7 100644 --- a/lib/htmlpurifier/HTMLPurifier/Config.php +++ b/lib/htmlpurifier/HTMLPurifier/Config.php @@ -42,7 +42,7 @@ class HTMLPurifier_Config /** * HTML Purifier's version */ - var $version = '2.1.2'; + var $version = '2.1.3'; /** * Two-level associative array of configuration directives diff --git a/lib/htmlpurifier/HTMLPurifier/HTMLDefinition.php b/lib/htmlpurifier/HTMLPurifier/HTMLDefinition.php index fe6bd141877..e13e0c62b0e 100644 --- a/lib/htmlpurifier/HTMLPurifier/HTMLDefinition.php +++ b/lib/htmlpurifier/HTMLPurifier/HTMLDefinition.php @@ -236,13 +236,26 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition /** * Adds a custom element to your HTML definition * @note See HTMLPurifier_HTMLModule::addElement for detailed - * parameter descriptions. + * parameter and return value descriptions. */ - function addElement($element_name, $type, $contents, $attr_collections, $attributes) { + function &addElement($element_name, $type, $contents, $attr_collections, $attributes) { $module =& $this->getAnonymousModule(); // assume that if the user is calling this, the element // is safe. This may not be a good idea - $module->addElement($element_name, true, $type, $contents, $attr_collections, $attributes); + $element =& $module->addElement($element_name, true, $type, $contents, $attr_collections, $attributes); + return $element; + } + + /** + * Adds a blank element to your HTML definition, for overriding + * existing behavior + * @note See HTMLPurifier_HTMLModule::addBlankElement for detailed + * parameter and return value descriptions. + */ + function &addBlankElement($element_name) { + $module =& $this->getAnonymousModule(); + $element =& $module->addBlankElement($element_name); + return $element; } /** diff --git a/lib/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php b/lib/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php index 386cf365a26..dcf306a0197 100644 --- a/lib/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php +++ b/lib/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php @@ -13,6 +13,8 @@ require_once 'HTMLPurifier/AttrTransform/Length.php'; require_once 'HTMLPurifier/AttrTransform/ImgSpace.php'; require_once 'HTMLPurifier/AttrTransform/EnumToCSS.php'; +require_once 'HTMLPurifier/ChildDef/StrictBlockquote.php'; + class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends HTMLPurifier_HTMLModule_Tidy { @@ -188,5 +190,17 @@ class HTMLPurifier_HTMLModule_Tidy_Strict extends { var $name = 'Tidy_Strict'; var $defaultLevel = 'light'; + + function makeFixes() { + $r = parent::makeFixes(); + $r['blockquote#content_model_type'] = 'strictblockquote'; + return $r; + } + + var $defines_child_def = true; + function getChildDef($def) { + if ($def->content_model_type != 'strictblockquote') return parent::getChildDef($def); + return new HTMLPurifier_ChildDef_StrictBlockquote($def->content_model); + } } diff --git a/lib/htmlpurifier/HTMLPurifier/HTMLModuleManager.php b/lib/htmlpurifier/HTMLPurifier/HTMLModuleManager.php index 74a233ff2f9..3fc86160201 100644 --- a/lib/htmlpurifier/HTMLPurifier/HTMLModuleManager.php +++ b/lib/htmlpurifier/HTMLPurifier/HTMLModuleManager.php @@ -35,7 +35,6 @@ require_once 'HTMLPurifier/HTMLModule/Object.php'; require_once 'HTMLPurifier/HTMLModule/Tidy.php'; require_once 'HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php'; require_once 'HTMLPurifier/HTMLModule/Tidy/XHTML.php'; -require_once 'HTMLPurifier/HTMLModule/Tidy/XHTMLStrict.php'; require_once 'HTMLPurifier/HTMLModule/Tidy/Proprietary.php'; HTMLPurifier_ConfigSchema::define( @@ -209,7 +208,7 @@ class HTMLPurifier_HTMLModuleManager $this->doctypes->register( 'XHTML 1.0 Strict', true, array_merge($common, $xml, $non_xml), - array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_XHTMLStrict', 'Tidy_Proprietary'), + array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Strict', 'Tidy_Proprietary'), array(), '-//W3C//DTD XHTML 1.0 Strict//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd' @@ -218,7 +217,7 @@ class HTMLPurifier_HTMLModuleManager $this->doctypes->register( 'XHTML 1.1', true, array_merge($common, $xml, array('Ruby')), - array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_XHTMLStrict'), // Tidy_XHTML1_1 + array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Strict'), // Tidy_XHTML1_1 array(), '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd' diff --git a/lib/htmlpurifier/HTMLPurifier/IDAccumulator.php b/lib/htmlpurifier/HTMLPurifier/IDAccumulator.php index 525c9aa0800..60715afc1ec 100644 --- a/lib/htmlpurifier/HTMLPurifier/IDAccumulator.php +++ b/lib/htmlpurifier/HTMLPurifier/IDAccumulator.php @@ -1,11 +1,15 @@ load($config->get('Attr', 'IDBlacklist')); + return $id_accumulator; + } + /** * Add an ID to the lookup table. * @param $id ID to be added. diff --git a/lib/htmlpurifier/HTMLPurifier/Injector.php b/lib/htmlpurifier/HTMLPurifier/Injector.php index 59017163877..3b847097673 100644 --- a/lib/htmlpurifier/HTMLPurifier/Injector.php +++ b/lib/htmlpurifier/HTMLPurifier/Injector.php @@ -4,6 +4,9 @@ * Injects tokens into the document while parsing for well-formedness. * This enables "formatter-like" functionality such as auto-paragraphing, * smiley-ification and linkification to take place. + * + * @todo Allow injectors to request a re-run on their output. This + * would help if an operation is recursive. */ class HTMLPurifier_Injector { @@ -107,5 +110,12 @@ class HTMLPurifier_Injector */ function handleElement(&$token) {} + /** + * Notifier that is called when an end token is processed + * @note This differs from handlers in that the token is read-only + */ + function notifyEnd($token) {} + + } diff --git a/lib/htmlpurifier/HTMLPurifier/Injector/AutoParagraph.php b/lib/htmlpurifier/HTMLPurifier/Injector/AutoParagraph.php index 6e0a6a3ed5c..56a6a268788 100644 --- a/lib/htmlpurifier/HTMLPurifier/Injector/AutoParagraph.php +++ b/lib/htmlpurifier/HTMLPurifier/Injector/AutoParagraph.php @@ -6,20 +6,28 @@ HTMLPurifier_ConfigSchema::define( 'AutoFormat', 'AutoParagraph', false, 'bool', '
This directive turns on auto-paragraphing, where double newlines are - converted in to paragraphs whenever possible. Auto-paragraphing - applies when: + converted in to paragraphs whenever possible. Auto-paragraphing:
p tags must be allowed for this directive to take effect.
We do not use br tags for paragraphing, as that is
semantically incorrect.
+ To prevent auto-paragraphing as a content-producer, refrain from using
+ double-newlines except to specify a new paragraph or in contexts where
+ it has special meaning (whitespace usually has no meaning except in
+ tags like pre, so this should not be difficult.) To prevent
+ the paragraphing of inline text adjacent to block elements, wrap them
+ in div tags (the behavior is slightly different outside of
+ the root node.)
+
This directive has been available since 2.0.1.
@@ -62,19 +70,27 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector $ok = false; // test if up-coming tokens are either block or have // a double newline in them + $nesting = 0; for ($i = $this->inputIndex + 1; isset($this->inputTokens[$i]); $i++) { if ($this->inputTokens[$i]->type == 'start'){ if (!$this->_isInline($this->inputTokens[$i])) { - $ok = true; + // we haven't found a double-newline, and + // we've hit a block element, so don't paragraph + $ok = false; + break; } - break; + $nesting++; + } + if ($this->inputTokens[$i]->type == 'end') { + if ($nesting <= 0) break; + $nesting--; } - if ($this->inputTokens[$i]->type == 'end') break; if ($this->inputTokens[$i]->type == 'text') { + // found it! if (strpos($this->inputTokens[$i]->data, "\n\n") !== false) { $ok = true; + break; } - if (!$this->inputTokens[$i]->is_whitespace) break; } } if ($ok) { diff --git a/lib/htmlpurifier/HTMLPurifier/Lexer.php b/lib/htmlpurifier/HTMLPurifier/Lexer.php index 78abebd07bf..22ef1d6dd0b 100644 --- a/lib/htmlpurifier/HTMLPurifier/Lexer.php +++ b/lib/htmlpurifier/HTMLPurifier/Lexer.php @@ -13,11 +13,14 @@ if (version_compare(PHP_VERSION, "5", ">=")) { } HTMLPurifier_ConfigSchema::define( - 'Core', 'AcceptFullDocuments', true, 'bool', - 'This parameter determines whether or not the filter should accept full '. - 'HTML documents, not just HTML fragments. When on, it will '. - 'drop all sections except the content between body.' -); + 'Core', 'ConvertDocumentToFragment', true, 'bool', ' +This parameter determines whether or not the filter should convert +input that is a full document with html and body tags to a fragment +of just the contents of a body tag. This parameter is simply something +HTML Purifier can do during an edge-case: for most inputs, this +processing is not necessary. +'); +HTMLPurifier_ConfigSchema::defineAlias('Core', 'AcceptFullDocuments', 'Core', 'ConvertDocumentToFragment'); HTMLPurifier_ConfigSchema::define( 'Core', 'LexerImpl', null, 'mixed/null', ' @@ -316,7 +319,7 @@ class HTMLPurifier_Lexer function normalize($html, $config, &$context) { // extract body from document if applicable - if ($config->get('Core', 'AcceptFullDocuments')) { + if ($config->get('Core', 'ConvertDocumentToFragment')) { $html = $this->extractBody($html); } diff --git a/lib/htmlpurifier/HTMLPurifier/Lexer/DirectLex.php b/lib/htmlpurifier/HTMLPurifier/Lexer/DirectLex.php index b3639916d1d..86c0a2112b0 100644 --- a/lib/htmlpurifier/HTMLPurifier/Lexer/DirectLex.php +++ b/lib/htmlpurifier/HTMLPurifier/Lexer/DirectLex.php @@ -160,9 +160,15 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer $segment = substr($html, $cursor, $strlen_segment); + if ($segment === false) { + // somehow, we attempted to access beyond the end of + // the string, defense-in-depth, reported by Nate Abele + break; + } + // Check if it's a comment if ( - substr($segment, 0, 3) == '!--' + substr($segment, 0, 3) === '!--' ) { // re-determine segment length, looking for --> $position_comment_end = strpos($html, '-->', $cursor); @@ -237,7 +243,7 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer // trailing slash. Remember, we could have a tag like