提取 zip 中的特定文件(包括子目录)
Extract specific files in zip (include sub directories)
我只想从 zip 文件中提取图像,但我也希望它提取在子文件夹中找到的图像,因为 well.How 我可以根据我的代码实现这个吗 below.Note:我是不想在这里保留目录结构,只是想提取在 zip 中找到的任何图像。
//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
$file_name = $zip->getNameIndex($i);
$file_info = pathinfo($file_name);
//if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
if (in_array($file_info['extension'], $this->config->getValidExtensions())) {
//extract only images
copy("zip://" . $zip_path . "#" . $file_name, $this->tmp_dir . '/images/' . $file_info['basename']);
}
}
$zip->close();
编辑
我的代码工作正常我需要知道的是如何使 ziparchive 也进入子目录
根据文件扩展名(不一定是最可靠的方法),您可能会发现以下内容对您有所帮助。
/* source zip file and target location for extracted files */
$file='c:/temp2/experimental.zip';
$destination='c:/temp2/extracted/';
/* Image file extensions to allow */
$exts=array('jpg','jpeg','png','gif','JPG','JPEG','PNG','GIF');
$files=array();
/* create the ZipArchive object */
$zip = new ZipArchive();
$status = $zip->open( $file, ZIPARCHIVE::FL_COMPRESSED );
if( $status ){
/* how many files are in the archive */
$count = $zip->numFiles;
for( $i=0; $i < $count; $i++ ){
try{
$name = $zip->getNameIndex( $i );
$ext = pathinfo( $name, PATHINFO_EXTENSION );
$basename = pathinfo( $name, PATHINFO_BASENAME );
/* store a reference to the file name for extraction or copy */
if( in_array( $ext, $exts ) ) {
$files[]=$name;
/* To extract files and ignore directory structure */
$res = copy( 'zip://'.$file.'#'.$name, $destination . $basename );
echo ( $res ? 'Copied: '.$basename : 'unable to copy '.$basename ) . '<br />';
}
}catch( Exception $e ){
echo $e->getMessage();
continue;
}
}
/* To extract files, with original directory structure, uncomment below */
if( !empty( $files ) ){
#$zip->extractTo( $destination, $files );
}
$zip->close();
} else {
echo $zip->getStatusString();
}
这将允许您遍历路径中的所有目录,并搜索任何 image/has 您定义的扩展名。因为你告诉其他用户你已经完成了 ziarchive 部分,所以我省略了......
<?php
function traverse($path, $images = [])
{
$files = array_diff(scandir($path), ['.', '..']);
foreach ($files as $file) {
// check if the file is an image
if (in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), ['jpg', 'jpeg', 'png', 'gif'])) {
$images[] = $file;
}
if (is_dir($path . '/' . $file)) {
$images = traverse($path . '/' . $file, $images);
}
}
return $images;
}
$images = traverse('/Users/kyle/Downloads');
您想遵循这个过程:
- 获取当前工作目录下的所有文件
- 如果 CWD 中的文件是图像,则将其添加到图像数组中
- 如果CWD中的文件是目录,则递归调用遍历函数,在目录中查找图片
- 在新的 CWD 中查找图像,如果文件是目录递归等...
跟踪当前路径很重要,这样您才能对文件调用 is_dir。另外,您要确保不要搜索“。”或 '..' 否则你将永远不会命中基本递归 case/it 将是无限的。
而且这样不会保留图片的目录路径!如果你想这样做,你应该做 $image[] = $path . '/' . $file;
。您可能想这样做,然后获取所有文件内容,希望函数完成 运行。我不建议对 $image 数组中的内容进行排序,因为它可能会占用大量内存。
您的代码是正确的。我用文件 a/b/c.png
、d.png
:
创建了 a.zip
$ mkdir -p a/b
$ zip -r a.zip d.png a
adding: d.png (deflated 4%)
adding: a/ (stored 0%)
adding: a/b/ (stored 0%)
adding: a/b/c.png (deflated 8%)
$ unzip -l a.zip
Archive: a.zip
Length Date Time Name
--------- ---------- ----- ----
122280 11-05-2016 14:45 d.png
0 11-05-2016 14:44 a/
0 11-05-2016 14:44 a/b/
36512 11-05-2016 14:44 a/b/c.png
--------- -------
158792 4 files
代码将 d.png
和 c.png
从 a.zip
提取到目标目录:
$arch_filename = 'a.zip';
$dest_dir = './dest';
if (!is_dir($dest_dir)) {
if (!mkdir($dest_dir, 0755, true))
die("failed to make directory $dest_dir\n");
}
$zip = new ZipArchive;
if (!$zip->open($arch_filename))
die("failed to open $arch_filename");
for ($i = 0; $i < $zip->numFiles; ++$i) {
$path = $zip->getNameIndex($i);
$ext = pathinfo($path, PATHINFO_EXTENSION);
if (!preg_match('/(?:jpg|png)/i', $ext))
continue;
$dest_basename = pathinfo($path, PATHINFO_BASENAME);
echo $path, PHP_EOL;
copy("zip://{$arch_filename}#{$path}", "$dest_dir/{$dest_basename}");
}
$zip->close();
测试
$ php script.php
d.png
a/b/c.png
$ find ./dest -type f
./dest/d.png
./dest/c.png
所以代码是正确的,问题一定出在其他地方。
关注文件夹的第一件事就是关注它 - 您的代码不会这样做。
ZIP 中没有文件夹(事实上,即使在文件系统中,"folder" 也是一个文件,只是一个特殊的文件)。文件(数据)有一个名称,可能包含一个路径(很可能是一个相对路径)。如果按 "go in subdiectories" 表示,您希望文件系统中的压缩文件具有相同的相对文件夹结构,则必须编写代码来创建这些文件夹。我认为复制不会自动为您执行此操作。
我修改了你的代码并添加了文件夹的创建。请注意我必须添加以使其可运行的配置变量,将其配置到您的环境中。我还将所有调试输出留在其中。代码在 Windows 7、PHP 5.6
上独立运行
error_reporting(-1 );
ini_set('display_errors', 1);
$zip_path = './test/cgiwsour.zip';
$write_dir = './test'; // base path for output
$zip = new ZipArchive();
if (!$zip->open($zip_path))
die('could not open zip file '.PHP_EOL);
$valid_extensions = ['cpp'];
$create_subfolders = true;
//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
$file_name = $zip->getNameIndex($i);var_dump($file_name, $i);
$file_info = pathinfo($file_name);//print_r($file_info);
//if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
if (isset($file_info['extension']) && in_array(strtolower($file_info['extension']), $valid_extensions)) {
$tmp_dir = $write_dir;
if ($create_subfolders) {
$dir_parts = explode('/', $file_info['dirname']);
print_r($dir_parts);
foreach($dir_parts as $folder) {
$tmp_dir = $tmp_dir . '/' . $folder;
var_dump($tmp_dir);
if (!file_exists($tmp_dir)) {
$res = mkdir($tmp_dir);
var_dump($res);
echo 'created '.$tmp_dir.PHP_EOL;
}
}
}
else {
$tmp_dir .= '/' . $file_info['dirname'];
}
//extract only images
$res = copy("zip://" . $zip_path . "#" . $file_name, $tmp_dir . '/' . $file_info['basename']);
echo 'match : '.$file_name.PHP_EOL;
var_dump($res);
}
}
$zip->close();
值得注意的是,由于 access/rights 限制,mkdir() 调用可能无法在所有系统上完美运行。
我只想从 zip 文件中提取图像,但我也希望它提取在子文件夹中找到的图像,因为 well.How 我可以根据我的代码实现这个吗 below.Note:我是不想在这里保留目录结构,只是想提取在 zip 中找到的任何图像。
//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
$file_name = $zip->getNameIndex($i);
$file_info = pathinfo($file_name);
//if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
if (in_array($file_info['extension'], $this->config->getValidExtensions())) {
//extract only images
copy("zip://" . $zip_path . "#" . $file_name, $this->tmp_dir . '/images/' . $file_info['basename']);
}
}
$zip->close();
编辑
我的代码工作正常我需要知道的是如何使 ziparchive 也进入子目录
根据文件扩展名(不一定是最可靠的方法),您可能会发现以下内容对您有所帮助。
/* source zip file and target location for extracted files */
$file='c:/temp2/experimental.zip';
$destination='c:/temp2/extracted/';
/* Image file extensions to allow */
$exts=array('jpg','jpeg','png','gif','JPG','JPEG','PNG','GIF');
$files=array();
/* create the ZipArchive object */
$zip = new ZipArchive();
$status = $zip->open( $file, ZIPARCHIVE::FL_COMPRESSED );
if( $status ){
/* how many files are in the archive */
$count = $zip->numFiles;
for( $i=0; $i < $count; $i++ ){
try{
$name = $zip->getNameIndex( $i );
$ext = pathinfo( $name, PATHINFO_EXTENSION );
$basename = pathinfo( $name, PATHINFO_BASENAME );
/* store a reference to the file name for extraction or copy */
if( in_array( $ext, $exts ) ) {
$files[]=$name;
/* To extract files and ignore directory structure */
$res = copy( 'zip://'.$file.'#'.$name, $destination . $basename );
echo ( $res ? 'Copied: '.$basename : 'unable to copy '.$basename ) . '<br />';
}
}catch( Exception $e ){
echo $e->getMessage();
continue;
}
}
/* To extract files, with original directory structure, uncomment below */
if( !empty( $files ) ){
#$zip->extractTo( $destination, $files );
}
$zip->close();
} else {
echo $zip->getStatusString();
}
这将允许您遍历路径中的所有目录,并搜索任何 image/has 您定义的扩展名。因为你告诉其他用户你已经完成了 ziarchive 部分,所以我省略了......
<?php
function traverse($path, $images = [])
{
$files = array_diff(scandir($path), ['.', '..']);
foreach ($files as $file) {
// check if the file is an image
if (in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), ['jpg', 'jpeg', 'png', 'gif'])) {
$images[] = $file;
}
if (is_dir($path . '/' . $file)) {
$images = traverse($path . '/' . $file, $images);
}
}
return $images;
}
$images = traverse('/Users/kyle/Downloads');
您想遵循这个过程:
- 获取当前工作目录下的所有文件
- 如果 CWD 中的文件是图像,则将其添加到图像数组中
- 如果CWD中的文件是目录,则递归调用遍历函数,在目录中查找图片
- 在新的 CWD 中查找图像,如果文件是目录递归等...
跟踪当前路径很重要,这样您才能对文件调用 is_dir。另外,您要确保不要搜索“。”或 '..' 否则你将永远不会命中基本递归 case/it 将是无限的。
而且这样不会保留图片的目录路径!如果你想这样做,你应该做 $image[] = $path . '/' . $file;
。您可能想这样做,然后获取所有文件内容,希望函数完成 运行。我不建议对 $image 数组中的内容进行排序,因为它可能会占用大量内存。
您的代码是正确的。我用文件 a/b/c.png
、d.png
:
a.zip
$ mkdir -p a/b
$ zip -r a.zip d.png a
adding: d.png (deflated 4%)
adding: a/ (stored 0%)
adding: a/b/ (stored 0%)
adding: a/b/c.png (deflated 8%)
$ unzip -l a.zip
Archive: a.zip
Length Date Time Name
--------- ---------- ----- ----
122280 11-05-2016 14:45 d.png
0 11-05-2016 14:44 a/
0 11-05-2016 14:44 a/b/
36512 11-05-2016 14:44 a/b/c.png
--------- -------
158792 4 files
代码将 d.png
和 c.png
从 a.zip
提取到目标目录:
$arch_filename = 'a.zip';
$dest_dir = './dest';
if (!is_dir($dest_dir)) {
if (!mkdir($dest_dir, 0755, true))
die("failed to make directory $dest_dir\n");
}
$zip = new ZipArchive;
if (!$zip->open($arch_filename))
die("failed to open $arch_filename");
for ($i = 0; $i < $zip->numFiles; ++$i) {
$path = $zip->getNameIndex($i);
$ext = pathinfo($path, PATHINFO_EXTENSION);
if (!preg_match('/(?:jpg|png)/i', $ext))
continue;
$dest_basename = pathinfo($path, PATHINFO_BASENAME);
echo $path, PHP_EOL;
copy("zip://{$arch_filename}#{$path}", "$dest_dir/{$dest_basename}");
}
$zip->close();
测试
$ php script.php
d.png
a/b/c.png
$ find ./dest -type f
./dest/d.png
./dest/c.png
所以代码是正确的,问题一定出在其他地方。
关注文件夹的第一件事就是关注它 - 您的代码不会这样做。
ZIP 中没有文件夹(事实上,即使在文件系统中,"folder" 也是一个文件,只是一个特殊的文件)。文件(数据)有一个名称,可能包含一个路径(很可能是一个相对路径)。如果按 "go in subdiectories" 表示,您希望文件系统中的压缩文件具有相同的相对文件夹结构,则必须编写代码来创建这些文件夹。我认为复制不会自动为您执行此操作。
我修改了你的代码并添加了文件夹的创建。请注意我必须添加以使其可运行的配置变量,将其配置到您的环境中。我还将所有调试输出留在其中。代码在 Windows 7、PHP 5.6
上独立运行error_reporting(-1 );
ini_set('display_errors', 1);
$zip_path = './test/cgiwsour.zip';
$write_dir = './test'; // base path for output
$zip = new ZipArchive();
if (!$zip->open($zip_path))
die('could not open zip file '.PHP_EOL);
$valid_extensions = ['cpp'];
$create_subfolders = true;
//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
$file_name = $zip->getNameIndex($i);var_dump($file_name, $i);
$file_info = pathinfo($file_name);//print_r($file_info);
//if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
if (isset($file_info['extension']) && in_array(strtolower($file_info['extension']), $valid_extensions)) {
$tmp_dir = $write_dir;
if ($create_subfolders) {
$dir_parts = explode('/', $file_info['dirname']);
print_r($dir_parts);
foreach($dir_parts as $folder) {
$tmp_dir = $tmp_dir . '/' . $folder;
var_dump($tmp_dir);
if (!file_exists($tmp_dir)) {
$res = mkdir($tmp_dir);
var_dump($res);
echo 'created '.$tmp_dir.PHP_EOL;
}
}
}
else {
$tmp_dir .= '/' . $file_info['dirname'];
}
//extract only images
$res = copy("zip://" . $zip_path . "#" . $file_name, $tmp_dir . '/' . $file_info['basename']);
echo 'match : '.$file_name.PHP_EOL;
var_dump($res);
}
}
$zip->close();
值得注意的是,由于 access/rights 限制,mkdir() 调用可能无法在所有系统上完美运行。