ext/xml: Deprecate xml_set_object() and passing non-callable strings as handlers (#15293)

This commit is contained in:
Gina Peter Banyard 2024-08-08 23:37:49 +01:00 committed by GitHub
parent 6eca7839af
commit 25b4696530
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 102 additions and 69 deletions

5
NEWS
View file

@ -55,6 +55,11 @@ PHP NEWS
. Implemented GH-15155 (Stream context is lost when custom stream wrapper is . Implemented GH-15155 (Stream context is lost when custom stream wrapper is
being filtered). (Quentin Dreyer) being filtered). (Quentin Dreyer)
- XML:
. The xml_set_object() function has been deprecated. (Girgias)
. Passing non-callable strings to the xml_set_*_handler() functions is now
deprecated. (Girgias)
01 Aug 2024, PHP 8.4.0alpha4 01 Aug 2024, PHP 8.4.0alpha4
- GMP: - GMP:

View file

@ -189,7 +189,7 @@ PHP 8.4 UPGRADE NOTES
This means that xml_set_object() must now always be called prior to setting This means that xml_set_object() must now always be called prior to setting
method names as callables. method names as callables.
Passing an empty string to disable the handler is still allowed, Passing an empty string to disable the handler is still allowed,
but not recommended. but deprecated.
- XMLReader: - XMLReader:
. Passing an invalid character encoding to XMLReader::open() or . Passing an invalid character encoding to XMLReader::open() or
@ -478,6 +478,13 @@ PHP 8.4 UPGRADE NOTES
. Unserializing strings using the uppercase 'S' tag is deprecated. . Unserializing strings using the uppercase 'S' tag is deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_4 RFC: https://wiki.php.net/rfc/deprecations_php_8_4
- XML:
. The xml_set_object() function has been deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_4#xml_set_object_and_xml_set_handler_with_string_method_names
. Passing non-callable strings to the xml_set_*_handler() functions is now
deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_4#xml_set_object_and_xml_set_handler_with_string_method_names
======================================== ========================================
5. Changed Functions 5. Changed Functions
======================================== ========================================

View file

@ -15,5 +15,6 @@ function boom()
} }
boom(); boom();
?> ?>
--EXPECT-- --EXPECTF--
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
ok ok

View file

@ -1,51 +0,0 @@
--TEST--
Bug #30266 (Invalid opcode 137/1/8)
--EXTENSIONS--
xml
--FILE--
<?php
/*
Currently (Feb 10, 2005) CVS HEAD fails with the following message:
Fatal error: Invalid opcode 137/1/8. in /home/hartmut/projects/php/dev/head/ext/xml/tests/bug30266.php on line 22
*/
class XML_Parser
{
public $dummy = "a";
function parse($data)
{
$parser = xml_parser_create();
xml_set_object($parser, $this);
xml_set_element_handler($parser, 'startHandler', 'endHandler');
xml_parse($parser, $data, true);
xml_parser_free($parser);
}
function startHandler($XmlParser, $tag, $attr)
{
$this->dummy = "b";
throw new Exception("ex");
}
function endHandler($XmlParser, $tag)
{
}
}
$p1 = new Xml_Parser();
try {
$p1->parse('<tag1><tag2></tag2></tag1>');
echo "Exception swallowed\n";
} catch (Exception $e) {
echo "OK\n";
}
?>
--EXPECT--
OK

View file

@ -100,8 +100,7 @@ HERE;
$parser = xml_parser_create(NULL); $parser = xml_parser_create(NULL);
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_set_object($parser, $this); xml_set_element_handler($parser, $this->start_element(...), $this->end_element(...));
xml_set_element_handler($parser, "start_element", "end_element");
if ($this->chunk_size == 0) { if ($this->chunk_size == 0) {
$success = @xml_parse($parser, $data, true); $success = @xml_parse($parser, $data, true);

View file

@ -31,5 +31,6 @@ $xml_parser->free();
?> ?>
===DONE=== ===DONE===
--EXPECT-- --EXPECTF--
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
===DONE=== ===DONE===

View file

@ -59,7 +59,7 @@ xml_parse($parser, $xml, true);
xml_parser_free($parser); xml_parser_free($parser);
?> ?>
--EXPECT-- --EXPECTF--
Both handlers are trampolines: Both handlers are trampolines:
Trampoline for start_handler Trampoline for start_handler
Tag: A Tag: A
@ -75,6 +75,10 @@ Trampoline for end_handler
Tag: A Tag: A
Start handler is trampoline, end handler method string: Start handler is trampoline, end handler method string:
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
Deprecated: xml_set_element_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
Trampoline for start_handler Trampoline for start_handler
Tag: A Tag: A
Trampoline for start_handler Trampoline for start_handler
@ -86,6 +90,10 @@ Method end handler: C
Method end handler: A Method end handler: A
End handler is trampoline, start handler method string: End handler is trampoline, start handler method string:
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
Deprecated: xml_set_element_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
Method start handler: A Method start handler: A
Method start handler: B Method start handler: B
Trampoline for end_handler Trampoline for end_handler

View file

@ -48,7 +48,7 @@ try {
} }
?> ?>
--EXPECT-- --EXPECTF--
Invalid $parser: Invalid $parser:
TypeError: xml_set_processing_instruction_handler(): Argument #1 ($parser) must be of type XMLParser, stdClass given TypeError: xml_set_processing_instruction_handler(): Argument #1 ($parser) must be of type XMLParser, stdClass given
Invalid callable type true: Invalid callable type true:
@ -56,6 +56,12 @@ TypeError: xml_set_processing_instruction_handler(): Argument #2 ($handler) must
Invalid callable type int: Invalid callable type int:
TypeError: xml_set_processing_instruction_handler(): Argument #2 ($handler) must be of type callable|string|null TypeError: xml_set_processing_instruction_handler(): Argument #2 ($handler) must be of type callable|string|null
String not callable and no object set: String not callable and no object set:
Deprecated: xml_set_processing_instruction_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
ValueError: xml_set_processing_instruction_handler(): Argument #2 ($handler) an object must be set via xml_set_object() to be able to lookup method ValueError: xml_set_processing_instruction_handler(): Argument #2 ($handler) an object must be set via xml_set_object() to be able to lookup method
String non existent method on set object: String non existent method on set object:
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
Deprecated: xml_set_processing_instruction_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
ValueError: xml_set_processing_instruction_handler(): Argument #2 ($handler) method stdClass::nonexistent_method() does not exist ValueError: xml_set_processing_instruction_handler(): Argument #2 ($handler) method stdClass::nonexistent_method() does not exist

View file

@ -74,7 +74,7 @@ try {
} }
?> ?>
--EXPECT-- --EXPECTF--
Invalid $parser: Invalid $parser:
TypeError: xml_set_element_handler(): Argument #1 ($parser) must be of type XMLParser, stdClass given TypeError: xml_set_element_handler(): Argument #1 ($parser) must be of type XMLParser, stdClass given
Invalid start callable type true: Invalid start callable type true:
@ -86,10 +86,22 @@ TypeError: xml_set_element_handler(): Argument #2 ($start_handler) must be of ty
Invalid end callable type int: Invalid end callable type int:
TypeError: xml_set_element_handler(): Argument #3 ($end_handler) must be of type callable|string|null TypeError: xml_set_element_handler(): Argument #3 ($end_handler) must be of type callable|string|null
Invalid start callable, no object set and string not callable: Invalid start callable, no object set and string not callable:
Deprecated: xml_set_element_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
ValueError: xml_set_element_handler(): Argument #2 ($start_handler) an object must be set via xml_set_object() to be able to lookup method ValueError: xml_set_element_handler(): Argument #2 ($start_handler) an object must be set via xml_set_object() to be able to lookup method
Invalid end callable, no object set and string not callable: Invalid end callable, no object set and string not callable:
Deprecated: xml_set_element_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
ValueError: xml_set_element_handler(): Argument #3 ($end_handler) an object must be set via xml_set_object() to be able to lookup method ValueError: xml_set_element_handler(): Argument #3 ($end_handler) an object must be set via xml_set_object() to be able to lookup method
Invalid start callable, string non existent method on set object: Invalid start callable, string non existent method on set object:
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
Deprecated: xml_set_element_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
ValueError: xml_set_element_handler(): Argument #2 ($start_handler) method stdClass::nonexistent_method() does not exist ValueError: xml_set_element_handler(): Argument #2 ($start_handler) method stdClass::nonexistent_method() does not exist
Invalid end callable, string non existent method on set object: Invalid end callable, string non existent method on set object:
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
Deprecated: xml_set_element_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
ValueError: xml_set_element_handler(): Argument #3 ($end_handler) method stdClass::nonexistent_method() does not exist ValueError: xml_set_element_handler(): Argument #3 ($end_handler) method stdClass::nonexistent_method() does not exist

View file

@ -29,9 +29,8 @@ class XML_Parser
function parse($data) function parse($data)
{ {
$parser = xml_parser_create(); $parser = xml_parser_create();
xml_set_object($parser, $this); xml_set_notation_decl_handler($parser, $this->notation_decl_handler(...));
xml_set_notation_decl_handler($parser, "notation_decl_handler"); xml_set_unparsed_entity_decl_handler($parser, $this->unparsed_entity_decl_handler(...));
xml_set_unparsed_entity_decl_handler($parser, "unparsed_entity_decl_handler");
xml_parse($parser, $data, true); xml_parse($parser, $data, true);
xml_parser_free($parser); xml_parser_free($parser);
} }

View file

@ -48,7 +48,12 @@ xml_parse($parser, <<<XML
XML); XML);
?> ?>
--EXPECT-- --EXPECTF--
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
Deprecated: xml_set_element_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
A::start_element(CONTAINER) A::start_element(CONTAINER)
B::start_element(CHILD) B::start_element(CHILD)
end_handler(CHILD) end_handler(CHILD)

View file

@ -41,6 +41,11 @@ xml_parse($parser, <<<XML
XML); XML);
?> ?>
--EXPECT-- --EXPECTF--
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
Deprecated: xml_set_element_handler(): Passing non-callable strings is deprecated since 8.4 in %s on line %d
A::start_element(CONTAINER) A::start_element(CONTAINER)
Deprecated: Function xml_set_object() is deprecated since 8.4, provide a proper method callable to xml_set_*_handler() functions in %s on line %d
ValueError: xml_set_object(): Argument #2 ($object) cannot safely swap to object of class B as method "end_element" does not exist, which was set via xml_set_element_handler() ValueError: xml_set_object(): Argument #2 ($object) cannot safely swap to object of class B as method "end_element" does not exist, which was set via xml_set_element_handler()

View file

@ -16,8 +16,7 @@ class XML_Parser
function parse($data) function parse($data)
{ {
$parser = xml_parser_create(); $parser = xml_parser_create();
xml_set_object($parser, $this); xml_set_processing_instruction_handler($parser, $this->PIHandler(...));
xml_set_processing_instruction_handler($parser, "PIHandler");
xml_parse($parser, $data, true); xml_parse($parser, $data, true);
xml_parser_free($parser); xml_parser_free($parser);
} }

View file

@ -23,6 +23,7 @@
#include "php.h" #include "php.h"
#include "zend_variables.h" #include "zend_variables.h"
#include "zend_attributes.h"
#include "ext/standard/info.h" #include "ext/standard/info.h"
#include "ext/standard/html.h" /* For php_next_utf8_char() */ #include "ext/standard/html.h" /* For php_next_utf8_char() */
@ -1184,6 +1185,13 @@ PHP_FUNCTION(xml_set_element_handler)
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OF!S", &pind, xml_parser_ce, &start_fci, &start_fcc, &end_method_name) == SUCCESS) { if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OF!S", &pind, xml_parser_ce, &start_fci, &start_fcc, &end_method_name) == SUCCESS) {
parser = Z_XMLPARSER_P(pind); parser = Z_XMLPARSER_P(pind);
php_error_docref(NULL, E_DEPRECATED, "Passing non-callable strings is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
zend_release_fcall_info_cache(&start_fcc);
zend_release_fcall_info_cache(&end_fcc);
RETURN_THROWS();
}
bool status = php_xml_check_string_method_arg(3, parser->object, end_method_name, &end_fcc); bool status = php_xml_check_string_method_arg(3, parser->object, end_method_name, &end_fcc);
if (status == false) { if (status == false) {
zend_release_fcall_info_cache(&start_fcc); zend_release_fcall_info_cache(&start_fcc);
@ -1193,6 +1201,13 @@ PHP_FUNCTION(xml_set_element_handler)
} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OSF!", &pind, xml_parser_ce, &start_method_name, &end_fci, &end_fcc) == SUCCESS) { } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OSF!", &pind, xml_parser_ce, &start_method_name, &end_fci, &end_fcc) == SUCCESS) {
parser = Z_XMLPARSER_P(pind); parser = Z_XMLPARSER_P(pind);
php_error_docref(NULL, E_DEPRECATED, "Passing non-callable strings is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
zend_release_fcall_info_cache(&start_fcc);
zend_release_fcall_info_cache(&end_fcc);
RETURN_THROWS();
}
bool status = php_xml_check_string_method_arg(2, parser->object, start_method_name, &start_fcc); bool status = php_xml_check_string_method_arg(2, parser->object, start_method_name, &start_fcc);
if (status == false) { if (status == false) {
zend_release_fcall_info_cache(&start_fcc); zend_release_fcall_info_cache(&start_fcc);
@ -1203,6 +1218,11 @@ PHP_FUNCTION(xml_set_element_handler)
zend_release_fcall_info_cache(&start_fcc); zend_release_fcall_info_cache(&start_fcc);
zend_release_fcall_info_cache(&end_fcc); zend_release_fcall_info_cache(&end_fcc);
php_error_docref(NULL, E_DEPRECATED, "Passing non-callable strings is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
parser = Z_XMLPARSER_P(pind); parser = Z_XMLPARSER_P(pind);
bool status = php_xml_check_string_method_arg(2, parser->object, start_method_name, &start_fcc); bool status = php_xml_check_string_method_arg(2, parser->object, start_method_name, &start_fcc);
@ -1263,7 +1283,10 @@ static void php_xml_set_handler_parse_callable(
memcpy(parser_handler_fcc, &handler_fcc, sizeof(zend_fcall_info_cache)); memcpy(parser_handler_fcc, &handler_fcc, sizeof(zend_fcall_info_cache));
} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OS", &pind, xml_parser_ce, &method_name) == SUCCESS) { } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OS", &pind, xml_parser_ce, &method_name) == SUCCESS) {
*parser = Z_XMLPARSER_P(pind); *parser = Z_XMLPARSER_P(pind);
php_error_docref(NULL, E_DEPRECATED, "Passing non-callable strings is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
bool status = php_xml_check_string_method_arg(2, (*parser)->object, method_name, parser_handler_fcc); bool status = php_xml_check_string_method_arg(2, (*parser)->object, method_name, parser_handler_fcc);
if (status == false) { if (status == false) {
RETURN_THROWS(); RETURN_THROWS();

View file

@ -149,6 +149,7 @@ function xml_parser_create(?string $encoding = null): XMLParser {}
function xml_parser_create_ns(?string $encoding = null, string $separator = ":"): XMLParser {} function xml_parser_create_ns(?string $encoding = null, string $separator = ":"): XMLParser {}
#[\Deprecated(since: '8.4', message: 'provide a proper method callable to xml_set_*_handler() functions')]
function xml_set_object(XMLParser $parser, object $object): true {} function xml_set_object(XMLParser $parser, object $object): true {}
function xml_set_element_handler(XMLParser $parser, callable|string|null $start_handler, callable|string|null $end_handler): true {} function xml_set_element_handler(XMLParser $parser, callable|string|null $start_handler, callable|string|null $end_handler): true {}

17
ext/xml/xml_arginfo.h generated
View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 69734dd8094fd69c878383d488900886d1162998 */ * Stub hash: 94b232499672dfd61c2c585a5d1d8a27d1a4a7ce */
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_xml_parser_create, 0, 0, XMLParser, 0) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_xml_parser_create, 0, 0, XMLParser, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 1, "null")
@ -108,7 +108,7 @@ ZEND_FUNCTION(xml_parser_get_option);
static const zend_function_entry ext_functions[] = { static const zend_function_entry ext_functions[] = {
ZEND_FE(xml_parser_create, arginfo_xml_parser_create) ZEND_FE(xml_parser_create, arginfo_xml_parser_create)
ZEND_FE(xml_parser_create_ns, arginfo_xml_parser_create_ns) ZEND_FE(xml_parser_create_ns, arginfo_xml_parser_create_ns)
ZEND_FE(xml_set_object, arginfo_xml_set_object) ZEND_RAW_FENTRY("xml_set_object", zif_xml_set_object, arginfo_xml_set_object, ZEND_ACC_DEPRECATED, NULL, NULL)
ZEND_FE(xml_set_element_handler, arginfo_xml_set_element_handler) ZEND_FE(xml_set_element_handler, arginfo_xml_set_element_handler)
ZEND_FE(xml_set_character_data_handler, arginfo_xml_set_character_data_handler) ZEND_FE(xml_set_character_data_handler, arginfo_xml_set_character_data_handler)
ZEND_FE(xml_set_processing_instruction_handler, arginfo_xml_set_processing_instruction_handler) ZEND_FE(xml_set_processing_instruction_handler, arginfo_xml_set_processing_instruction_handler)
@ -165,6 +165,19 @@ static void register_xml_symbols(int module_number)
REGISTER_LONG_CONSTANT("XML_OPTION_SKIP_WHITE", PHP_XML_OPTION_SKIP_WHITE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("XML_OPTION_SKIP_WHITE", PHP_XML_OPTION_SKIP_WHITE, CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XML_OPTION_PARSE_HUGE", PHP_XML_OPTION_PARSE_HUGE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("XML_OPTION_PARSE_HUGE", PHP_XML_OPTION_PARSE_HUGE, CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("XML_SAX_IMPL", PHP_XML_SAX_IMPL, CONST_PERSISTENT); REGISTER_STRING_CONSTANT("XML_SAX_IMPL", PHP_XML_SAX_IMPL, CONST_PERSISTENT);
zend_attribute *attribute_Deprecated_func_xml_set_object_0 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "xml_set_object", sizeof("xml_set_object") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED), 2);
zval attribute_Deprecated_func_xml_set_object_0_arg0;
zend_string *attribute_Deprecated_func_xml_set_object_0_arg0_str = zend_string_init("8.4", strlen("8.4"), 1);
ZVAL_STR(&attribute_Deprecated_func_xml_set_object_0_arg0, attribute_Deprecated_func_xml_set_object_0_arg0_str);
ZVAL_COPY_VALUE(&attribute_Deprecated_func_xml_set_object_0->args[0].value, &attribute_Deprecated_func_xml_set_object_0_arg0);
attribute_Deprecated_func_xml_set_object_0->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE);
zval attribute_Deprecated_func_xml_set_object_0_arg1;
zend_string *attribute_Deprecated_func_xml_set_object_0_arg1_str = zend_string_init("provide a proper method callable to xml_set_*_handler() functions", strlen("provide a proper method callable to xml_set_*_handler() functions"), 1);
ZVAL_STR(&attribute_Deprecated_func_xml_set_object_0_arg1, attribute_Deprecated_func_xml_set_object_0_arg1_str);
ZVAL_COPY_VALUE(&attribute_Deprecated_func_xml_set_object_0->args[1].value, &attribute_Deprecated_func_xml_set_object_0_arg1);
attribute_Deprecated_func_xml_set_object_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
} }
static zend_class_entry *register_class_XMLParser(void) static zend_class_entry *register_class_XMLParser(void)