Commit 971728fe109 for php.net
commit 971728fe109f4e48fd0ac0734872fc585eb53799
Author: Niels Dossche <7771979+ndossche@users.noreply.github.com>
Date: Fri Jan 2 08:57:30 2026 -0800
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.
diff --git a/NEWS b/NEWS
index 14b47a44d38..cadfda9bde6 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 85cad750f08..0ea423b32d3 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 baae7571549..50695981796 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 00000000000..b443393f826
--- /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--
+<?php
+if (@!include "./ext/standard/tests/http/server.inc") die('skip server.inc not available');
+http_server_skipif();
+?>
+--FILE--
+<?php
+require "./ext/standard/tests/http/server.inc";
+
+['pid' => $pid, 'uri' => $uri] = http_server([
+ "data://text/plain,HTTP/1.0 200 Ok\r\n\r\n<html>foo",
+], $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"