| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 | <?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. * * A note on how handlers create changes; this is done by assigning a new * value to the $token reference. These values can take a variety of forms and * are best described HTMLPurifier_Strategy_MakeWellFormed->processToken() * documentation. * * @todo Allow injectors to request a re-run on their output. This *       would help if an operation is recursive. */abstract class HTMLPurifier_Injector{    /**     * Advisory name of injector, this is for friendly error messages.     * @type string     */    public $name;    /**     * @type HTMLPurifier_HTMLDefinition     */    protected $htmlDefinition;    /**     * Reference to CurrentNesting variable in Context. This is an array     * list of tokens that we are currently "inside"     * @type array     */    protected $currentNesting;    /**     * Reference to current token.     * @type HTMLPurifier_Token     */    protected $currentToken;    /**     * Reference to InputZipper variable in Context.     * @type HTMLPurifier_Zipper     */    protected $inputZipper;    /**     * 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')     * @type array     */    public $needed = array();    /**     * Number of elements to rewind backwards (relative).     * @type bool|int     */    protected $rewindOffset = 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.     * @param bool|int $offset     * @warning HTML Purifier will prevent you from fast-forwarding with this     *          function.     */    public function rewindOffset($offset)    {        $this->rewindOffset = $offset;    }    /**     * Retrieves rewind offset, and then unsets it.     * @return bool|int     */    public function getRewindOffset()    {        $r = $this->rewindOffset;        $this->rewindOffset = false;        return $r;    }    /**     * 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     * will work with the Injector (see checkNeeded()).     * @param HTMLPurifier_Config $config     * @param HTMLPurifier_Context $context     * @return bool|string Boolean false if success, string of missing needed element/attribute if failure     */    public function prepare($config, $context)    {        $this->htmlDefinition = $config->getHTMLDefinition();        // 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->currentToken   =& $context->get('CurrentToken');        $this->inputZipper    =& $context->get('InputZipper');        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 HTMLPurifier_Config $config     * @return bool|string Boolean false if success, string of missing needed element/attribute if failure     */    public function checkNeeded($config)    {        $def = $config->getHTMLDefinition();        foreach ($this->needed as $element => $attributes) {            if (is_int($element)) {                $element = $attributes;            }            if (!isset($def->info[$element])) {                return $element;            }            if (!is_array($attributes)) {                continue;            }            foreach ($attributes as $name) {                if (!isset($def->info[$element]->attr[$name])) {                    return "$element.$name";                }            }        }        return false;    }    /**     * Tests if the context node allows a certain element     * @param string $name Name of element to test for     * @return bool True if element is allowed, false if it is not     */    public function allowsElement($name)    {        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;        }        // check for exclusion        if (!empty($this->currentNesting)) {            for ($i = count($this->currentNesting) - 2; $i >= 0; $i--) {                $node = $this->currentNesting[$i];                $def  = $this->htmlDefinition->info[$node->name];                if (isset($def->excludes[$name])) {                    return false;                }            }        }        return true;    }    /**     * 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 int $i Current integer index variable for inputTokens     * @param HTMLPurifier_Token $current Current token variable.     *          Do NOT use $token, as that variable is also a reference     * @return bool     */    protected function forward(&$i, &$current)    {        if ($i === null) {            $i = count($this->inputZipper->back) - 1;        } else {            $i--;        }        if ($i < 0) {            return false;        }        $current = $this->inputZipper->back[$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.     * @param int $i Current integer index variable for inputTokens     * @param HTMLPurifier_Token $current Current token variable.     *          Do NOT use $token, as that variable is also a reference     * @param int $nesting     * @return bool     */    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 int $i Current integer index variable for inputTokens     * @param HTMLPurifier_Token $current Current token variable.     *          Do NOT use $token, as that variable is also a reference     * @return bool     */    protected function backward(&$i, &$current)    {        if ($i === null) {            $i = count($this->inputZipper->front) - 1;        } else {            $i--;        }        if ($i < 0) {            return false;        }        $current = $this->inputZipper->front[$i];        return true;    }    /**     * Handler that is called when a text token is processed     */    public function handleText(&$token)    {    }    /**     * Handler that is called when a start or empty token is processed     */    public function handleElement(&$token)    {    }    /**     * Handler that is called when an end token is processed     */    public function handleEnd(&$token)    {        $this->notifyEnd($token);    }    /**     * Notifier that is called when an end token is processed     * @param HTMLPurifier_Token $token Current token variable.     * @note This differs from handlers in that the token is read-only     * @deprecated     */    public function notifyEnd($token)    {    }}// vim: et sw=4 sts=4
 |