49 $definition =
$config->getHTMLDefinition();
53 $escape_invalid_tags =
$config->get(
'Core.EscapeInvalidTags');
55 $global_parent_allowed_elements = array();
56 if (isset($definition->info[$definition->info_parent])) {
58 $global_parent_allowed_elements = $definition->info[$definition->info_parent]->child->getAllowedElements(
$config);
60 $e =
$context->get(
'ErrorCollector',
true);
78 $context->register(
'CurrentToken', $token);
82 $this->injectors = array();
85 $def_injectors = $definition->info_injector;
90 if (strpos($injector,
'.') !==
false)
continue;
91 $injector =
"HTMLPurifier_Injector_$injector";
93 $this->injectors[] =
new $injector;
95 foreach ($def_injectors as $injector) {
97 $this->injectors[] = $injector;
99 foreach ($custom_injectors as $injector) {
100 if (!$injector)
continue;
101 if (is_string($injector)) {
102 $injector =
"HTMLPurifier_Injector_$injector";
103 $injector =
new $injector;
105 $this->injectors[] = $injector;
110 foreach ($this->injectors as $ix => $injector) {
112 if (!$error)
continue;
113 array_splice($this->injectors, $ix, 1);
114 trigger_error(
"Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING);
132 $reprocess ? $reprocess =
false :
$t++
136 if (is_int($i) && $i >= 0) {
140 $rewind_to = $this->injectors[$i]->getRewind();
141 if (is_int($rewind_to) && $rewind_to <
$t) {
142 if ($rewind_to < 0) $rewind_to = 0;
143 while (
$t > $rewind_to) {
148 unset($prev->skip[$i]);
160 if (empty($this->stack))
break;
163 $top_nesting = array_pop($this->stack);
164 $this->stack[] = $top_nesting;
167 if ($e && !isset($top_nesting->armor[
'MakeWellFormed_TagClosedError'])) {
168 $e->send(E_NOTICE,
'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting);
185 if (empty($token->is_tag)) {
187 foreach ($this->injectors as $i => $injector) {
188 if (isset($token->skip[$i]))
continue;
189 if ($token->rewind !== null && $token->rewind !== $i)
continue;
190 $injector->handleText($token);
200 if (isset($definition->info[$token->name])) {
201 $type = $definition->info[$token->name]->child->type;
215 $this->
insertBefore(
new HTMLPurifier_Token_Start($token->name, $token->attr, $token->line, $token->col, $token->armor));
219 } elseif ($token instanceof HTMLPurifier_Token_Empty) {
222 } elseif ($token instanceof HTMLPurifier_Token_Start) {
226 if (!empty($this->stack)) {
241 $parent = array_pop($this->stack);
242 $this->stack[] = $parent;
244 if (isset($definition->info[$parent->name])) {
245 $elements = $definition->info[$parent->name]->child->getAllowedElements(
$config);
246 $autoclose = !isset($elements[$token->name]);
251 if ($autoclose && $definition->info[$token->name]->wrap) {
255 $wrapname = $definition->info[$token->name]->wrap;
256 $wrapdef = $definition->info[$wrapname];
257 $elements = $wrapdef->child->getAllowedElements(
$config);
258 $parent_elements = $definition->info[$parent->name]->child->getAllowedElements(
$config);
259 if (isset($elements[$token->name]) && isset($parent_elements[$wrapname])) {
260 $newtoken =
new HTMLPurifier_Token_Start($wrapname);
268 if ($autoclose && $definition->info[$parent->name]->formatting) {
275 $autoclose_ok = isset($global_parent_allowed_elements[$token->name]);
276 if (!$autoclose_ok) {
277 foreach ($this->stack as $ancestor) {
278 $elements = $definition->info[$ancestor->name]->child->getAllowedElements(
$config);
279 if (isset($elements[$token->name])) {
280 $autoclose_ok =
true;
283 if ($definition->info[$token->name]->wrap) {
284 $wrapname = $definition->info[$token->name]->wrap;
285 $wrapdef = $definition->info[$wrapname];
286 $wrap_elements = $wrapdef->child->getAllowedElements(
$config);
287 if (isset($wrap_elements[$token->name]) && isset($elements[$wrapname])) {
288 $autoclose_ok =
true;
297 $new_token->start = $parent;
299 $element = clone $parent;
301 $element->armor[
'MakeWellFormed_TagClosedError'] =
true;
302 $element->carryover =
true;
303 $this->
processToken(array($new_token, $token, $element));
308 if ($e && !isset($parent->armor[
'MakeWellFormed_TagClosedError'])) {
310 $e->send(E_NOTICE,
'Strategy_MakeWellFormed: Tag auto closed', $parent);
312 $e->send(E_NOTICE,
'Strategy_MakeWellFormed: Tag carryover', $parent);
327 foreach ($this->injectors as $i => $injector) {
328 if (isset($token->skip[$i]))
continue;
329 if ($token->rewind !== null && $token->rewind !== $i)
continue;
330 $injector->handleElement($token);
338 if ($token instanceof HTMLPurifier_Token_Start) {
339 $this->stack[] = $token;
341 throw new HTMLPurifier_Exception(
'Improper handling of end tag in start code; possible error in MakeWellFormed');
353 if (empty($this->stack)) {
354 if ($escape_invalid_tags) {
355 if ($e) $e->send(E_WARNING,
'Strategy_MakeWellFormed: Unnecessary end tag to text');
357 $generator->generateFromToken($token)
361 if ($e) $e->send(E_WARNING,
'Strategy_MakeWellFormed: Unnecessary end tag removed');
371 $current_parent = array_pop($this->stack);
372 if ($current_parent->name == $token->name) {
373 $token->start = $current_parent;
374 foreach ($this->injectors as $i => $injector) {
375 if (isset($token->skip[$i]))
continue;
376 if ($token->rewind !== null && $token->rewind !== $i)
continue;
377 $injector->handleEnd($token);
379 $this->stack[] = $current_parent;
389 $this->stack[] = $current_parent;
393 $size = count($this->stack);
395 $skipped_tags =
false;
396 for ($j =
$size - 2; $j >= 0; $j--) {
397 if ($this->stack[$j]->name == $token->name) {
398 $skipped_tags = array_slice($this->stack, $j);
404 if ($skipped_tags ===
false) {
405 if ($escape_invalid_tags) {
407 $generator->generateFromToken($token)
409 if ($e) $e->send(E_WARNING,
'Strategy_MakeWellFormed: Stray end tag to text');
412 if ($e) $e->send(E_WARNING,
'Strategy_MakeWellFormed: Stray end tag removed');
419 $c = count($skipped_tags);
421 for ($j = $c - 1; $j > 0; $j--) {
424 if (!isset($skipped_tags[$j]->armor[
'MakeWellFormed_TagClosedError'])) {
425 $e->send(E_NOTICE,
'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$j]);
431 $replace = array($token);
432 for ($j = 1; $j < $c; $j++) {
434 $new_token =
new HTMLPurifier_Token_End($skipped_tags[$j]->name);
435 $new_token->start = $skipped_tags[$j];
436 array_unshift($replace, $new_token);
437 if (isset($definition->info[$new_token->name]) && $definition->info[$new_token->name]->formatting) {
439 $element = clone $skipped_tags[$j];
440 $element->carryover =
true;
441 $element->armor[
'MakeWellFormed_TagClosedError'] =
true;
442 $replace[] = $element;
450 $context->destroy(
'CurrentNesting');
455 unset($this->injectors, $this->stack, $this->tokens, $this->t);
482 if (is_object($token)) $token = array(1, $token);
483 if (is_int($token)) $token = array($token);
484 if ($token ===
false) $token = array(1);
486 if (!is_int($token[0])) array_unshift($token, 1);
492 $delete = array_shift($token);
493 $old = array_splice($this->tokens, $this->t, $delete, $token);
495 if ($injector > -1) {
497 $oldskip = isset($old[0]) ? $old[0]->skip : array();
498 foreach ($token as $object) {
499 $object->skip = $oldskip;
500 $object->skip[$injector] =
true;
511 array_splice($this->tokens, $this->t, 0, array($token));
518 private function remove() {
519 array_splice($this->tokens, $this->t, 1);
526 private function swap($token) {