File indexing completed on 2024-12-22 05:36:21
0001 <?php 0002 0003 /** 0004 * Validates the attributes of a token. Doesn't manage required attributes 0005 * very well. The only reason we factored this out was because RemoveForeignElements 0006 * also needed it besides ValidateAttributes. 0007 */ 0008 class HTMLPurifier_AttrValidator 0009 { 0010 0011 /** 0012 * Validates the attributes of a token, mutating it as necessary. 0013 * that has valid tokens 0014 * @param HTMLPurifier_Token $token Token to validate. 0015 * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config 0016 * @param HTMLPurifier_Context $context Instance of HTMLPurifier_Context 0017 */ 0018 public function validateToken($token, $config, $context) 0019 { 0020 $definition = $config->getHTMLDefinition(); 0021 $e =& $context->get('ErrorCollector', true); 0022 0023 // initialize IDAccumulator if necessary 0024 $ok =& $context->get('IDAccumulator', true); 0025 if (!$ok) { 0026 $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); 0027 $context->register('IDAccumulator', $id_accumulator); 0028 } 0029 0030 // initialize CurrentToken if necessary 0031 $current_token =& $context->get('CurrentToken', true); 0032 if (!$current_token) { 0033 $context->register('CurrentToken', $token); 0034 } 0035 0036 if (!$token instanceof HTMLPurifier_Token_Start && 0037 !$token instanceof HTMLPurifier_Token_Empty 0038 ) { 0039 return; 0040 } 0041 0042 // create alias to global definition array, see also $defs 0043 // DEFINITION CALL 0044 $d_defs = $definition->info_global_attr; 0045 0046 // don't update token until the very end, to ensure an atomic update 0047 $attr = $token->attr; 0048 0049 // do global transformations (pre) 0050 // nothing currently utilizes this 0051 foreach ($definition->info_attr_transform_pre as $transform) { 0052 $attr = $transform->transform($o = $attr, $config, $context); 0053 if ($e) { 0054 if ($attr != $o) { 0055 $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); 0056 } 0057 } 0058 } 0059 0060 // do local transformations only applicable to this element (pre) 0061 // ex. <p align="right"> to <p style="text-align:right;"> 0062 foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { 0063 $attr = $transform->transform($o = $attr, $config, $context); 0064 if ($e) { 0065 if ($attr != $o) { 0066 $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); 0067 } 0068 } 0069 } 0070 0071 // create alias to this element's attribute definition array, see 0072 // also $d_defs (global attribute definition array) 0073 // DEFINITION CALL 0074 $defs = $definition->info[$token->name]->attr; 0075 0076 $attr_key = false; 0077 $context->register('CurrentAttr', $attr_key); 0078 0079 // iterate through all the attribute keypairs 0080 // Watch out for name collisions: $key has previously been used 0081 foreach ($attr as $attr_key => $value) { 0082 0083 // call the definition 0084 if (isset($defs[$attr_key])) { 0085 // there is a local definition defined 0086 if ($defs[$attr_key] === false) { 0087 // We've explicitly been told not to allow this element. 0088 // This is usually when there's a global definition 0089 // that must be overridden. 0090 // Theoretically speaking, we could have a 0091 // AttrDef_DenyAll, but this is faster! 0092 $result = false; 0093 } else { 0094 // validate according to the element's definition 0095 $result = $defs[$attr_key]->validate( 0096 $value, 0097 $config, 0098 $context 0099 ); 0100 } 0101 } elseif (isset($d_defs[$attr_key])) { 0102 // there is a global definition defined, validate according 0103 // to the global definition 0104 $result = $d_defs[$attr_key]->validate( 0105 $value, 0106 $config, 0107 $context 0108 ); 0109 } else { 0110 // system never heard of the attribute? DELETE! 0111 $result = false; 0112 } 0113 0114 // put the results into effect 0115 if ($result === false || $result === null) { 0116 // this is a generic error message that should replaced 0117 // with more specific ones when possible 0118 if ($e) { 0119 $e->send(E_ERROR, 'AttrValidator: Attribute removed'); 0120 } 0121 0122 // remove the attribute 0123 unset($attr[$attr_key]); 0124 } elseif (is_string($result)) { 0125 // generally, if a substitution is happening, there 0126 // was some sort of implicit correction going on. We'll 0127 // delegate it to the attribute classes to say exactly what. 0128 0129 // simple substitution 0130 $attr[$attr_key] = $result; 0131 } else { 0132 // nothing happens 0133 } 0134 0135 // we'd also want slightly more complicated substitution 0136 // involving an array as the return value, 0137 // although we're not sure how colliding attributes would 0138 // resolve (certain ones would be completely overriden, 0139 // others would prepend themselves). 0140 } 0141 0142 $context->destroy('CurrentAttr'); 0143 0144 // post transforms 0145 0146 // global (error reporting untested) 0147 foreach ($definition->info_attr_transform_post as $transform) { 0148 $attr = $transform->transform($o = $attr, $config, $context); 0149 if ($e) { 0150 if ($attr != $o) { 0151 $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); 0152 } 0153 } 0154 } 0155 0156 // local (error reporting untested) 0157 foreach ($definition->info[$token->name]->attr_transform_post as $transform) { 0158 $attr = $transform->transform($o = $attr, $config, $context); 0159 if ($e) { 0160 if ($attr != $o) { 0161 $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); 0162 } 0163 } 0164 } 0165 0166 $token->attr = $attr; 0167 0168 // destroy CurrentToken if we made it ourselves 0169 if (!$current_token) { 0170 $context->destroy('CurrentToken'); 0171 } 0172 0173 } 0174 0175 0176 } 0177 0178 // vim: et sw=4 sts=4