偶然发现PHP的addGlob
的remove_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
给了点修复意见