[php-src] PHP-8.5: ext/zip: php_zip_ops_stat() succeeds when the archive cannot be opened.
David Carlier <[email protected]>
| Newsgroups | gmane.comp.php.cvs.general |
|---|---|
| Message-ID | <[email protected]> |
Author: David Carlier (devnexen)
Date: 2026-08-30T15:26:29+01:00
Commit: https://github.com/php/php-src/commit/614afe7b09fd37c57f71a02fecfac33191ea141a
Raw diff: https://github.com/php/php-src/commit/614afe7b09fd37c57f71a02fecfac33191ea141a.diff
ext/zip: php_zip_ops_stat() succeeds when the archive cannot be opened.
When zip_open() failed the whole stat block was skipped, yet the function
still returned 0. fstat() on a zip:// stream therefore succeeded with the
zeroed statbuf it was given, reporting a zero size and no file type bits,
instead of failing. Return -1 on that path.
Close GH-23511
Changed paths:
A ext/zip/tests/stream_fstat_unreadable_archive.phpt
M NEWS
M ext/zip/zip_stream.c
Diff:
diff --git a/NEWS b/NEWS
index aa7862f63bb4..db1aba15a8e6 100644
--- a/NEWS
+++ b/NEWS
@@ -82,6 +82,8 @@ PHP NEWS
on corrupted entries. (David Carlier)
. Fixed ZipArchive::getNameIndex() truncating the entry index to int.
(David Carlier)
+ . Fixed fstat() on a zip:// stream reporting success when the archive cannot
+ be opened. (David Carlier)
- SAPI:
. Fixed fuzzer targets failing to build in isolation. (Mrmaxmeier)
diff --git a/ext/zip/tests/stream_fstat_unreadable_archive.phpt b/ext/zip/tests/stream_fstat_unreadable_archive.phpt
new file mode 100644
index 000000000000..a81fc8fc3cfc
--- /dev/null
+++ b/ext/zip/tests/stream_fstat_unreadable_archive.phpt
@@ -0,0 +1,38 @@
+--TEST--
+fstat() on a zip:// stream whose archive can no longer be opened
+--EXTENSIONS--
+zip
+--SKIPIF--
+<?php
+if (PHP_OS_FAMILY === 'Windows') die('skip the archive cannot be rewritten while it is open');
+?>
+--FILE--
+<?php
+$file = __DIR__ . '/stream_fstat_unreadable_archive.zip';
+
+@unlink($file);
+
+$zip = new ZipArchive;
+if (!$zip->open($file, ZipArchive::CREATE)) {
+ exit('failed');
+}
+
+$zip->addFromString('entry.txt', 'entry');
+$zip->close();
+
+$fp = fopen('zip://' . $file . '#entry.txt', 'rb');
+var_dump($fp !== false);
+
+file_put_contents($file, 'this is not a zip archive');
+
+var_dump(fstat($fp));
+
+fclose($fp);
+?>
+--EXPECT--
+bool(true)
+bool(false)
+--CLEAN--
+<?php
+unlink(__DIR__ . '/stream_fstat_unreadable_archive.zip');
+?>
diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c
index 0356863ef7ce..b70b82a415ec 100644
--- a/ext/zip/zip_stream.c
+++ b/ext/zip/zip_stream.c
@@ -195,6 +195,9 @@ static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{
ssb->sb.st_blocks = -1;
#endif
ssb->sb.st_ino = -1;
+ } else {
+ zend_string_release_ex(file_basename, 0);
+ return -1;
}
zend_string_release_ex(file_basename, 0);
return 0;