偶然发现PHP的addGlobremove_path有一点点问题

<?php
$zip = new ZipArchive();
$filename = "./test.zip";

if ($zip->open($filename, ZipArchive::CREATE)!==TRUE) {
    exit("无法打开 <$filename>\n");
}

$dev_dir = '/test/a.p'; // 设置 remove_path

// 使用 addGlob 添加文件
//$zip->addGlob('/test/test/test/.htaccess', 0, ['add_path' => 'var/www/html/', 'remove_path' => $dev_dir]);
$zip->addGlob('/test/test/a.php', 0, ['add_path' => 'var/www/html/', 'remove_path' => $dev_dir]);
//$zip->addGlob('/test/test/.htaccess', 0, ['add_path' => 'var/www/html/', 'remove_path' => $dev_dir]);

$zip->close();

if ($zip->open($filename) === true) {

    $extractPath = '/test'; 
    $zip->extractTo($extractPath);

    $zip->close();

    $files = scandir($extractPath);
    foreach ($files as $file) {
        echo $file . "\n";
    }
} else {
    echo "无法打开 <$filename>\n";
}

由于设置的是/test/a.p,原始/test/test/a.php,最后结果/t/a.php 移除了/test/tes这与设置的remove_path长度相同 (不是移除,是指针 )

需要注意的是,只能有唯一的串,如果是多次出现的就没有这个效果了

正如源码里所展示的这样,addGlob展示的remove_path是去除前缀 public ZipArchive::addGlob(string $pattern, int $flags = 0, array $options = []): array|false

然而实际上我发现匹配的是整个文件名的内容

if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(return_value), i)) != NULL) {
				if (opts.remove_all_path) {
					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 && strstr(Z_STRVAL_P(zval_file), opts.remove_path) != NULL) {
					if (IS_SLASH(Z_STRVAL_P(zval_file)[opts.remove_path_len])) {
						file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len + 1;
						file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len - 1;
					} else {
						file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len;
						file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len;
					}
				} else {
					file_stripped = Z_STRVAL_P(zval_file);
					file_stripped_len = Z_STRLEN_P(zval_file);
				}

而当指定的remove_path是文件路径后半段中的某些部分的时候,指针也会做移动,然而这是错误的,因此我们得到了一个奇怪的答案,这里我们演示一下

/tmp
├── Dire
│   └── This_Is_A_File
└── test.php

2 directories, 2 files

我的演示文件

<?php
$zip = new ZipArchive();
$filename = "./HereIsZip.zip";

if ($zip->open($filename, ZipArchive::CREATE)!==TRUE) {
    exit("Wrong!!!\n");
}
$dir = '/tmp/Dire';
$FirstDir = '/Dire/';
$SecondDir = 'This_Is';
$ThirdDir = '/D';
$zip->addGlob('/tmp/Dire/This_Is_A_File', 0, ['add_path' => '/', 'remove_path' => $FirstDir]);
$zip->addGlob('/tmp/Dire/This_Is_A_File', 0, ['add_path' => '/', 'remove_path' => $SecondDir]);
$zip->addGlob('/tmp/Dire/This_Is_A_File', 0, ['add_path' => '/', 'remove_path' => $ThirdDir]);
$zip->addGlob('/tmp/Dire/This_Is_A_File', 0, ['add_path' => '/', 'remove_path' => $dir]);
$zip->close();

if ($zip->open($filename) === true) {

    $extractPath = '/tmp'; 
    $zip->extractTo($extractPath);

    $zip->close();

} else {
    echo "Wrong\n";
}

运行php test.php 结果是

/tmp
├── Dire
│   └── This_Is_A_File
├── HereIsZip.zip
├── ire
│   └── This_Is_A_File
├── mp
│   └── Dire
│       └── This_Is_A_File
├── re
│   └── This_Is_A_File
├── test.php
└── This_Is_A_File

6 directories, 7 files

我想结果非常显然

$dir = '/tmp/Dire' //正常结果,This_Is_A_File
$FirstDir = '/Dire/'; //结果是, ire/This_Is_A_File
$SecondDir = 'This_Is';//结果是 re/This_Is_A_File
$ThirdDir = '/D';//结果是 mp/Dire/This_Is_A_File

给了点修复意见