[php-src] master: Merge branch 'PHP-8.4' into PHP-8.5
| From: | Ilia Alshanetsky | Date: | Sun, 04 Oct 2026 14:39:54 +0000 |
| Subject: | [php-src] master: Merge branch 'PHP-8.4' into PHP-8.5 | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-141915@lists.php.net to get a copy of this message | ||
Author: Ilia Alshanetsky (iliaal)
Date: 2026-10-04T10:18:25-04:00
Commit: https://github.com/php/php-src/commit/0c543c52fb662efe92bf6a1b97bab64425e1c736
Raw diff: https://github.com/php/php-src/commit/0c543c52fb662efe92bf6a1b97bab64425e1c736.diff
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
ext/standard: Reject incomplete sha1_file reads
Changed paths:
A ext/standard/tests/strings/sha1_file_stream_error.phpt
M NEWS
M ext/standard/sha1.c
Diff:
diff --git a/NEWS b/NEWS
index f14d47d2aca5..9e7c1c4907c5 100644
--- a/NEWS
+++ b/NEWS
@@ -192,6 +192,8 @@ PHP NEWS
(Ilia Alshanetsky)
- Standard:
+ . Fixed sha1_file() returning a digest for incomplete data after a stream
+ read failure. (Ilia Alshanetsky)
. Fixed three Windows-only proc_open() defects: an uninitialized
PROCESS_INFORMATION, an indeterminate comspec pointer after a failed
lookup, and an unchecked CreateFileA() failure. (Ilia Alshanetsky)
diff --git a/ext/standard/sha1.c b/ext/standard/sha1.c
index 95f2b54d0fd0..7dd801c01514 100644
--- a/ext/standard/sha1.c
+++ b/ext/standard/sha1.c
@@ -84,10 +84,16 @@ PHP_FUNCTION(sha1_file)
PHP_SHA1Update(&context, buf, n);
}
+ bool failed = n < 0 || !php_stream_eof(stream);
+
PHP_SHA1Final(digest, &context);
php_stream_close(stream);
+ if (failed) {
+ RETURN_FALSE;
+ }
+
if (raw_output) {
RETURN_STRINGL((char *) digest, 20);
} else {
diff --git a/ext/standard/tests/strings/sha1_file_stream_error.phpt
b/ext/standard/tests/strings/sha1_file_stream_error.phpt
new file mode 100644
index 000000000000..751cf5e7240c
--- /dev/null
+++ b/ext/standard/tests/strings/sha1_file_stream_error.phpt
@@ -0,0 +1,77 @@
+--TEST--
+sha1_file() returns false when a stream read fails
+--FILE--
+<?php
+class TestStream
+{
+ public $context;
+ private string $mode;
+ private int $position = 0;
+
+ public function stream_open(string $path): bool
+ {
+ $this->mode = substr($path, strlen('test://'));
+
+ return true;
+ }
+
+ public function stream_read(int $count): string|false
+ {
+ $position = $this->position++;
+ if ($this->mode === 'error') {
+ return false;
+ }
+ if ($this->mode === 'empty' || $this->mode === 'stalled') {
+ return '';
+ }
+ if ($this->mode === 'short') {
+ return substr('prefix', $position * 2, 2);
+ }
+ if ($position === 0) {
+ return 'prefix';
+ }
+
+ return $this->mode === 'prefix-error' ? false : '';
+ }
+
+ public function stream_eof(): bool
+ {
+ return $this->mode === 'empty'
+ || ($this->mode === 'eof' && $this->position > 1)
+ || ($this->mode === 'short' && $this->position >= 3);
+ }
+}
+
+stream_wrapper_register('test', TestStream::class);
+
+foreach (['error', 'prefix-error', 'stalled',
'prefix-stalled', 'empty', 'eof', 'short'] as $mode) {
+ echo "$mode: ";
+ var_dump(sha1_file("test://$mode"));
+ echo "$mode (raw): ";
+ $result = sha1_file("test://$mode", true);
+ var_dump(is_string($result) ? bin2hex($result) : $result);
+}
+
+echo "directory: ";
+var_dump(@sha1_file(__DIR__));
+echo "directory (raw): ";
+$result = @sha1_file(__DIR__, true);
+var_dump(is_string($result) ? bin2hex($result) : $result);
+?>
+--EXPECT--
+error: bool(false)
+error (raw): bool(false)
+prefix-error: bool(false)
+prefix-error (raw): bool(false)
+stalled: bool(false)
+stalled (raw): bool(false)
+prefix-stalled: bool(false)
+prefix-stalled (raw): bool(false)
+empty: string(40) "da39a3ee5e6b4b0d3255bfef95601890afd80709"
+empty (raw): string(40) "da39a3ee5e6b4b0d3255bfef95601890afd80709"
+eof: string(40) "b4ebfe34d0fa97f0dd2bb1234fad8f59805f4e8d"
+eof (raw): string(40) "b4ebfe34d0fa97f0dd2bb1234fad8f59805f4e8d"
+short: string(40) "b4ebfe34d0fa97f0dd2bb1234fad8f59805f4e8d"
+short (raw): string(40) "b4ebfe34d0fa97f0dd2bb1234fad8f59805f4e8d"
+directory: bool(false)
+directory (raw): bool(false)