diff --git a/library/HTMLPurifier/AttrCollections.php b/library/HTMLPurifier/AttrCollections.php index 018efb19..9e056626 100644 --- a/library/HTMLPurifier/AttrCollections.php +++ b/library/HTMLPurifier/AttrCollections.php @@ -63,6 +63,7 @@ class HTMLPurifier_AttrCollections if (isset($seen[$merge[$i]])) continue; $seen[$merge[$i]] = true; // foreach attribute of the inclusion, copy it over + if (!isset($this->info[$merge[$i]])) continue; foreach ($this->info[$merge[$i]] as $key => $value) { if (isset($attr[$key])) continue; // also catches more inclusions $attr[$key] = $value; diff --git a/library/HTMLPurifier/HTMLDefinition.php b/library/HTMLPurifier/HTMLDefinition.php index 0a99f58a..4a1d5a04 100644 --- a/library/HTMLPurifier/HTMLDefinition.php +++ b/library/HTMLPurifier/HTMLDefinition.php @@ -7,48 +7,63 @@ require_once 'HTMLPurifier/HTMLModuleManager.php'; // outside of the HTML or Attr namespaces HTMLPurifier_ConfigSchema::define( - 'HTML', 'BlockWrapper', 'p', 'string', - 'String name of element to wrap inline elements that are inside a block '. - 'context. This only occurs in the children of blockquote in strict mode. '. - 'Example: by default value, <blockquote>Foo</blockquote> '. - 'would become <blockquote><p>Foo</p></blockquote>. The '. - '<p> tags can be replaced '. - 'with whatever you desire, as long as it is a block level element. '. - 'This directive has been available since 1.3.0.' -); + 'HTML', 'BlockWrapper', 'p', 'string', ' +

+ String name of element to wrap inline elements that are inside a block + context. This only occurs in the children of blockquote in strict mode. +

+

+ Example: by default value, + <blockquote>Foo</blockquote> would become + <blockquote><p>Foo</p></blockquote>. + The <p> tags can be replaced with whatever you desire, + as long as it is a block level element. 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.' -); + '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.' -); + '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.' -); + '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, diff --git a/library/HTMLPurifier/HTMLModuleManager.php b/library/HTMLPurifier/HTMLModuleManager.php index bfce9c7c..cad46136 100644 --- a/library/HTMLPurifier/HTMLModuleManager.php +++ b/library/HTMLPurifier/HTMLModuleManager.php @@ -53,6 +53,43 @@ HTMLPurifier_ConfigSchema::define( 'will be used. This directive has been available since 1.7.0.' ); +HTMLPurifier_ConfigSchema::define( + 'HTML', 'AllowedModules', null, 'lookup/null', ' +

+ A doctype comes with a set of usual modules to use. Without having + to mucking about with the doctypes, you can quickly activate or + disable these modules by specifying which modules you wish to allow + with this directive. This is most useful for unit testing specific + modules, although end users may find it useful for their own ends. +

+

+ If you specify a module that does not exist, the manager will silently + fail to use it, so be careful! User-defined modules are not affected + by this directive. Modules defined in %HTML.CoreModules are not + affected by this directive. This directive has been available since 1.7.0. +

+'); + +HTMLPurifier_ConfigSchema::define( + 'HTML', 'CoreModules', array( + 'Structure' => true, + 'Text' => true, + 'Hypertext' => true, + 'List' => true, + 'NonXMLCommonAttributes' => true, + 'XMLCommonAttributes' => true, + 'CommonAttributes' => true + ), 'lookup', ' +

+ Certain modularized doctypes (XHTML, namely), have certain modules + that must be included for the doctype to be an conforming document + type: put those modules here. By default, XHTML\'s core modules + are used. You can set this to a blank array to disable core module + protection, but this is not recommended. This directive has been + available since 1.7.0. +

+'); + class HTMLPurifier_HTMLModuleManager { @@ -254,6 +291,17 @@ class HTMLPurifier_HTMLModuleManager $doctype = $this->doctypes->make($config); $modules = $doctype->modules; + // take out the default modules that aren't allowed + $lookup = $config->get('HTML', 'AllowedModules'); + $special_cases = $config->get('HTML', 'CoreModules'); + + if (is_array($lookup)) { + foreach ($modules as $k => $m) { + if (isset($special_cases[$m])) continue; + if (!isset($lookup[$m])) unset($modules[$k]); + } + } + // merge in custom modules $modules = array_merge($modules, $this->userModules); @@ -291,7 +339,6 @@ class HTMLPurifier_HTMLModuleManager // the module in your custom doctype should be sufficient $this->modules ); - } /** diff --git a/tests/HTMLPurifier/AttrCollectionsTest.php b/tests/HTMLPurifier/AttrCollectionsTest.php index f43ee90e..c121fd50 100644 --- a/tests/HTMLPurifier/AttrCollectionsTest.php +++ b/tests/HTMLPurifier/AttrCollectionsTest.php @@ -70,7 +70,7 @@ class HTMLPurifier_AttrCollectionsTest extends UnitTestCase $types = new HTMLPurifier_AttrTypesMock($this); $collections = new HTMLPurifier_AttrCollections($types, array()); $collections->info = array( - 'Core' => array(0 => array('Inclusion'), 'attr-original' => 'Type'), + 'Core' => array(0 => array('Inclusion', 'Undefined'), 'attr-original' => 'Type'), 'Inclusion' => array(0 => array('SubInclusion'), 'attr' => 'Type'), 'SubInclusion' => array('attr2' => 'Type') ); diff --git a/tests/HTMLPurifier/HTMLModule/BdoTest.php b/tests/HTMLPurifier/HTMLModule/BdoTest.php index b2fcc1c8..51a74b3e 100644 --- a/tests/HTMLPurifier/HTMLModule/BdoTest.php +++ b/tests/HTMLPurifier/HTMLModule/BdoTest.php @@ -7,21 +7,15 @@ class HTMLPurifier_HTMLModule_BdoTest extends HTMLPurifier_HTMLModuleHarness function test() { + $this->setupScaffold('Bdo'); + // max $this->assertResult( ' - + #PCDATA Inline - ', true, array('Attr.EnableID' => true) + ' ); // min diff --git a/tests/HTMLPurifier/HTMLModule/EditTest.php b/tests/HTMLPurifier/HTMLModule/EditTest.php index 3acf7917..e6fe8c44 100644 --- a/tests/HTMLPurifier/HTMLModule/EditTest.php +++ b/tests/HTMLPurifier/HTMLModule/EditTest.php @@ -7,21 +7,23 @@ class HTMLPurifier_HTMLModule_EditTest extends HTMLPurifier_HTMLModuleHarness function test() { + $this->setupScaffold('Edit'); + // max $this->assertResult( ' - + #PCDATA - + #PCDATA
- + #PCDATA
- + #PCDATA
' diff --git a/tests/HTMLPurifier/HTMLModule/HypertextTest.php b/tests/HTMLPurifier/HTMLModule/HypertextTest.php index 41d364dc..11d316cc 100644 --- a/tests/HTMLPurifier/HTMLModule/HypertextTest.php +++ b/tests/HTMLPurifier/HTMLModule/HypertextTest.php @@ -7,6 +7,11 @@ class HTMLPurifier_HTMLModule_HypertextTest extends HTMLPurifier_HTMLModuleHarne function test() { + $this->setupScaffold('Hypertext', array( + 'Attr.AllowedRel' => 'nofollow', + 'Attr.AllowedRev' => 'index' + )); + // max $this->assertResult( ' @@ -14,13 +19,11 @@ class HTMLPurifier_HTMLModule_HypertextTest extends HTMLPurifier_HTMLModuleHarne href="http://www.example.com/" rel="nofollow" rev="index" + ac:common="true" > #PCDATA Inline - ', true, array( - 'Attr.AllowedRel' => 'nofollow', - 'Attr.AllowedRev' => 'index' - ) + ', true ); // invalid children diff --git a/tests/HTMLPurifier/HTMLModule/ImageTest.php b/tests/HTMLPurifier/HTMLModule/ImageTest.php index 3156af8a..11178ff5 100644 --- a/tests/HTMLPurifier/HTMLModule/ImageTest.php +++ b/tests/HTMLPurifier/HTMLModule/ImageTest.php @@ -7,6 +7,8 @@ class HTMLPurifier_HTMLModule_ImageTest extends HTMLPurifier_HTMLModuleHarness function test() { + $this->setupScaffold('Image'); + // max $this->assertResult( ' @@ -16,6 +18,7 @@ class HTMLPurifier_HTMLModule_ImageTest extends HTMLPurifier_HTMLModuleHarness longdesc="example.description.txt" height="42" width="42" + ac:common="yes" /> ' ); diff --git a/tests/HTMLPurifier/HTMLModule/LegacyTest.php b/tests/HTMLPurifier/HTMLModule/LegacyTest.php index 8d345552..5f8ca364 100644 --- a/tests/HTMLPurifier/HTMLModule/LegacyTest.php +++ b/tests/HTMLPurifier/HTMLModule/LegacyTest.php @@ -7,12 +7,14 @@ class HTMLPurifier_HTMLModule_LegacyTest extends HTMLPurifier_HTMLModuleHarness function test() { + $this->setupScaffold('Legacy'); + // max $this->assertResult( ' - Text - Text - Text + Text + Text + Text ' ); diff --git a/tests/HTMLPurifier/HTMLModuleHarness.php b/tests/HTMLPurifier/HTMLModuleHarness.php index 1f60f435..70dc8ed5 100644 --- a/tests/HTMLPurifier/HTMLModuleHarness.php +++ b/tests/HTMLPurifier/HTMLModuleHarness.php @@ -9,6 +9,27 @@ class HTMLPurifier_HTMLModuleHarness extends HTMLPurifier_StrategyHarness parent::setup(); $this->obj = new HTMLPurifier_Strategy_Core(); } + + function setupScaffold($module, $config = array()) { + + $this->config = HTMLPurifier_Config::create($config); + $this->config->set('HTML', 'AllowedModules', $module); + $def =& $this->config->getHTMLDefinition(true); + $def->manager->addModule(new HTMLPurifier_HTMLModuleHarness_Scaffold()); + + } +} + +/** + * Special module that defines scaffolding for easy unit testing + */ +class HTMLPurifier_HTMLModuleHarness_Scaffold extends HTMLPurifier_HTMLModule +{ + var $name = 'Scaffold'; + var $attr_collections = array( + 'Common' => array('ac:common' => 'Text'), + 'Core' => array('ac:core' => 'Text') + ); } ?> \ No newline at end of file diff --git a/tests/HTMLPurifier/HTMLModuleManagerTest.php b/tests/HTMLPurifier/HTMLModuleManagerTest.php index aa695a98..a8581bfe 100644 --- a/tests/HTMLPurifier/HTMLModuleManagerTest.php +++ b/tests/HTMLPurifier/HTMLModuleManagerTest.php @@ -72,6 +72,34 @@ class HTMLPurifier_HTMLModuleManagerTest extends UnitTestCase } + function testAllowedModules() { + + $manager = new HTMLPurifier_HTMLModuleManager(); + $manager->doctypes->register( + 'Fantasy Inventory 1.0', true, + array('Weapons', 'Magic') + ); + + // register these modules so it doesn't blow up + $weapons_module = new HTMLPurifier_HTMLModule(); + $weapons_module->name = 'Weapons'; + $manager->registerModule($weapons_module); + + $magic_module = new HTMLPurifier_HTMLModule(); + $magic_module->name = 'Magic'; + $manager->registerModule($magic_module); + + $config = HTMLPurifier_Config::create(array( + 'HTML.Doctype' => 'Fantasy Inventory 1.0', + 'HTML.AllowedModules' => 'Weapons' + )); + $manager->setup($config); + + $this->assertTrue( isset($manager->modules['Weapons'])); + $this->assertFalse(isset($manager->modules['Magic'])); + + } + } ?> \ No newline at end of file diff --git a/tests/HTMLPurifier/Harness.php b/tests/HTMLPurifier/Harness.php index 237105d1..efb821f0 100644 --- a/tests/HTMLPurifier/Harness.php +++ b/tests/HTMLPurifier/Harness.php @@ -42,6 +42,11 @@ class HTMLPurifier_Harness extends UnitTestCase */ var $generator; + /** + * Default config to fall back on if no config is available + */ + var $config; + function HTMLPurifier_Harness() { $this->lexer = new HTMLPurifier_Lexer_DirectLex(); $this->generator = new HTMLPurifier_Generator(); @@ -52,22 +57,24 @@ class HTMLPurifier_Harness extends UnitTestCase * Asserts a specific result from a one parameter + config/context function * @param $input Input parameter * @param $expect Expectation - * @param $config_array Configuration array in form of - * Namespace.Directive => Value or an actual config - * object. + * @param $config Configuration array in form of Ns.Directive => Value. + * Has no effect if $this->config is set. * @param $context_array Context array in form of Key => Value or an actual * context object. */ function assertResult($input, $expect = true, - $config_array = array(), $context_array = array() + $config_array = false, $context_array = array() ) { - // setup config object - $config = HTMLPurifier_Config::createDefault(); - $config->loadArray($config_array); + // setup config + if ($this->config) { + $config = HTMLPurifier_Config::create($this->config); + } else { + $config = HTMLPurifier_Config::create($config_array); + } // setup context object. Note that we are operating on a copy of it! - // We will extend the test harness to allow you to do post-tests + // When necessary, extend the test harness to allow post-tests // on the context object $context = new HTMLPurifier_Context(); $context->loadArray($context_array);