2007-06-23 18:50:41 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Injects tokens into the document while parsing for well-formedness.
|
|
|
|
* This enables "formatter-like" functionality such as auto-paragraphing,
|
|
|
|
* smiley-ification and linkification to take place.
|
2007-09-09 01:27:09 +00:00
|
|
|
*
|
|
|
|
* @todo Allow injectors to request a re-run on their output. This
|
|
|
|
* would help if an operation is recursive.
|
2007-06-23 18:50:41 +00:00
|
|
|
*/
|
2007-12-05 01:26:28 +00:00
|
|
|
abstract class HTMLPurifier_Injector
|
2007-06-23 18:50:41 +00:00
|
|
|
{
|
|
|
|
|
2007-06-28 13:06:15 +00:00
|
|
|
/**
|
|
|
|
* Advisory name of injector, this is for friendly error messages
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
public $name;
|
2007-06-28 13:06:15 +00:00
|
|
|
|
2007-06-24 17:44:27 +00:00
|
|
|
/**
|
|
|
|
* Instance of HTMLPurifier_HTMLDefinition
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
protected $htmlDefinition;
|
2007-06-24 17:44:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to CurrentNesting variable in Context. This is an array
|
|
|
|
* list of tokens that we are currently "inside"
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
protected $currentNesting;
|
2007-06-24 17:44:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to InputTokens variable in Context. This is an array
|
|
|
|
* list of the input tokens that are being processed.
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
protected $inputTokens;
|
2007-06-24 17:44:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to InputIndex variable in Context. This is an integer
|
|
|
|
* array index for $this->inputTokens that indicates what token
|
|
|
|
* is currently being processed.
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
protected $inputIndex;
|
2007-06-24 17:44:27 +00:00
|
|
|
|
|
|
|
/**
|
2007-06-28 13:06:15 +00:00
|
|
|
* Array of elements and attributes this injector creates and therefore
|
|
|
|
* need to be allowed by the definition. Takes form of
|
|
|
|
* array('element' => array('attr', 'attr2'), 'element2')
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
public $needed = array();
|
2007-06-28 13:06:15 +00:00
|
|
|
|
2008-06-27 20:09:14 +00:00
|
|
|
/**
|
|
|
|
* Index of inputTokens to rewind to.
|
|
|
|
*/
|
|
|
|
protected $rewind = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Rewind to a spot to re-perform processing. This is useful if you
|
|
|
|
* deleted a node, and now need to see if this change affected any
|
|
|
|
* earlier nodes. Rewinding does not affect other injectors, and can
|
|
|
|
* result in infinite loops if not used carefully.
|
|
|
|
*/
|
|
|
|
public function rewind($index) {
|
|
|
|
$this->rewind = $index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves rewind, and then unsets it.
|
|
|
|
*/
|
|
|
|
public function getRewind() {
|
|
|
|
$r = $this->rewind;
|
|
|
|
$this->rewind = false;
|
|
|
|
return $r;
|
|
|
|
}
|
|
|
|
|
2007-06-28 13:06:15 +00:00
|
|
|
/**
|
|
|
|
* Prepares the injector by giving it the config and context objects:
|
|
|
|
* this allows references to important variables to be made within
|
|
|
|
* the injector. This function also checks if the HTML environment
|
2008-06-09 01:23:05 +00:00
|
|
|
* will work with the Injector (see checkNeeded()).
|
2007-06-28 13:06:15 +00:00
|
|
|
* @param $config Instance of HTMLPurifier_Config
|
|
|
|
* @param $context Instance of HTMLPurifier_Context
|
|
|
|
* @return Boolean false if success, string of missing needed element/attribute if failure
|
2007-06-24 17:44:27 +00:00
|
|
|
*/
|
2008-01-05 00:10:43 +00:00
|
|
|
public function prepare($config, $context) {
|
2007-06-24 17:44:27 +00:00
|
|
|
$this->htmlDefinition = $config->getHTMLDefinition();
|
2008-06-09 01:23:05 +00:00
|
|
|
// Even though this might fail, some unit tests ignore this and
|
|
|
|
// still test checkNeeded, so be careful. Maybe get rid of that
|
|
|
|
// dependency.
|
|
|
|
$result = $this->checkNeeded($config);
|
|
|
|
if ($result !== false) return $result;
|
|
|
|
$this->currentNesting =& $context->get('CurrentNesting');
|
|
|
|
$this->inputTokens =& $context->get('InputTokens');
|
|
|
|
$this->inputIndex =& $context->get('InputIndex');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function checks if the HTML environment
|
|
|
|
* will work with the Injector: if p tags are not allowed, the
|
|
|
|
* Auto-Paragraphing injector should not be enabled.
|
|
|
|
* @param $config Instance of HTMLPurifier_Config
|
|
|
|
* @param $context Instance of HTMLPurifier_Context
|
|
|
|
* @return Boolean false if success, string of missing needed element/attribute if failure
|
|
|
|
*/
|
|
|
|
public function checkNeeded($config) {
|
|
|
|
$def = $config->getHTMLDefinition();
|
2007-06-28 13:06:15 +00:00
|
|
|
foreach ($this->needed as $element => $attributes) {
|
|
|
|
if (is_int($element)) $element = $attributes;
|
2008-06-09 01:23:05 +00:00
|
|
|
if (!isset($def->info[$element])) return $element;
|
2007-06-28 13:06:15 +00:00
|
|
|
if (!is_array($attributes)) continue;
|
|
|
|
foreach ($attributes as $name) {
|
2008-06-09 01:23:05 +00:00
|
|
|
if (!isset($def->info[$element]->attr[$name])) return "$element.$name";
|
2007-06-28 13:06:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2007-06-24 17:44:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tests if the context node allows a certain element
|
|
|
|
* @param $name Name of element to test for
|
|
|
|
* @return True if element is allowed, false if it is not
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
public function allowsElement($name) {
|
2007-06-24 17:44:27 +00:00
|
|
|
if (!empty($this->currentNesting)) {
|
|
|
|
$parent_token = array_pop($this->currentNesting);
|
|
|
|
$this->currentNesting[] = $parent_token;
|
|
|
|
$parent = $this->htmlDefinition->info[$parent_token->name];
|
|
|
|
} else {
|
|
|
|
$parent = $this->htmlDefinition->info_parent_def;
|
|
|
|
}
|
|
|
|
if (!isset($parent->child->elements[$name]) || isset($parent->excludes[$name])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Implement Injector->handleEnd, with lots of refactoring for injector.
Previous design of injector streaming involved editability only to start, empty
and text tokens, because they could be safely modified without causing formedness
errors. By modifying notifyEnd to operate before MakeWellFormed's safeguards
kick into effect, it can be converted into a handle function, allowing for
arbitrary modification of end tags.
This change involved quite a bit of restructuring of the MakeWellFormed code,
including the moving of end of document tags to inside the loop, so rewinding
on those tags would be functional, increased reuse of the end tag codepath by
code that inserts end tags (as they could be changed out from under you), and
processToken modified to have an extra parameter to force re-processing of
a token if the original token was an end token.
We're not exactly sure if handleEnd works at this point, but the important
talking point about this refactoring is that nothing else broke. Also, a number
of convenience functions were moved from AutoParagraph to the Injector
supertype (specifically: forward, forwardToEndToken, backward, and current).
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-01 04:54:51 +00:00
|
|
|
/**
|
|
|
|
* Iterator function, which starts with the next token and continues until
|
|
|
|
* you reach the end of the input tokens.
|
|
|
|
* @warning Please prevent previous references from interfering with this
|
|
|
|
* functions by setting $i = null beforehand!
|
|
|
|
* @param &$i Current integer index variable for inputTokens
|
|
|
|
* @param &$current Current token variable. Do NOT use $token, as that variable is also a reference
|
|
|
|
*/
|
|
|
|
protected function forward(&$i, &$current) {
|
|
|
|
if ($i === null) $i = $this->inputIndex + 1;
|
|
|
|
else $i++;
|
|
|
|
if (!isset($this->inputTokens[$i])) return false;
|
|
|
|
$current = $this->inputTokens[$i];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Similar to _forward, but accepts a third parameter $nesting (which
|
|
|
|
* should be initialized at 0) and stops when we hit the end tag
|
|
|
|
* for the node $this->inputIndex starts in.
|
|
|
|
*/
|
|
|
|
protected function forwardUntilEndToken(&$i, &$current, &$nesting) {
|
|
|
|
$result = $this->forward($i, $current);
|
|
|
|
if (!$result) return false;
|
|
|
|
if ($nesting === null) $nesting = 0;
|
|
|
|
if ($current instanceof HTMLPurifier_Token_Start) $nesting++;
|
|
|
|
elseif ($current instanceof HTMLPurifier_Token_End) {
|
|
|
|
if ($nesting <= 0) return false;
|
|
|
|
$nesting--;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Iterator function, starts with the previous token and continues until
|
|
|
|
* you reach the beginning of input tokens.
|
|
|
|
* @warning Please prevent previous references from interfering with this
|
|
|
|
* functions by setting $i = null beforehand!
|
|
|
|
* @param &$i Current integer index variable for inputTokens
|
|
|
|
* @param &$current Current token variable. Do NOT use $token, as that variable is also a reference
|
|
|
|
*/
|
|
|
|
protected function backward(&$i, &$current) {
|
|
|
|
if ($i === null) $i = $this->inputIndex - 1;
|
|
|
|
else $i--;
|
|
|
|
if ($i < 0) return false;
|
|
|
|
$current = $this->inputTokens[$i];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the iterator at the current position. Use in a do {} while;
|
|
|
|
* loop to force the _forward and _backward functions to start at the
|
|
|
|
* current location.
|
|
|
|
* @warning Please prevent previous references from interfering with this
|
|
|
|
* functions by setting $i = null beforehand!
|
|
|
|
* @param &$i Current integer index variable for inputTokens
|
|
|
|
* @param &$current Current token variable. Do NOT use $token, as that variable is also a reference
|
|
|
|
*/
|
|
|
|
protected function current(&$i, &$current) {
|
|
|
|
if ($i === null) $i = $this->inputIndex;
|
|
|
|
$current = $this->inputTokens[$i];
|
|
|
|
}
|
|
|
|
|
2007-06-23 18:50:41 +00:00
|
|
|
/**
|
|
|
|
* Handler that is called when a text token is processed
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
public function handleText(&$token) {}
|
2007-06-23 18:50:41 +00:00
|
|
|
|
|
|
|
/**
|
2007-06-29 00:24:59 +00:00
|
|
|
* Handler that is called when a start or empty token is processed
|
2007-06-23 18:50:41 +00:00
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
public function handleElement(&$token) {}
|
2007-06-23 18:50:41 +00:00
|
|
|
|
Implement Injector->handleEnd, with lots of refactoring for injector.
Previous design of injector streaming involved editability only to start, empty
and text tokens, because they could be safely modified without causing formedness
errors. By modifying notifyEnd to operate before MakeWellFormed's safeguards
kick into effect, it can be converted into a handle function, allowing for
arbitrary modification of end tags.
This change involved quite a bit of restructuring of the MakeWellFormed code,
including the moving of end of document tags to inside the loop, so rewinding
on those tags would be functional, increased reuse of the end tag codepath by
code that inserts end tags (as they could be changed out from under you), and
processToken modified to have an extra parameter to force re-processing of
a token if the original token was an end token.
We're not exactly sure if handleEnd works at this point, but the important
talking point about this refactoring is that nothing else broke. Also, a number
of convenience functions were moved from AutoParagraph to the Injector
supertype (specifically: forward, forwardToEndToken, backward, and current).
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-01 04:54:51 +00:00
|
|
|
/**
|
|
|
|
* Handler that is called when an end token is processed
|
|
|
|
*/
|
|
|
|
public function handleEnd(&$token) {
|
|
|
|
$this->notifyEnd($token);
|
|
|
|
}
|
|
|
|
|
2007-10-02 22:50:59 +00:00
|
|
|
/**
|
|
|
|
* Notifier that is called when an end token is processed
|
|
|
|
* @note This differs from handlers in that the token is read-only
|
|
|
|
*/
|
2007-11-25 02:24:39 +00:00
|
|
|
public function notifyEnd($token) {}
|
2007-10-02 22:50:59 +00:00
|
|
|
|
|
|
|
|
2007-06-23 18:50:41 +00:00
|
|
|
}
|
|
|
|
|