简体   繁体   中英

How to escape xpath in php

What is the best way to escape a var given to xpath.

$test = simplexml_load_file('test.xml');
$var = $_GET['var']; // injection heaven
$result = $test->xpath('/catalog/items/item[title="'.$var.'"]');

Normally I use PDO binding. OR stuff like that but they all require a database connection. Is it enough to just addslashes and htmlentities .
Or is there a better to do this?

According to the XPath 1.0 spec , the syntax for literals is as follows:

[29]    Literal    ::=      '"' [^"]* '"'   
                          | "'" [^']* "'"

Which means that in a single-quoted string, anything other than a single quote is allowed. In a double-quoted string, anything other than a double quote is allowed.

you can't really make a general xpath escape function, but you can make an XPath quote function, which can be used like

$result = $test->xpath('/catalog/items/item[title='.xpath_quote($var).']');

implementation:

//based on https://stackoverflow.com/a/1352556/1067003
function xpath_quote(string $value):string{
    if(false===strpos($value,'"')){
        return '"'.$value.'"';
    }
    if(false===strpos($value,'\'')){
        return '\''.$value.'\'';
    }
    // if the value contains both single and double quotes, construct an
    // expression that concatenates all non-double-quote substrings with
    // the quotes, e.g.:
    //
    //    concat("'foo'", '"', "bar")
    $sb='concat(';
    $substrings=explode('"',$value);
    for($i=0;$i<count($substrings);++$i){
        $needComma=($i>0);
        if($substrings[$i]!==''){
            if($i>0){
                $sb.=', ';
            }
            $sb.='"'.$substrings[$i].'"';
            $needComma=true;
        }
        if($i < (count($substrings) -1)){
            if($needComma){
                $sb.=', ';
            }
            $sb.="'\"'";
        }
    }
    $sb.=')';
    return $sb;
}

and it's based on the C# xpath quote function from https://stackoverflow.com/a/1352556/1067003

Is it enough to just addslashes and htmlentities. Or is there a better to do this?

i would be sleeping better at night by using a proper xpath quote function, rather than addslashes/htmlentities, but i don't really know if those technically are sufficient or not.

The above answers are for XPath 1.0, which is the only version PHP supports. For completeness, I'll note that starting with XPath 2.0 , string literals can contain quotes by doubling them:

[74]        StringLiteral      ::=      ('"' (EscapeQuot | [^"])* '"') | ("'" (EscapeApos | [^'])* "'")
[75]        EscapeQuot     ::=      '""'
[76]        EscapeApos     ::=      "''"

eg to search for the title Some "quoted" title , you would use the following xpath:

/catalog/items/item[title="Some ""quoted"" title"]

This could be implemented with a simple string escape (but I won't give an example, since you're using PHP and as mentioned PHP does not support XPath 2.0).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM