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);
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) {
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;
190 $injector->handleText(
$token);
200 if (isset($definition->info[
$token->name])) {
201 $type = $definition->info[
$token->name]->child->type;
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;
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;
330 $injector->handleElement(
$token);
338 if (
$token instanceof HTMLPurifier_Token_Start) {
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;
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]);
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);
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);