From 610361845bfb16a2cf5a107205eb9c5f59e1c949 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 2 Jan 2026 17:06:56 +0100 Subject: [PATCH 1/3] Remove unnecessary optimization FIXME As the comment suggests, the return value of frameless calls is rarely not used. When it isn't used (and isn't refcounted) the FREE is already elided by the optimizer. Closes GH-20819 --- Zend/zend_compile.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5eba2ec1366f..0cb4ee3740f1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -816,8 +816,6 @@ static void zend_do_free(znode *op1) /* {{{ */ } else { /* Frameless calls usually use the return value, so always emit a free. This should be * faster than checking RETURN_VALUE_USED inside the handler. */ - // FIXME: We may actually look at the function signature to determine whether a free - // is necessary. zend_emit_op(NULL, ZEND_FREE, op1, NULL); } } else { From 971728fe109f4e48fd0ac0734872fc585eb53799 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Fri, 2 Jan 2026 08:57:30 -0800 Subject: [PATCH 2/3] Fix GH-20679: finfo_file() doesn't work on remote resources (#20700) The remote resources don't work because remote streams don't have a stat method. Since the check is only here for a best-effort check to return "directory" instead of "empty", we can try the stat and still execute the magic_stream() code even if it failed. Unfortunately we can't distinguish between a failed stat and an unimplemented stat. If we could, then this code could be even more robust. --- NEWS | 4 ++++ UPGRADING | 3 +++ ext/fileinfo/fileinfo.c | 11 ++++++----- ext/fileinfo/tests/remote_resource.phpt | 26 +++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 ext/fileinfo/tests/remote_resource.phpt diff --git a/NEWS b/NEWS index 14b47a44d386..cadfda9bde6b 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,10 @@ PHP NEWS needing to be present beforehand. (ndossche) . Added `clamp()`. (kylekatarnls, thinkverse) +- Fileinfo: + . Fixed bug GH-20679 (finfo_file() doesn't work on remote resources). + (ndossche) + - Hash: . Upgrade xxHash to 0.8.2. (timwolla) diff --git a/UPGRADING b/UPGRADING index 85cad750f086..0ea423b32d38 100644 --- a/UPGRADING +++ b/UPGRADING @@ -31,6 +31,9 @@ PHP 8.6 UPGRADE NOTES . It is now possible to use reference assign on WeakMap without the key needing to be present beforehand. +- Fileinfo: + . finfo_file() now works with remote streams. + - Intl: . Added IntlNumberRangeFormatter class to format an interval of two numbers with a given skeleton, locale, IntlNumberRangeFormatter::COLLAPSE_AUTO, IntlNumberRangeFormatter::COLLAPSE_NONE, IntlNumberRangeFormatter::COLLAPSE_UNIT, IntlNumberRangeFormatter::COLLAPSE_ALL collapse and IntlNumberRangeFormatter::IDENTITY_FALLBACK_SINGLE_VALUE, IntlNumberRangeFormatter::IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE, IntlNumberRangeFormatter::IDENTITY_FALLBACK_APPROXIMATELY and diff --git a/ext/fileinfo/fileinfo.c b/ext/fileinfo/fileinfo.c index baae75715495..50695981796e 100644 --- a/ext/fileinfo/fileinfo.c +++ b/ext/fileinfo/fileinfo.c @@ -268,11 +268,12 @@ static const char* php_fileinfo_from_path(struct magic_set *magic, const zend_st if (php_stream_stat(stream, &ssb) == SUCCESS) { if (ssb.sb.st_mode & S_IFDIR) { ret_val = "directory"; - } else { - ret_val = magic_stream(magic, stream); - if (UNEXPECTED(ret_val == NULL)) { - php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); - } + } + } + if (!ret_val) { + ret_val = magic_stream(magic, stream); + if (UNEXPECTED(ret_val == NULL)) { + php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); } } diff --git a/ext/fileinfo/tests/remote_resource.phpt b/ext/fileinfo/tests/remote_resource.phpt new file mode 100644 index 000000000000..b443393f826b --- /dev/null +++ b/ext/fileinfo/tests/remote_resource.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-20679 (finfo_file() doesn't work on remote resources) +--EXTENSIONS-- +fileinfo +--INI-- +allow_url_fopen=1 +--SKIPIF-- + +--FILE-- + $pid, 'uri' => $uri] = http_server([ + "data://text/plain,HTTP/1.0 200 Ok\r\n\r\nfoo", +], $output); + +$f = finfo_open(); +var_dump(finfo_file($f, $uri)); + +http_server_kill($pid); +?> +--EXPECT-- +string(51) "HTML document, ASCII text, with no line terminators" From 5484ebcc49a4cf6d598bef44b4e4e4c8f6cfcc6e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Fri, 2 Jan 2026 09:03:17 -0800 Subject: [PATCH 3/3] streams/memory: Ensure internal string is NUL terminated (#20812) zend_string_truncate() doesn't put a NUL byte. --- main/streams/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/streams/memory.c b/main/streams/memory.c index 785109db6582..2f411ff8e8c9 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -247,8 +247,8 @@ static int php_stream_memory_set_option(php_stream *stream, int option, int valu size_t old_size = ZSTR_LEN(ms->data); ms->data = zend_string_realloc(ms->data, newsize, 0); memset(ZSTR_VAL(ms->data) + old_size, 0, newsize - old_size); - ZSTR_VAL(ms->data)[ZSTR_LEN(ms->data)] = '\0'; } + ZSTR_VAL(ms->data)[ZSTR_LEN(ms->data)] = '\0'; return PHP_STREAM_OPTION_RETURN_OK; } }