-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Request #64137: XSLTProcessor::setParameter() should allow both quotes to be used #12331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,8 +9,9 @@ $proc->importStylesheet($xsl); | |
$proc->setParameter('', '', '"\''); | ||
$proc->transformToXml($dom); | ||
?> | ||
--EXPECTF-- | ||
Warning: XSLTProcessor::transformToXml(): Cannot create XPath expression (string contains both quote and double-quotes) in %s on line %d | ||
Done | ||
--EXPECT-- | ||
Done | ||
--CREDITS-- | ||
Christian Weiske, [email protected] | ||
PHP Testfest Berlin 2009-05-09 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--TEST-- | ||
Request #64137 (XSLTProcessor::setParameter() should allow both quotes to be used) | ||
--EXTENSIONS-- | ||
xsl | ||
--FILE-- | ||
<?php | ||
|
||
function test(string $input) { | ||
$xml = new DOMDocument; | ||
$xml->loadXML('<X/>'); | ||
|
||
$xsl = new DOMDocument; | ||
$xsl->loadXML('<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="text"/><xsl:param name="foo"/><xsl:template match="/"><xsl:value-of select="$foo"/></xsl:template></xsl:stylesheet>'); | ||
|
||
$xslt = new XSLTProcessor; | ||
$xslt->importStylesheet($xsl); | ||
$xslt->setParameter('', 'foo', $input); | ||
|
||
echo $xslt->transformToXml($xml), "\n"; | ||
} | ||
|
||
test(""); | ||
test("a'"); | ||
test("a\""); | ||
test("fo'o\"ba'r\"ba'z"); | ||
test("\"\"\"fo'o\"ba'r\"ba'z\"\"\""); | ||
test("'''\"\"\"fo'o\"ba'r\"ba'z\"\"\"'''"); | ||
|
||
?> | ||
--EXPECT-- | ||
a' | ||
a" | ||
fo'o"ba'r"ba'z | ||
"""fo'o"ba'r"ba'z""" | ||
'''"""fo'o"ba'r"ba'z"""''' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
--TEST-- | ||
setParameter exceptions test | ||
--EXTENSIONS-- | ||
xsl | ||
--FILE-- | ||
<?php | ||
|
||
function test(array $options) { | ||
$xml = new DOMDocument; | ||
$xml->loadXML('<X/>'); | ||
|
||
$xsl = new DOMDocument; | ||
$xsl->loadXML('<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="text"/><xsl:param name="foo"/><xsl:template match="/"><xsl:value-of select="$foo"/></xsl:template></xsl:stylesheet>'); | ||
|
||
$xslt = new XSLTProcessor; | ||
$xslt->importStylesheet($xsl); | ||
$xslt->setParameter('', $options); | ||
|
||
echo $xslt->transformToXml($xml), "\n"; | ||
} | ||
|
||
echo "--- Invalid key ---\n"; | ||
|
||
try { | ||
test([ | ||
12345 => "foo" | ||
]); | ||
} catch (TypeError $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
echo "--- Valid key and value, but special cases ---\n"; | ||
|
||
test([ | ||
"foo" => null, | ||
]); | ||
|
||
test([ | ||
"foo" => true, | ||
]); | ||
|
||
echo "--- Exception from Stringable should abort execution ---\n"; | ||
|
||
class MyStringable { | ||
public function __toString(): string { | ||
throw new Exception("exception!"); | ||
} | ||
} | ||
|
||
try { | ||
test([ | ||
"foo" => new MyStringable, | ||
]); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
echo "--- Exception from warning should abort execution ---\n"; | ||
|
||
set_error_handler(function($errno, $errstr) { | ||
throw new Exception($errstr); | ||
}, E_WARNING); | ||
|
||
try { | ||
test([ | ||
"foo" => [], | ||
"foo2" => [], | ||
]); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
set_error_handler(null, E_WARNING); | ||
|
||
echo "--- Warning may continue execution ---\n"; | ||
|
||
try { | ||
test([ | ||
"foo" => [], | ||
"foo2" => [], | ||
]); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
--- Invalid key --- | ||
XSLTProcessor::setParameter(): Argument #2 ($name) must contain only string keys | ||
--- Valid key and value, but special cases --- | ||
|
||
1 | ||
--- Exception from Stringable should abort execution --- | ||
exception! | ||
--- Exception from warning should abort execution --- | ||
Array to string conversion | ||
--- Warning may continue execution --- | ||
|
||
Warning: Array to string conversion in %s on line %d | ||
|
||
Warning: Array to string conversion in %s on line %d | ||
Array |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,8 +11,9 @@ $proc->importStylesheet($xsl); | |
$proc->setParameter('', '', '"\''); | ||
$proc->transformToXml($dom); | ||
?> | ||
--EXPECTF-- | ||
Warning: XSLTProcessor::transformToXml(): Cannot create XPath expression (string contains both quote and double-quotes) in %s on line %d | ||
Done | ||
--EXPECT-- | ||
Done | ||
--CREDITS-- | ||
Christian Weiske, [email protected] | ||
PHP Testfest Berlin 2009-05-09 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,75 +21,29 @@ | |
|
||
#include "php.h" | ||
#include "php_xsl.h" | ||
#include <libxslt/variables.h> | ||
#include "ext/libxml/php_libxml.h" | ||
|
||
/* {{{ php_xsl_xslt_string_to_xpathexpr() | ||
Translates a string to a XPath Expression */ | ||
static char *php_xsl_xslt_string_to_xpathexpr(const char *str) | ||
{ | ||
const xmlChar *string = (const xmlChar *)str; | ||
|
||
xmlChar *value; | ||
int str_len; | ||
|
||
str_len = xmlStrlen(string) + 3; | ||
|
||
if (xmlStrchr(string, '"')) { | ||
if (xmlStrchr(string, '\'')) { | ||
php_error_docref(NULL, E_WARNING, "Cannot create XPath expression (string contains both quote and double-quotes)"); | ||
return NULL; | ||
} | ||
value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0); | ||
snprintf((char*)value, str_len, "'%s'", string); | ||
} else { | ||
value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0); | ||
snprintf((char *)value, str_len, "\"%s\"", string); | ||
} | ||
return (char *) value; | ||
} | ||
/* }}} */ | ||
|
||
/* {{{ php_xsl_xslt_make_params() | ||
Translates a PHP array to a libxslt parameters array */ | ||
static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params) | ||
static zend_result php_xsl_xslt_apply_params(xsltTransformContextPtr ctxt, HashTable *params) | ||
{ | ||
|
||
int parsize; | ||
zval *value; | ||
char *xpath_expr; | ||
zend_string *string_key; | ||
char **params = NULL; | ||
int i = 0; | ||
|
||
parsize = (2 * zend_hash_num_elements(parht) + 1) * sizeof(char *); | ||
params = (char **)safe_emalloc((2 * zend_hash_num_elements(parht) + 1), sizeof(char *), 0); | ||
memset((char *)params, 0, parsize); | ||
zval *value; | ||
|
||
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(parht, string_key, value) { | ||
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(params, string_key, value) { | ||
ZEND_ASSERT(string_key != NULL); | ||
if (Z_TYPE_P(value) != IS_STRING) { | ||
if (!try_convert_to_string(value)) { | ||
efree(params); | ||
return NULL; | ||
} | ||
} | ||
/* Already a string because of setParameter() */ | ||
ZEND_ASSERT(Z_TYPE_P(value) == IS_STRING); | ||
|
||
if (!xpath_params) { | ||
xpath_expr = php_xsl_xslt_string_to_xpathexpr(Z_STRVAL_P(value)); | ||
} else { | ||
xpath_expr = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); | ||
} | ||
if (xpath_expr) { | ||
params[i++] = estrndup(ZSTR_VAL(string_key), ZSTR_LEN(string_key)); | ||
params[i++] = xpath_expr; | ||
int result = xsltQuoteOneUserParam(ctxt, (const xmlChar *) ZSTR_VAL(string_key), (const xmlChar *) Z_STRVAL_P(value)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Won't this potentially cause issues with values (or even keys...) that have a nul byte? Seems with the manual quoting this would have been taken care of? Maybe this needs to be checked in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes this causes issues with NUL bytes.
Nope, even today if you do this: $xslt->setParameter('', 'foo', "a\0b");
var_dump($xslt->getParameter('', 'foo')); you get the output
That would be best. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok implemented the null byte check now |
||
if (result < 0) { | ||
php_error_docref(NULL, E_WARNING, "Could not apply parameter '%s'", ZSTR_VAL(string_key)); | ||
nielsdos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return FAILURE; | ||
} | ||
} ZEND_HASH_FOREACH_END(); | ||
|
||
params[i++] = NULL; | ||
|
||
return params; | ||
return SUCCESS; | ||
} | ||
/* }}} */ | ||
|
||
static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */ | ||
{ | ||
|
@@ -402,8 +356,6 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl | |
xmlNodePtr node = NULL; | ||
xsltTransformContextPtr ctxt; | ||
php_libxml_node_object *object; | ||
char **params = NULL; | ||
int clone; | ||
zval *doXInclude, rv; | ||
zend_string *member; | ||
FILE *f; | ||
|
@@ -440,10 +392,6 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl | |
f = NULL; | ||
} | ||
|
||
if (intern->parameter) { | ||
params = php_xsl_xslt_make_params(intern->parameter, 0); | ||
} | ||
|
||
intern->doc = emalloc(sizeof(php_libxml_node_object)); | ||
memset(intern->doc, 0, sizeof(php_libxml_node_object)); | ||
|
||
|
@@ -459,6 +407,13 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl | |
ctxt = xsltNewTransformContext(style, doc); | ||
ctxt->_private = (void *) intern; | ||
|
||
if (intern->parameter) { | ||
zend_result status = php_xsl_xslt_apply_params(ctxt, intern->parameter); | ||
if (UNEXPECTED(status != SUCCESS) && EG(exception)) { | ||
goto out; | ||
} | ||
} | ||
|
||
member = ZSTR_INIT_LITERAL("doXInclude", 0); | ||
doXInclude = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_IS, NULL, &rv); | ||
if (Z_TYPE_P(doXInclude) != IS_NULL) { | ||
|
@@ -506,8 +461,10 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl | |
if (secPrefsError == 1) { | ||
php_error_docref(NULL, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons"); | ||
} else { | ||
newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params, NULL, f, ctxt); | ||
newdocp = xsltApplyStylesheetUser(style, doc, /* params (handled manually) */ NULL, /* output */ NULL, f, ctxt); | ||
} | ||
|
||
out: | ||
if (f) { | ||
fclose(f); | ||
} | ||
|
@@ -527,14 +484,6 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl | |
efree(intern->doc); | ||
intern->doc = NULL; | ||
|
||
if (params) { | ||
clone = 0; | ||
while(params[clone]) { | ||
efree(params[clone++]); | ||
} | ||
efree(params); | ||
} | ||
|
||
return newdocp; | ||
|
||
} | ||
|
@@ -737,7 +686,7 @@ PHP_METHOD(XSLTProcessor, getParameter) | |
} | ||
intern = Z_XSL_P(id); | ||
if ((value = zend_hash_find(intern->parameter, name)) != NULL) { | ||
RETURN_STR(zval_get_string(value)); | ||
RETURN_STR_COPY(Z_STR_P(value)); | ||
} else { | ||
RETURN_FALSE; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be clearer, as I was slightly confused just reading the output