Commit 44d6417bd7c for php.net
commit 44d6417bd7c12ae2e7fadd7cf950529743e5bb42
Author: David Carlier <devnexen@gmail.com>
Date: Wed Nov 19 21:19:33 2025 +0000
ext/sockets: GH-20532 socket_addrinfo_lookup() sets EAI error code on resolution failures with a new optional argument.
close GH-20534
diff --git a/NEWS b/NEWS
index 74816c94a29..86a2174a986 100644
--- a/NEWS
+++ b/NEWS
@@ -86,6 +86,8 @@ PHP NEWS
transmitted data can remain unacknowledged. (James Lucas)
. Added AF_UNSPEC support for sock_addrinfo_lookup() as a sole umbrella for
AF_INET* family only. (David Carlier)
+ . Fixed GH-20532 (socket_addrinfo_lookup gives the error code with a new optional
+ parameter). (David Carlier)
- SPL:
. DirectoryIterator key can now work better with filesystem supporting larger
diff --git a/UPGRADING b/UPGRADING
index 3d0a56756cd..b72a6379664 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -77,6 +77,11 @@ PHP 8.6 UPGRADE NOTES
- Phar:
. Phar::mungServer() now supports reference values.
+- Sockets:
+ . socket_addrinfo_lookup() now has an additional optional argument $error
+ when not null, and on failure, gives the error code (one of the EAI_*
+ constants).
+
- Zip:
. ZipArchive::extractTo now raises a TypeError for the
files argument if one or more of the entries is not
@@ -112,6 +117,23 @@ PHP 8.6 UPGRADE NOTES
- Sockets:
. TCP_USER_TIMEOUT (Linux only).
. AF_UNSPEC.
+ . EAI_BADFLAGS.
+ . EAI_NONAME.
+ . EAI_AGAIN.
+ . EAI_FAIL.
+ . EAI_NODATA.
+ . EAI_FAMILY.
+ . EAI_SOCKTYPE.
+ . EAI_SERVICE.
+ . EAI_ADDRFAMILY.
+ . EAI_SYSTEM.
+ . EAI_OVERFLOW
+ . EAI_INPROGRESS.
+ . EAI_CANCELED.
+ . EAI_NOTCANCELED.
+ . EAI_ALLDONE.
+ . EAI_INTR.
+ . EAI_IDN_ENCODE.
========================================
11. Changes to INI File Handling
diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c
index 54f862d5536..accaf4bbbcf 100644
--- a/ext/sockets/sockets.c
+++ b/ext/sockets/sockets.c
@@ -2751,16 +2751,18 @@ PHP_FUNCTION(socket_addrinfo_lookup)
{
zend_string *service = NULL;
zend_string *hostname, *key;
- zval *hint, *zhints = NULL;
+ zval *hint, *zhints = NULL, *error_code = NULL;
+ int ret = 0;
struct addrinfo hints, *result, *rp;
php_addrinfo *res;
- ZEND_PARSE_PARAMETERS_START(1, 3)
+ ZEND_PARSE_PARAMETERS_START(1, 4)
Z_PARAM_STR(hostname)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(service)
Z_PARAM_ARRAY(zhints)
+ Z_PARAM_ZVAL_OR_NULL(error_code)
ZEND_PARSE_PARAMETERS_END();
memset(&hints, 0, sizeof(hints));
@@ -2848,7 +2850,10 @@ PHP_FUNCTION(socket_addrinfo_lookup)
} ZEND_HASH_FOREACH_END();
}
- if (getaddrinfo(ZSTR_VAL(hostname), service ? ZSTR_VAL(service) : NULL, &hints, &result) != 0) {
+ if ((ret = getaddrinfo(ZSTR_VAL(hostname), service ? ZSTR_VAL(service) : NULL, &hints, &result)) != 0) {
+ if (error_code) {
+ ZEND_TRY_ASSIGN_REF_LONG(error_code, ret);
+ }
RETURN_FALSE;
}
diff --git a/ext/sockets/sockets.stub.php b/ext/sockets/sockets.stub.php
index 0f645da25ce..56b2ac07e86 100644
--- a/ext/sockets/sockets.stub.php
+++ b/ext/sockets/sockets.stub.php
@@ -2067,6 +2067,136 @@
const SHUT_RDWR = UNKNOWN;
#endif
+
+#ifdef EAI_BADFLAGS
+/**
+ * @var int
+ * @cvalue EAI_BADFLAGS
+ */
+const EAI_BADFLAGS = UNKNOWN;
+#endif
+#ifdef EAI_NONAME
+/**
+ * @var int
+ * @cvalue EAI_NONAME
+ */
+const EAI_NONAME = UNKNOWN;
+#endif
+#ifdef EAI_AGAIN
+/**
+ * @var int
+ * @cvalue EAI_AGAIN
+ */
+const EAI_AGAIN = UNKNOWN;
+#endif
+#ifdef EAI_FAIL
+/**
+ * @var int
+ * @cvalue EAI_FAIL
+ */
+const EAI_FAIL = UNKNOWN;
+#endif
+#ifdef EAI_NODATA
+/**
+ * @var int
+ * @cvalue EAI_NODATA
+ */
+const EAI_NODATA = UNKNOWN;
+#endif
+#ifdef EAI_FAMILY
+/**
+ * @var int
+ * @cvalue EAI_FAMILY
+ */
+const EAI_FAMILY = UNKNOWN;
+#endif
+#ifdef EAI_SOCKTYPE
+/**
+ * @var int
+ * @cvalue EAI_SOCKTYPE
+ */
+const EAI_SOCKTYPE = UNKNOWN;
+#endif
+#ifdef EAI_SERVICE
+/**
+ * @var int
+ * @cvalue EAI_SERVICE
+ */
+const EAI_SERVICE = UNKNOWN;
+#endif
+#ifdef EAI_ADDRFAMILY
+/**
+ * @var int
+ * @cvalue EAI_ADDRFAMILY
+ */
+const EAI_ADDRFAMILY = UNKNOWN;
+#else
+#ifdef EAI_FAMILY
+/**
+ * @var int
+ * @cvalue EAI_FAMILY
+ */
+const EAI_ADDRFAMILY = UNKNOWN;
+#else
+#endif
+#endif
+#ifdef EAI_SYSTEM
+/**
+ * @var int
+ * @cvalue EAI_SYSTEM
+ */
+const EAI_SYSTEM = UNKNOWN;
+#endif
+#ifdef EAI_OVERFLOW
+/**
+ * @var int
+ * @cvalue EAI_OVERFLOW
+ */
+const EAI_OVERFLOW = UNKNOWN;
+#endif
+#ifdef EAI_INPROGRESS
+/**
+ * @var int
+ * @cvalue EAI_INPROGRESS
+ */
+const EAI_INPROGRESS = UNKNOWN;
+#endif
+#ifdef EAI_CANCELED
+/**
+ * @var int
+ * @cvalue EAI_CANCELED
+ */
+const EAI_CANCELED = UNKNOWN;
+#endif
+#ifdef EAI_NOTCANCELED
+/**
+ * @var int
+ * @cvalue EAI_NOTCANCELED
+ */
+const EAI_NOTCANCELED = UNKNOWN;
+#endif
+#ifdef EAI_ALLDONE
+/**
+ * @var int
+ * @cvalue EAI_ALLDONE
+ */
+const EAI_ALLDONE = UNKNOWN;
+#endif
+#ifdef EAI_INTR
+/**
+ * @var int
+ * @cvalue EAI_INTR
+ */
+const EAI_INTR = UNKNOWN;
+#endif
+#ifdef EAI_IDN_ENCODE
+/**
+ * @var int
+ * @cvalue EAI_IDN_ENCODE
+ */
+const EAI_IDN_ENCODE = UNKNOWN;
+#endif
+
/**
* @strict-properties
* @not-serializable
@@ -2187,9 +2317,10 @@ function socket_cmsg_space(int $level, int $type, int $num = 0): ?int {}
/**
* @return array<int, AddressInfo>|false
+ * @param int $error_code
* @refcount 1
*/
-function socket_addrinfo_lookup(string $host, ?string $service = null, array $hints = []): array|false {}
+function socket_addrinfo_lookup(string $host, ?string $service = null, array $hints = [], &$error_code = null): array|false {}
function socket_addrinfo_connect(AddressInfo $address): Socket|false {}
diff --git a/ext/sockets/sockets_arginfo.h b/ext/sockets/sockets_arginfo.h
index 50a81c5ee3a..522f356f853 100644
Binary files a/ext/sockets/sockets_arginfo.h and b/ext/sockets/sockets_arginfo.h differ
diff --git a/ext/sockets/tests/gh20532.phpt b/ext/sockets/tests/gh20532.phpt
new file mode 100644
index 00000000000..f3368c83036
--- /dev/null
+++ b/ext/sockets/tests/gh20532.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-20562 - socket_addrinfo_lookup() returns error codes on resolution failures.
+--EXTENSIONS--
+sockets
+--FILE--
+<?php
+$error_code = 0;
+var_dump(socket_addrinfo_lookup(".whynot", null, [], $error_code) === false && $error_code === EAI_NONAME);
+var_dump(socket_addrinfo_lookup("2001:db8::1", null, ['ai_family' => AF_INET], $error_code) === false && in_array($error_code, [EAI_FAMILY, EAI_ADDRFAMILY, EAI_NONAME, EAI_NODATA]));
+var_dump(socket_addrinfo_lookup("example.com", "http", ['ai_socktype' => SOCK_RAW, 'ai_flags' => 2147483647], $error_code) === false && in_array($error_code, [EAI_SOCKTYPE, EAI_SERVICE, EAI_BADFLAGS, EAI_NONAME]));
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+