', $matches );
+var_dump($matches);
+?>
+--EXPECT--
+array(2) {
+ [0]=>
+ string(20) "
"
+ [1]=>
+ string(2) "di"
+}
diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c
index 7a6719a5737ee..37c6aa8fc0ac8 100644
--- a/ext/simplexml/simplexml.c
+++ b/ext/simplexml/simplexml.c
@@ -45,6 +45,7 @@ PHP_SXE_API zend_class_entry *sxe_get_element_class_entry(void) /* {{{ */
static php_sxe_object* php_sxe_object_new(zend_class_entry *ce, zend_function *fptr_count);
static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data);
+static xmlNodePtr php_sxe_reset_iterator_no_clear_iter_data(php_sxe_object *sxe, int use_data);
static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data);
static void php_sxe_iterator_dtor(zend_object_iterator *iter);
static int php_sxe_iterator_valid(zend_object_iterator *iter);
@@ -77,23 +78,14 @@ static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE
}
/* }}} */
-static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node) /* {{{ */
+static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node)
{
- php_sxe_object *intern;
- xmlNodePtr retnode = NULL;
-
if (sxe && sxe->iter.type != SXE_ITER_NONE) {
- php_sxe_reset_iterator(sxe, 1);
- if (!Z_ISUNDEF(sxe->iter.data)) {
- intern = Z_SXEOBJ_P(&sxe->iter.data);
- GET_NODE(intern, retnode)
- }
- return retnode;
+ return php_sxe_reset_iterator(sxe, 1);
} else {
return node;
}
}
-/* }}} */
static inline int match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name, int prefix) /* {{{ */
{
@@ -1186,6 +1178,12 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
sxe_properties_add(rv, name, namelen, &value);
}
next_iter:
+ if (UNEXPECTED(node->type == XML_ENTITY_DECL)) {
+ /* Entity decls are linked together via the next pointer.
+ * The only way to get to an entity decl is via an entity reference in the document.
+ * If we then continue iterating, we'll end up in the DTD. Even worse, if the entities reference each other we'll infinite loop. */
+ break;
+ }
if (use_iter) {
node = php_sxe_iterator_fetch(sxe, node->next, 0);
} else {
@@ -1322,7 +1320,7 @@ PHP_METHOD(SimpleXMLElement, xpath)
for (i = 0; i < result->nodeNr; ++i) {
nodeptr = result->nodeTab[i];
- if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE || nodeptr->type == XML_PI_NODE) {
+ if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE || nodeptr->type == XML_PI_NODE || nodeptr->type == XML_COMMENT_NODE) {
/**
* Detect the case where the last selector is text(), simplexml
* always accesses the text() child by default, therefore we assign
@@ -1837,6 +1835,7 @@ static zend_result sxe_object_cast_ex(zend_object *readobj, zval *writeobj, int
{
php_sxe_object *sxe;
xmlChar *contents = NULL;
+ bool free_contents = true;
xmlNodePtr node;
zend_result rv;
@@ -1867,13 +1866,16 @@ static zend_result sxe_object_cast_ex(zend_object *readobj, zval *writeobj, int
if (sxe->node && sxe->node->node) {
if (sxe->node->node->children) {
contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
+ } else if (sxe->node->node->type == XML_COMMENT_NODE || sxe->node->node->type == XML_PI_NODE) {
+ contents = sxe->node->node->content;
+ free_contents = false;
}
}
}
rv = cast_object(writeobj, type, (char *)contents);
- if (contents) {
+ if (contents && free_contents) {
xmlFree(contents);
}
@@ -2450,15 +2452,9 @@ static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, i
}
/* }}} */
-static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data) /* {{{ */
+static xmlNodePtr php_sxe_reset_iterator_no_clear_iter_data(php_sxe_object *sxe, int use_data)
{
xmlNodePtr node;
-
- if (!Z_ISUNDEF(sxe->iter.data)) {
- zval_ptr_dtor(&sxe->iter.data);
- ZVAL_UNDEF(&sxe->iter.data);
- }
-
GET_NODE(sxe, node)
if (node) {
@@ -2471,10 +2467,23 @@ static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data) /* {
case SXE_ITER_ATTRLIST:
node = (xmlNodePtr) node->properties;
}
+ if (use_data) {
+ ZEND_ASSERT(Z_ISUNDEF(sxe->iter.data));
+ }
return php_sxe_iterator_fetch(sxe, node, use_data);
}
return NULL;
}
+
+static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data) /* {{{ */
+{
+ if (!Z_ISUNDEF(sxe->iter.data)) {
+ zval_ptr_dtor(&sxe->iter.data);
+ ZVAL_UNDEF(&sxe->iter.data);
+ }
+
+ return php_sxe_reset_iterator_no_clear_iter_data(sxe, use_data);
+}
/* }}} */
zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
diff --git a/ext/simplexml/tests/bug12170.phpt b/ext/simplexml/tests/bug12170.phpt
new file mode 100644
index 0000000000000..c1535fe7640f0
--- /dev/null
+++ b/ext/simplexml/tests/bug12170.phpt
@@ -0,0 +1,52 @@
+--TEST--
+Bug GH-12170 (Can't use xpath with comments in SimpleXML)
+--EXTENSIONS--
+simplexml
+--FILE--
+
+
+ text node
+
+
+
+XML;
+
+$sxe = simplexml_load_string($xml);
+
+var_dump(
+ $sxe->xpath('//bar')
+);
+
+foreach ($sxe->xpath('//comment()') as $comment) {
+ var_dump($comment->getName());
+ var_dump($comment->asXML());
+}
+
+?>
+--EXPECT--
+array(3) {
+ [0]=>
+ object(SimpleXMLElement)#2 (1) {
+ [0]=>
+ string(9) "text node"
+ }
+ [1]=>
+ object(SimpleXMLElement)#3 (1) {
+ ["comment"]=>
+ object(SimpleXMLElement)#5 (0) {
+ }
+ }
+ [2]=>
+ object(SimpleXMLElement)#4 (1) {
+ ["comment"]=>
+ object(SimpleXMLElement)#5 (0) {
+ }
+ }
+}
+string(7) "comment"
+string(12) ""
+string(7) "comment"
+string(12) ""
diff --git a/ext/simplexml/tests/gh12167.phpt b/ext/simplexml/tests/gh12167.phpt
new file mode 100644
index 0000000000000..80ff496aa7e43
--- /dev/null
+++ b/ext/simplexml/tests/gh12167.phpt
@@ -0,0 +1,23 @@
+--TEST--
+GH-12167 (Unable to get processing instruction contents in SimpleXML)
+--EXTENSIONS--
+simplexml
+--FILE--
+
+
+
+
+XML;
+
+$sxe = simplexml_load_string($xml);
+
+var_dump($sxe->xpath("//processing-instruction()")[0]->getName());
+var_dump((string) $sxe->xpath("//processing-instruction()")[0]);
+
+?>
+--EXPECT--
+string(3) "foo"
+string(12) "pi contents "
diff --git a/ext/simplexml/tests/gh12169.phpt b/ext/simplexml/tests/gh12169.phpt
new file mode 100644
index 0000000000000..ca2d26b537636
--- /dev/null
+++ b/ext/simplexml/tests/gh12169.phpt
@@ -0,0 +1,23 @@
+--TEST--
+GH-12169 (Unable to get comment contents in SimpleXML)
+--EXTENSIONS--
+simplexml
+--FILE--
+
+
+
+
+XML;
+
+$sxe = simplexml_load_string($xml);
+
+var_dump($sxe->xpath("//comment()")[0]->getName());
+var_dump((string) $sxe->xpath("//comment()")[0]);
+
+?>
+--EXPECT--
+string(7) "comment"
+string(18) " comment contents "
diff --git a/ext/simplexml/tests/gh12223.phpt b/ext/simplexml/tests/gh12223.phpt
new file mode 100644
index 0000000000000..0be61dec2ffa6
--- /dev/null
+++ b/ext/simplexml/tests/gh12223.phpt
@@ -0,0 +1,67 @@
+--TEST--
+GH-12223: Entity reference produces infinite loop in var_dump/print_r
+--EXTENSIONS--
+simplexml
+--FILE--
+
+
+
+
+]>
+&c;
+XML;
+
+$sxe = simplexml_load_string($xml);
+
+var_dump($sxe);
+print_r($sxe);
+
+?>
+--EXPECT--
+object(SimpleXMLElement)#1 (1) {
+ ["c"]=>
+ object(SimpleXMLElement)#2 (1) {
+ ["c"]=>
+ object(SimpleXMLElement)#3 (1) {
+ ["b"]=>
+ object(SimpleXMLElement)#4 (1) {
+ ["b"]=>
+ object(SimpleXMLElement)#5 (1) {
+ ["a"]=>
+ object(SimpleXMLElement)#6 (1) {
+ ["a"]=>
+ string(9) "something"
+ }
+ }
+ }
+ }
+ }
+}
+SimpleXMLElement Object
+(
+ [c] => SimpleXMLElement Object
+ (
+ [c] => SimpleXMLElement Object
+ (
+ [b] => SimpleXMLElement Object
+ (
+ [b] => SimpleXMLElement Object
+ (
+ [a] => SimpleXMLElement Object
+ (
+ [a] => something
+ )
+
+ )
+
+ )
+
+ )
+
+ )
+
+)
diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c
index 01372c2aaf41c..2a15aa18945b5 100644
--- a/ext/sockets/sockets.c
+++ b/ext/sockets/sockets.c
@@ -2202,7 +2202,7 @@ PHP_FUNCTION(socket_export_stream)
php_socket *socket;
php_stream *stream = NULL;
php_netstream_data_t *stream_data;
- char *protocol = NULL;
+ const char *protocol = NULL;
size_t protocollen = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zsocket, socket_ce) == FAILURE) {
@@ -2238,12 +2238,12 @@ PHP_FUNCTION(socket_export_stream)
if (protoid == IPPROTO_TCP)
#endif
{
- protocol = "tcp";
- protocollen = 3;
+ protocol = "tcp://";
+ protocollen = sizeof("tcp://") - 1;
}
} else if (protoid == SOCK_DGRAM) {
- protocol = "udp";
- protocollen = 3;
+ protocol = "udp://";
+ protocollen = sizeof("udp://") - 1;
}
#ifdef PF_UNIX
} else if (socket->type == PF_UNIX) {
@@ -2253,11 +2253,11 @@ PHP_FUNCTION(socket_export_stream)
getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen);
if (type == SOCK_STREAM) {
- protocol = "unix";
- protocollen = 4;
+ protocol = "unix://";
+ protocollen = sizeof("unix://") - 1;
} else if (type == SOCK_DGRAM) {
- protocol = "udg";
- protocollen = 3;
+ protocol = "udg://";
+ protocollen = sizeof("udg://") - 1;
}
#endif
}
diff --git a/ext/sockets/tests/bug_export_stream_type.phpt b/ext/sockets/tests/bug_export_stream_type.phpt
new file mode 100644
index 0000000000000..b9dcbf63ce774
--- /dev/null
+++ b/ext/sockets/tests/bug_export_stream_type.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug - socket_export_stream() with wrong protocol
+--EXTENSIONS--
+sockets
+--FILE--
+
+--EXPECT--
+udp_socket
diff --git a/ext/standard/dl.c b/ext/standard/dl.c
index ebf8a3a507ebb..04670fc0adf8c 100644
--- a/ext/standard/dl.c
+++ b/ext/standard/dl.c
@@ -230,15 +230,30 @@ PHPAPI int php_load_extension(const char *filename, int type, int start_now)
DL_UNLOAD(handle);
return FAILURE;
}
+
+ int old_type = module_entry->type;
+ int old_module_number = module_entry->module_number;
+ void *old_handle = module_entry->handle;
+
module_entry->type = type;
module_entry->module_number = zend_next_free_module();
module_entry->handle = handle;
- if ((module_entry = zend_register_module_ex(module_entry)) == NULL) {
+ zend_module_entry *added_module_entry;
+ if ((added_module_entry = zend_register_module_ex(module_entry)) == NULL) {
+ /* Module loading failed, potentially because the module was already loaded.
+ * It is especially important in that case to restore the old type, module_number, and handle.
+ * Overwriting the values for an already-loaded module causes problem when these fields are used
+ * to uniquely identify module boundaries (e.g. in dom and reflection). */
+ module_entry->type = old_type;
+ module_entry->module_number = old_module_number;
+ module_entry->handle = old_handle;
DL_UNLOAD(handle);
return FAILURE;
}
+ module_entry = added_module_entry;
+
if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry) == FAILURE) {
DL_UNLOAD(handle);
return FAILURE;
diff --git a/ext/standard/tests/general_functions/proc_nice_basic.phpt b/ext/standard/tests/general_functions/proc_nice_basic.phpt
index 55622eaf46b48..9e73a7f890b15 100644
--- a/ext/standard/tests/general_functions/proc_nice_basic.phpt
+++ b/ext/standard/tests/general_functions/proc_nice_basic.phpt
@@ -19,7 +19,7 @@ if ($exit_code !== 0) {
function getNice($id)
{
$res = shell_exec('ps -p ' . $id .' -o "pid,nice"');
- preg_match('/^\s*\w+\s+\w+\s*(\d+)\s+(\d+)/m', $res, $matches);
+ preg_match('/^\s*\w+\s+\w+\s*(\d+)\s+(-?\d+)/m', $res, $matches);
if (count($matches) > 2)
return $matches[2];
else
diff --git a/ext/standard/tests/network/gh12190.phpt b/ext/standard/tests/network/gh12190.phpt
new file mode 100644
index 0000000000000..043e7f1b08175
--- /dev/null
+++ b/ext/standard/tests/network/gh12190.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #12190 (Setting 0 with port 0 too)
+--SKIPIF--
+
+--FILE--
+ ['bindto' => '0:0']]);
+var_dump(file_get_contents('https://httpbin.org/get', false, $context) !== false);
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/xml/tests/gh12254.phpt b/ext/xml/tests/gh12254.phpt
new file mode 100644
index 0000000000000..0ecc6a4ecc38e
--- /dev/null
+++ b/ext/xml/tests/gh12254.phpt
@@ -0,0 +1,31 @@
+--TEST--
+GH-12254: xml_parse_into_struct() memory leak when called twice
+--EXTENSIONS--
+xml
+--FILE--
+", $values, $tags));
+}, function ($parser, $name) {
+ echo "close\n";
+ var_dump($name);
+});
+xml_parse_into_struct($parser, "", $values, $tags);
+// Yes, this doesn't do anything but it at least shouldn't leak...
+xml_parse_into_struct($parser, "", $values, $tags);
+
+?>
+--EXPECTF--
+open
+string(9) "CONTAINER"
+array(0) {
+}
+
+Warning: xml_parse_into_struct(): Parser must not be called recursively in %s on line %d
+bool(false)
+close
+string(9) "CONTAINER"
diff --git a/ext/xml/xml.c b/ext/xml/xml.c
index 655b963d066bb..1e8a97c9059f4 100644
--- a/ext/xml/xml.c
+++ b/ext/xml/xml.c
@@ -318,19 +318,24 @@ static zend_object *xml_parser_create_object(zend_class_entry *class_type) {
return &intern->std;
}
-static void xml_parser_free_obj(zend_object *object)
+static void xml_parser_free_ltags(xml_parser *parser)
{
- xml_parser *parser = xml_parser_from_obj(object);
-
- if (parser->parser) {
- XML_ParserFree(parser->parser);
- }
if (parser->ltags) {
int inx;
for (inx = 0; ((inx < parser->level) && (inx < XML_MAXLEVEL)); inx++)
efree(parser->ltags[ inx ]);
efree(parser->ltags);
}
+}
+
+static void xml_parser_free_obj(zend_object *object)
+{
+ xml_parser *parser = xml_parser_from_obj(object);
+
+ if (parser->parser) {
+ XML_ParserFree(parser->parser);
+ }
+ xml_parser_free_ltags(parser);
if (!Z_ISUNDEF(parser->startElementHandler)) {
zval_ptr_dtor(&parser->startElementHandler);
}
@@ -1261,6 +1266,11 @@ PHP_FUNCTION(xml_parse_into_struct)
parser = Z_XMLPARSER_P(pind);
+ if (parser->isparsing) {
+ php_error_docref(NULL, E_WARNING, "Parser must not be called recursively");
+ RETURN_FALSE;
+ }
+
if (info) {
info = zend_try_array_init(info);
if (!info) {
@@ -1280,15 +1290,12 @@ PHP_FUNCTION(xml_parse_into_struct)
}
parser->level = 0;
+ xml_parser_free_ltags(parser);
parser->ltags = safe_emalloc(XML_MAXLEVEL, sizeof(char *), 0);
XML_SetElementHandler(parser->parser, _xml_startElementHandler, _xml_endElementHandler);
XML_SetCharacterDataHandler(parser->parser, _xml_characterDataHandler);
- if (parser->isparsing) {
- php_error_docref(NULL, E_WARNING, "Parser must not be called recursively");
- RETURN_FALSE;
- }
parser->isparsing = 1;
ret = XML_Parse(parser->parser, (XML_Char*)data, data_len, 1);
parser->isparsing = 0;
diff --git a/ext/xml/xml.stub.php b/ext/xml/xml.stub.php
index b650e0cc538a5..b91de3cccce0c 100644
--- a/ext/xml/xml.stub.php
+++ b/ext/xml/xml.stub.php
@@ -176,7 +176,7 @@ function xml_parse(XMLParser $parser, string $data, bool $is_final = false): int
* @param array $values
* @param array $index
*/
-function xml_parse_into_struct(XMLParser $parser, string $data, &$values, &$index = null): int {}
+function xml_parse_into_struct(XMLParser $parser, string $data, &$values, &$index = null): int|false {}
function xml_get_error_code(XMLParser $parser): int {}
diff --git a/ext/xml/xml_arginfo.h b/ext/xml/xml_arginfo.h
index ef67e7f253856..e0b6bc6af38d7 100644
--- a/ext/xml/xml_arginfo.h
+++ b/ext/xml/xml_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 97ce33bf2fbe970f7ca1c1845fbf5063dbd118dd */
+ * Stub hash: be5c43665b81e1274d6cdf7d8b18011119f442de */
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")
@@ -46,7 +46,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xml_parse, 0, 2, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, is_final, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xml_parse_into_struct, 0, 3, IS_LONG, 0)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_xml_parse_into_struct, 0, 3, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_OBJ_INFO(0, parser, XMLParser, 0)
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
ZEND_ARG_INFO(1, values)
diff --git a/ext/xsl/php_xsl.stub.php b/ext/xsl/php_xsl.stub.php
index 140c498523b42..801e78416a5da 100644
--- a/ext/xsl/php_xsl.stub.php
+++ b/ext/xsl/php_xsl.stub.php
@@ -81,7 +81,7 @@ public function importStylesheet(object $stylesheet): bool {}
* @param DOMDocument|SimpleXMLElement $document
* @tentative-return-type
*/
- public function transformToDoc(object $document, ?string $returnClass = null): DOMDocument|false {}
+ public function transformToDoc(object $document, ?string $returnClass = null): object|false {}
/**
* @param DOMDocument|SimpleXMLElement $document
diff --git a/ext/xsl/php_xsl_arginfo.h b/ext/xsl/php_xsl_arginfo.h
index 546dc3229efa6..5425c04eb5dbb 100644
--- a/ext/xsl/php_xsl_arginfo.h
+++ b/ext/xsl/php_xsl_arginfo.h
@@ -1,11 +1,11 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: a0615bef7b2211570d9da95a31857832a06360dd */
+ * Stub hash: 2385a6857c261123f9b9b892a669dbb12d5976e6 */
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_XSLTProcessor_importStylesheet, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, stylesheet, IS_OBJECT, 0)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_XSLTProcessor_transformToDoc, 0, 1, DOMDocument, MAY_BE_FALSE)
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_XSLTProcessor_transformToDoc, 0, 1, MAY_BE_OBJECT|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, document, IS_OBJECT, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, returnClass, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
diff --git a/ext/xsl/tests/transformToDoc_sxe_type_error.phpt b/ext/xsl/tests/transformToDoc_sxe_type_error.phpt
new file mode 100644
index 0000000000000..536f66bc0eaa8
--- /dev/null
+++ b/ext/xsl/tests/transformToDoc_sxe_type_error.phpt
@@ -0,0 +1,53 @@
+--TEST--
+XSLTProcessor::transformToDoc return value type error with SimpleXML
+--EXTENSIONS--
+xsl
+simplexml
+--FILE--
+load(__DIR__ . '/53965/collection.xsl');
+$processor->importStylesheet($dom);
+$result = $processor->transformToDoc($sxe, AdvancedXMLElement::class);
+
+var_dump($result);
+var_dump($result->h1->foo());
+
+?>
+--EXPECT--
+object(AdvancedXMLElement)#4 (3) {
+ ["h1"]=>
+ array(2) {
+ [0]=>
+ string(19) "Fight for your mind"
+ [1]=>
+ string(17) "Electric Ladyland"
+ }
+ ["h2"]=>
+ array(2) {
+ [0]=>
+ string(20) "by Ben Harper - 1995"
+ [1]=>
+ string(22) "by Jimi Hendrix - 1997"
+ }
+ ["hr"]=>
+ array(2) {
+ [0]=>
+ object(AdvancedXMLElement)#5 (0) {
+ }
+ [1]=>
+ object(AdvancedXMLElement)#6 (0) {
+ }
+ }
+}
+string(24) "foo: Fight for your mind"
diff --git a/main/network.c b/main/network.c
index a189714aafbf9..a1165f6a29d6b 100644
--- a/main/network.c
+++ b/main/network.c
@@ -835,8 +835,8 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short
case AF_INET:
((struct sockaddr_in *)sa)->sin_port = htons(port);
socklen = sizeof(struct sockaddr_in);
- if (bindto && strchr(bindto, ':')) {
- /* IPV4 sock cannot bind to IPV6 address */
+ if (bindto && (strchr(bindto, ':') || !strcmp(bindto, "0"))) {
+ /* IPV4 sock can not bind to IPV6 address */
bindto = NULL;
}
break;
diff --git a/main/php_version.h b/main/php_version.h
index afeeec17ccc3e..92225c8d92bfd 100644
--- a/main/php_version.h
+++ b/main/php_version.h
@@ -2,7 +2,7 @@
/* edit configure.ac to change version number */
#define PHP_MAJOR_VERSION 8
#define PHP_MINOR_VERSION 2
-#define PHP_RELEASE_VERSION 11
-#define PHP_EXTRA_VERSION "-dev"
-#define PHP_VERSION "8.2.11-dev"
-#define PHP_VERSION_ID 80211
+#define PHP_RELEASE_VERSION 12
+#define PHP_EXTRA_VERSION ""
+#define PHP_VERSION "8.2.12"
+#define PHP_VERSION_ID 80212
diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c
index cf01d27d7a62b..f51c549282a13 100644
--- a/sapi/cli/php_cli_server.c
+++ b/sapi/cli/php_cli_server.c
@@ -347,10 +347,25 @@ static void append_http_status_line(smart_str *buffer, int protocol_version, int
smart_str_appendl_ex(buffer, "\r\n", 2, persistent);
} /* }}} */
-static void append_essential_headers(smart_str* buffer, php_cli_server_client *client, bool persistent) /* {{{ */
+static void append_essential_headers(smart_str* buffer, php_cli_server_client *client, bool persistent, sapi_headers_struct *sapi_headers) /* {{{ */
{
zval *val;
struct timeval tv = {0};
+ bool append_date_header = true;
+
+ if (sapi_headers != NULL) {
+ zend_llist_position pos;
+ sapi_header_struct *h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
+ while (h) {
+ if (h->header_len > strlen("Date:")) {
+ if (strncasecmp(h->header, "Date:", strlen("Date:")) == 0) {
+ append_date_header = false;
+ break;
+ }
+ }
+ h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
+ }
+ }
if (NULL != (val = zend_hash_str_find(&client->request.headers, "host", sizeof("host")-1))) {
smart_str_appends_ex(buffer, "Host: ", persistent);
@@ -358,7 +373,7 @@ static void append_essential_headers(smart_str* buffer, php_cli_server_client *c
smart_str_appends_ex(buffer, "\r\n", persistent);
}
- if (!gettimeofday(&tv, NULL)) {
+ if (append_date_header && !gettimeofday(&tv, NULL)) {
zend_string *dt = php_format_date("D, d M Y H:i:s", sizeof("D, d M Y H:i:s") - 1, tv.tv_sec, 0);
smart_str_appends_ex(buffer, "Date: ", persistent);
smart_str_append_ex(buffer, dt, persistent);
@@ -542,7 +557,7 @@ static int sapi_cli_server_send_headers(sapi_headers_struct *sapi_headers) /* {{
append_http_status_line(&buffer, client->request.protocol_version, SG(sapi_headers).http_response_code, 0);
}
- append_essential_headers(&buffer, client, 0);
+ append_essential_headers(&buffer, client, 0, sapi_headers);
h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
while (h) {
@@ -2039,7 +2054,7 @@ static zend_result php_cli_server_send_error_page(php_cli_server *server, php_cl
/* out of memory */
goto fail;
}
- append_essential_headers(&buffer, client, 1);
+ append_essential_headers(&buffer, client, 1, NULL);
smart_str_appends_ex(&buffer, "Content-Type: text/html; charset=UTF-8\r\n", 1);
smart_str_appends_ex(&buffer, "Content-Length: ", 1);
smart_str_append_unsigned_ex(&buffer, php_cli_server_buffer_size(&client->content_sender.buffer), 1);
@@ -2155,7 +2170,7 @@ static zend_result php_cli_server_begin_send_static(php_cli_server *server, php_
php_cli_server_log_response(client, 500, NULL);
return FAILURE;
}
- append_essential_headers(&buffer, client, 1);
+ append_essential_headers(&buffer, client, 1, NULL);
if (mime_type) {
smart_str_appendl_ex(&buffer, "Content-Type: ", sizeof("Content-Type: ") - 1, 1);
smart_str_appends_ex(&buffer, mime_type, 1);
diff --git a/sapi/cli/tests/bug80092.phpt b/sapi/cli/tests/bug80092.phpt
new file mode 100644
index 0000000000000..32e76c41e6766
--- /dev/null
+++ b/sapi/cli/tests/bug80092.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Bug #80092 (ZTS + preload = segfault on shutdown)
+--SKIPIF--
+
+--FILE--
+
+--EXPECTF--
+preloaded
+PHP %s
+Copyright (c) The PHP Group
+Zend Engine %s
+ with Zend OPcache %s
diff --git a/sapi/cli/tests/gh12363.phpt b/sapi/cli/tests/gh12363.phpt
new file mode 100644
index 0000000000000..5093030642b67
--- /dev/null
+++ b/sapi/cli/tests/gh12363.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Ensure a single Date header is present
+--SKIPIF--
+
+--FILE--
+
+--EXPECTF--
+HTTP/1.1 200 OK
+Host: %s
+Connection: close
+X-Powered-By: %s
+Date: Mon, 25 Mar 1985 00:20:00 GMT
+Content-type: text/html; charset=UTF-8
+
diff --git a/sapi/cli/tests/preload.inc b/sapi/cli/tests/preload.inc
new file mode 100644
index 0000000000000..469ba934415b4
--- /dev/null
+++ b/sapi/cli/tests/preload.inc
@@ -0,0 +1,7 @@
+