1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
--TEST--
Test DOMXPath::quote with various inputs
--EXTENSIONS--
dom
--SKIPIF--
<?php if (!class_exists('DOMXPath')) die('skip DOMXPath not available.'); ?>
--FILE--
<?php
$dom = new DOMDocument();
$xpath = new DOMXPath($dom);
/**
* Quote a string for use in an XPath expression.
*
* Example: $xp->query("//span[contains(text()," . $xp->quote($string) . ")]")
*
* @param string $string string to quote.
* @return string quoted string.
*/
function UserlandDOMXPathQuote(string $string): string
{
if (false === \strpos($string, '\'')) {
return '\'' . $string . '\'';
}
if (false === \strpos($string, '"')) {
return '"' . $string . '"';
}
// if the string contains both single and double quotes, construct an
// expression that concatenates all non-double-quote substrings with
// the quotes, e.g.:
// 'foo'"bar => concat("'foo'", '"bar")
$sb = [];
while ($string !== '') {
$bytesUntilSingleQuote = \strcspn($string, '\'');
$bytesUntilDoubleQuote = \strcspn($string, '"');
$quoteMethod = ($bytesUntilSingleQuote > $bytesUntilDoubleQuote) ? "'" : '"';
$bytesUntilQuote = \max($bytesUntilSingleQuote, $bytesUntilDoubleQuote);
$sb[] = $quoteMethod . \substr($string, 0, $bytesUntilQuote) . $quoteMethod;
$string = \substr($string, $bytesUntilQuote);
}
$sb = \implode(',', $sb);
return 'concat(' . $sb . ')';
}
$tests = [
'' => "''", // empty string
'foo' => "'foo'", // no quotes
'"foo' => '\'"foo\'', // double quotes only
'\'foo' => '"\'foo"', // single quotes only
'\'foo"bar' => 'concat("\'foo",\'"bar\')', // both; double quotes in mid-string
'\'foo"bar"baz' => 'concat("\'foo",\'"bar"baz\')', // multiple double quotes in mid-string
'\'foo"' => 'concat("\'foo",\'"\')', // string ends with double quotes
'\'foo""' => 'concat("\'foo",\'""\')', // string ends with run of double quotes
'"\'foo' => 'concat(\'"\',"\'foo")', // string begins with double quotes
'""\'foo' => 'concat(\'""\',"\'foo")', // string begins with run of double quotes
'\'foo""bar' => 'concat("\'foo",\'""bar\')', // run of double quotes in mid-string
];
foreach ($tests as $input => $expected) {
$result = $xpath->quote($input);
if ($result === $expected) {
echo "Pass: {$input} => {$result}\n";
} else {
echo 'Fail: ';
var_dump([
'input' => $input,
'expected' => $expected,
'result' => $result,
'userland_implementation_result' => UserlandDOMXPathQuote($input),
]);
}
}
?>
--EXPECT--
Pass: => ''
Pass: foo => 'foo'
Pass: "foo => '"foo'
Pass: 'foo => "'foo"
Pass: 'foo"bar => concat("'foo",'"bar')
Pass: 'foo"bar"baz => concat("'foo",'"bar"baz')
Pass: 'foo" => concat("'foo",'"')
Pass: 'foo"" => concat("'foo",'""')
Pass: "'foo => concat('"',"'foo")
Pass: ""'foo => concat('""',"'foo")
Pass: 'foo""bar => concat("'foo",'""bar')
|