mirror of
https://github.com/php/php-src.git
synced 2024-11-23 01:44:06 +08:00
Implement request #30622: make $namespace parameter functional
This parameter never actually did anything and was forgotten about. We solve this by detecting when we have a $namespace argument (that won't conflict with the name argument) and creating a Clark notation name out of it. Closes GH-16123.
This commit is contained in:
parent
f5e81fe182
commit
daa94cf279
3
NEWS
3
NEWS
@ -22,4 +22,7 @@ PHP NEWS
|
||||
- XMLWriter:
|
||||
. Improved performance and reduce memory consumption. (nielsdos)
|
||||
|
||||
- XSL:
|
||||
. Implement request #30622 (make $namespace parameter functional). (nielsdos)
|
||||
|
||||
<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>
|
||||
|
@ -37,6 +37,14 @@ PHP 8.5 UPGRADE NOTES
|
||||
2. New Features
|
||||
========================================
|
||||
|
||||
- XSL:
|
||||
. The $namespace argument of XSLTProcessor::getParameter(),
|
||||
XSLTProcessor::setParameter() and XSLTProcessor::removeParameter()
|
||||
now actually works instead of being treated as empty.
|
||||
This only works if the $name argument does not use Clark notation
|
||||
and is not a QName because in those cases the namespace is taken
|
||||
from the namespace href or prefix respectively.
|
||||
|
||||
========================================
|
||||
3. Changes in SAPI modules
|
||||
========================================
|
||||
|
85
ext/xsl/tests/req30622.phpt
Normal file
85
ext/xsl/tests/req30622.phpt
Normal file
@ -0,0 +1,85 @@
|
||||
--TEST--
|
||||
Request #30622 (XSLT: xsltProcessor->setParameter() cannot set namespace URI)
|
||||
--EXTENSIONS--
|
||||
xsl
|
||||
--CREDITS--
|
||||
Based on a test by <ishikawa at arielworks dot com>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$xmlDom = new DOMDocument();
|
||||
$xmlDom->loadXML('<root/>');
|
||||
|
||||
$xslDom = new DOMDocument();
|
||||
$xslDom->loadXML(<<<'XML'
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:test="http://www.php.net/test">
|
||||
<xsl:param name="foo" select="'EMPTY'"/>
|
||||
<xsl:param name="test:foo" select="'EMPTY'"/>
|
||||
|
||||
<xsl:template match="/root">
|
||||
<xsl:text>Namespace "NULL": </xsl:text>
|
||||
<xsl:value-of select="$foo"/>
|
||||
<xsl:text>, Namespace "http://www.php.net/test": </xsl:text>
|
||||
<xsl:value-of select="$test:foo"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
XML);
|
||||
|
||||
$proc = new XSLTProcessor();
|
||||
$proc->importStyleSheet($xslDom);
|
||||
|
||||
echo "--- Set both empty and non-empty namespace ---\n";
|
||||
|
||||
$proc->setParameter("", "foo", "SET1");
|
||||
$proc->setParameter("http://www.php.net/test", "foo", "SET2");
|
||||
var_dump($proc->getParameter("", "foo"));
|
||||
var_dump($proc->getParameter("http://www.php.net/test", "foo"));
|
||||
|
||||
print $proc->transformToXML($xmlDom);
|
||||
|
||||
echo "--- Remove empty namespace entry ---\n";
|
||||
|
||||
var_dump($proc->removeParameter("", "foo"));
|
||||
var_dump($proc->getParameter("", "foo"));
|
||||
var_dump($proc->getParameter("http://www.php.net/test", "foo"));
|
||||
|
||||
print $proc->transformToXML($xmlDom);
|
||||
|
||||
echo "--- Remove non-empty namespace entry ---\n";
|
||||
|
||||
var_dump($proc->removeParameter("http://www.php.net/test", "foo"));
|
||||
var_dump($proc->getParameter("", "foo"));
|
||||
var_dump($proc->getParameter("http://www.php.net/test", "foo"));
|
||||
|
||||
print $proc->transformToXML($xmlDom);
|
||||
|
||||
echo "--- Set via array ---\n";
|
||||
|
||||
$proc->setParameter("", ["foo" => "SET1"]);
|
||||
$proc->setParameter("http://www.php.net/test", ["foo" => "SET2"]);
|
||||
|
||||
print $proc->transformToXML($xmlDom);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--- Set both empty and non-empty namespace ---
|
||||
string(4) "SET1"
|
||||
string(4) "SET2"
|
||||
<?xml version="1.0"?>
|
||||
Namespace "NULL": SET1, Namespace "http://www.php.net/test": SET2
|
||||
--- Remove empty namespace entry ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
string(4) "SET2"
|
||||
<?xml version="1.0"?>
|
||||
Namespace "NULL": EMPTY, Namespace "http://www.php.net/test": SET2
|
||||
--- Remove non-empty namespace entry ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
<?xml version="1.0"?>
|
||||
Namespace "NULL": EMPTY, Namespace "http://www.php.net/test": EMPTY
|
||||
--- Set via array ---
|
||||
<?xml version="1.0"?>
|
||||
Namespace "NULL": SET1, Namespace "http://www.php.net/test": SET2
|
59
ext/xsl/tests/req30622_errors.phpt
Normal file
59
ext/xsl/tests/req30622_errors.phpt
Normal file
@ -0,0 +1,59 @@
|
||||
--TEST--
|
||||
Request #30622 (XSLT: xsltProcessor->setParameter() cannot set namespace URI) - error cases
|
||||
--EXTENSIONS--
|
||||
xsl
|
||||
--CREDITS--
|
||||
Based on a test by <ishikawa at arielworks dot com>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$proc = new XSLTProcessor();
|
||||
|
||||
try {
|
||||
$proc->setParameter("urn:x", "{urn:a}x", "");
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$proc->setParameter("urn:x", "a:b", "");
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$proc->getParameter("urn:x", "{urn:a}x");
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$proc->getParameter("urn:x", "a:b");
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$proc->removeParameter("urn:x", "{urn:a}x");
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$proc->removeParameter("urn:x", "a:b");
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
// Edge cases, should work
|
||||
$proc->setParameter("urn:x", ":b", "");
|
||||
$proc->setParameter("urn:x", ":", "");
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
XSLTProcessor::setParameter(): Argument #2 ($name) must not use clark notation when argument #1 ($namespace) is not empty
|
||||
XSLTProcessor::setParameter(): Argument #2 ($name) must not be a QName when argument #1 ($namespace) is not empty
|
||||
XSLTProcessor::getParameter(): Argument #2 ($name) must not use clark notation when argument #1 ($namespace) is not empty
|
||||
XSLTProcessor::getParameter(): Argument #2 ($name) must not be a QName when argument #1 ($namespace) is not empty
|
||||
XSLTProcessor::removeParameter(): Argument #2 ($name) must not use clark notation when argument #1 ($namespace) is not empty
|
||||
XSLTProcessor::removeParameter(): Argument #2 ($name) must not be a QName when argument #1 ($namespace) is not empty
|
@ -549,6 +549,32 @@ PHP_METHOD(XSLTProcessor, transformToXml)
|
||||
}
|
||||
/* }}} end XSLTProcessor::transformToXml */
|
||||
|
||||
static zend_string *xsl_create_parameter_key(uint32_t arg_num, const zend_string *namespace, zend_string *name)
|
||||
{
|
||||
if (ZSTR_LEN(namespace) == 0) {
|
||||
return zend_string_copy(name);
|
||||
}
|
||||
|
||||
/* Clark notation already sets the namespace and we cannot have a double namespace declaration. */
|
||||
if (ZSTR_VAL(name)[0] == '{') {
|
||||
zend_argument_value_error(arg_num, "must not use clark notation when argument #1 ($namespace) is not empty");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Cannot be a QName as that would cause a namespace lookup in the document. */
|
||||
if (ZSTR_VAL(name)[0] != ':' && strchr(ZSTR_VAL(name), ':')) {
|
||||
zend_argument_value_error(arg_num, "must not be a QName when argument #1 ($namespace) is not empty");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
zend_string *clark_str = zend_string_safe_alloc(1, ZSTR_LEN(name), 2 + ZSTR_LEN(namespace), false);
|
||||
ZSTR_VAL(clark_str)[0] = '{';
|
||||
memcpy(ZSTR_VAL(clark_str) + 1, ZSTR_VAL(namespace), ZSTR_LEN(namespace));
|
||||
ZSTR_VAL(clark_str)[ZSTR_LEN(namespace) + 1] = '}';
|
||||
memcpy(ZSTR_VAL(clark_str) + 2 + ZSTR_LEN(namespace), ZSTR_VAL(name), ZSTR_LEN(name) + 1 /* include '\0' */);
|
||||
return clark_str;
|
||||
}
|
||||
|
||||
/* {{{ */
|
||||
PHP_METHOD(XSLTProcessor, setParameter)
|
||||
{
|
||||
@ -557,12 +583,10 @@ PHP_METHOD(XSLTProcessor, setParameter)
|
||||
zval *entry, new_string;
|
||||
HashTable *array_value;
|
||||
xsl_object *intern;
|
||||
char *namespace;
|
||||
size_t namespace_len;
|
||||
zend_string *string_key, *name, *value = NULL;
|
||||
zend_string *namespace, *string_key, *name, *value = NULL;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(2, 3)
|
||||
Z_PARAM_STRING(namespace, namespace_len)
|
||||
Z_PARAM_PATH_STR(namespace)
|
||||
Z_PARAM_ARRAY_HT_OR_STR(array_value, name)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_PATH_STR_OR_NULL(value)
|
||||
@ -590,19 +614,27 @@ PHP_METHOD(XSLTProcessor, setParameter)
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zend_string *ht_key = xsl_create_parameter_key(2, namespace, string_key);
|
||||
if (!ht_key) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
str = zval_try_get_string(entry);
|
||||
if (UNEXPECTED(!str)) {
|
||||
zend_string_release_ex(ht_key, false);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (UNEXPECTED(CHECK_NULL_PATH(ZSTR_VAL(str), ZSTR_LEN(str)))) {
|
||||
zend_string_release(str);
|
||||
zend_string_release_ex(ht_key, false);
|
||||
zend_argument_value_error(3, "must not contain values with any null bytes");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
ZVAL_STR(&tmp, str);
|
||||
zend_hash_update(intern->parameter, string_key, &tmp);
|
||||
zend_hash_update(intern->parameter, ht_key, &tmp);
|
||||
zend_string_release_ex(ht_key, false);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
RETURN_TRUE;
|
||||
} else {
|
||||
@ -616,9 +648,15 @@ PHP_METHOD(XSLTProcessor, setParameter)
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zend_string *key = xsl_create_parameter_key(2, namespace, name);
|
||||
if (!key) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
ZVAL_STR_COPY(&new_string, value);
|
||||
|
||||
zend_hash_update(intern->parameter, name, &new_string);
|
||||
zend_hash_update(intern->parameter, key, &new_string);
|
||||
zend_string_release_ex(key, false);
|
||||
RETURN_TRUE;
|
||||
}
|
||||
}
|
||||
@ -628,17 +666,21 @@ PHP_METHOD(XSLTProcessor, setParameter)
|
||||
PHP_METHOD(XSLTProcessor, getParameter)
|
||||
{
|
||||
zval *id = ZEND_THIS;
|
||||
char *namespace;
|
||||
size_t namespace_len = 0;
|
||||
zval *value;
|
||||
zend_string *name;
|
||||
zend_string *namespace, *name;
|
||||
xsl_object *intern;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "PP", &namespace, &name) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
zend_string *key = xsl_create_parameter_key(2, namespace, name);
|
||||
if (!key) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
intern = Z_XSL_P(id);
|
||||
if ((value = zend_hash_find(intern->parameter, name)) != NULL) {
|
||||
value = zend_hash_find(intern->parameter, key);
|
||||
zend_string_release_ex(key, false);
|
||||
if (value != NULL) {
|
||||
RETURN_STR_COPY(Z_STR_P(value));
|
||||
} else {
|
||||
RETURN_FALSE;
|
||||
@ -650,20 +692,23 @@ PHP_METHOD(XSLTProcessor, getParameter)
|
||||
PHP_METHOD(XSLTProcessor, removeParameter)
|
||||
{
|
||||
zval *id = ZEND_THIS;
|
||||
size_t namespace_len = 0;
|
||||
char *namespace;
|
||||
zend_string *name;
|
||||
zend_string *namespace, *name;
|
||||
xsl_object *intern;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "PP", &namespace, &name) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
zend_string *key = xsl_create_parameter_key(2, namespace, name);
|
||||
if (!key) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
intern = Z_XSL_P(id);
|
||||
if (zend_hash_del(intern->parameter, name) == SUCCESS) {
|
||||
RETURN_TRUE;
|
||||
if (zend_hash_del(intern->parameter, key) == SUCCESS) {
|
||||
RETVAL_TRUE;
|
||||
} else {
|
||||
RETURN_FALSE;
|
||||
RETVAL_FALSE;
|
||||
}
|
||||
zend_string_release_ex(key, false);
|
||||
}
|
||||
/* }}} end XSLTProcessor::removeParameter */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user