如何[递归]在PHP中压缩目录?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何[递归]在PHP中压缩目录?相关的知识,希望对你有一定的参考价值。

目录是这样的:

home/
    file1.html
    file2.html
Another_Dir/
    file8.html
    Sub_Dir/
        file19.html

我使用phpMyAdmin http://trac.seagullproject.org/browser/branches/0.6-bugfix/lib/other/Zip.php中使用的相同PHP Zip类。我不确定如何压缩目录而不仅仅是文件。这是我到目前为止所拥有的:

$aFiles = $this->da->getDirTree($target);
/* $aFiles is something like, path => filetime
Array
(
    [home] => 
    [home/file1.html] => 1251280379
    [home/file2.html] => 1251280377
    etc...
)

*/
$zip = & new Zip();
foreach( $aFiles as $fileLocation => $time ){
    $file = $target . "/" . $fileLocation;
    if ( is_file($file) ){
        $buffer = file_get_contents($file);
        $zip->addFile($buffer, $fileLocation);
    }
}
THEN_SOME_PHP_CLASS::toDownloadData($zip); // this bit works ok

但是当我尝试解压缩相应的下载zip文件时,我得到“不允许操作”

这个错误只发生在我尝试解压缩我的mac时,当我通过命令行解压缩文件解压缩时。我是否需要在下载时发送特定的内容类型,目前为'application / zip'

答案

这是一个简单的函数,可以递归地压缩任何文件或目录,只需要加载zip扩展。

function Zip($source, $destination)
{
    if (!extension_loaded('zip') || !file_exists($source)) {
        return false;
    }

    $zip = new ZipArchive();
    if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
        return false;
    }

    $source = str_replace('\', '/', realpath($source));

    if (is_dir($source) === true)
    {
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);

        foreach ($files as $file)
        {
            $file = str_replace('\', '/', $file);

            // Ignore "." and ".." folders
            if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) )
                continue;

            $file = realpath($file);

            if (is_dir($file) === true)
            {
                $zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
            }
            else if (is_file($file) === true)
            {
                $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
            }
        }
    }
    else if (is_file($source) === true)
    {
        $zip->addFromString(basename($source), file_get_contents($source));
    }

    return $zip->close();
}

像这样称呼它:

Zip('/folder/to/compress/', './compressed.zip');
另一答案

这是我在Alix上的版本,适用于Windows,希望也适用于* nix:

function Zip($source, $destination){

if (!extension_loaded('zip') || !file_exists($source)) {
    return false;
}

$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
    return false;
}

$source = str_replace('\', '/', realpath($source));

if (is_dir($source) === true)
{
    $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);

    foreach ($files as $file)
    {
        $file = str_replace('\', '/', $file);

        // Ignore "." and ".." folders
        if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) )
            continue;

        if (is_dir($file) === true)
        {
            $zip->addEmptyDir(str_replace($source . '/', '', $file));
        }
        else if (is_file($file) === true)
        {

            $str1 = str_replace($source . '/', '', '/'.$file);
            $zip->addFromString($str1, file_get_contents($file));

        }
    }
}
else if (is_file($source) === true)
{
    $zip->addFromString(basename($source), file_get_contents($source));
}

return $zip->close();
}
另一答案

这是一个简单易读的递归函数,效果很好:

function Zip($source, $destination)
{
if (!extension_loaded('zip') || !file_exists($source)) {
    return false;
}

$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
    return false;
}

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    DEFINE('DS', DIRECTORY_SEPARATOR); //for windows
} else {
    DEFINE('DS', '/'); //for linux
}


$source = str_replace('\', DS, realpath($source));

if (is_dir($source) === true)
{
    $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
    echo $source;
    foreach ($files as $file)
    {
        $file = str_replace('\',DS, $file);
        // Ignore "." and ".." folders
        if( in_array(substr($file, strrpos($file, DS)+1), array('.', '..')) )
            continue;

        $file = realpath($file);

        if (is_dir($file) === true)
        {
            $zip->addEmptyDir(str_replace($source . DS, '', $file . DS));
        }
        else if (is_file($file) === true)
        {
            $zip->addFromString(str_replace($source . DS, '', $file), file_get_contents($file));
        }
        echo $source;
    }
}
else if (is_file($source) === true)
{
    $zip->addFromString(basename($source), file_get_contents($source));
}

return $zip->close();
}
另一答案

另一个递归目录树归档,作为ZipArchive的扩展实现。作为奖励,包括单语句树压缩助手功能。支持可选的localname,与其他ZipArchive函数一样。处理要添加的代码时出错...

class ExtendedZip extends ZipArchive {

    // Member function to add a whole file system subtree to the archive
    public function addTree($dirname, $localname = '') {
        if ($localname)
            $this->addEmptyDir($localname);
        $this->_addTree($dirname, $localname);
    }

    // Internal function, to recurse
    protected function _addTree($dirname, $localname) {
        $dir = opendir($dirname);
        while ($filename = readdir($dir)) {
            // Discard . and ..
            if ($filename == '.' || $filename == '..')
                continue;

            // Proceed according to type
            $path = $dirname . '/' . $filename;
            $localpath = $localname ? ($localname . '/' . $filename) : $filename;
            if (is_dir($path)) {
                // Directory: add & recurse
                $this->addEmptyDir($localpath);
                $this->_addTree($path, $localpath);
            }
            else if (is_file($path)) {
                // File: just add
                $this->addFile($path, $localpath);
            }
        }
        closedir($dir);
    }

    // Helper function
    public static function zipTree($dirname, $zipFilename, $flags = 0, $localname = '') {
        $zip = new self();
        $zip->open($zipFilename, $flags);
        $zip->addTree($dirname, $localname);
        $zip->close();
    }
}

// Example
ExtendedZip::zipTree('/foo/bar', '/tmp/archive.zip', ZipArchive::CREATE);
另一答案

我已经编辑了Alix Axel的答案,采取了第三个方面,当将第三个设置设置为true时,所有文件都将添加到主目录下,而不是直接添加到zip文件夹中。

如果zip文件存在,则文件也将被删除。

例:

Zip('/path/to/maindirectory','/path/to/compressed.zip',true);

第三个论点qazxsw poi zip结构:

true

第三个论点qazxsw poi或缺少zip结构:

maindirectory
--- file 1
--- file 2
--- subdirectory 1
------ file 3
------ file 4
--- subdirectory 2
------ file 5
------ file 6

编辑代码:

false
另一答案

用法:thisfile.php?dir =。/ path / to / folder(压缩后,它也开始下载:)

file 1
file 2
subdirectory 1
--- file 3
--- file 4
subdirectory 2
--- file 5
--- file 6
另一答案

试试function Zip($source, $destination, $include_dir = false) { if (!extension_loaded('zip') || !file_exists($source)) { return false; } if (file_exists($destination)) { unlink ($destination); } $zip = new ZipArchive(); if (!$zip->open($destination, ZIPARCHIVE::CREATE)) { return false; } $source = str_replace('\', '/', realpath($source)); if (is_dir($source) === true) { $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST); if ($include_dir) { $arr = explode("/",$source); $maindir = $arr[count($arr)- 1]; $source = ""; for ($i=0; $i < count($arr) - 1; $i++) { $source .= '/' . $arr[$i]; } $source = substr($source, 1); $zip->addEmptyDir($maindir); } foreach ($files as $file) { $file = str_replace('\', '/', $file); // Ignore "." and ".." folders if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) ) continue; $file = realpath($file); if (is_dir($file) === true) {

以上是关于如何[递归]在PHP中压缩目录?的主要内容,如果未能解决你的问题,请参考以下文章

在 python 中压缩文件时如何保留目录?

如何在PHP中压缩整个文件夹,甚至是空文件夹?

如何在拉取请求中压缩提交

如何在 laravel 5 中压缩 HTML

如何在 django python 中压缩上传的图像

如何在android中压缩和解压缩png图像