Commit 473a7e04515 for php.net
commit 473a7e04515f19612ade59e489671e5d49a0fab4
Author: David Carlier <devnexen@gmail.com>
Date: Sat Aug 29 20:57:55 2026 +0100
ext/zip: ZipArchive::getNameIndex() index truncated to int.
The index was cast to int before being handed to zip_get_name(), whose
parameter is a zip_uint64_t, so any value with a non-zero upper half
wrapped and selected the wrong entry: getNameIndex(1 << 32) returned the
name of entry 0 instead of false. Cast to zip_uint64_t instead, letting
libzip reject out of range indices.
diff --git a/NEWS b/NEWS
index 04adab59625..aa7862f63bb 100644
--- a/NEWS
+++ b/NEWS
@@ -80,6 +80,8 @@ PHP NEWS
garbage collected). (Weilin Du, ndossche)
. Fixed ZipArchive::extractTo() and ZipArchive::getFrom*() reporting success
on corrupted entries. (David Carlier)
+ . Fixed ZipArchive::getNameIndex() truncating the entry index to int.
+ (David Carlier)
- SAPI:
. Fixed fuzzer targets failing to build in isolation. (Mrmaxmeier)
diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c
index 5e640df9a10..69b81b88753 100644
--- a/ext/zip/php_zip.c
+++ b/ext/zip/php_zip.c
@@ -2181,7 +2181,7 @@ PHP_METHOD(ZipArchive, getNameIndex)
ZIP_FROM_OBJECT(intern, self);
- name = zip_get_name(intern, (int) index, flags);
+ name = zip_get_name(intern, (zip_uint64_t) index, flags);
if (name) {
RETVAL_STRING((char *)name);
diff --git a/ext/zip/tests/oo_getnameindex_large_index.phpt b/ext/zip/tests/oo_getnameindex_large_index.phpt
new file mode 100644
index 00000000000..471dffc38d9
--- /dev/null
+++ b/ext/zip/tests/oo_getnameindex_large_index.phpt
@@ -0,0 +1,44 @@
+--TEST--
+ZipArchive::getNameIndex() with an index that does not fit in an int
+--EXTENSIONS--
+zip
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE != 8) die('skip 64-bit only');
+?>
+--FILE--
+<?php
+$file = __DIR__ . '/oo_getnameindex_large_index.zip';
+
+@unlink($file);
+
+$zip = new ZipArchive;
+if (!$zip->open($file, ZipArchive::CREATE)) {
+ exit('failed');
+}
+
+$zip->addFromString('entry1.txt', 'entry #1');
+$zip->close();
+
+if (!$zip->open($file)) {
+ exit('failed');
+}
+
+var_dump($zip->getNameIndex(0));
+var_dump($zip->getNameIndex(1 << 32));
+var_dump($zip->getNameIndex((1 << 32) + 1));
+var_dump($zip->getNameIndex(PHP_INT_MAX));
+var_dump($zip->getNameIndex(-1));
+
+$zip->close();
+?>
+--EXPECT--
+string(10) "entry1.txt"
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+--CLEAN--
+<?php
+unlink(__DIR__ . '/oo_getnameindex_large_index.zip');
+?>