Skip to content

Commit c3ce90c

Browse files
committed
Implement request #64137 (XSLTProcessor::setParameter() should allow both quotes to be used)
This reimplements the parameter handling. Instead of quoting the strings manually, adding them to an array, and passing that as input; use the libxslt API to pass data verbatim to the processor. This also simplifies the code a lot.
1 parent 2fb9ef0 commit c3ce90c

File tree

5 files changed

+164
-79
lines changed

5 files changed

+164
-79
lines changed

ext/xsl/tests/bug48221.phpt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ $proc->importStylesheet($xsl);
99
$proc->setParameter('', '', '"\'');
1010
$proc->transformToXml($dom);
1111
?>
12-
--EXPECTF--
13-
Warning: XSLTProcessor::transformToXml(): Cannot create XPath expression (string contains both quote and double-quotes) in %s on line %d
14-
--CREDITS--
15-
Christian Weiske, cweiske@php.net
16-
PHP Testfest Berlin 2009-05-09
12+
Done
13+
--EXPECT--
14+
Done

ext/xsl/tests/bug64137.phpt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Request #64137 (XSLTProcessor::setParameter() should allow both quotes to be used)
3+
--EXTENSIONS--
4+
xsl
5+
--FILE--
6+
<?php
7+
8+
function test(string $input) {
9+
$xml = new DOMDocument;
10+
$xml->loadXML('<X/>');
11+
12+
$xsl = new DOMDocument;
13+
$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>');
14+
15+
$xslt = new XSLTProcessor;
16+
$xslt->importStylesheet($xsl);
17+
$xslt->setParameter('', 'foo', $input);
18+
19+
echo $xslt->transformToXml($xml), "\n";
20+
}
21+
22+
test("");
23+
test("a'");
24+
test("a\"");
25+
test("fo'o\"ba'r\"ba'z");
26+
test("\"\"\"fo'o\"ba'r\"ba'z\"\"\"");
27+
test("'''\"\"\"fo'o\"ba'r\"ba'z\"\"\"'''");
28+
29+
?>
30+
--EXPECT--
31+
a'
32+
a"
33+
fo'o"ba'r"ba'z
34+
"""fo'o"ba'r"ba'z"""
35+
'''"""fo'o"ba'r"ba'z"""'''
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
--TEST--
2+
setParameter exceptions test
3+
--EXTENSIONS--
4+
xsl
5+
--FILE--
6+
<?php
7+
8+
function test(array $options) {
9+
$xml = new DOMDocument;
10+
$xml->loadXML('<X/>');
11+
12+
$xsl = new DOMDocument;
13+
$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>');
14+
15+
$xslt = new XSLTProcessor;
16+
$xslt->importStylesheet($xsl);
17+
$xslt->setParameter('', $options);
18+
19+
echo $xslt->transformToXml($xml), "\n";
20+
}
21+
22+
echo "--- Invalid key ---\n";
23+
24+
try {
25+
test([
26+
12345 => "foo"
27+
]);
28+
} catch (TypeError $e) {
29+
echo $e->getMessage(), "\n";
30+
}
31+
32+
echo "--- Valid key and value, but special cases ---\n";
33+
34+
test([
35+
"foo" => null,
36+
]);
37+
38+
test([
39+
"foo" => true,
40+
]);
41+
42+
echo "--- Exception from Stringable should abort execution ---\n";
43+
44+
class MyStringable {
45+
public function __toString(): string {
46+
throw new Exception("exception!");
47+
}
48+
}
49+
50+
try {
51+
test([
52+
"foo" => new MyStringable,
53+
]);
54+
} catch (Throwable $e) {
55+
echo $e->getMessage(), "\n";
56+
}
57+
58+
echo "--- Exception from warning should abort execution ---\n";
59+
60+
set_error_handler(function($errno, $errstr) {
61+
throw new Exception($errstr);
62+
}, E_WARNING);
63+
64+
try {
65+
test([
66+
"foo" => [],
67+
"foo2" => [],
68+
]);
69+
} catch (Throwable $e) {
70+
echo $e->getMessage(), "\n";
71+
}
72+
73+
set_error_handler(null, E_WARNING);
74+
75+
echo "--- Warning may continue execution ---\n";
76+
77+
try {
78+
test([
79+
"foo" => [],
80+
"foo2" => [],
81+
]);
82+
} catch (Throwable $e) {
83+
echo $e->getMessage(), "\n";
84+
}
85+
86+
?>
87+
--EXPECTF--
88+
--- Invalid key ---
89+
XSLTProcessor::setParameter(): Argument #2 ($name) must contain only string keys
90+
--- Valid key and value, but special cases ---
91+
92+
1
93+
--- Exception from Stringable should abort execution ---
94+
exception!
95+
--- Exception from warning should abort execution ---
96+
Array to string conversion
97+
--- Warning may continue execution ---
98+
99+
Warning: Array to string conversion in %s on line %d
100+
101+
Warning: Array to string conversion in %s on line %d
102+
Array

ext/xsl/tests/xsltprocessor_setparameter-errorquote.phpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ $proc->importStylesheet($xsl);
1111
$proc->setParameter('', '', '"\'');
1212
$proc->transformToXml($dom);
1313
?>
14-
--EXPECTF--
15-
Warning: XSLTProcessor::transformToXml(): Cannot create XPath expression (string contains both quote and double-quotes) in %s on line %d
14+
Done
15+
--EXPECT--
16+
Done
1617
--CREDITS--
1718
Christian Weiske, cweiske@php.net
1819
PHP Testfest Berlin 2009-05-09

ext/xsl/xsltprocessor.c

Lines changed: 21 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -21,75 +21,29 @@
2121

2222
#include "php.h"
2323
#include "php_xsl.h"
24+
#include <libxslt/variables.h>
2425
#include "ext/libxml/php_libxml.h"
2526

26-
/* {{{ php_xsl_xslt_string_to_xpathexpr()
27-
Translates a string to a XPath Expression */
28-
static char *php_xsl_xslt_string_to_xpathexpr(const char *str)
29-
{
30-
const xmlChar *string = (const xmlChar *)str;
31-
32-
xmlChar *value;
33-
int str_len;
3427

35-
str_len = xmlStrlen(string) + 3;
36-
37-
if (xmlStrchr(string, '"')) {
38-
if (xmlStrchr(string, '\'')) {
39-
php_error_docref(NULL, E_WARNING, "Cannot create XPath expression (string contains both quote and double-quotes)");
40-
return NULL;
41-
}
42-
value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
43-
snprintf((char*)value, str_len, "'%s'", string);
44-
} else {
45-
value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
46-
snprintf((char *)value, str_len, "\"%s\"", string);
47-
}
48-
return (char *) value;
49-
}
50-
/* }}} */
51-
52-
/* {{{ php_xsl_xslt_make_params()
53-
Translates a PHP array to a libxslt parameters array */
54-
static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params)
28+
static zend_result php_xsl_xslt_apply_params(xsltTransformContextPtr ctxt, HashTable *params)
5529
{
56-
57-
int parsize;
58-
zval *value;
59-
char *xpath_expr;
6030
zend_string *string_key;
61-
char **params = NULL;
62-
int i = 0;
63-
64-
parsize = (2 * zend_hash_num_elements(parht) + 1) * sizeof(char *);
65-
params = (char **)safe_emalloc((2 * zend_hash_num_elements(parht) + 1), sizeof(char *), 0);
66-
memset((char *)params, 0, parsize);
31+
zval *value;
6732

68-
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(parht, string_key, value) {
33+
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(params, string_key, value) {
6934
ZEND_ASSERT(string_key != NULL);
70-
if (Z_TYPE_P(value) != IS_STRING) {
71-
if (!try_convert_to_string(value)) {
72-
efree(params);
73-
return NULL;
74-
}
75-
}
35+
/* Already a string because of setParameter() */
36+
ZEND_ASSERT(Z_TYPE_P(value) == IS_STRING);
7637

77-
if (!xpath_params) {
78-
xpath_expr = php_xsl_xslt_string_to_xpathexpr(Z_STRVAL_P(value));
79-
} else {
80-
xpath_expr = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
81-
}
82-
if (xpath_expr) {
83-
params[i++] = estrndup(ZSTR_VAL(string_key), ZSTR_LEN(string_key));
84-
params[i++] = xpath_expr;
38+
int result = xsltQuoteOneUserParam(ctxt, (const xmlChar *) ZSTR_VAL(string_key), (const xmlChar *) Z_STRVAL_P(value));
39+
if (result < 0) {
40+
php_error_docref(NULL, E_WARNING, "Could not apply parameter '%s'", ZSTR_VAL(string_key));
41+
return FAILURE;
8542
}
8643
} ZEND_HASH_FOREACH_END();
8744

88-
params[i++] = NULL;
89-
90-
return params;
45+
return SUCCESS;
9146
}
92-
/* }}} */
9347

9448
static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
9549
{
@@ -402,8 +356,6 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl
402356
xmlNodePtr node = NULL;
403357
xsltTransformContextPtr ctxt;
404358
php_libxml_node_object *object;
405-
char **params = NULL;
406-
int clone;
407359
zval *doXInclude, rv;
408360
zend_string *member;
409361
FILE *f;
@@ -440,10 +392,6 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl
440392
f = NULL;
441393
}
442394

443-
if (intern->parameter) {
444-
params = php_xsl_xslt_make_params(intern->parameter, 0);
445-
}
446-
447395
intern->doc = emalloc(sizeof(php_libxml_node_object));
448396
memset(intern->doc, 0, sizeof(php_libxml_node_object));
449397

@@ -459,6 +407,13 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl
459407
ctxt = xsltNewTransformContext(style, doc);
460408
ctxt->_private = (void *) intern;
461409

410+
if (intern->parameter) {
411+
zend_result status = php_xsl_xslt_apply_params(ctxt, intern->parameter);
412+
if (UNEXPECTED(status != SUCCESS) && EG(exception)) {
413+
goto out;
414+
}
415+
}
416+
462417
member = ZSTR_INIT_LITERAL("doXInclude", 0);
463418
doXInclude = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_IS, NULL, &rv);
464419
if (Z_TYPE_P(doXInclude) != IS_NULL) {
@@ -506,8 +461,10 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl
506461
if (secPrefsError == 1) {
507462
php_error_docref(NULL, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons");
508463
} else {
509-
newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params, NULL, f, ctxt);
464+
newdocp = xsltApplyStylesheetUser(style, doc, /* params (handled manually) */ NULL, /* output */ NULL, f, ctxt);
510465
}
466+
467+
out:
511468
if (f) {
512469
fclose(f);
513470
}
@@ -527,14 +484,6 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl
527484
efree(intern->doc);
528485
intern->doc = NULL;
529486

530-
if (params) {
531-
clone = 0;
532-
while(params[clone]) {
533-
efree(params[clone++]);
534-
}
535-
efree(params);
536-
}
537-
538487
return newdocp;
539488

540489
}

0 commit comments

Comments
 (0)