2 The Modularization of HTMLDefinition in HTML Purifier
4 WARNING: This document was drafted before the implementation of this
5 system, and some implementation details may have evolved over time.
7 HTML Purifier uses the modularization of XHTML
8 <http://www.w3.org/TR/xhtml-modularization/> to organize the internals
9 of HTMLDefinition into a more manageable and extensible fashion. Rather
10 than have one super-object, HTMLDefinition is split into HTMLModules,
11 each of which are responsible for defining elements, their attributes,
12 and other properties (for a more indepth coverage, see
13 /library/HTMLPurifier/HTMLModule.php's docblock comments). These modules
14 are managed by HTMLModuleManager.
16 Modules that we don't support but could support are:
19 o 5.6.1. Basic Tables Module [?]
20 * 5.8. Client-side Image Map Module [?]
21 * 5.9. Server-side Image Map Module [?]
22 * 5.12. Target Module [?]
23 * 5.21. Name Identification Module [deprecated]
25 These modules would be implemented as "unsafe":
28 o 5.2.1. Structure Module
31 o 5.5.1. Basic Forms Module
36 * 5.14. Intrinsic Events Module
37 * 5.15. Metainformation Module
38 * 5.16. Scripting Module
39 * 5.17. Style Sheet Module
43 We will not be using W3C's XML Schemas or DTDs directly due to the lack
44 of robust tools for handling them (the main problem is that all the
45 current parsers are usually PHP 5 only and solely-validating, not
48 This system may be generalized and ported over for CSS.
50 == General Use-Case ==
52 The outwards API of HTMLDefinition has been largely preserved, not
53 only for backwards-compatibility but also by design. Instead,
54 HTMLDefinition can be retrieved "raw", in which it loads a structure
55 that closely resembles the modules of XHTML 1.1. This structure is very
56 dynamic, making it easy to make cascading changes to global content
57 sets or remove elements in bulk.
59 However, once HTML Purifier needs the actual definition, it retrieves
60 a finalized version of HTMLDefinition. The finalized definition involves
61 processing the modules into a form that it is optimized for multiple
62 calls. This final version is immutable and, even if editable, would
63 be extremely hard to change.
65 So, some code taking advantage of the XHTML modularization may look
69 $config = HTMLPurifier_Config::createDefault();
70 $def =& $config->getHTMLDefinition(true); // reference to raw
71 $def->addElement('marquee', 'Block', 'Flow', 'Common');
72 $purifier = new HTMLPurifier($config);
73 $purifier->purify($html); // now the definition is finalized
78 One of the nice features of HTMLDefinition is that piggy-backing off
79 of global attribute and content sets is extremely easy to do.
83 HTMLModule->elements[$element]->attr stores attribute information for the
84 specific attributes of $element. This is quite close to the final
85 API that HTML Purifier interfaces with, but there's an important
86 extra feature: attr may also contain a array with a member index zero.
89 HTMLModule->elements[$element]->attr[0] = array('AttrSet');
92 Rather than map the attribute key 0 to an array (which should be
93 an AttrDef), it defines a number of attribute collections that should
94 be merged into this elements attribute array.
96 Furthermore, the value of an attribute key, attribute value pair need
97 not be a fully fledged AttrDef object. They can also be a string, which
98 signifies a AttrDef that is looked up from a centralized registry
99 AttrTypes. This allows more concise attribute definitions that look
100 more like W3C's declarations, as well as offering a centralized point
101 for modifying the behavior of one attribute type. And, of course, the
102 old method of manually instantiating an AttrDef still works.
104 === Attribute Collections ===
106 Attribute collections are stored and processed in the AttrCollections
107 object, which is responsible for performing the inclusions signified
108 by the 0 index. These attribute collections, too, are mutable, by
109 using HTMLModule->attr_collections. You may add new attributes
110 to a collection or define an entirely new collection for your module's
111 use. Inclusions can also be cumulative.
113 Attribute collections allow us to get rid of so called "global attributes"
114 (which actually aren't so global).
116 === Content Models and ChildDef ===
118 An implementation of the above-mentioned attributes and attribute
119 collections was applied to the ChildDef system. HTML Purifier uses
120 a proprietary system called ChildDef for performance and flexibility
121 reasons, but this does not line up very well with W3C's notion of
122 regexps for defining the allowed children of an element.
124 HTMLPurifier->elements[$element]->content_model and
125 HTMLPurifier->elements[$element]->content_model_type store information
126 about the final ChildDef that will be stored in
127 HTMLPurifier->elements[$element]->child (we use a different variable
128 because the two forms are sufficiently different).
130 $content_model is an abstract, string representation of the internal
131 state of ChildDef, while $content_model_type is a string identifier
132 of which ChildDef subclass to instantiate. $content_model is processed
133 by substituting all content set identifiers (capitalized element names)
134 with their contents. It is then parsed and passed into the appropriate
135 ChildDef class, as defined by the ContentSets->getChildDef() or the
136 custom fallback HTMLModule->getChildDef() for custom child definitions
139 You'll need to use these facilities if you plan on referencing a content
140 set like "Inline" or "Block", and using them is recommended even if you're
141 not due to their conciseness.
143 A few notes on $content_model: it's structure can be as complicated
144 as you want, but the pipe symbol (|) is reserved for defining possible
145 choices, due to the content sets implementation. For example, a content
146 model that looks like:
148 "Inline -> Block -> a"
150 ...when the Inline content set is defined as "span | b" and the Block
151 content set is defined as "div | blockquote", will expand into:
153 "span | b -> div | blockquote -> a"
155 The custom HTMLModule->getChildDef() function will need to be able to
156 then feed this information to ChildDef in a usable manner.
160 Content sets can be altered using HTMLModule->content_sets, an associative
161 array of content set names to content set contents. If the content set
162 already exists, your values are appended on to it (great for, say,
163 registering the font tag as an inline element), otherwise it is
164 created. They are substituted into content_model.