--- /dev/null
+<?php\r
+\r
+/**\r
+ * Validates the attributes of a token. Doesn't manage required attributes\r
+ * very well. The only reason we factored this out was because RemoveForeignElements\r
+ * also needed it besides ValidateAttributes.\r
+ */\r
+class HTMLPurifier_AttrValidator\r
+{\r
+\r
+ /**\r
+ * Validates the attributes of a token, mutating it as necessary.\r
+ * that has valid tokens\r
+ * @param HTMLPurifier_Token $token Token to validate.\r
+ * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config\r
+ * @param HTMLPurifier_Context $context Instance of HTMLPurifier_Context\r
+ */\r
+ public function validateToken($token, $config, $context)\r
+ {\r
+ $definition = $config->getHTMLDefinition();\r
+ $e =& $context->get('ErrorCollector', true);\r
+\r
+ // initialize IDAccumulator if necessary\r
+ $ok =& $context->get('IDAccumulator', true);\r
+ if (!$ok) {\r
+ $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);\r
+ $context->register('IDAccumulator', $id_accumulator);\r
+ }\r
+\r
+ // initialize CurrentToken if necessary\r
+ $current_token =& $context->get('CurrentToken', true);\r
+ if (!$current_token) {\r
+ $context->register('CurrentToken', $token);\r
+ }\r
+\r
+ if (!$token instanceof HTMLPurifier_Token_Start &&\r
+ !$token instanceof HTMLPurifier_Token_Empty\r
+ ) {\r
+ return;\r
+ }\r
+\r
+ // create alias to global definition array, see also $defs\r
+ // DEFINITION CALL\r
+ $d_defs = $definition->info_global_attr;\r
+\r
+ // don't update token until the very end, to ensure an atomic update\r
+ $attr = $token->attr;\r
+\r
+ // do global transformations (pre)\r
+ // nothing currently utilizes this\r
+ foreach ($definition->info_attr_transform_pre as $transform) {\r
+ $attr = $transform->transform($o = $attr, $config, $context);\r
+ if ($e) {\r
+ if ($attr != $o) {\r
+ $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);\r
+ }\r
+ }\r
+ }\r
+\r
+ // do local transformations only applicable to this element (pre)\r
+ // ex. <p align="right"> to <p style="text-align:right;">\r
+ foreach ($definition->info[$token->name]->attr_transform_pre as $transform) {\r
+ $attr = $transform->transform($o = $attr, $config, $context);\r
+ if ($e) {\r
+ if ($attr != $o) {\r
+ $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);\r
+ }\r
+ }\r
+ }\r
+\r
+ // create alias to this element's attribute definition array, see\r
+ // also $d_defs (global attribute definition array)\r
+ // DEFINITION CALL\r
+ $defs = $definition->info[$token->name]->attr;\r
+\r
+ $attr_key = false;\r
+ $context->register('CurrentAttr', $attr_key);\r
+\r
+ // iterate through all the attribute keypairs\r
+ // Watch out for name collisions: $key has previously been used\r
+ foreach ($attr as $attr_key => $value) {\r
+\r
+ // call the definition\r
+ if (isset($defs[$attr_key])) {\r
+ // there is a local definition defined\r
+ if ($defs[$attr_key] === false) {\r
+ // We've explicitly been told not to allow this element.\r
+ // This is usually when there's a global definition\r
+ // that must be overridden.\r
+ // Theoretically speaking, we could have a\r
+ // AttrDef_DenyAll, but this is faster!\r
+ $result = false;\r
+ } else {\r
+ // validate according to the element's definition\r
+ $result = $defs[$attr_key]->validate(\r
+ $value,\r
+ $config,\r
+ $context\r
+ );\r
+ }\r
+ } elseif (isset($d_defs[$attr_key])) {\r
+ // there is a global definition defined, validate according\r
+ // to the global definition\r
+ $result = $d_defs[$attr_key]->validate(\r
+ $value,\r
+ $config,\r
+ $context\r
+ );\r
+ } else {\r
+ // system never heard of the attribute? DELETE!\r
+ $result = false;\r
+ }\r
+\r
+ // put the results into effect\r
+ if ($result === false || $result === null) {\r
+ // this is a generic error message that should replaced\r
+ // with more specific ones when possible\r
+ if ($e) {\r
+ $e->send(E_ERROR, 'AttrValidator: Attribute removed');\r
+ }\r
+\r
+ // remove the attribute\r
+ unset($attr[$attr_key]);\r
+ } elseif (is_string($result)) {\r
+ // generally, if a substitution is happening, there\r
+ // was some sort of implicit correction going on. We'll\r
+ // delegate it to the attribute classes to say exactly what.\r
+\r
+ // simple substitution\r
+ $attr[$attr_key] = $result;\r
+ } else {\r
+ // nothing happens\r
+ }\r
+\r
+ // we'd also want slightly more complicated substitution\r
+ // involving an array as the return value,\r
+ // although we're not sure how colliding attributes would\r
+ // resolve (certain ones would be completely overriden,\r
+ // others would prepend themselves).\r
+ }\r
+\r
+ $context->destroy('CurrentAttr');\r
+\r
+ // post transforms\r
+\r
+ // global (error reporting untested)\r
+ foreach ($definition->info_attr_transform_post as $transform) {\r
+ $attr = $transform->transform($o = $attr, $config, $context);\r
+ if ($e) {\r
+ if ($attr != $o) {\r
+ $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);\r
+ }\r
+ }\r
+ }\r
+\r
+ // local (error reporting untested)\r
+ foreach ($definition->info[$token->name]->attr_transform_post as $transform) {\r
+ $attr = $transform->transform($o = $attr, $config, $context);\r
+ if ($e) {\r
+ if ($attr != $o) {\r
+ $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);\r
+ }\r
+ }\r
+ }\r
+\r
+ $token->attr = $attr;\r
+\r
+ // destroy CurrentToken if we made it ourselves\r
+ if (!$current_token) {\r
+ $context->destroy('CurrentToken');\r
+ }\r
+\r
+ }\r
+\r
+\r
+}\r
+\r
+// vim: et sw=4 sts=4\r