4 require_once 'HTMLPurifier/HTMLModuleManager.php';
6 // this definition and its modules MUST NOT define configuration directives
7 // outside of the HTML or Attr namespaces
9 // will be superceded by more accurate doctype declaration schemes
10 HTMLPurifier_ConfigSchema
::define(
11 'HTML', 'Strict', false, 'bool',
12 'Determines whether or not to use Transitional (loose) or Strict rulesets. '.
13 'This directive has been available since 1.3.0.'
16 HTMLPurifier_ConfigSchema
::define(
17 'HTML', 'BlockWrapper', 'p', 'string',
18 'String name of element to wrap inline elements that are inside a block '.
19 'context. This only occurs in the children of blockquote in strict mode. '.
20 'Example: by default value, <code><blockquote>Foo</blockquote></code> '.
21 'would become <code><blockquote><p>Foo</p></blockquote></code>. The '.
22 '<code><p></code> tags can be replaced '.
23 'with whatever you desire, as long as it is a block level element. '.
24 'This directive has been available since 1.3.0.'
27 HTMLPurifier_ConfigSchema
::define(
28 'HTML', 'Parent', 'div', 'string',
29 'String name of element that HTML fragment passed to library will be '.
30 'inserted in. An interesting variation would be using span as the '.
31 'parent element, meaning that only inline tags would be allowed. '.
32 'This directive has been available since 1.3.0.'
35 HTMLPurifier_ConfigSchema
::define(
36 'HTML', 'AllowedElements', null, 'lookup/null',
37 'If HTML Purifier\'s tag set is unsatisfactory for your needs, you '.
38 'can overload it with your own list of tags to allow. Note that this '.
39 'method is subtractive: it does its job by taking away from HTML Purifier '.
40 'usual feature set, so you cannot add a tag that HTML Purifier never '.
41 'supported in the first place (like embed, form or head). If you change this, you '.
42 'probably also want to change %HTML.AllowedAttributes. '.
43 '<strong>Warning:</strong> If another directive conflicts with the '.
44 'elements here, <em>that</em> directive will win and override. '.
45 'This directive has been available since 1.3.0.'
48 HTMLPurifier_ConfigSchema
::define(
49 'HTML', 'AllowedAttributes', null, 'lookup/null',
50 'IF HTML Purifier\'s attribute set is unsatisfactory, overload it! '.
51 'The syntax is \'tag.attr\' or \'*.attr\' for the global attributes '.
52 '(style, id, class, dir, lang, xml:lang).'.
53 '<strong>Warning:</strong> If another directive conflicts with the '.
54 'elements here, <em>that</em> directive will win and override. For '.
55 'example, %HTML.EnableAttrID will take precedence over *.id in this '.
56 'directive. You must set that directive to true before you can use '.
57 'IDs at all. This directive has been available since 1.3.0.'
61 * Definition of the purified HTML that describes allowed children,
62 * attributes, and many other things.
66 * All member variables that are prefixed with info
67 * (including the main $info array) are used by HTML Purifier internals
68 * and should not be directly edited when customizing the HTMLDefinition.
69 * They can usually be set via configuration directives or custom
72 * On the other hand, member variables without the info prefix are used
73 * internally by the HTMLDefinition and MUST NOT be used by other HTML
74 * Purifier internals. Many of them, however, are public, and may be
75 * edited by userspace code to tweak the behavior of HTMLDefinition.
77 * HTMLPurifier_Printer_HTMLDefinition is a notable exception to this
78 * rule: in the interest of comprehensiveness, it will sniff everything.
80 class HTMLPurifier_HTMLDefinition
83 /** FULLY-PUBLIC VARIABLES */
86 * Associative array of element names to HTMLPurifier_ElementDef
92 * Associative array of global attribute name to attribute definition.
95 var $info_global_attr = array();
98 * String name of parent element HTML will be going into.
101 var $info_parent = 'div';
104 * Definition for parent element, allows parent element to be a
105 * tag that's not allowed inside the HTML fragment.
108 var $info_parent_def;
111 * String name of element used to wrap inline elements in block context
112 * @note This is rarely used except for BLOCKQUOTEs in strict mode
115 var $info_block_wrapper = 'p';
118 * Associative array of deprecated tag name to HTMLPurifier_TagTransform
121 var $info_tag_transform = array();
124 * Indexed list of HTMLPurifier_AttrTransform to be performed before validation.
127 var $info_attr_transform_pre = array();
130 * Indexed list of HTMLPurifier_AttrTransform to be performed after validation.
133 var $info_attr_transform_post = array();
136 * Nested lookup array of content set name (Block, Inline) to
137 * element name to whether or not it belongs in that content set.
140 var $info_content_sets = array();
144 /** PUBLIC BUT INTERNAL VARIABLES */
146 var $setup = false; /**< Has setup() been called yet? */
147 var $config; /**< Temporary instance of HTMLPurifier_Config */
149 var $manager; /**< Instance of HTMLPurifier_HTMLModuleManager */
152 * Performs low-cost, preliminary initialization.
153 * @param $config Instance of HTMLPurifier_Config
155 function HTMLPurifier_HTMLDefinition(&$config) {
156 $this->config
=& $config;
157 $this->manager
= new HTMLPurifier_HTMLModuleManager();
161 * Processes internals into form usable by HTMLPurifier internals.
162 * Modifying the definition after calling this function should not
167 // multiple call guard
168 if ($this->setup
) {return;} else {$this->setup
= true;}
170 $this->processModules();
171 $this->setupConfigStuff();
173 unset($this->config
);
174 unset($this->manager
);
179 * Extract out the information from the manager
181 function processModules() {
183 $this->manager
->setup($this->config
);
185 foreach ($this->manager
->activeModules
as $module) {
186 foreach($module->info_tag_transform
as $k => $v) {
187 if ($v === false) unset($this->info_tag_transform
[$k]);
188 else $this->info_tag_transform
[$k] = $v;
190 foreach($module->info_attr_transform_pre
as $k => $v) {
191 if ($v === false) unset($this->info_attr_transform_pre
[$k]);
192 else $this->info_attr_transform_pre
[$k] = $v;
194 foreach($module->info_attr_transform_post
as $k => $v) {
195 if ($v === false) unset($this->info_attr_transform_post
[$k]);
196 else $this->info_attr_transform_post
[$k] = $v;
200 $this->info
= $this->manager
->getElements($this->config
);
201 $this->info_content_sets
= $this->manager
->contentSets
->lookup
;
206 * Sets up stuff based on config. We need a better way of doing this.
208 function setupConfigStuff() {
210 $block_wrapper = $this->config
->get('HTML', 'BlockWrapper');
211 if (isset($this->info_content_sets
['Block'][$block_wrapper])) {
212 $this->info_block_wrapper
= $block_wrapper;
214 trigger_error('Cannot use non-block element as block wrapper.',
218 $parent = $this->config
->get('HTML', 'Parent');
219 $def = $this->manager
->getElement($parent, $this->config
);
221 $this->info_parent
= $parent;
222 $this->info_parent_def
= $def;
224 trigger_error('Cannot use unrecognized element as parent.',
226 $this->info_parent_def
= $this->manager
->getElement(
227 $this->info_parent
, $this->config
);
230 // support template text
231 $support = "(for information on implementing this, see the ".
234 // setup allowed elements, SubtractiveWhitelist module
235 $allowed_elements = $this->config
->get('HTML', 'AllowedElements');
236 if (is_array($allowed_elements)) {
237 foreach ($this->info
as $name => $d) {
238 if(!isset($allowed_elements[$name])) unset($this->info
[$name]);
239 unset($allowed_elements[$name]);
242 foreach ($allowed_elements as $element => $d) {
243 trigger_error("Element '$element' is not supported $support", E_USER_WARNING
);
247 $allowed_attributes = $this->config
->get('HTML', 'AllowedAttributes');
248 $allowed_attributes_mutable = $allowed_attributes; // by copy!
249 if (is_array($allowed_attributes)) {
250 foreach ($this->info_global_attr
as $attr_key => $info) {
251 if (!isset($allowed_attributes["*.$attr_key"])) {
252 unset($this->info_global_attr
[$attr_key]);
253 } elseif (isset($allowed_attributes_mutable["*.$attr_key"])) {
254 unset($allowed_attributes_mutable["*.$attr_key"]);
257 foreach ($this->info
as $tag => $info) {
258 foreach ($info->attr
as $attr => $attr_info) {
259 if (!isset($allowed_attributes["$tag.$attr"]) &&
260 !isset($allowed_attributes["*.$attr"])) {
261 unset($this->info
[$tag]->attr
[$attr]);
263 if (isset($allowed_attributes_mutable["$tag.$attr"])) {
264 unset($allowed_attributes_mutable["$tag.$attr"]);
265 } elseif (isset($allowed_attributes_mutable["*.$attr"])) {
266 unset($allowed_attributes_mutable["*.$attr"]);
272 foreach ($allowed_attributes_mutable as $elattr => $d) {
273 list($element, $attribute) = explode('.', $elattr);
274 if ($element == '*') {
275 trigger_error("Global attribute '$attribute' is not ".
276 "supported in any elements $support",
279 trigger_error("Attribute '$attribute' in element '$element' not supported $support",