From 14aeafcf22da1e733ffcfd5de721a37e184c6ea1 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Thu, 31 Aug 2006 20:33:07 +0000 Subject: [PATCH] De-singleton-ized (HTML|CSS)Definition, tying them to the configuration and making them more amenable to changes. git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@350 48356398-32a2-884e-a903-53898d9a118a --- NEWS | 1 + TODO | 1 - library/HTMLPurifier/AttrDef/Border.php | 4 +-- library/HTMLPurifier/AttrDef/CSS.php | 2 +- library/HTMLPurifier/AttrDef/Font.php | 4 +-- library/HTMLPurifier/AttrDef/ListStyle.php | 4 +-- library/HTMLPurifier/CSSDefinition.php | 25 +++------------ library/HTMLPurifier/Config.php | 32 +++++++++++++++++++ library/HTMLPurifier/ConfigDef.php | 20 ++++++------ library/HTMLPurifier/HTMLDefinition.php | 21 +----------- library/HTMLPurifier/Strategy/FixNesting.php | 17 ++++------ .../HTMLPurifier/Strategy/MakeWellFormed.php | 18 ++++------- .../Strategy/RemoveForeignElements.php | 23 +++++-------- .../Strategy/ValidateAttributes.php | 20 +++++------- tests/HTMLPurifier/AttrDef/BorderTest.php | 2 +- tests/HTMLPurifier/AttrDef/FontTest.php | 2 +- tests/HTMLPurifier/AttrDef/ListStyleTest.php | 2 +- 17 files changed, 88 insertions(+), 110 deletions(-) diff --git a/NEWS b/NEWS index c889eae2..c3cf3d6d 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier - Shorthand CSS properties implemented: font, border, background, list-style - Basic color keywords translated into hexadecimal values - Table CSS properties implemented +- (HTML|CSS)Definition de-singleton-ized 1.0.0beta, released 2006-08-16 - First public release, most functionality implemented. Notable omissions are: diff --git a/TODO b/TODO index 9ea3f1ff..fa18414c 100644 --- a/TODO +++ b/TODO @@ -8,7 +8,6 @@ Ongoing 1.0 release - Lossy alternate character encoding support (characters not in the encoding will get silently dropped). - - Revise (HTML|CSS)Definition and Config relationship (groundwork for 2.0) 1.1 release - Directive documentation generation diff --git a/library/HTMLPurifier/AttrDef/Border.php b/library/HTMLPurifier/AttrDef/Border.php index f737cb1a..ecd016a3 100644 --- a/library/HTMLPurifier/AttrDef/Border.php +++ b/library/HTMLPurifier/AttrDef/Border.php @@ -13,8 +13,8 @@ class HTMLPurifier_AttrDef_Border extends HTMLPurifier_AttrDef */ var $info = array(); - function HTMLPurifier_AttrDef_Border() { - $def = HTMLPurifier_CSSDefinition::instance(); + function HTMLPurifier_AttrDef_Border($config) { + $def = $config->getCSSDefinition(); $this->info['border-width'] = $def->info['border-width']; $this->info['border-style'] = $def->info['border-style']; $this->info['border-top-color'] = $def->info['border-top-color']; diff --git a/library/HTMLPurifier/AttrDef/CSS.php b/library/HTMLPurifier/AttrDef/CSS.php index c5314067..ce1b791c 100644 --- a/library/HTMLPurifier/AttrDef/CSS.php +++ b/library/HTMLPurifier/AttrDef/CSS.php @@ -16,7 +16,7 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef $css = $this->parseCDATA($css); - $definition = HTMLPurifier_CSSDefinition::instance(); + $definition = $config->getCSSDefinition(); // we're going to break the spec and explode by semicolons. // This is because semicolon rarely appears in escaped form diff --git a/library/HTMLPurifier/AttrDef/Font.php b/library/HTMLPurifier/AttrDef/Font.php index 4c987dcb..7357e282 100644 --- a/library/HTMLPurifier/AttrDef/Font.php +++ b/library/HTMLPurifier/AttrDef/Font.php @@ -30,8 +30,8 @@ class HTMLPurifier_AttrDef_Font extends HTMLPurifier_AttrDef 'status-bar' => true ); - function HTMLPurifier_AttrDef_Font() { - $def = HTMLPurifier_CSSDefinition::instance(); + function HTMLPurifier_AttrDef_Font($config) { + $def = $config->getCSSDefinition(); $this->info['font-style'] = $def->info['font-style']; $this->info['font-variant'] = $def->info['font-variant']; $this->info['font-weight'] = $def->info['font-weight']; diff --git a/library/HTMLPurifier/AttrDef/ListStyle.php b/library/HTMLPurifier/AttrDef/ListStyle.php index a310db2a..a2df527a 100644 --- a/library/HTMLPurifier/AttrDef/ListStyle.php +++ b/library/HTMLPurifier/AttrDef/ListStyle.php @@ -16,8 +16,8 @@ class HTMLPurifier_AttrDef_ListStyle extends HTMLPurifier_AttrDef */ var $info; - function HTMLPurifier_AttrDef_ListStyle() { - $def = HTMLPurifier_CSSDefinition::instance(); + function HTMLPurifier_AttrDef_ListStyle($config) { + $def = $config->getCSSDefinition(); $this->info['list-style-type'] = $def->info['list-style-type']; $this->info['list-style-position'] = $def->info['list-style-position']; } diff --git a/library/HTMLPurifier/CSSDefinition.php b/library/HTMLPurifier/CSSDefinition.php index 6f982bfa..5647c4b7 100644 --- a/library/HTMLPurifier/CSSDefinition.php +++ b/library/HTMLPurifier/CSSDefinition.php @@ -24,27 +24,10 @@ class HTMLPurifier_CSSDefinition */ var $info = array(); - /** - * Returns sole instance of this definition. - * @param $prototype Optional prototype you may pass in to overload - * the sole instance. Good for replacing an instance of - * the object with your own, custom object. - */ - function &instance($prototype = null) { - static $instance = null; - if ($prototype) { - $instance = $prototype; - } elseif (!$instance) { - $instance = new HTMLPurifier_CSSDefinition(); - $instance->setup(); - } - return $instance; - } - /** * Constructs the info array. The meat of this class. */ - function setup() { + function setup($config) { $this->info['text-align'] = new HTMLPurifier_AttrDef_Enum( array('left', 'right', 'center', 'justify'), false); @@ -74,7 +57,7 @@ class HTMLPurifier_CSSDefinition array('disc', 'circle', 'square', 'decimal', 'lower-roman', 'upper-roman', 'lower-alpha', 'upper-alpha'), false); - $this->info['list-style'] = new HTMLPurifier_AttrDef_ListStyle(); + $this->info['list-style'] = new HTMLPurifier_AttrDef_ListStyle($config); $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( array('capitalize', 'uppercase', 'lowercase', 'none'), false); @@ -183,14 +166,14 @@ class HTMLPurifier_CSSDefinition // MUST be called after other font properties, as it references // a CSSDefinition object - $this->info['font'] = new HTMLPurifier_AttrDef_Font(); + $this->info['font'] = new HTMLPurifier_AttrDef_Font($config); // same here $this->info['border'] = $this->info['border-bottom'] = $this->info['border-top'] = $this->info['border-left'] = - $this->info['border-right'] = new HTMLPurifier_AttrDef_Border(); + $this->info['border-right'] = new HTMLPurifier_AttrDef_Border($config); $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(array( 'collapse', 'seperate')); diff --git a/library/HTMLPurifier/Config.php b/library/HTMLPurifier/Config.php index 52a39362..040f0b3e 100644 --- a/library/HTMLPurifier/Config.php +++ b/library/HTMLPurifier/Config.php @@ -25,6 +25,16 @@ class HTMLPurifier_Config */ var $def; + /** + * Instance of HTMLPurifier_HTMLDefinition + */ + var $html_definition; + + /** + * Instance of HTMLPurifier_CSSDefinition + */ + var $css_definition; + /** * @param $definition HTMLPurifier_ConfigDef that defines what directives * are allowed. @@ -92,6 +102,28 @@ class HTMLPurifier_Config $this->conf[$namespace][$key] = $value; } + /** + * Retrieves a copy of the HTML definition. + */ + function getHTMLDefinition() { + if ($this->html_definition === null) { + $this->html_definition = new HTMLPurifier_HTMLDefinition(); + $this->html_definition->setup($this); + } + return $this->html_definition; + } + + /** + * Retrieves a copy of the CSS definition + */ + function getCSSDefinition() { + if ($this->css_definition === null) { + $this->css_definition = new HTMLPurifier_CSSDefinition(); + $this->css_definition->setup($this); + } + return $this->css_definition; + } + } ?> \ No newline at end of file diff --git a/library/HTMLPurifier/ConfigDef.php b/library/HTMLPurifier/ConfigDef.php index 3607450a..b19e97a5 100644 --- a/library/HTMLPurifier/ConfigDef.php +++ b/library/HTMLPurifier/ConfigDef.php @@ -26,15 +26,15 @@ class HTMLPurifier_ConfigDef { * Lookup table of allowed types. */ var $types = array( - 'string' => true, - 'istring' => true, - 'int' => true, - 'float' => true, - 'bool' => true, - 'lookup' => true, - 'list' => true, - 'hash' => true, - 'mixed' => true + 'string' => true, + 'istring' => true, + 'int' => true, + 'float' => true, + 'bool' => true, + 'lookup' => true, + 'list' => true, + 'hash' => true, + 'mixed' => true ); /** @@ -44,6 +44,8 @@ class HTMLPurifier_ConfigDef { $this->defineNamespace('Core', 'Core features that are always available.'); $this->defineNamespace('Attr', 'Features regarding attribute validation.'); $this->defineNamespace('URI', 'Features regarding Uniform Resource Identifiers.'); + $this->defineNamespace('HTML', 'Configuration regarding allowed HTML.'); + $this->defineNamespace('CSS', 'Configuration regarding allowed CSS.'); } /** diff --git a/library/HTMLPurifier/HTMLDefinition.php b/library/HTMLPurifier/HTMLDefinition.php index 709663e4..4d261526 100644 --- a/library/HTMLPurifier/HTMLDefinition.php +++ b/library/HTMLPurifier/HTMLDefinition.php @@ -78,29 +78,10 @@ class HTMLPurifier_HTMLDefinition */ var $info_attr_transform_post = array(); - /** - * Retrieve sole instance of definition object. - * @param $prototype Optional prototype to overload instance with. - * @warning Prototype is not passed by reference, so in order to get - * a copy of the real one, you'll have to destroy your copy - * and use instance() to get it. We strongly recommend modifying - * the default returned definition instead. - */ - function &instance($prototype = null) { - static $instance = null; - if ($prototype) { - $instance = $prototype; - } elseif (!$instance) { - $instance = new HTMLPurifier_HTMLDefinition(); - $instance->setup(); - } - return $instance; - } - /** * Initializes the definition, the meat of the class. */ - function setup() { + function setup($config) { // emulates the structure of the DTD // these are condensed, however, with bad stuff taken out diff --git a/library/HTMLPurifier/Strategy/FixNesting.php b/library/HTMLPurifier/Strategy/FixNesting.php index 1585147e..f682ea89 100644 --- a/library/HTMLPurifier/Strategy/FixNesting.php +++ b/library/HTMLPurifier/Strategy/FixNesting.php @@ -34,21 +34,18 @@ require_once 'HTMLPurifier/HTMLDefinition.php'; class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy { - var $definition; - - function HTMLPurifier_Strategy_FixNesting() { - $this->definition = HTMLPurifier_HTMLDefinition::instance(); - } - function execute($tokens, $config) { //####################################################################// // Pre-processing + // get a copy of the HTML definition + $definition = $config->getHTMLDefinition(); + // insert implicit "parent" node, will be removed at end. // ! we might want to move this to configuration // DEFINITION CALL - $parent_name = $this->definition->info_parent; + $parent_name = $definition->info_parent; array_unshift($tokens, new HTMLPurifier_Token_Start($parent_name)); $tokens[] = new HTMLPurifier_Token_End($parent_name); @@ -104,7 +101,7 @@ class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy if ($count = count($stack)) { $parent_index = $stack[$count-1]; $parent_name = $tokens[$parent_index]->name; - $parent_def = $this->definition->info[$parent_name]; + $parent_def = $definition->info[$parent_name]; } else { // unknown info, it won't be used anyway $parent_index = $parent_name = $parent_def = null; @@ -143,7 +140,7 @@ class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy $result = false; } else { // DEFINITION CALL - $def = $this->definition->info[$tokens[$i]->name]; + $def = $definition->info[$tokens[$i]->name]; $child_def = $def->child; // have DTD child def validate children @@ -233,7 +230,7 @@ class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy array_pop($stack); // pop an exclusion lookup off exclusion stack if // we ended node and that node had exclusions - if ($this->definition->info[$tokens[$i]->name]->excludes) { + if ($definition->info[$tokens[$i]->name]->excludes) { array_pop($exclude_stack); } } diff --git a/library/HTMLPurifier/Strategy/MakeWellFormed.php b/library/HTMLPurifier/Strategy/MakeWellFormed.php index e3ebfcf8..d82205bb 100644 --- a/library/HTMLPurifier/Strategy/MakeWellFormed.php +++ b/library/HTMLPurifier/Strategy/MakeWellFormed.php @@ -10,15 +10,9 @@ require_once 'HTMLPurifier/Generator.php'; class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy { - var $generator; - var $definition; - - function HTMLPurifier_Strategy_MakeWellFormed() { - $this->generator = new HTMLPurifier_Generator(); - $this->definition = HTMLPurifier_HTMLDefinition::instance(); - } - function execute($tokens, $config) { + $definition = $config->getHTMLDefinition(); + $generator = new HTMLPurifier_Generator(); $result = array(); $current_nesting = array(); $escape_invalid_tags = $config->get('Core', 'EscapeInvalidTags'); @@ -29,7 +23,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy } // DEFINITION CALL - $info = $this->definition->info[$token->name]->child; + $info = $definition->info[$token->name]->child; // test if it claims to be a start tag but is empty if ($info->type == 'empty' && @@ -66,7 +60,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy $parent = array_pop($current_nesting); $parent_name = $parent->name; - $parent_info = $this->definition->info[$parent_name]; + $parent_info = $definition->info[$parent_name]; if (isset($parent_info->auto_close[$token->name])) { $result[] = new HTMLPurifier_Token_End($parent_name); @@ -92,7 +86,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy if (empty($current_nesting)) { if ($escape_invalid_tags) { $result[] = new HTMLPurifier_Token_Text( - $this->generator->generateFromToken($token, $config) + $generator->generateFromToken($token, $config) ); } continue; @@ -129,7 +123,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy if ($skipped_tags === false) { if ($escape_invalid_tags) { $result[] = new HTMLPurifier_Token_Text( - $this->generator->generateFromToken($token, $config) + $generator->generateFromToken($token, $config) ); } continue; diff --git a/library/HTMLPurifier/Strategy/RemoveForeignElements.php b/library/HTMLPurifier/Strategy/RemoveForeignElements.php index 637642a8..1d9f7ae5 100644 --- a/library/HTMLPurifier/Strategy/RemoveForeignElements.php +++ b/library/HTMLPurifier/Strategy/RemoveForeignElements.php @@ -16,35 +16,28 @@ require_once 'HTMLPurifier/TagTransform.php'; class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy { - var $generator; - var $definition; - - function HTMLPurifier_Strategy_RemoveForeignElements() { - $this->generator = new HTMLPurifier_Generator(); - $this->definition = HTMLPurifier_HTMLDefinition::instance(); - } - function execute($tokens, $config) { + $definition = $config->getHTMLDefinition(); + $generator = new HTMLPurifier_Generator(); $result = array(); $escape_invalid_tags = $config->get('Core', 'EscapeInvalidTags'); foreach($tokens as $token) { if (!empty( $token->is_tag )) { // DEFINITION CALL - if (isset($this->definition->info[$token->name])) { + if (isset($definition->info[$token->name])) { // leave untouched } elseif ( - isset($this->definition->info_tag_transform[$token->name]) + isset($definition->info_tag_transform[$token->name]) ) { // there is a transformation for this tag // DEFINITION CALL - $token = $this-> - definition-> - info_tag_transform[$token->name]-> - transform($token); + $token = $definition-> + info_tag_transform[$token->name]-> + transform($token); } elseif ($escape_invalid_tags) { // invalid tag, generate HTML and insert in $token = new HTMLPurifier_Token_Text( - $this->generator->generateFromToken($token, $config) + $generator->generateFromToken($token, $config) ); } else { continue; diff --git a/library/HTMLPurifier/Strategy/ValidateAttributes.php b/library/HTMLPurifier/Strategy/ValidateAttributes.php index dc447ce0..5f73d1dc 100644 --- a/library/HTMLPurifier/Strategy/ValidateAttributes.php +++ b/library/HTMLPurifier/Strategy/ValidateAttributes.php @@ -17,14 +17,10 @@ HTMLPurifier_ConfigDef::define( class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy { - var $definition; - - function HTMLPurifier_Strategy_ValidateAttributes() { - $this->definition = HTMLPurifier_HTMLDefinition::instance(); - } - function execute($tokens, $config) { + $definition = $config->getHTMLDefinition(); + // setup StrategyContext $context = new HTMLPurifier_AttrContext(); @@ -36,7 +32,7 @@ class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy // create alias to global definition array, see also $defs // DEFINITION CALL - $d_defs = $this->definition->info_global_attr; + $d_defs = $definition->info_global_attr; foreach ($tokens as $key => $token) { @@ -50,14 +46,14 @@ class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy // do global transformations (pre) // ex. to // DEFINITION CALL - foreach ($this->definition->info_attr_transform_pre as $transform) { + foreach ($definition->info_attr_transform_pre as $transform) { $attr = $transform->transform($attr, $config); } // do local transformations only applicable to this element (pre) // ex.

to

// DEFINITION CALL - foreach ($this->definition->info[$token->name]->attr_transform_pre + foreach ($definition->info[$token->name]->attr_transform_pre as $transform ) { $attr = $transform->transform($attr, $config); @@ -66,7 +62,7 @@ class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy // create alias to this element's attribute definition array, see // also $d_defs (global attribute definition array) // DEFINITION CALL - $defs = $this->definition->info[$token->name]->attr; + $defs = $definition->info[$token->name]->attr; // iterate through all the attribute keypairs // Watch out for name collisions: $key has previously been used @@ -116,10 +112,10 @@ class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy } // post transforms - foreach ($this->definition->info_attr_transform_post as $transform) { + foreach ($definition->info_attr_transform_post as $transform) { $attr = $transform->transform($attr, $config); } - foreach ($this->definition->info[$token->name]->attr_transform_post as $transform) { + foreach ($definition->info[$token->name]->attr_transform_post as $transform) { $attr = $transform->transform($attr, $config); } diff --git a/tests/HTMLPurifier/AttrDef/BorderTest.php b/tests/HTMLPurifier/AttrDef/BorderTest.php index 54d64457..7a8153d5 100644 --- a/tests/HTMLPurifier/AttrDef/BorderTest.php +++ b/tests/HTMLPurifier/AttrDef/BorderTest.php @@ -7,7 +7,7 @@ class HTMLPurifier_AttrDef_BorderTest extends HTMLPurifier_AttrDef_PixelsTest function test() { - $this->def = new HTMLPurifier_AttrDef_Border(); + $this->def = new HTMLPurifier_AttrDef_Border(HTMLPurifier_Config::createDefault()); $this->assertDef('thick solid red', 'thick solid #F00'); $this->assertDef('thick solid'); diff --git a/tests/HTMLPurifier/AttrDef/FontTest.php b/tests/HTMLPurifier/AttrDef/FontTest.php index 18ce3bae..49b3652c 100644 --- a/tests/HTMLPurifier/AttrDef/FontTest.php +++ b/tests/HTMLPurifier/AttrDef/FontTest.php @@ -8,7 +8,7 @@ class HTMLPurifier_AttrDef_FontTest extends HTMLPurifier_AttrDefHarness function test() { - $this->def = new HTMLPurifier_AttrDef_Font(); + $this->def = new HTMLPurifier_AttrDef_Font(HTMLPurifier_Config::createDefault()); // hodgepodge of usage cases from W3C spec, but " -> ' $this->assertDef('12px/14px sans-serif'); diff --git a/tests/HTMLPurifier/AttrDef/ListStyleTest.php b/tests/HTMLPurifier/AttrDef/ListStyleTest.php index 3ce74af5..a12080f8 100644 --- a/tests/HTMLPurifier/AttrDef/ListStyleTest.php +++ b/tests/HTMLPurifier/AttrDef/ListStyleTest.php @@ -8,7 +8,7 @@ class HTMLPurifier_AttrDef_ListStyleTest extends HTMLPurifier_AttrDefHarness function test() { - $this->def = new HTMLPurifier_AttrDef_ListStyle(); + $this->def = new HTMLPurifier_AttrDef_ListStyle(HTMLPurifier_Config::createDefault()); $this->assertDef('lower-alpha'); $this->assertDef('upper-roman inside');