3 require_once 'HTMLPurifier/Strategy.php';
4 require_once 'HTMLPurifier/HTMLDefinition.php';
5 require_once 'HTMLPurifier/IDAccumulator.php';
6 require_once 'HTMLPurifier/ConfigSchema.php';
7 require_once 'HTMLPurifier/AttrContext.php';
9 HTMLPurifier_ConfigSchema
::define(
10 'Attr', 'IDBlacklist', array(), 'list',
11 'Array of IDs not allowed in the document.');
14 * Validate all attributes in the tokens.
17 class HTMLPurifier_Strategy_ValidateAttributes
extends HTMLPurifier_Strategy
20 function execute($tokens, $config) {
22 $definition = $config->getHTMLDefinition();
24 // setup StrategyContext
25 $context = new HTMLPurifier_AttrContext();
27 // setup ID accumulator and load it with blacklisted IDs
28 // eventually, we'll have a dedicated context object to hold
29 // all these accumulators and caches. For now, just an IDAccumulator
30 $context->id_accumulator
= new HTMLPurifier_IDAccumulator();
31 $context->id_accumulator
->load($config->get('Attr', 'IDBlacklist'));
33 // create alias to global definition array, see also $defs
35 $d_defs = $definition->info_global_attr
;
37 foreach ($tokens as $key => $token) {
39 // only process tokens that have attributes,
40 // namely start and empty tags
41 if ($token->type
!== 'start' && $token->type
!== 'empty') continue;
43 // copy out attributes for easy manipulation
44 $attr = $token->attributes
;
46 // do global transformations (pre)
47 // ex. <ELEMENT lang="fr"> to <ELEMENT lang="fr" xml:lang="fr">
49 foreach ($definition->info_attr_transform_pre
as $transform) {
50 $attr = $transform->transform($attr, $config);
53 // do local transformations only applicable to this element (pre)
54 // ex. <p align="right"> to <p style="text-align:right;">
56 foreach ($definition->info
[$token->name
]->attr_transform_pre
59 $attr = $transform->transform($attr, $config);
62 // create alias to this element's attribute definition array, see
63 // also $d_defs (global attribute definition array)
65 $defs = $definition->info
[$token->name
]->attr
;
67 // iterate through all the attribute keypairs
68 // Watch out for name collisions: $key has previously been used
69 foreach ($attr as $attr_key => $value) {
71 // call the definition
72 if ( isset($defs[$attr_key]) ) {
73 // there is a local definition defined
74 if ($defs[$attr_key] === false) {
75 // We've explicitly been told not to allow this element.
76 // This is usually when there's a global definition
77 // that must be overridden.
78 // Theoretically speaking, we could have a
79 // AttrDef_DenyAll, but this is faster!
82 // validate according to the element's definition
83 $result = $defs[$attr_key]->validate(
84 $value, $config, $context
87 } elseif ( isset($d_defs[$attr_key]) ) {
88 // there is a global definition defined, validate according
89 // to the global definition
90 $result = $d_defs[$attr_key]->validate(
91 $value, $config, $context
94 // system never heard of the attribute? DELETE!
98 // put the results into effect
99 if ($result === false ||
$result === null) {
100 // remove the attribute
101 unset($attr[$attr_key]);
102 } elseif (is_string($result)) {
103 // simple substitution
104 $attr[$attr_key] = $result;
107 // we'd also want slightly more complicated substitution
108 // involving an array as the return value,
109 // although we're not sure how colliding attributes would
110 // resolve (certain ones would be completely overriden,
111 // others would prepend themselves).
115 foreach ($definition->info_attr_transform_post
as $transform) {
116 $attr = $transform->transform($attr, $config);
118 foreach ($definition->info
[$token->name
]->attr_transform_post
as $transform) {
119 $attr = $transform->transform($attr, $config);
123 // could interfere with flyweight implementation
124 $tokens[$key]->attributes
= $attr;