diff --git a/NEWS b/NEWS index e35599d1..64d98a6d 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,9 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier # HTMLPurifier_Config will now throw E_USER_NOTICE when you use a directive alias; to get rid of these errors just modify your configuration to use the new directive name. +# Directive-level safety properties superceded in favor of module-level + safety. Internal method HTMLModule->addElement() has changed, although + the externally visible HTMLDefinition->addElement has *not* changed. ! Extra utility classes for testing and non-library operations can 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 @@ -89,6 +92,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier . Command line scripts now honor exit codes . When --flush fails in unit testers, abort tests and print message . Improved documentation in docs/dev-flush.html about the maintenance scripts +. copy() methods removed in favor of clone keyword 3.0.0, released 2008-01-06 # HTML Purifier is PHP 5 only! The 2.1.x branch will be maintained diff --git a/library/HTMLPurifier/AttrTypes.php b/library/HTMLPurifier/AttrTypes.php index 0d30d378..9262a098 100644 --- a/library/HTMLPurifier/AttrTypes.php +++ b/library/HTMLPurifier/AttrTypes.php @@ -8,7 +8,7 @@ class HTMLPurifier_AttrTypes /** * Lookup array of attribute string identifiers to concrete implementations */ - public $info = array(); + protected $info = array(); /** * Constructs the info array, supplying default implementations for attribute diff --git a/library/HTMLPurifier/Doctype.php b/library/HTMLPurifier/Doctype.php index 673c6a3b..5e83a869 100644 --- a/library/HTMLPurifier/Doctype.php +++ b/library/HTMLPurifier/Doctype.php @@ -55,12 +55,5 @@ class HTMLPurifier_Doctype $this->dtdPublic = $dtd_public; $this->dtdSystem = $dtd_system; } - - /** - * Clones the doctype, use before resolving modes and the like - */ - public function copy() { - return unserialize(serialize($this)); - } } diff --git a/library/HTMLPurifier/DoctypeRegistry.php b/library/HTMLPurifier/DoctypeRegistry.php index 8a2b0b9d..ee39bcca 100644 --- a/library/HTMLPurifier/DoctypeRegistry.php +++ b/library/HTMLPurifier/DoctypeRegistry.php @@ -72,9 +72,7 @@ class HTMLPurifier_DoctypeRegistry * based or not). */ public function make($config) { - $original_doctype = $this->get($this->getDoctypeFromConfig($config)); - $doctype = $original_doctype->copy(); - return $doctype; + return clone $this->get($this->getDoctypeFromConfig($config)); } /** diff --git a/library/HTMLPurifier/ElementDef.php b/library/HTMLPurifier/ElementDef.php index a16dc5da..341ce349 100644 --- a/library/HTMLPurifier/ElementDef.php +++ b/library/HTMLPurifier/ElementDef.php @@ -90,17 +90,11 @@ class HTMLPurifier_ElementDef */ public $excludes = array(); - /** - * Is this element safe for untrusted users to use? - */ - public $safe; - /** * Low-level factory constructor for creating new standalone element defs */ - public static function create($safe, $content_model, $content_model_type, $attr) { + public static function create($content_model, $content_model_type, $attr) { $def = new HTMLPurifier_ElementDef(); - $def->safe = (bool) $safe; $def->content_model = $content_model; $def->content_model_type = $content_model_type; $def->attr = $attr; @@ -144,7 +138,6 @@ class HTMLPurifier_ElementDef } if(!is_null($def->child)) $this->child = $def->child; if($def->descendants_are_inline) $this->descendants_are_inline = $def->descendants_are_inline; - if(!is_null($def->safe)) $this->safe = $def->safe; } @@ -163,13 +156,6 @@ class HTMLPurifier_ElementDef } } - /** - * Retrieves a copy of the element definition - */ - public function copy() { - return unserialize(serialize($this)); - } - } diff --git a/library/HTMLPurifier/HTMLDefinition.php b/library/HTMLPurifier/HTMLDefinition.php index a327dabb..331f4f45 100644 --- a/library/HTMLPurifier/HTMLDefinition.php +++ b/library/HTMLPurifier/HTMLDefinition.php @@ -113,7 +113,7 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition $module =& $this->getAnonymousModule(); // assume that if the user is calling this, the element // is safe. This may not be a good idea - $element =& $module->addElement($element_name, true, $type, $contents, $attr_collections, $attributes); + $element =& $module->addElement($element_name, $type, $contents, $attr_collections, $attributes); return $element; } diff --git a/library/HTMLPurifier/HTMLModule.php b/library/HTMLPurifier/HTMLModule.php index 031766b4..20989f70 100644 --- a/library/HTMLPurifier/HTMLModule.php +++ b/library/HTMLPurifier/HTMLModule.php @@ -79,6 +79,20 @@ class HTMLPurifier_HTMLModule */ public $defines_child_def = false; + /** + * Boolean flag whether or not this module is safe. If it is not safe, all + * of its members are unsafe. Modules are safe by default (this might be + * slightly dangerous, but it doesn't make much sense to force HTML Purifier, + * which is based off of safe HTML, to explicitly say, "This is safe," even + * though there are modules which are "unsafe") + * + * @note Previously, safety could be applied at an element level granularity. + * We've removed this ability, so in order to add "unsafe" elements + * or attributes, a dedicated module with this property set to false + * must be used. + */ + public $safe = true; + /** * Retrieves a proper HTMLPurifier_ChildDef subclass based on * content_model and content_model_type member variables of @@ -94,7 +108,6 @@ class HTMLPurifier_HTMLModule /** * Convenience function that sets up a new element * @param $element Name of element to add - * @param $safe Is element safe for untrusted users to use? * @param $type What content set should element be registered to? * Set as false to skip this step. * @param $contents Allowed children in form of: @@ -106,7 +119,7 @@ class HTMLPurifier_HTMLModule * @return Reference to created element definition object, so you * can set advanced parameters */ - public function &addElement($element, $safe, $type, $contents, $attr_includes = array(), $attr = array()) { + public function &addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) { $this->elements[] = $element; // parse content_model list($content_model_type, $content_model) = $this->parseContents($contents); @@ -116,7 +129,7 @@ class HTMLPurifier_HTMLModule if ($type) $this->addElementToContentSet($element, $type); // create element $this->info[$element] = HTMLPurifier_ElementDef::create( - $safe, $content_model, $content_model_type, $attr + $content_model, $content_model_type, $attr ); // literal object $contents means direct child manipulation if (!is_string($contents)) $this->info[$element]->child = $contents; diff --git a/library/HTMLPurifier/HTMLModule/Bdo.php b/library/HTMLPurifier/HTMLModule/Bdo.php index db5af7ef..f556c66c 100644 --- a/library/HTMLPurifier/HTMLModule/Bdo.php +++ b/library/HTMLPurifier/HTMLModule/Bdo.php @@ -14,7 +14,7 @@ class HTMLPurifier_HTMLModule_Bdo extends HTMLPurifier_HTMLModule public function __construct() { $bdo =& $this->addElement( - 'bdo', true, 'Inline', 'Inline', array('Core', 'Lang'), + 'bdo', 'Inline', 'Inline', array('Core', 'Lang'), array( 'dir' => 'Enum#ltr,rtl', // required // The Abstract Module specification has the attribute diff --git a/library/HTMLPurifier/HTMLModule/Edit.php b/library/HTMLPurifier/HTMLModule/Edit.php index a4eac324..07d972e3 100644 --- a/library/HTMLPurifier/HTMLModule/Edit.php +++ b/library/HTMLPurifier/HTMLModule/Edit.php @@ -15,8 +15,8 @@ class HTMLPurifier_HTMLModule_Edit extends HTMLPurifier_HTMLModule 'cite' => 'URI', // 'datetime' => 'Datetime', // not implemented ); - $this->addElement('del', true, 'Inline', $contents, 'Common', $attr); - $this->addElement('ins', true, 'Inline', $contents, 'Common', $attr); + $this->addElement('del', 'Inline', $contents, 'Common', $attr); + $this->addElement('ins', 'Inline', $contents, 'Common', $attr); } // HTML 4.01 specifies that ins/del must not contain block diff --git a/library/HTMLPurifier/HTMLModule/Hypertext.php b/library/HTMLPurifier/HTMLModule/Hypertext.php index 12524297..c723ce72 100644 --- a/library/HTMLPurifier/HTMLModule/Hypertext.php +++ b/library/HTMLPurifier/HTMLModule/Hypertext.php @@ -10,7 +10,7 @@ class HTMLPurifier_HTMLModule_Hypertext extends HTMLPurifier_HTMLModule public function __construct() { $a =& $this->addElement( - 'a', true, 'Inline', 'Inline', 'Common', + 'a', 'Inline', 'Inline', 'Common', array( // 'accesskey' => 'Character', // 'charset' => 'Charset', diff --git a/library/HTMLPurifier/HTMLModule/Image.php b/library/HTMLPurifier/HTMLModule/Image.php index d81ec6f6..7a0b27da 100644 --- a/library/HTMLPurifier/HTMLModule/Image.php +++ b/library/HTMLPurifier/HTMLModule/Image.php @@ -12,7 +12,7 @@ class HTMLPurifier_HTMLModule_Image extends HTMLPurifier_HTMLModule public function __construct() { $img =& $this->addElement( - 'img', true, 'Inline', 'Empty', 'Common', + 'img', 'Inline', 'Empty', 'Common', array( 'alt*' => 'Text', 'height' => 'Length', diff --git a/library/HTMLPurifier/HTMLModule/Legacy.php b/library/HTMLPurifier/HTMLModule/Legacy.php index b8e7cf34..c134845c 100644 --- a/library/HTMLPurifier/HTMLModule/Legacy.php +++ b/library/HTMLPurifier/HTMLModule/Legacy.php @@ -23,27 +23,27 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule public function __construct() { - $this->addElement('basefont', true, 'Inline', 'Empty', false, array( + $this->addElement('basefont', 'Inline', 'Empty', false, array( 'color' => 'Color', 'face' => 'Text', // extremely broad, we should 'size' => 'Text', // tighten it 'id' => 'ID' )); - $this->addElement('center', true, 'Block', 'Flow', 'Common'); - $this->addElement('dir', true, 'Block', 'Required: li', 'Common', array( + $this->addElement('center', 'Block', 'Flow', 'Common'); + $this->addElement('dir', 'Block', 'Required: li', 'Common', array( 'compact' => 'Bool#compact' )); - $this->addElement('font', true, 'Inline', 'Inline', array('Core', 'I18N'), array( + $this->addElement('font', 'Inline', 'Inline', array('Core', 'I18N'), array( 'color' => 'Color', 'face' => 'Text', // extremely broad, we should 'size' => 'Text', // tighten it )); - $this->addElement('menu', true, 'Block', 'Required: li', 'Common', array( + $this->addElement('menu', 'Block', 'Required: li', 'Common', array( 'compact' => 'Bool#compact' )); - $this->addElement('s', true, 'Inline', 'Inline', 'Common'); - $this->addElement('strike', true, 'Inline', 'Inline', 'Common'); - $this->addElement('u', true, 'Inline', 'Inline', 'Common'); + $this->addElement('s', 'Inline', 'Inline', 'Common'); + $this->addElement('strike', 'Inline', 'Inline', 'Common'); + $this->addElement('u', 'Inline', 'Inline', 'Common'); // setup modifications to old elements diff --git a/library/HTMLPurifier/HTMLModule/List.php b/library/HTMLPurifier/HTMLModule/List.php index 112756bd..7d4f9cf2 100644 --- a/library/HTMLPurifier/HTMLModule/List.php +++ b/library/HTMLPurifier/HTMLModule/List.php @@ -20,14 +20,14 @@ class HTMLPurifier_HTMLModule_List extends HTMLPurifier_HTMLModule public $content_sets = array('Flow' => 'List'); public function __construct() { - $this->addElement('ol', true, 'List', 'Required: li', 'Common'); - $this->addElement('ul', true, 'List', 'Required: li', 'Common'); - $this->addElement('dl', true, 'List', 'Required: dt | dd', 'Common'); + $this->addElement('ol', 'List', 'Required: li', 'Common'); + $this->addElement('ul', 'List', 'Required: li', 'Common'); + $this->addElement('dl', 'List', 'Required: dt | dd', 'Common'); - $this->addElement('li', true, false, 'Flow', 'Common'); + $this->addElement('li', false, 'Flow', 'Common'); - $this->addElement('dd', true, false, 'Flow', 'Common'); - $this->addElement('dt', true, false, 'Inline', 'Common'); + $this->addElement('dd', false, 'Flow', 'Common'); + $this->addElement('dt', false, 'Inline', 'Common'); } } diff --git a/library/HTMLPurifier/HTMLModule/Object.php b/library/HTMLPurifier/HTMLModule/Object.php index 6bc4331e..609d3351 100644 --- a/library/HTMLPurifier/HTMLModule/Object.php +++ b/library/HTMLPurifier/HTMLModule/Object.php @@ -9,10 +9,11 @@ class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule { public $name = 'Object'; + public $safe = false; public function __construct() { - $this->addElement('object', false, 'Inline', 'Optional: #PCDATA | Flow | param', 'Common', + $this->addElement('object', 'Inline', 'Optional: #PCDATA | Flow | param', 'Common', array( 'archive' => 'URI', 'classid' => 'URI', @@ -29,7 +30,7 @@ class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule ) ); - $this->addElement('param', false, false, 'Empty', false, + $this->addElement('param', false, 'Empty', false, array( 'id' => 'ID', 'name*' => 'Text', diff --git a/library/HTMLPurifier/HTMLModule/Presentation.php b/library/HTMLPurifier/HTMLModule/Presentation.php index 05bb7d51..bd8368a8 100644 --- a/library/HTMLPurifier/HTMLModule/Presentation.php +++ b/library/HTMLPurifier/HTMLModule/Presentation.php @@ -16,14 +16,14 @@ class HTMLPurifier_HTMLModule_Presentation extends HTMLPurifier_HTMLModule public $name = 'Presentation'; public function __construct() { - $this->addElement('b', true, 'Inline', 'Inline', 'Common'); - $this->addElement('big', true, 'Inline', 'Inline', 'Common'); - $this->addElement('hr', true, 'Block', 'Empty', 'Common'); - $this->addElement('i', true, 'Inline', 'Inline', 'Common'); - $this->addElement('small', true, 'Inline', 'Inline', 'Common'); - $this->addElement('sub', true, 'Inline', 'Inline', 'Common'); - $this->addElement('sup', true, 'Inline', 'Inline', 'Common'); - $this->addElement('tt', true, 'Inline', 'Inline', 'Common'); + $this->addElement('b', 'Inline', 'Inline', 'Common'); + $this->addElement('big', 'Inline', 'Inline', 'Common'); + $this->addElement('hr', 'Block', 'Empty', 'Common'); + $this->addElement('i', 'Inline', 'Inline', 'Common'); + $this->addElement('small', 'Inline', 'Inline', 'Common'); + $this->addElement('sub', 'Inline', 'Inline', 'Common'); + $this->addElement('sup', 'Inline', 'Inline', 'Common'); + $this->addElement('tt', 'Inline', 'Inline', 'Common'); } } diff --git a/library/HTMLPurifier/HTMLModule/Proprietary.php b/library/HTMLPurifier/HTMLModule/Proprietary.php index 4e33fa5b..d5c72418 100644 --- a/library/HTMLPurifier/HTMLModule/Proprietary.php +++ b/library/HTMLPurifier/HTMLModule/Proprietary.php @@ -11,7 +11,7 @@ class HTMLPurifier_HTMLModule_Proprietary extends HTMLPurifier_HTMLModule public function __construct() { - $this->addElement('marquee', true, 'Inline', 'Flow', 'Common', + $this->addElement('marquee', 'Inline', 'Flow', 'Common', array( 'direction' => 'Enum#left,right,up,down', 'behavior' => 'Enum#alternate', diff --git a/library/HTMLPurifier/HTMLModule/Ruby.php b/library/HTMLPurifier/HTMLModule/Ruby.php index ac979c67..fc3caf7e 100644 --- a/library/HTMLPurifier/HTMLModule/Ruby.php +++ b/library/HTMLPurifier/HTMLModule/Ruby.php @@ -10,16 +10,16 @@ class HTMLPurifier_HTMLModule_Ruby extends HTMLPurifier_HTMLModule public $name = 'Ruby'; public function __construct() { - $this->addElement('ruby', true, 'Inline', + $this->addElement('ruby', 'Inline', 'Custom: ((rb, (rt | (rp, rt, rp))) | (rbc, rtc, rtc?))', 'Common'); - $this->addElement('rbc', true, false, 'Required: rb', 'Common'); - $this->addElement('rtc', true, false, 'Required: rt', 'Common'); - $rb =& $this->addElement('rb', true, false, 'Inline', 'Common'); + $this->addElement('rbc', false, 'Required: rb', 'Common'); + $this->addElement('rtc', false, 'Required: rt', 'Common'); + $rb =& $this->addElement('rb', false, 'Inline', 'Common'); $rb->excludes = array('ruby' => true); - $rt =& $this->addElement('rt', true, false, 'Inline', 'Common', array('rbspan' => 'Number')); + $rt =& $this->addElement('rt', false, 'Inline', 'Common', array('rbspan' => 'Number')); $rt->excludes = array('ruby' => true); - $this->addElement('rp', true, false, 'Optional: #PCDATA', 'Common'); + $this->addElement('rp', false, 'Optional: #PCDATA', 'Common'); } } diff --git a/library/HTMLPurifier/HTMLModule/Scripting.php b/library/HTMLPurifier/HTMLModule/Scripting.php index 1b348e70..ba1e23ce 100644 --- a/library/HTMLPurifier/HTMLModule/Scripting.php +++ b/library/HTMLPurifier/HTMLModule/Scripting.php @@ -31,6 +31,7 @@ class HTMLPurifier_HTMLModule_Scripting extends HTMLPurifier_HTMLModule public $name = 'Scripting'; public $elements = array('script', 'noscript'); public $content_sets = array('Block' => 'script | noscript', 'Inline' => 'script | noscript'); + public $safe = false; public function __construct() { // TODO: create custom child-definition for noscript that @@ -41,13 +42,15 @@ class HTMLPurifier_HTMLModule_Scripting extends HTMLPurifier_HTMLModule // TODO: convert this to new syntax, main problem is getting // both content sets working - foreach ($this->elements as $element) { - $this->info[$element] = new HTMLPurifier_ElementDef(); - $this->info[$element]->safe = false; - } + + // In theory, this could be safe, but I don't see any reason to + // allow it. + $this->info['noscript'] = new HTMLPurifier_ElementDef(); $this->info['noscript']->attr = array( 0 => array('Common') ); $this->info['noscript']->content_model = 'Heading | List | Block'; $this->info['noscript']->content_model_type = 'required'; + + $this->info['script'] = new HTMLPurifier_ElementDef(); $this->info['script']->attr = array( 'defer' => new HTMLPurifier_AttrDef_Enum(array('defer')), 'src' => new HTMLPurifier_AttrDef_URI(true), diff --git a/library/HTMLPurifier/HTMLModule/Tables.php b/library/HTMLPurifier/HTMLModule/Tables.php index e326852d..d6a13fff 100644 --- a/library/HTMLPurifier/HTMLModule/Tables.php +++ b/library/HTMLPurifier/HTMLModule/Tables.php @@ -10,9 +10,9 @@ class HTMLPurifier_HTMLModule_Tables extends HTMLPurifier_HTMLModule public function __construct() { - $this->addElement('caption', true, false, 'Inline', 'Common'); + $this->addElement('caption', false, 'Inline', 'Common'); - $this->addElement('table', true, 'Block', + $this->addElement('table', 'Block', new HTMLPurifier_ChildDef_Table(), 'Common', array( 'border' => 'Pixels', @@ -40,10 +40,10 @@ class HTMLPurifier_HTMLModule_Tables extends HTMLPurifier_HTMLModule ), $cell_align ); - $this->addElement('td', true, false, 'Flow', 'Common', $cell_t); - $this->addElement('th', true, false, 'Flow', 'Common', $cell_t); + $this->addElement('td', false, 'Flow', 'Common', $cell_t); + $this->addElement('th', false, 'Flow', 'Common', $cell_t); - $this->addElement('tr', true, false, 'Required: td | th', 'Common', $cell_align); + $this->addElement('tr', false, 'Required: td | th', 'Common', $cell_align); $cell_col = array_merge( array( @@ -52,12 +52,12 @@ class HTMLPurifier_HTMLModule_Tables extends HTMLPurifier_HTMLModule ), $cell_align ); - $this->addElement('col', true, false, 'Empty', 'Common', $cell_col); - $this->addElement('colgroup', true, false, 'Optional: col', 'Common', $cell_col); + $this->addElement('col', false, 'Empty', 'Common', $cell_col); + $this->addElement('colgroup', false, 'Optional: col', 'Common', $cell_col); - $this->addElement('tbody', true, false, 'Required: tr', 'Common', $cell_align); - $this->addElement('thead', true, false, 'Required: tr', 'Common', $cell_align); - $this->addElement('tfoot', true, false, 'Required: tr', 'Common', $cell_align); + $this->addElement('tbody', false, 'Required: tr', 'Common', $cell_align); + $this->addElement('thead', false, 'Required: tr', 'Common', $cell_align); + $this->addElement('tfoot', false, 'Required: tr', 'Common', $cell_align); } diff --git a/library/HTMLPurifier/HTMLModule/Text.php b/library/HTMLPurifier/HTMLModule/Text.php index 8a608763..3acec4a6 100644 --- a/library/HTMLPurifier/HTMLModule/Text.php +++ b/library/HTMLPurifier/HTMLModule/Text.php @@ -23,38 +23,38 @@ class HTMLPurifier_HTMLModule_Text extends HTMLPurifier_HTMLModule public function __construct() { // Inline Phrasal ------------------------------------------------- - $this->addElement('abbr', true, 'Inline', 'Inline', 'Common'); - $this->addElement('acronym', true, 'Inline', 'Inline', 'Common'); - $this->addElement('cite', true, 'Inline', 'Inline', 'Common'); - $this->addElement('code', true, 'Inline', 'Inline', 'Common'); - $this->addElement('dfn', true, 'Inline', 'Inline', 'Common'); - $this->addElement('em', true, 'Inline', 'Inline', 'Common'); - $this->addElement('kbd', true, 'Inline', 'Inline', 'Common'); - $this->addElement('q', true, 'Inline', 'Inline', 'Common', array('cite' => 'URI')); - $this->addElement('samp', true, 'Inline', 'Inline', 'Common'); - $this->addElement('strong', true, 'Inline', 'Inline', 'Common'); - $this->addElement('var', true, 'Inline', 'Inline', 'Common'); + $this->addElement('abbr', 'Inline', 'Inline', 'Common'); + $this->addElement('acronym', 'Inline', 'Inline', 'Common'); + $this->addElement('cite', 'Inline', 'Inline', 'Common'); + $this->addElement('code', 'Inline', 'Inline', 'Common'); + $this->addElement('dfn', 'Inline', 'Inline', 'Common'); + $this->addElement('em', 'Inline', 'Inline', 'Common'); + $this->addElement('kbd', 'Inline', 'Inline', 'Common'); + $this->addElement('q', 'Inline', 'Inline', 'Common', array('cite' => 'URI')); + $this->addElement('samp', 'Inline', 'Inline', 'Common'); + $this->addElement('strong', 'Inline', 'Inline', 'Common'); + $this->addElement('var', 'Inline', 'Inline', 'Common'); // Inline Structural ---------------------------------------------- - $this->addElement('span', true, 'Inline', 'Inline', 'Common'); - $this->addElement('br', true, 'Inline', 'Empty', 'Core'); + $this->addElement('span', 'Inline', 'Inline', 'Common'); + $this->addElement('br', 'Inline', 'Empty', 'Core'); // Block Phrasal -------------------------------------------------- - $this->addElement('address', true, 'Block', 'Inline', 'Common'); - $this->addElement('blockquote', true, 'Block', 'Optional: Heading | Block | List', 'Common', array('cite' => 'URI') ); - $pre =& $this->addElement('pre', true, 'Block', 'Inline', 'Common'); + $this->addElement('address', 'Block', 'Inline', 'Common'); + $this->addElement('blockquote', 'Block', 'Optional: Heading | Block | List', 'Common', array('cite' => 'URI') ); + $pre =& $this->addElement('pre', 'Block', 'Inline', 'Common'); $pre->excludes = $this->makeLookup( 'img', 'big', 'small', 'object', 'applet', 'font', 'basefont' ); - $this->addElement('h1', true, 'Heading', 'Inline', 'Common'); - $this->addElement('h2', true, 'Heading', 'Inline', 'Common'); - $this->addElement('h3', true, 'Heading', 'Inline', 'Common'); - $this->addElement('h4', true, 'Heading', 'Inline', 'Common'); - $this->addElement('h5', true, 'Heading', 'Inline', 'Common'); - $this->addElement('h6', true, 'Heading', 'Inline', 'Common'); + $this->addElement('h1', 'Heading', 'Inline', 'Common'); + $this->addElement('h2', 'Heading', 'Inline', 'Common'); + $this->addElement('h3', 'Heading', 'Inline', 'Common'); + $this->addElement('h4', 'Heading', 'Inline', 'Common'); + $this->addElement('h5', 'Heading', 'Inline', 'Common'); + $this->addElement('h6', 'Heading', 'Inline', 'Common'); // Block Structural ----------------------------------------------- - $this->addElement('p', true, 'Block', 'Inline', 'Common'); - $this->addElement('div', true, 'Block', 'Flow', 'Common'); + $this->addElement('p', 'Block', 'Inline', 'Common'); + $this->addElement('div', 'Block', 'Flow', 'Common'); } diff --git a/library/HTMLPurifier/HTMLModuleManager.php b/library/HTMLPurifier/HTMLModuleManager.php index 7bd97247..612c3c01 100644 --- a/library/HTMLPurifier/HTMLModuleManager.php +++ b/library/HTMLPurifier/HTMLModuleManager.php @@ -59,9 +59,7 @@ class HTMLPurifier_HTMLModuleManager $this->attrTypes = new HTMLPurifier_AttrTypes(); $this->doctypes = new HTMLPurifier_DoctypeRegistry(); - // setup default HTML doctypes - - // module reuse + // setup basic modules $common = array( 'CommonAttributes', 'Text', 'Hypertext', 'List', 'Presentation', 'Edit', 'Bdo', 'Tables', 'Image', @@ -71,6 +69,7 @@ class HTMLPurifier_HTMLModuleManager $xml = array('XMLCommonAttributes'); $non_xml = array('NonXMLCommonAttributes'); + // setup basic doctypes $this->doctypes->register( 'HTML 4.01 Transitional', false, array_merge($common, $transitional, $non_xml), @@ -124,6 +123,9 @@ class HTMLPurifier_HTMLModuleManager * @param $module Mixed: string module name, with or without * HTMLPurifier_HTMLModule prefix, or instance of * subclass of HTMLPurifier_HTMLModule. + * @param $overload Boolean whether or not to overload previous modules. + * If this is not set, and you do overload a module, + * HTML Purifier will complain with a warning. * @note This function will not call autoload, you must instantiate * (and thus invoke) autoload outside the method. * @note If a string is passed as a module name, different variants @@ -135,11 +137,8 @@ class HTMLPurifier_HTMLModuleManager * If your object name collides with an internal class, specify * your module manually. All modules must have been included * externally: registerModule will not perform inclusions for you! - * @warning If your module has the same name as an already loaded - * module, your module will overload the old one WITHOUT - * warning. */ - public function registerModule($module) { + public function registerModule($module, $overload = false) { if (is_string($module)) { // attempt to load the module $original_module = $module; @@ -165,6 +164,9 @@ class HTMLPurifier_HTMLModuleManager trigger_error('Module instance of ' . get_class($module) . ' must have name'); return; } + if (!$overload && isset($this->registeredModules[$module->name])) { + trigger_error('Overloading ' . $module->name . ' without explicit overload parameter', E_USER_WARNING); + } $this->registeredModules[$module->name] = $module; } @@ -274,10 +276,9 @@ class HTMLPurifier_HTMLModuleManager $elements = array(); foreach ($this->modules as $module) { + if (!$this->trusted && !$module->safe) continue; foreach ($module->info as $name => $v) { if (isset($elements[$name])) continue; - // if element is not safe, don't use it - if (!$this->trusted && ($v->safe === false)) continue; $elements[$name] = $this->getElement($name); } } @@ -298,43 +299,45 @@ class HTMLPurifier_HTMLModuleManager * @param $trusted Boolean trusted overriding parameter: set to true * if you want the full version of an element * @return Merged HTMLPurifier_ElementDef + * @note You may notice that modules are getting iterated over twice (once + * in getElements() and once here). This + * is because */ public function getElement($name, $trusted = null) { - $def = false; - if ($trusted === null) $trusted = $this->trusted; - - $modules = $this->modules; - if (!isset($this->elementLookup[$name])) { return false; } + // setup global state variables + $def = false; + if ($trusted === null) $trusted = $this->trusted; + + // iterate through each module that has registered itself to this + // element foreach($this->elementLookup[$name] as $module_name) { - $module = $modules[$module_name]; + $module = $this->modules[$module_name]; - // copy is used because, ideally speaking, the original - // definition should not be modified. Usually, this will - // make no difference, but for consistency's sake - $new_def = $module->info[$name]->copy(); - - // refuse to create/merge in a definition that is deemed unsafe - if (!$trusted && ($new_def->safe === false)) { - $def = false; + // refuse to create/merge from a module that is deemed unsafe-- + // pretend the module doesn't exist--when trusted mode is not on. + if (!$trusted && !$module->safe) { continue; } + // clone is used because, ideally speaking, the original + // definition should not be modified. Usually, this will + // make no difference, but for consistency's sake + $new_def = clone $module->info[$name]; + if (!$def && $new_def->standalone) { - // element with unknown safety is not to be trusted. - // however, a merge-in definition with undefined safety - // is fine - if (!$trusted && !$new_def->safe) continue; $def = $new_def; } elseif ($def) { + // This will occur even if $new_def is standalone. In practice, + // this will usually result in a full replacement. $def->mergeIn($new_def); } else { - // could "save it for another day": + // :TODO: // non-standalone definitions that don't have a standalone // to merge into could be deferred to the end continue; diff --git a/library/HTMLPurifier/URI.php b/library/HTMLPurifier/URI.php index 55246f6a..d63b324e 100644 --- a/library/HTMLPurifier/URI.php +++ b/library/HTMLPurifier/URI.php @@ -105,12 +105,5 @@ class HTMLPurifier_URI return $result; } - /** - * Returns a copy of the URI object - */ - public function copy() { - return unserialize(serialize($this)); - } - } diff --git a/library/HTMLPurifier/URIFilter/MakeAbsolute.php b/library/HTMLPurifier/URIFilter/MakeAbsolute.php index 0ac4aaeb..647f779e 100644 --- a/library/HTMLPurifier/URIFilter/MakeAbsolute.php +++ b/library/HTMLPurifier/URIFilter/MakeAbsolute.php @@ -27,7 +27,7 @@ class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment) ) { // reference to current document - $uri = $this->base->copy(); + $uri = clone $this->base; return true; } if (!is_null($uri->scheme)) { diff --git a/tests/HTMLPurifier/AttrTypesTest.php b/tests/HTMLPurifier/AttrTypesTest.php index b1c8a3f7..2be2fca9 100644 --- a/tests/HTMLPurifier/AttrTypesTest.php +++ b/tests/HTMLPurifier/AttrTypesTest.php @@ -8,7 +8,7 @@ class HTMLPurifier_AttrTypesTest extends HTMLPurifier_Harness $this->assertIdentical( $types->get('CDATA'), - $types->info['CDATA'] + new HTMLPurifier_AttrDef_Text() ); $this->expectError('Cannot retrieve undefined attribute type foobar'); diff --git a/tests/HTMLPurifier/ElementDefTest.php b/tests/HTMLPurifier/ElementDefTest.php index fd85f6f8..e81ca515 100644 --- a/tests/HTMLPurifier/ElementDefTest.php +++ b/tests/HTMLPurifier/ElementDefTest.php @@ -36,7 +36,6 @@ class HTMLPurifier_ElementDefTest extends HTMLPurifier_Harness 'old' => true, 'removed-old' => true ); - $def1->safe = false; $def2->standalone = false; $def2->attr = array( @@ -59,7 +58,6 @@ class HTMLPurifier_ElementDefTest extends HTMLPurifier_Harness 'new' => true, 'removed-old' => false ); - $def2->safe = true; $def1->mergeIn($def2); $def1->mergeIn($def3); // empty, has no effect @@ -85,7 +83,6 @@ class HTMLPurifier_ElementDefTest extends HTMLPurifier_Harness 'old' => true, 'new' => true )); - $this->assertIdentical($def1->safe, true); } diff --git a/tests/HTMLPurifier/HTMLModuleManagerTest.php b/tests/HTMLPurifier/HTMLModuleManagerTest.php index f6eee019..1aeed0b6 100644 --- a/tests/HTMLPurifier/HTMLModuleManagerTest.php +++ b/tests/HTMLPurifier/HTMLModuleManagerTest.php @@ -12,7 +12,7 @@ class HTMLPurifier_HTMLModuleManagerTest extends HTMLPurifier_Harness generate_mock_once('HTMLPurifier_AttrDef'); $attrdef = new HTMLPurifier_AttrDefMock(); $attrdef->setReturnValue('make', $attrdef_nmtokens); - $manager->attrTypes->info['NMTOKENS'] =& $attrdef; + $manager->attrTypes->set('NMTOKENS', $attrdef); // ...but we add user modules @@ -24,15 +24,20 @@ class HTMLPurifier_HTMLModuleManagerTest extends HTMLPurifier_Harness $structural_module = new HTMLPurifier_HTMLModule(); $structural_module->name = 'Structural'; - $structural_module->addElement('p', true, 'Block', 'Inline', 'Common'); - $structural_module->addElement('div', false, 'Block', 'Flow'); + $structural_module->addElement('p', 'Block', 'Inline', 'Common'); $manager->addModule($structural_module); $formatting_module = new HTMLPurifier_HTMLModule(); $formatting_module->name = 'Formatting'; - $formatting_module->addElement('em', true, 'Inline', 'Inline', 'Common'); + $formatting_module->addElement('em', 'Inline', 'Inline', 'Common'); $manager->addModule($formatting_module); + $unsafe_module = new HTMLPurifier_HTMLModule(); + $unsafe_module->name = 'Unsafe'; + $unsafe_module->safe = false; + $unsafe_module->addElement('div', 'Block', 'Flow'); + $manager->addModule($unsafe_module); + $config = HTMLPurifier_Config::createDefault(); $config->set('HTML', 'Trusted', false); $config->set('HTML', 'CustomDoctype', 'Blank'); @@ -45,7 +50,6 @@ class HTMLPurifier_HTMLModuleManagerTest extends HTMLPurifier_Harness $p->content_model = 'em | #PCDATA'; $p->content_model_type = 'optional'; $p->descendants_are_inline = true; - $p->safe = true; $em = new HTMLPurifier_ElementDef(); $em->attr['class'] = $attrdef_nmtokens; @@ -53,7 +57,6 @@ class HTMLPurifier_HTMLModuleManagerTest extends HTMLPurifier_Harness $em->content_model = 'em | #PCDATA'; $em->content_model_type = 'optional'; $em->descendants_are_inline = true; - $em->safe = true; $this->assertEqual( array('p' => $p, 'em' => $em), @@ -67,7 +70,6 @@ class HTMLPurifier_HTMLModuleManagerTest extends HTMLPurifier_Harness $div->content_model = 'p | div | em | #PCDATA'; $div->content_model_type = 'optional'; $div->descendants_are_inline = false; - $div->safe = false; $this->assertEqual($div, $manager->getElement('div', true)); diff --git a/tests/HTMLPurifier/HTMLModuleTest.php b/tests/HTMLPurifier/HTMLModuleTest.php index 06d7cdd8..ac88df0e 100644 --- a/tests/HTMLPurifier/HTMLModuleTest.php +++ b/tests/HTMLPurifier/HTMLModuleTest.php @@ -19,7 +19,7 @@ class HTMLPurifier_HTMLModuleTest extends HTMLPurifier_Harness $module = new HTMLPurifier_HTMLModule(); $def =& $module->addElement( - 'a', true, 'Inline', 'Optional: #PCDATA', array('Common'), + 'a', 'Inline', 'Optional: #PCDATA', array('Common'), array( 'href' => 'URI' ) @@ -27,7 +27,6 @@ class HTMLPurifier_HTMLModuleTest extends HTMLPurifier_Harness $module2 = new HTMLPurifier_HTMLModule(); $def2 = new HTMLPurifier_ElementDef(); - $def2->safe = true; $def2->content_model = '#PCDATA'; $def2->content_model_type = 'optional'; $def2->attr = array(