Commit a184a512507 for php.net
commit a184a51250708728789d0be28048101d43e949f9
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Fri Jul 31 11:54:47 2026 -0400
zip: require remove_path to be shorter than the path it strips (#22973)
The zend_string conversion in bcb05dcf6f3 replaced the length check with
zend_string_starts_with(), which also matches on equality. A path equal to
remove_path then hits the non-slash branch, strips its whole length and
produces an empty archive entry name instead of keeping the path.
Closes GH-22973
diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c
index 06bd6691be1..1b5749c53a5 100644
--- a/ext/zip/php_zip.c
+++ b/ext/zip/php_zip.c
@@ -1832,7 +1832,8 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0);
file_stripped = ZSTR_VAL(basename);
file_stripped_len = ZSTR_LEN(basename);
- } else if (opts.remove_path && zend_string_starts_with(Z_STR_P(zval_file), opts.remove_path)) {
+ } else if (opts.remove_path && Z_STRLEN_P(zval_file) > ZSTR_LEN(opts.remove_path)
+ && zend_string_starts_with(Z_STR_P(zval_file), opts.remove_path)) {
if (IS_SLASH(Z_STRVAL_P(zval_file)[ZSTR_LEN(opts.remove_path)])) {
file_stripped = Z_STRVAL_P(zval_file) + ZSTR_LEN(opts.remove_path) + 1;
file_stripped_len = Z_STRLEN_P(zval_file) - ZSTR_LEN(opts.remove_path) - 1;
diff --git a/ext/zip/tests/addGlob_remove_path_full_match.phpt b/ext/zip/tests/addGlob_remove_path_full_match.phpt
new file mode 100644
index 00000000000..55b54ade08a
--- /dev/null
+++ b/ext/zip/tests/addGlob_remove_path_full_match.phpt
@@ -0,0 +1,40 @@
+--TEST--
+ZipArchive::addGlob() with remove_path equal to a matched path
+--EXTENSIONS--
+zip
+--FILE--
+<?php
+$dirname = __DIR__ . '/addGlob_remove_path_full_match_dir';
+@mkdir($dirname);
+touch($dirname . '/foo.txt');
+touch($dirname . '/bar.txt');
+
+$zip = new ZipArchive();
+$zip->open($dirname . '/tmp.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
+$zip->addGlob($dirname . '/*.txt', 0, ['remove_path' => $dirname . '/foo.txt']);
+
+$names = [];
+for ($i = 0; $i < $zip->numFiles; $i++) {
+ $names[] = str_replace(__DIR__ . '/', '', $zip->getNameIndex($i));
+}
+sort($names);
+var_dump($names);
+
+$zip->close();
+
+?>
+--CLEAN--
+<?php
+$dirname = __DIR__ . '/addGlob_remove_path_full_match_dir';
+unlink($dirname . '/tmp.zip');
+unlink($dirname . '/foo.txt');
+unlink($dirname . '/bar.txt');
+rmdir($dirname);
+?>
+--EXPECT--
+array(2) {
+ [0]=>
+ string(42) "addGlob_remove_path_full_match_dir/bar.txt"
+ [1]=>
+ string(42) "addGlob_remove_path_full_match_dir/foo.txt"
+}