使用 PHP 创建 .tar.gz 文件
Create .tar.gz file using PHP
我正在从事的项目需要创建 .tar.gz 档案并将其提供给外部服务。此外部服务仅适用于 .tar.gz,因此另一种类型的存档是不可能的。我正在处理的代码将执行的服务器不允许访问系统调用。所以 system
、exec
、反引号等都不是什么好东西。这意味着我必须依靠纯 PHP 实现来创建 .tar.gz 文件。
经过一些研究,PharData
似乎有助于实现该结果。但是我遇到了困难,需要一些指导。
考虑以下文件夹布局:
parent folder
- child folder 1
- child folder 2
- file1
- file2
我正在使用下面的代码片段创建 .tar.gz 存档,它可以解决问题,但最终结果存在一个小问题,它不包含父文件夹,但包含其中的所有内容。
$pd = new PharData('archive.tar');
$dir = realpath("parent-folder");
$pd->buildFromDirectory($dir);
$pd->compress(Phar::GZ);
unset( $pd );
unlink('archive.tar');
创建存档时,它必须包含与上述完全相同的文件夹布局。使用上面提到的代码片段,存档包含除父文件夹之外的所有内容,这是外部服务的交易破坏者:
- child folder 1
- child folder 2
- file1
- file2
buildFromDirectory
的描述确实提到了以下内容,因此它不包含存档中的父文件夹是可以理解的:
Construct a tar/zip archive from the files within a directory.
我也尝试过使用 buildFromIterator
但最终结果也是一样的,即父文件夹不包含在存档中。我能够使用 addFile
获得所需的结果,但这 非常慢 。
经过更多研究,我发现了以下库:https://github.com/alchemy-fr/Zippy。但这需要服务器上不可用的 composer
支持。如果有人可以指导我实现最终结果,我将不胜感激。我也愿意使用其他一些方法或库,只要它是纯 PHP 实现并且不需要任何外部依赖项。不确定它是否有帮助,但是执行代码的服务器有 PHP 5.6
使用 "parent-folder" 的父级作为 Phar::buildFromDirectory()
的基础,并使用其第二个参数将结果限制为 "parent-folder",例如:
$parent = dirname("parent-folder");
$pd->buildFromDirectory($parent, '#^'.preg_quote("$parent/parent-folder/", "#").'#');
$pd->compress(Phar::GZ);
我最终不得不这样做,因为这个问题是 google 上的第一个结果,这里是解决这个问题的最佳方法,不使用正则表达式(如果你想从包含许多其他目录的目录中提取一个目录)。
function buildFiles($folder, $dir, $retarr = []) {
$i = new DirectoryIterator("$folder/$dir");
foreach ($i as $d) {
if ($d->isDot()) {
continue;
}
if ($d->isDir()) {
$newdir = "$dir/" . basename($d->getPathname());
$retarr = buildFiles($folder, $newdir, $retarr);
} else {
$dest = "$dir/" . $d->getFilename();
$retarr[$dest] = $d->getPathname();
}
}
return $retarr;
}
$out = "/tmp/file.tar";
$sourcedir = "/data/folder";
$subfolder = "folder2";
$p = new PharData($out);
$filemap = buildFiles($sourcedir, $subfolder);
$iterator = new ArrayIterator($filemap);
$p->buildFromIterator($iterator);
$p->compress(\Phar::GZ);
unlink($out); // $out.gz has been created, remove the original .tar
这允许您从 /data/folder 中选择 /data/folder/folder2,即使 /data/folder 包含数百万个其他文件夹。然后它会创建一个 tar.gz,其中的内容都以文件夹名称作为前缀。
我正在从事的项目需要创建 .tar.gz 档案并将其提供给外部服务。此外部服务仅适用于 .tar.gz,因此另一种类型的存档是不可能的。我正在处理的代码将执行的服务器不允许访问系统调用。所以 system
、exec
、反引号等都不是什么好东西。这意味着我必须依靠纯 PHP 实现来创建 .tar.gz 文件。
经过一些研究,PharData
似乎有助于实现该结果。但是我遇到了困难,需要一些指导。
考虑以下文件夹布局:
parent folder
- child folder 1
- child folder 2
- file1
- file2
我正在使用下面的代码片段创建 .tar.gz 存档,它可以解决问题,但最终结果存在一个小问题,它不包含父文件夹,但包含其中的所有内容。
$pd = new PharData('archive.tar');
$dir = realpath("parent-folder");
$pd->buildFromDirectory($dir);
$pd->compress(Phar::GZ);
unset( $pd );
unlink('archive.tar');
创建存档时,它必须包含与上述完全相同的文件夹布局。使用上面提到的代码片段,存档包含除父文件夹之外的所有内容,这是外部服务的交易破坏者:
- child folder 1
- child folder 2
- file1
- file2
buildFromDirectory
的描述确实提到了以下内容,因此它不包含存档中的父文件夹是可以理解的:
Construct a tar/zip archive from the files within a directory.
我也尝试过使用 buildFromIterator
但最终结果也是一样的,即父文件夹不包含在存档中。我能够使用 addFile
获得所需的结果,但这 非常慢 。
经过更多研究,我发现了以下库:https://github.com/alchemy-fr/Zippy。但这需要服务器上不可用的 composer
支持。如果有人可以指导我实现最终结果,我将不胜感激。我也愿意使用其他一些方法或库,只要它是纯 PHP 实现并且不需要任何外部依赖项。不确定它是否有帮助,但是执行代码的服务器有 PHP 5.6
使用 "parent-folder" 的父级作为 Phar::buildFromDirectory()
的基础,并使用其第二个参数将结果限制为 "parent-folder",例如:
$parent = dirname("parent-folder");
$pd->buildFromDirectory($parent, '#^'.preg_quote("$parent/parent-folder/", "#").'#');
$pd->compress(Phar::GZ);
我最终不得不这样做,因为这个问题是 google 上的第一个结果,这里是解决这个问题的最佳方法,不使用正则表达式(如果你想从包含许多其他目录的目录中提取一个目录)。
function buildFiles($folder, $dir, $retarr = []) {
$i = new DirectoryIterator("$folder/$dir");
foreach ($i as $d) {
if ($d->isDot()) {
continue;
}
if ($d->isDir()) {
$newdir = "$dir/" . basename($d->getPathname());
$retarr = buildFiles($folder, $newdir, $retarr);
} else {
$dest = "$dir/" . $d->getFilename();
$retarr[$dest] = $d->getPathname();
}
}
return $retarr;
}
$out = "/tmp/file.tar";
$sourcedir = "/data/folder";
$subfolder = "folder2";
$p = new PharData($out);
$filemap = buildFiles($sourcedir, $subfolder);
$iterator = new ArrayIterator($filemap);
$p->buildFromIterator($iterator);
$p->compress(\Phar::GZ);
unlink($out); // $out.gz has been created, remove the original .tar
这允许您从 /data/folder 中选择 /data/folder/folder2,即使 /data/folder 包含数百万个其他文件夹。然后它会创建一个 tar.gz,其中的内容都以文件夹名称作为前缀。