Commit ae429f100b7 for php

commit ae429f100b70183a7d93e099be0dc911c49e019b
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Sat Sep 26 18:15:04 2026 -0400

    ext/openssl: Restore blocking mode after a handshake timeout

    A handshake timeout returned before php_openssl_enable_crypto() restored
    the socket blocking mode saved at entry. That return now restores it, as
    the normal return already does.

    Closes GH-23932

diff --git a/NEWS b/NEWS
index 9756d72077d..7468a698253 100644
--- a/NEWS
+++ b/NEWS
@@ -81,6 +81,10 @@ PHP                                                                        NEWS
     (David Carlier)
   . Fix incorrect DCE due to unsound escape analysis. (ndossche)

+- OpenSSL:
+  . Fixed stream_socket_enable_crypto() leaving the socket non-blocking
+    after a handshake timeout. (Ilia Alshanetsky)
+
 - PCNTL:
   . Fixed pcntl_signal_dispatch() dropping the queued signals when it runs while
     an exception is pending. (nicolas-grekas)
diff --git a/ext/openssl/tests/stream_crypto_enable_timeout_blocking.phpt b/ext/openssl/tests/stream_crypto_enable_timeout_blocking.phpt
new file mode 100644
index 00000000000..39a8f973b86
--- /dev/null
+++ b/ext/openssl/tests/stream_crypto_enable_timeout_blocking.phpt
@@ -0,0 +1,53 @@
+--TEST--
+OpenSSL handshake timeout restores the stream blocking mode
+--EXTENSIONS--
+openssl
+--SKIPIF--
+<?php
+if (!function_exists('proc_open')) die('skip no proc_open');
+?>
+--FILE--
+<?php
+$serverCode = <<<'CODE'
+    $server = stream_socket_server('tcp://127.0.0.1:0', $errno, $errstr);
+    phpt_notify_server_start($server);
+
+    $conn = stream_socket_accept($server, 5);
+    phpt_wait();
+    fclose($conn);
+CODE;
+
+$clientCode = <<<'CODE'
+    $context = stream_context_create(['ssl' => [
+        'verify_peer' => false,
+        'verify_peer_name' => false,
+    ]]);
+    $client = stream_socket_client('tcp://{{ ADDR }}', $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $context);
+
+    $metadata = stream_get_meta_data($client);
+    var_dump($metadata['blocked']);
+
+    set_error_handler(function (int $errno, string $errstr) use ($client): bool {
+        $metadata = stream_get_meta_data($client);
+        var_dump($metadata['blocked']);
+        echo $errstr, "\n";
+        fclose($client);
+        return true;
+    });
+
+    var_dump(stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_TLS_CLIENT));
+    restore_error_handler();
+    var_dump(is_resource($client));
+
+    phpt_notify();
+CODE;
+
+include 'ServerClientTestCase.inc';
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+?>
+--EXPECT--
+bool(true)
+bool(true)
+stream_socket_enable_crypto(): SSL: Handshake timed out
+bool(false)
+bool(false)
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index ae12c8eb612..b564be8cad5 100644
--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -2004,6 +2004,7 @@ static int php_openssl_enable_crypto(php_stream *stream,
 				elapsed_time = php_openssl_subtract_timeval(cur_time, start_time);

 				if (php_openssl_compare_timeval( elapsed_time, *timeout) > 0) {
+					php_openssl_set_blocking(sslsock, blocked);
 					php_error_docref(NULL, E_WARNING, "SSL: Handshake timed out");
 					return -1;
 				}