From d7c87d2f7bd821075270a43c8fcee6e318be4367 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Tue, 4 Aug 2026 22:06:13 -0400 Subject: [PATCH] Balance stream error ops on file_put_contents LOCK_EX URL reject file_put_contents begins a stream error operation then returns early when LOCK_EX is used with a non-file URL, without ending the operation. After ~1000 such failures the depth limit is exhausted and later stream ops fail. Call php_stream_error_operation_end before that RETURN_FALSE. Closes GH-23186 --- NEWS | 4 ++++ ext/standard/file.c | 1 + .../file/file_put_contents_lock_ex_url.phpt | 20 +++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 ext/standard/tests/file/file_put_contents_lock_ex_url.phpt diff --git a/NEWS b/NEWS index 16a4ae4e99b8..14de103fcaa9 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.6.0beta1 +- Streams: + . Fixed file_put_contents() LOCK_EX early return leaking stream error + operation depth. (iliaal) + - Core: . Changed run-tests.php to run test subprocesses without a shell where possible. (NickSdot) diff --git a/ext/standard/file.c b/ext/standard/file.c index fd6f578e4ef0..d6a8b9f1d0ea 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -474,6 +474,7 @@ PHP_FUNCTION(file_put_contents) if (php_memnstr(filename, "://", sizeof("://") - 1, filename + filename_len)) { if (strncasecmp(filename, "file://", sizeof("file://") - 1)) { php_error_docref(NULL, E_WARNING, "Exclusive locks may only be set for regular files"); + php_stream_error_operation_end(context); RETURN_FALSE; } } diff --git a/ext/standard/tests/file/file_put_contents_lock_ex_url.phpt b/ext/standard/tests/file/file_put_contents_lock_ex_url.phpt new file mode 100644 index 000000000000..6bd346f39f46 --- /dev/null +++ b/ext/standard/tests/file/file_put_contents_lock_ex_url.phpt @@ -0,0 +1,20 @@ +--TEST-- +file_put_contents LOCK_EX on non-file URL balances stream error operation +--INI-- +allow_url_fopen=1 +--FILE-- + +--EXPECT-- +done