Release 2.0.1, merged in 1181 to HEAD.
[htmlpurifier.git] / library / HTMLPurifier / AttrValidator.php
blobf02bd2087cfcd79dbee66e46808e8b0276e4c65d
1 <?php
3 /**
4 * Validates the attributes of a token. Doesn't manage required attributes
5 * very well. The only reason we factored this out was because RemoveForeignElements
6 * also needed it besides ValidateAttributes.
7 */
8 class HTMLPurifier_AttrValidator
11 /**
12 * Validates the attributes of a token, returning a modified token
13 * that has valid tokens
14 * @param $token Reference to token to validate. We require a reference
15 * because the operation this class performs on the token are
16 * not atomic, so the context CurrentToken to be updated
17 * throughout
18 * @param $config Instance of HTMLPurifier_Config
19 * @param $context Instance of HTMLPurifier_Context
21 function validateToken(&$token, &$config, &$context) {
23 $definition = $config->getHTMLDefinition();
24 $e =& $context->get('ErrorCollector', true);
26 // initialize CurrentToken if necessary
27 $current_token =& $context->get('CurrentToken', true);
28 if (!$current_token) $context->register('CurrentToken', $token);
30 if ($token->type !== 'start' && $token->type !== 'empty') return $token;
32 // create alias to global definition array, see also $defs
33 // DEFINITION CALL
34 $d_defs = $definition->info_global_attr;
36 // reference attributes for easy manipulation
37 $attr =& $token->attr;
39 // do global transformations (pre)
40 // nothing currently utilizes this
41 foreach ($definition->info_attr_transform_pre as $transform) {
42 $attr = $transform->transform($o = $attr, $config, $context);
43 if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
46 // do local transformations only applicable to this element (pre)
47 // ex. <p align="right"> to <p style="text-align:right;">
48 foreach ($definition->info[$token->name]->attr_transform_pre as $transform) {
49 $attr = $transform->transform($o = $attr, $config, $context);
50 if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
53 // create alias to this element's attribute definition array, see
54 // also $d_defs (global attribute definition array)
55 // DEFINITION CALL
56 $defs = $definition->info[$token->name]->attr;
58 $attr_key = false;
59 $context->register('CurrentAttr', $attr_key);
61 // iterate through all the attribute keypairs
62 // Watch out for name collisions: $key has previously been used
63 foreach ($attr as $attr_key => $value) {
65 // call the definition
66 if ( isset($defs[$attr_key]) ) {
67 // there is a local definition defined
68 if ($defs[$attr_key] === false) {
69 // We've explicitly been told not to allow this element.
70 // This is usually when there's a global definition
71 // that must be overridden.
72 // Theoretically speaking, we could have a
73 // AttrDef_DenyAll, but this is faster!
74 $result = false;
75 } else {
76 // validate according to the element's definition
77 $result = $defs[$attr_key]->validate(
78 $value, $config, $context
81 } elseif ( isset($d_defs[$attr_key]) ) {
82 // there is a global definition defined, validate according
83 // to the global definition
84 $result = $d_defs[$attr_key]->validate(
85 $value, $config, $context
87 } else {
88 // system never heard of the attribute? DELETE!
89 $result = false;
92 // put the results into effect
93 if ($result === false || $result === null) {
94 // this is a generic error message that should replaced
95 // with more specific ones when possible
96 if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed');
98 // remove the attribute
99 unset($attr[$attr_key]);
100 } elseif (is_string($result)) {
101 // generally, if a substitution is happening, there
102 // was some sort of implicit correction going on. We'll
103 // delegate it to the attribute classes to say exactly what.
105 // simple substitution
106 $attr[$attr_key] = $result;
109 // we'd also want slightly more complicated substitution
110 // involving an array as the return value,
111 // although we're not sure how colliding attributes would
112 // resolve (certain ones would be completely overriden,
113 // others would prepend themselves).
116 $context->destroy('CurrentAttr');
118 // post transforms
120 // global (error reporting untested)
121 foreach ($definition->info_attr_transform_post as $transform) {
122 $attr = $transform->transform($o = $attr, $config, $context);
123 if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
126 // local (error reporting untested)
127 foreach ($definition->info[$token->name]->attr_transform_post as $transform) {
128 $attr = $transform->transform($o = $attr, $config, $context);
129 if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
132 // destroy CurrentToken if we made it ourselves
133 if (!$current_token) $context->destroy('CurrentToken');