]>
Commit | Line | Data |
---|---|---|
f45a286b AD |
1 | <?php |
2 | ||
3 | /** | |
4 | * Injects tokens into the document while parsing for well-formedness. | |
5 | * This enables "formatter-like" functionality such as auto-paragraphing, | |
6 | * smiley-ification and linkification to take place. | |
7 | * | |
8 | * A note on how handlers create changes; this is done by assigning a new | |
9 | * value to the $token reference. These values can take a variety of forms and | |
10 | * are best described HTMLPurifier_Strategy_MakeWellFormed->processToken() | |
11 | * documentation. | |
12 | * | |
13 | * @todo Allow injectors to request a re-run on their output. This | |
14 | * would help if an operation is recursive. | |
15 | */ | |
16 | abstract class HTMLPurifier_Injector | |
17 | { | |
18 | ||
19 | /** | |
20 | * Advisory name of injector, this is for friendly error messages | |
21 | */ | |
22 | public $name; | |
23 | ||
24 | /** | |
25 | * Instance of HTMLPurifier_HTMLDefinition | |
26 | */ | |
27 | protected $htmlDefinition; | |
28 | ||
29 | /** | |
30 | * Reference to CurrentNesting variable in Context. This is an array | |
31 | * list of tokens that we are currently "inside" | |
32 | */ | |
33 | protected $currentNesting; | |
34 | ||
35 | /** | |
36 | * Reference to InputTokens variable in Context. This is an array | |
37 | * list of the input tokens that are being processed. | |
38 | */ | |
39 | protected $inputTokens; | |
40 | ||
41 | /** | |
42 | * Reference to InputIndex variable in Context. This is an integer | |
43 | * array index for $this->inputTokens that indicates what token | |
44 | * is currently being processed. | |
45 | */ | |
46 | protected $inputIndex; | |
47 | ||
48 | /** | |
49 | * Array of elements and attributes this injector creates and therefore | |
50 | * need to be allowed by the definition. Takes form of | |
51 | * array('element' => array('attr', 'attr2'), 'element2') | |
52 | */ | |
53 | public $needed = array(); | |
54 | ||
55 | /** | |
56 | * Index of inputTokens to rewind to. | |
57 | */ | |
58 | protected $rewind = false; | |
59 | ||
60 | /** | |
61 | * Rewind to a spot to re-perform processing. This is useful if you | |
62 | * deleted a node, and now need to see if this change affected any | |
63 | * earlier nodes. Rewinding does not affect other injectors, and can | |
64 | * result in infinite loops if not used carefully. | |
65 | * @warning HTML Purifier will prevent you from fast-forwarding with this | |
66 | * function. | |
67 | */ | |
68 | public function rewind($index) { | |
69 | $this->rewind = $index; | |
70 | } | |
71 | ||
72 | /** | |
73 | * Retrieves rewind, and then unsets it. | |
74 | */ | |
75 | public function getRewind() { | |
76 | $r = $this->rewind; | |
77 | $this->rewind = false; | |
78 | return $r; | |
79 | } | |
80 | ||
81 | /** | |
82 | * Prepares the injector by giving it the config and context objects: | |
83 | * this allows references to important variables to be made within | |
84 | * the injector. This function also checks if the HTML environment | |
85 | * will work with the Injector (see checkNeeded()). | |
86 | * @param $config Instance of HTMLPurifier_Config | |
87 | * @param $context Instance of HTMLPurifier_Context | |
88 | * @return Boolean false if success, string of missing needed element/attribute if failure | |
89 | */ | |
90 | public function prepare($config, $context) { | |
91 | $this->htmlDefinition = $config->getHTMLDefinition(); | |
92 | // Even though this might fail, some unit tests ignore this and | |
93 | // still test checkNeeded, so be careful. Maybe get rid of that | |
94 | // dependency. | |
95 | $result = $this->checkNeeded($config); | |
96 | if ($result !== false) return $result; | |
97 | $this->currentNesting =& $context->get('CurrentNesting'); | |
98 | $this->inputTokens =& $context->get('InputTokens'); | |
99 | $this->inputIndex =& $context->get('InputIndex'); | |
100 | return false; | |
101 | } | |
102 | ||
103 | /** | |
104 | * This function checks if the HTML environment | |
105 | * will work with the Injector: if p tags are not allowed, the | |
106 | * Auto-Paragraphing injector should not be enabled. | |
107 | * @param $config Instance of HTMLPurifier_Config | |
108 | * @param $context Instance of HTMLPurifier_Context | |
109 | * @return Boolean false if success, string of missing needed element/attribute if failure | |
110 | */ | |
111 | public function checkNeeded($config) { | |
112 | $def = $config->getHTMLDefinition(); | |
113 | foreach ($this->needed as $element => $attributes) { | |
114 | if (is_int($element)) $element = $attributes; | |
115 | if (!isset($def->info[$element])) return $element; | |
116 | if (!is_array($attributes)) continue; | |
117 | foreach ($attributes as $name) { | |
118 | if (!isset($def->info[$element]->attr[$name])) return "$element.$name"; | |
119 | } | |
120 | } | |
121 | return false; | |
122 | } | |
123 | ||
124 | /** | |
125 | * Tests if the context node allows a certain element | |
126 | * @param $name Name of element to test for | |
127 | * @return True if element is allowed, false if it is not | |
128 | */ | |
129 | public function allowsElement($name) { | |
130 | if (!empty($this->currentNesting)) { | |
131 | $parent_token = array_pop($this->currentNesting); | |
132 | $this->currentNesting[] = $parent_token; | |
133 | $parent = $this->htmlDefinition->info[$parent_token->name]; | |
134 | } else { | |
135 | $parent = $this->htmlDefinition->info_parent_def; | |
136 | } | |
137 | if (!isset($parent->child->elements[$name]) || isset($parent->excludes[$name])) { | |
138 | return false; | |
139 | } | |
f4f0f80d AD |
140 | // check for exclusion |
141 | for ($i = count($this->currentNesting) - 2; $i >= 0; $i--) { | |
142 | $node = $this->currentNesting[$i]; | |
143 | $def = $this->htmlDefinition->info[$node->name]; | |
144 | if (isset($def->excludes[$name])) return false; | |
145 | } | |
f45a286b AD |
146 | return true; |
147 | } | |
148 | ||
149 | /** | |
150 | * Iterator function, which starts with the next token and continues until | |
151 | * you reach the end of the input tokens. | |
152 | * @warning Please prevent previous references from interfering with this | |
153 | * functions by setting $i = null beforehand! | |
154 | * @param &$i Current integer index variable for inputTokens | |
155 | * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference | |
156 | */ | |
157 | protected function forward(&$i, &$current) { | |
158 | if ($i === null) $i = $this->inputIndex + 1; | |
159 | else $i++; | |
160 | if (!isset($this->inputTokens[$i])) return false; | |
161 | $current = $this->inputTokens[$i]; | |
162 | return true; | |
163 | } | |
164 | ||
165 | /** | |
166 | * Similar to _forward, but accepts a third parameter $nesting (which | |
167 | * should be initialized at 0) and stops when we hit the end tag | |
168 | * for the node $this->inputIndex starts in. | |
169 | */ | |
170 | protected function forwardUntilEndToken(&$i, &$current, &$nesting) { | |
171 | $result = $this->forward($i, $current); | |
172 | if (!$result) return false; | |
173 | if ($nesting === null) $nesting = 0; | |
174 | if ($current instanceof HTMLPurifier_Token_Start) $nesting++; | |
175 | elseif ($current instanceof HTMLPurifier_Token_End) { | |
176 | if ($nesting <= 0) return false; | |
177 | $nesting--; | |
178 | } | |
179 | return true; | |
180 | } | |
181 | ||
182 | /** | |
183 | * Iterator function, starts with the previous token and continues until | |
184 | * you reach the beginning of input tokens. | |
185 | * @warning Please prevent previous references from interfering with this | |
186 | * functions by setting $i = null beforehand! | |
187 | * @param &$i Current integer index variable for inputTokens | |
188 | * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference | |
189 | */ | |
190 | protected function backward(&$i, &$current) { | |
191 | if ($i === null) $i = $this->inputIndex - 1; | |
192 | else $i--; | |
193 | if ($i < 0) return false; | |
194 | $current = $this->inputTokens[$i]; | |
195 | return true; | |
196 | } | |
197 | ||
198 | /** | |
199 | * Initializes the iterator at the current position. Use in a do {} while; | |
200 | * loop to force the _forward and _backward functions to start at the | |
201 | * current location. | |
202 | * @warning Please prevent previous references from interfering with this | |
203 | * functions by setting $i = null beforehand! | |
204 | * @param &$i Current integer index variable for inputTokens | |
205 | * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference | |
206 | */ | |
207 | protected function current(&$i, &$current) { | |
208 | if ($i === null) $i = $this->inputIndex; | |
209 | $current = $this->inputTokens[$i]; | |
210 | } | |
211 | ||
212 | /** | |
213 | * Handler that is called when a text token is processed | |
214 | */ | |
215 | public function handleText(&$token) {} | |
216 | ||
217 | /** | |
218 | * Handler that is called when a start or empty token is processed | |
219 | */ | |
220 | public function handleElement(&$token) {} | |
221 | ||
222 | /** | |
223 | * Handler that is called when an end token is processed | |
224 | */ | |
225 | public function handleEnd(&$token) { | |
226 | $this->notifyEnd($token); | |
227 | } | |
228 | ||
229 | /** | |
230 | * Notifier that is called when an end token is processed | |
231 | * @note This differs from handlers in that the token is read-only | |
232 | * @deprecated | |
233 | */ | |
234 | public function notifyEnd($token) {} | |
235 | ||
236 | ||
237 | } | |
238 | ||
239 | // vim: et sw=4 sts=4 |