1 <?php 2 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 9 { 10 11 /** 12 * Validates the attributes of a token, mutating it as necessary. 13 * that has valid tokens 14 * @param HTMLPurifier_Token $token Token to validate. 15 * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config 16 * @param HTMLPurifier_Context $context Instance of HTMLPurifier_Context 17 */ 18 public function validateToken($token, $config, $context) 19 { 20 $definition = $config->getHTMLDefinition(); 21 $e =& $context->get('ErrorCollector', true); 22 23 // initialize IDAccumulator if necessary 24 $ok =& $context->get('IDAccumulator', true); 25 if (!$ok) { 26 $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); 27 $context->register('IDAccumulator', $id_accumulator); 28 } 29 30 // initialize CurrentToken if necessary 31 $current_token =& $context->get('CurrentToken', true); 32 if (!$current_token) { 33 $context->register('CurrentToken', $token); 34 } 35 36 if (!$token instanceof HTMLPurifier_Token_Start && 37 !$token instanceof HTMLPurifier_Token_Empty 38 ) { 39 return; 40 } 41 42 // create alias to global definition array, see also $defs 43 // DEFINITION CALL 44 $d_defs = $definition->info_global_attr; 45 46 // don't update token until the very end, to ensure an atomic update 47 $attr = $token->attr; 48 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) { 55 $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); 56 } 57 } 58 } 59 60 // do local transformations only applicable to this element (pre) 61 // ex. <p align="right"> to <p style="text-align:right;"> 62 foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { 63 $attr = $transform->transform($o = $attr, $config, $context); 64 if ($e) { 65 if ($attr != $o) { 66 $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); 67 } 68 } 69 } 70 71 // create alias to this element's attribute definition array, see 72 // also $d_defs (global attribute definition array) 73 // DEFINITION CALL 74 $defs = $definition->info[$token->name]->attr; 75 76 $attr_key = false; 77 $context->register('CurrentAttr', $attr_key); 78 79 // iterate through all the attribute keypairs 80 // Watch out for name collisions: $key has previously been used 81 foreach ($attr as $attr_key => $value) { 82 83 // call the definition 84 if (isset($defs[$attr_key])) { 85 // there is a local definition defined 86 if ($defs[$attr_key] === false) { 87 // We've explicitly been told not to allow this element. 88 // This is usually when there's a global definition 89 // that must be overridden. 90 // Theoretically speaking, we could have a 91 // AttrDef_DenyAll, but this is faster! 92 $result = false; 93 } else { 94 // validate according to the element's definition 95 $result = $defs[$attr_key]->validate( 96 $value, 97 $config, 98 $context 99 ); 100 } 101 } elseif (isset($d_defs[$attr_key])) { 102 // there is a global definition defined, validate according 103 // to the global definition 104 $result = $d_defs[$attr_key]->validate( 105 $value, 106 $config, 107 $context 108 ); 109 } else { 110 // system never heard of the attribute? DELETE! 111 $result = false; 112 } 113 114 // put the results into effect 115 if ($result === false || $result === null) { 116 // this is a generic error message that should replaced 117 // with more specific ones when possible 118 if ($e) { 119 $e->send(E_ERROR, 'AttrValidator: Attribute removed'); 120 } 121 122 // remove the attribute 123 unset($attr[$attr_key]); 124 } elseif (is_string($result)) { 125 // generally, if a substitution is happening, there 126 // was some sort of implicit correction going on. We'll 127 // delegate it to the attribute classes to say exactly what. 128 129 // simple substitution 130 $attr[$attr_key] = $result; 131 } else { 132 // nothing happens 133 } 134 135 // we'd also want slightly more complicated substitution 136 // involving an array as the return value, 137 // although we're not sure how colliding attributes would 138 // resolve (certain ones would be completely overriden, 139 // others would prepend themselves). 140 } 141 142 $context->destroy('CurrentAttr'); 143 144 // post transforms 145 146 // global (error reporting untested) 147 foreach ($definition->info_attr_transform_post as $transform) { 148 $attr = $transform->transform($o = $attr, $config, $context); 149 if ($e) { 150 if ($attr != $o) { 151 $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); 152 } 153 } 154 } 155 156 // local (error reporting untested) 157 foreach ($definition->info[$token->name]->attr_transform_post as $transform) { 158 $attr = $transform->transform($o = $attr, $config, $context); 159 if ($e) { 160 if ($attr != $o) { 161 $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); 162 } 163 } 164 } 165 166 $token->attr = $attr; 167 168 // destroy CurrentToken if we made it ourselves 169 if (!$current_token) { 170 $context->destroy('CurrentToken'); 171 } 172 173 } 174 175 176 } 177 178 // vim: et sw=4 sts=4
title
Description
Body
title
Description
Body
title
Description
Body
title
Body