diff --git a/library/HTMLPurifier/AttrDef/ID.php b/library/HTMLPurifier/AttrDef/ID.php index 63d30394..a4c54e4f 100644 --- a/library/HTMLPurifier/AttrDef/ID.php +++ b/library/HTMLPurifier/AttrDef/ID.php @@ -3,6 +3,22 @@ require_once 'HTMLPurifier/AttrDef.php'; require_once 'HTMLPurifier/IDAccumulator.php'; +HTMLPurifier_ConfigSchema::define( + 'Attr', 'EnableID', false, 'bool', + 'Allows the ID attribute in HTML. This is disabled by default '. + 'due to the fact that without proper configuration user input can '. + 'easily break the validation of a webpage by specifying an ID that is '. + 'already on the surrounding HTML. If you don\'t mind throwing caution to '. + 'the wind, enable this directive, but I strongly recommend you also '. + 'consider blacklisting IDs you use (%Attr.IDBlacklist) or prefixing all '. + 'user supplied IDs (%Attr.IDPrefix). This directive has been available '. + 'since 1.2.0, and when set to true reverts to the behavior of pre-1.2.0 '. + 'versions.' +); +HTMLPurifier_ConfigSchema::defineAlias( + 'HTML', 'EnableAttrID', 'Attr', 'EnableID' +); + HTMLPurifier_ConfigSchema::define( 'Attr', 'IDPrefix', '', 'string', 'String to prefix to IDs. If you have no idea what IDs your pages '. @@ -39,22 +55,13 @@ HTMLPurifier_ConfigSchema::define( class HTMLPurifier_AttrDef_ID extends HTMLPurifier_AttrDef { - /** - * Is the ID an actual ID, or a reference to one? - * @note IDAccumulator checking is disabled for references - * @bool - */ - var $ref = false; - - /** - * @param $ref bool indication if it's ID or IDREF - */ - function HTMLPurifier_AttrDef_ID($ref = false) { - $this->ref = $ref; - } + // ref functionality disabled, since we also have to verify + // whether or not the ID it refers to exists function validate($id, $config, &$context) { + if (!$config->get('Attr', 'EnableID')) return false; + $id = trim($id); // trim it first if ($id === '') return false; @@ -69,10 +76,10 @@ class HTMLPurifier_AttrDef_ID extends HTMLPurifier_AttrDef '%Attr.IDPrefix is set', E_USER_WARNING); } - if (!$this->ref) { + //if (!$this->ref) { $id_accumulator =& $context->get('IDAccumulator'); if (isset($id_accumulator->ids[$id])) return false; - } + //} // we purposely avoid using regex, hopefully this is faster @@ -87,7 +94,7 @@ class HTMLPurifier_AttrDef_ID extends HTMLPurifier_AttrDef $result = ($trim === ''); } - if (!$this->ref && $result) $id_accumulator->add($id); + if (/*!$this->ref && */$result) $id_accumulator->add($id); // if no change was made to the ID, return the result // else, return the new id if stripping whitespace made it diff --git a/library/HTMLPurifier/AttrTypes.php b/library/HTMLPurifier/AttrTypes.php index c942c856..29be5288 100644 --- a/library/HTMLPurifier/AttrTypes.php +++ b/library/HTMLPurifier/AttrTypes.php @@ -38,4 +38,4 @@ class HTMLPurifier_AttrTypes } } -?> \ No newline at end of file +?> diff --git a/library/HTMLPurifier/HTMLDefinition.php b/library/HTMLPurifier/HTMLDefinition.php index 0b66fc2f..3e71dab7 100644 --- a/library/HTMLPurifier/HTMLDefinition.php +++ b/library/HTMLPurifier/HTMLDefinition.php @@ -38,22 +38,14 @@ require_once 'HTMLPurifier/HTMLModule/StyleAttribute.php'; require_once 'HTMLPurifier/HTMLModule/TransformToStrict.php'; require_once 'HTMLPurifier/HTMLModule/Legacy.php'; +// config modules +require_once 'HTMLPurifier/HTMLModule/SetParent.php'; + // tweak modules +require_once 'HTMLPurifier/HTMLModule/TweakSubtractiveWhitelist.php'; // this definition and its modules MUST NOT define configuration directives // outside of the HTML or Attr namespaces -HTMLPurifier_ConfigSchema::define( - 'HTML', 'EnableAttrID', false, 'bool', - 'Allows the ID attribute in HTML. This is disabled by default '. - 'due to the fact that without proper configuration user input can '. - 'easily break the validation of a webpage by specifying an ID that is '. - 'already on the surrounding HTML. If you don\'t mind throwing caution to '. - 'the wind, enable this directive, but I strongly recommend you also '. - 'consider blacklisting IDs you use (%Attr.IDBlacklist) or prefixing all '. - 'user supplied IDs (%Attr.IDPrefix). This directive has been available '. - 'since 1.2.0, and when set to true reverts to the behavior of pre-1.2.0 '. - 'versions.' -); HTMLPurifier_ConfigSchema::define( 'HTML', 'Strict', false, 'bool', @@ -72,39 +64,6 @@ HTMLPurifier_ConfigSchema::define( 'This directive has been available since 1.3.0.' ); -HTMLPurifier_ConfigSchema::define( - 'HTML', 'Parent', 'div', 'string', - 'String name of element that HTML fragment passed to library will be '. - 'inserted in. An interesting variation would be using span as the '. - 'parent element, meaning that only inline tags would be allowed. '. - 'This directive has been available since 1.3.0.' -); - -HTMLPurifier_ConfigSchema::define( - 'HTML', 'AllowedElements', null, 'lookup/null', - 'If HTML Purifier\'s tag set is unsatisfactory for your needs, you '. - 'can overload it with your own list of tags to allow. Note that this '. - 'method is subtractive: it does its job by taking away from HTML Purifier '. - 'usual feature set, so you cannot add a tag that HTML Purifier never '. - 'supported in the first place (like embed, form or head). If you change this, you '. - 'probably also want to change %HTML.AllowedAttributes. '. - 'Warning: If another directive conflicts with the '. - 'elements here, that directive will win and override. '. - 'This directive has been available since 1.3.0.' -); - -HTMLPurifier_ConfigSchema::define( - 'HTML', 'AllowedAttributes', null, 'lookup/null', - 'IF HTML Purifier\'s attribute set is unsatisfactory, overload it! '. - 'The syntax is \'tag.attr\' or \'*.attr\' for the global attributes '. - '(style, id, class, dir, lang, xml:lang).'. - 'Warning: If another directive conflicts with the '. - 'elements here, that directive will win and override. For '. - 'example, %HTML.EnableAttrID will take precedence over *.id in this '. - 'directive. You must set that directive to true before you can use '. - 'IDs at all. This directive has been available since 1.3.0.' -); - /** * Definition of the purified HTML that describes allowed children, * attributes, and many other things. @@ -246,11 +205,19 @@ class HTMLPurifier_HTMLDefinition * @public */ var $order_keywords = array( - 'setup' => 10, - 'early' => 20, - 'main' => 30, - 'late' => 40, - 'cleanup' => 50, + 'begin' => 10, + 'setup' => 20, + + 'pre' => 30, + + 'early' => 40, + 'main' => 50, + 'late' => 60, + + 'post' => 70, + + 'cleanup' => 80, + 'end' => 90 ); /** @@ -277,23 +244,16 @@ class HTMLPurifier_HTMLDefinition // modules - // early - - // main $main_modules = array('Text', 'Hypertext', 'List', 'Presentation', 'Edit', 'Bdo', 'Tables', 'Image', 'StyleAttribute'); foreach ($main_modules as $module) $this->addModule($module, 'main'); - // late if (!$this->strict) $this->addModule('Legacy', 'late'); - // cleanup - $this->addModule('TransformToStrict', 'cleanup'); + $this->addModule('SetParent', 'post'); - // remove ID module (refactor to module) - if (!$config->get('HTML', 'EnableAttrID')) { - $this->attr_collections->info['Core']['id'] = false; - } + $this->addModule('TransformToStrict', 'cleanup'); + $this->addModule('TweakSubtractiveWhitelist', 'cleanup'); } @@ -341,8 +301,6 @@ class HTMLPurifier_HTMLDefinition $this->processModules(); $this->setupAttrTransform(); $this->setupBlockWrapper(); - $this->setupParent(); - $this->setupCompat(); unset($this->config); @@ -453,50 +411,6 @@ class HTMLPurifier_HTMLDefinition } } - /** - * Sets up parent of fragment based on config - */ - function setupParent() { - $parent = $this->config->get('HTML', 'Parent'); - if (isset($this->info[$parent])) { - $this->info_parent = $parent; - } else { - trigger_error('Cannot use unrecognized element as parent.', - E_USER_ERROR); - } - $this->info_parent_def = $this->info[$this->info_parent]; - } - - /** - * Sets up compat code from HTMLDefinition that has not been - * delegated to modules yet - */ - function setupCompat() { - - // setup allowed elements, SubtractiveWhitelist module - $allowed_elements = $this->config->get('HTML', 'AllowedElements'); - if (is_array($allowed_elements)) { - foreach ($this->info as $name => $d) { - if(!isset($allowed_elements[$name])) unset($this->info[$name]); - } - } - $allowed_attributes = $this->config->get('HTML', 'AllowedAttributes'); - if (is_array($allowed_attributes)) { - foreach ($this->info_global_attr as $attr_key => $info) { - if (!isset($allowed_attributes["*.$attr_key"])) { - unset($this->info_global_attr[$attr_key]); - } - } - foreach ($this->info as $tag => $info) { - foreach ($info->attr as $attr => $attr_info) { - if (!isset($allowed_attributes["$tag.$attr"])) { - unset($this->info[$tag]->attr[$attr]); - } - } - } - } - - } } diff --git a/library/HTMLPurifier/HTMLModule/SetParent.php b/library/HTMLPurifier/HTMLModule/SetParent.php new file mode 100644 index 00000000..0ca1ddfb --- /dev/null +++ b/library/HTMLPurifier/HTMLModule/SetParent.php @@ -0,0 +1,31 @@ +config->get('HTML', 'Parent'); + if (isset($definition->info[$parent])) { + $definition->info_parent = $parent; + } else { + trigger_error('Cannot use unrecognized element as parent.', + E_USER_ERROR); + } + $definition->info_parent_def = $definition->info[$definition->info_parent]; + } + +} + +?> \ No newline at end of file diff --git a/library/HTMLPurifier/HTMLModule/TweakSubtractiveWhitelist.php b/library/HTMLPurifier/HTMLModule/TweakSubtractiveWhitelist.php new file mode 100644 index 00000000..47f8e32b --- /dev/null +++ b/library/HTMLPurifier/HTMLModule/TweakSubtractiveWhitelist.php @@ -0,0 +1,68 @@ +Warning: If another directive conflicts with the '. + 'elements here, that directive will win and override. '. + 'This directive has been available since 1.3.0.' +); + +HTMLPurifier_ConfigSchema::define( + 'HTML', 'AllowedAttributes', null, 'lookup/null', + 'IF HTML Purifier\'s attribute set is unsatisfactory, overload it! '. + 'The syntax is \'tag.attr\' or \'*.attr\' for the global attributes '. + '(style, id, class, dir, lang, xml:lang).'. + 'Warning: If another directive conflicts with the '. + 'elements here, that directive will win and override. For '. + 'example, %HTML.EnableAttrID will take precedence over *.id in this '. + 'directive. You must set that directive to true before you can use '. + 'IDs at all. This directive has been available since 1.3.0.' +); + +/** + * Proprietary module that further narrows down allowed elements and + * attributes that were allowed to a user-defined whitelist. + * @warning This module cannot ADD elements or attributes, you must + * implement full definitions yourself! + */ + +class HTMLPurifier_HTMLModule_TweakSubtractiveWhitelist extends HTMLPurifier_HTMLModule +{ + + function postProcess(&$definition) { + + // setup allowed elements, SubtractiveWhitelist module + $allowed_elements = $definition->config->get('HTML', 'AllowedElements'); + if (is_array($allowed_elements)) { + foreach ($definition->info as $name => $d) { + if(!isset($allowed_elements[$name])) unset($definition->info[$name]); + } + } + $allowed_attributes = $definition->config->get('HTML', 'AllowedAttributes'); + if (is_array($allowed_attributes)) { + foreach ($definition->info_global_attr as $attr_key => $info) { + if (!isset($allowed_attributes["*.$attr_key"])) { + unset($definition->info_global_attr[$attr_key]); + } + } + foreach ($definition->info as $tag => $info) { + foreach ($info->attr as $attr => $attr_info) { + if (!isset($allowed_attributes["$tag.$attr"]) && + !isset($allowed_attributes["*.$attr"])) { + unset($definition->info[$tag]->attr[$attr]); + } + } + } + } + + } + +} + +?> \ No newline at end of file diff --git a/tests/HTMLPurifier/AttrDef/IDTest.php b/tests/HTMLPurifier/AttrDef/IDTest.php index 7fba690f..42be7e13 100644 --- a/tests/HTMLPurifier/AttrDef/IDTest.php +++ b/tests/HTMLPurifier/AttrDef/IDTest.php @@ -12,6 +12,7 @@ class HTMLPurifier_AttrDef_IDTest extends HTMLPurifier_AttrDefHarness $id_accumulator = new HTMLPurifier_IDAccumulator(); $this->context->register('IDAccumulator', $id_accumulator); + $this->config->set('Attr', 'EnableID', true); $this->def = new HTMLPurifier_AttrDef_ID(); } @@ -74,7 +75,8 @@ class HTMLPurifier_AttrDef_IDTest extends HTMLPurifier_AttrDefHarness } - function testIDReference() { + // reference functionality is disabled for now + function disabled_testIDReference() { $this->def = new HTMLPurifier_AttrDef_ID(true);