Add a little bit of documentation about contexts for URIFilters.
[htmlpurifier.git] / library / HTMLPurifier / AttrValidator.php
blob829a0f8f225e5f56125c2daafc8ad835d694065a
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 public function validateToken(&$token, &$config, $context) {
23 $definition = $config->getHTMLDefinition();
24 $e =& $context->get('ErrorCollector', true);
26 // initialize IDAccumulator if necessary
27 $ok =& $context->get('IDAccumulator', true);
28 if (!$ok) {
29 $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
30 $context->register('IDAccumulator', $id_accumulator);
33 // initialize CurrentToken if necessary
34 $current_token =& $context->get('CurrentToken', true);
35 if (!$current_token) $context->register('CurrentToken', $token);
37 if (
38 !$token instanceof HTMLPurifier_Token_Start &&
39 !$token instanceof HTMLPurifier_Token_Empty
40 ) return $token;
42 // create alias to global definition array, see also $defs
43 // DEFINITION CALL
44 $d_defs = $definition->info_global_attr;
46 // don't update token until the very end, to ensure an atomic update
47 $attr = $token->attr;
49 // do global transformations (pre)
50 // nothing currently utilizes this
51 foreach ($definition->info_attr_transform_pre as $transform) {
52 $attr = $transform->transform($o = $attr, $config, $context);
53 if ($e) {
54 if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
58 // do local transformations only applicable to this element (pre)
59 // ex. <p align="right"> to <p style="text-align:right;">
60 foreach ($definition->info[$token->name]->attr_transform_pre as $transform) {
61 $attr = $transform->transform($o = $attr, $config, $context);
62 if ($e) {
63 if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
67 // create alias to this element's attribute definition array, see
68 // also $d_defs (global attribute definition array)
69 // DEFINITION CALL
70 $defs = $definition->info[$token->name]->attr;
72 $attr_key = false;
73 $context->register('CurrentAttr', $attr_key);
75 // iterate through all the attribute keypairs
76 // Watch out for name collisions: $key has previously been used
77 foreach ($attr as $attr_key => $value) {
79 // call the definition
80 if ( isset($defs[$attr_key]) ) {
81 // there is a local definition defined
82 if ($defs[$attr_key] === false) {
83 // We've explicitly been told not to allow this element.
84 // This is usually when there's a global definition
85 // that must be overridden.
86 // Theoretically speaking, we could have a
87 // AttrDef_DenyAll, but this is faster!
88 $result = false;
89 } else {
90 // validate according to the element's definition
91 $result = $defs[$attr_key]->validate(
92 $value, $config, $context
95 } elseif ( isset($d_defs[$attr_key]) ) {
96 // there is a global definition defined, validate according
97 // to the global definition
98 $result = $d_defs[$attr_key]->validate(
99 $value, $config, $context
101 } else {
102 // system never heard of the attribute? DELETE!
103 $result = false;
106 // put the results into effect
107 if ($result === false || $result === null) {
108 // this is a generic error message that should replaced
109 // with more specific ones when possible
110 if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed');
112 // remove the attribute
113 unset($attr[$attr_key]);
114 } elseif (is_string($result)) {
115 // generally, if a substitution is happening, there
116 // was some sort of implicit correction going on. We'll
117 // delegate it to the attribute classes to say exactly what.
119 // simple substitution
120 $attr[$attr_key] = $result;
121 } else {
122 // nothing happens
125 // we'd also want slightly more complicated substitution
126 // involving an array as the return value,
127 // although we're not sure how colliding attributes would
128 // resolve (certain ones would be completely overriden,
129 // others would prepend themselves).
132 $context->destroy('CurrentAttr');
134 // post transforms
136 // global (error reporting untested)
137 foreach ($definition->info_attr_transform_post as $transform) {
138 $attr = $transform->transform($o = $attr, $config, $context);
139 if ($e) {
140 if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
144 // local (error reporting untested)
145 foreach ($definition->info[$token->name]->attr_transform_post as $transform) {
146 $attr = $transform->transform($o = $attr, $config, $context);
147 if ($e) {
148 if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
152 $token->attr = $attr;
154 // destroy CurrentToken if we made it ourselves
155 if (!$current_token) $context->destroy('CurrentToken');
162 // vim: et sw=4 sts=4