복붙노트

[재귀 적으로] PHP에서 디렉토리를 압축하는 방법?

PHP

[재귀 적으로] 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')을 보내야합니까?

해결법

  1. ==============================

    1.다음은 파일이나 디렉토리를 재귀 적으로 압축 할 수있는 간단한 함수이며,로드 할 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');
    
  2. ==============================

    2.ZipArchive의 확장으로 구현 된 또 다른 재귀 적 디렉토리 트리 보관. 보너스로, 단일 명령문 트리 압축 도우미 기능이 포함되어 있습니다. 선택적 localname은 다른 ZipArchive 함수와 마찬가지로 지원됩니다. 추가 할 오류 처리 코드 ...

    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);
    
  3. ==============================

    3.세 번째 인수를 취하기 위해 Alix Axel의 대답을 편집했습니다.이 세 번째 인수를 true로 설정하면 모든 파일이 zip 폴더에 직접 저장되는 것이 아니라 기본 디렉토리 아래에 추가됩니다.

    세 번째 인수를 취하기 위해 Alix Axel의 대답을 편집했습니다.이 세 번째 인수를 true로 설정하면 모든 파일이 zip 폴더에 직접 저장되는 것이 아니라 기본 디렉토리 아래에 추가됩니다.

    zip 파일이 있으면 파일도 삭제됩니다.

    예:

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

    세 번째 인수 진정한 zip 구조 :

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

    세 번째 인수 인 false 또는 missing zip structure :

    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)
                {
                    $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();
    }
    
  4. ==============================

    4.사용법 : thisfile.php? dir =. / path / to / folder (압축을 푼 후에도 다운로드가 시작됩니다 :)

    사용법 : thisfile.php? dir =. / path / to / folder (압축을 푼 후에도 다운로드가 시작됩니다 :)

    <?php
    $exclude_some_files=
    array(
            'mainfolder/folder1/filename.php',
            'mainfolder/folder5/otherfile.php'
    );
    
    //***************built from https://gist.github.com/ninadsp/6098467 ******
    class ModifiedFlxZipArchive extends ZipArchive {
        public function addDirDoo($location, $name , $prohib_filenames=false) {
            if (!file_exists($location)) {  die("maybe file/folder path incorrect");}
    
            $this->addEmptyDir($name);
            $name .= '/';
            $location.= '/';
            $dir = opendir ($location);   // Read all Files in Dir
    
            while ($file = readdir($dir)){
                if ($file == '.' || $file == '..') continue;
                if (!in_array($name.$file,$prohib_filenames)){
                    if (filetype( $location . $file) == 'dir'){
                        $this->addDirDoo($location . $file, $name . $file,$prohib_filenames );
                    }
                    else {
                        $this->addFile($location . $file, $name . $file);
                    }
                }
            }
        }
    
        public function downld($zip_name){
            ob_get_clean();
            header("Pragma: public");   header("Expires: 0");   header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
            header("Cache-Control: private", false);    header("Content-Type: application/zip");
            header("Content-Disposition: attachment; filename=" . basename($zip_name) . ";" );
            header("Content-Transfer-Encoding: binary");
            header("Content-Length: " . filesize($zip_name));
            readfile($zip_name);
        }
    }
    
    //set memory limits
    set_time_limit(3000);
    ini_set('max_execution_time', 3000);
    ini_set('memory_limit','100M');
    $new_zip_filename='down_zip_file_'.rand(1,1000000).'.zip';  
    // Download action
    if (isset($_GET['dir']))    {
        $za = new ModifiedFlxZipArchive;
        //create an archive
        if  ($za->open($new_zip_filename, ZipArchive::CREATE)) {
            $za->addDirDoo($_GET['dir'], basename($_GET['dir']), $exclude_some_files); $za->close();
        }else {die('cantttt');}
    
    if (isset($_GET['dir']))    {
        $za = new ModifiedFlxZipArchive;
        //create an archive
        if  ($za->open($new_zip_filename, ZipArchive::CREATE)) {
            $za->addDirDoo($_GET['dir'], basename($_GET['dir']), $exclude_some_files); $za->close();
        }else {die('cantttt');}
    
        //download archive
        //on the same execution,this made problems in some hostings, so better redirect
        //$za -> downld($new_zip_filename);
        header("location:?fildown=".$new_zip_filename); exit;
    }   
    if (isset($_GET['fildown'])){
        $za = new ModifiedFlxZipArchive;
        $za -> downld($_GET['fildown']);
    }
    ?>
    
  5. ==============================

    5.이 링크를 사용해보십시오. <- MORE SOURCE CODE DEERE

    이 링크를 사용해보십시오. <- MORE SOURCE CODE DEERE

    /** Include the Pear Library for Zip */
    include ('Archive/Zip.php');
    
    /** Create a Zipping Object...
    * Name of zip file to be created..
    * You can specify the path too */
    $obj = new Archive_Zip('test.zip');
    /**
    * create a file array of Files to be Added in Zip
    */
    $files = array('black.gif',
    'blue.gif',
    );
    
    /**
    * creating zip file..if success do something else do something...
    * if Error in file creation ..it is either due to permission problem (Solution: give 777 to that folder)
    * Or Corruption of File Problem..
    */
    
    if ($obj->create($files)) {
    // echo 'Created successfully!';
    } else {
    //echo 'Error in file creation';
    }
    
    ?>; // We'll be outputting a ZIP
    header('Content-type: application/zip');
    
    // It will be called test.zip
    header('Content-Disposition: attachment; filename="test.zip"');
    
    //read a file and send
    readfile('test.zip');
    ?>;
    
  6. ==============================

    6.여기에 내 코드는 폴더와 하위 폴더 및 해당 파일을 압축하여 zip 형식으로 다운로드 할 수있게합니다.

    여기에 내 코드는 폴더와 하위 폴더 및 해당 파일을 압축하여 zip 형식으로 다운로드 할 수있게합니다.

    function zip()
     {
    $source='path/folder'// Path To the folder;
    $destination='path/folder/abc.zip'// Path to the file and file name ; 
    $include_dir = false;
    $archive = 'abc.zip'// File Name ;
    
    if (!extension_loaded('zip') || !file_exists($source)) {
        return false;
    }
    
    if (file_exists($destination)) {
        unlink ($destination);
    }
    
    $zip = new ZipArchive;
    
    if (!$zip->open($archive, 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)
            {
                $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));
    }
    $zip->close();
    
    header('Content-Type: application/zip');
    header('Content-disposition: attachment; filename='.$archive);
    header('Content-Length: '.filesize($archive));
    readfile($archive);
    unlink($archive);
    }
    

    코드 관련 문제가 있으면 알려주십시오.

  7. ==============================

    7.Mac OSX에서이 Zip 기능을 실행해야했습니다.

    Mac OSX에서이 Zip 기능을 실행해야했습니다.

    그래서 나는 항상 성가신 .z_Store를 압축 할 것입니다.

    additionalIgnore 파일을 추가하여 https://stackoverflow.com/users/2019515/user2019515를 수정했습니다.

    function zipIt($source, $destination, $include_dir = false, $additionalIgnoreFiles = array())
    {
        // Ignore "." and ".." folders by default
        $defaultIgnoreFiles = array('.', '..');
    
        // include more files to ignore
        $ignoreFiles = array_merge($defaultIgnoreFiles, $additionalIgnoreFiles);
    
        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);
    
                // purposely ignore files that are irrelevant
                if( in_array(substr($file, strrpos($file, '/')+1), $ignoreFiles) )
                    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에서 .DS_Store를 무시하면 실행합니다.

    압축 ( '/ 경로 / 그래서 / 폴더', '/ 경로 / to / compressed.zip', falceae, 배열 ( '. Ten_store'));

  8. ==============================

    8.훌륭한 솔루션이지만 내 Windows 용으로 수정해야합니다. 수정 코드 아래

    훌륭한 솔루션이지만 내 Windows 용으로 수정해야합니다. 수정 코드 아래

    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();
    }
    
  9. ==============================

    9.이 코드는 Windows와 Linux 모두에서 작동합니다.

    이 코드는 Windows와 Linux 모두에서 작동합니다.

    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();
    }
    
  10. ==============================

    10.Alix의 내 버전 기반은 Windows에서 작동하고 잘만하면 * nix에서도 작동합니다.

    Alix의 내 버전 기반은 Windows에서 작동하고 잘만하면 * nix에서도 작동합니다.

    function addFolderToZip($source, $destination, $flags = ZIPARCHIVE::OVERWRITE)
    {
        $source = realpath($source);
        $destination = realpath($destination);
    
        if (!file_exists($source)) {
            die("file does not exist: " . $source);
        }
    
        $zip = new ZipArchive();
        if (!$zip->open($destination, $flags )) {
            die("Cannot open zip archive: " . $destination);
        }
    
        $files = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
    
        $sourceWithSeparator = $source . DIRECTORY_SEPARATOR;
        foreach ($files as $file)
        {
            // Ignore "." and ".." folders
            if(in_array(substr($file,strrpos($file, DIRECTORY_SEPARATOR)+1),array('.', '..')))
                continue;
    
            if (is_dir($file) === true)
            {
                $zip->addEmptyDir(
                    str_replace($sourceWithSeparator, '', $file . DIRECTORY_SEPARATOR));
            }
            else if (is_file($file) === true)
            {
                $zip->addFile($file, str_replace($sourceWithSeparator, '', $file));
            }
        }
    
        return $zip->close();
    }
    
  11. ==============================

    11.다음은 읽기 쉽고 재귀 적으로 사용하기 쉬운 함수입니다.

    다음은 읽기 쉽고 재귀 적으로 사용하기 쉬운 함수입니다.

    function zip_r($from, $zip, $base=false) {
        if (!file_exists($from) OR !extension_loaded('zip')) {return false;}
        if (!$base) {$base = $from;}
        $base = trim($base, '/');
        $zip->addEmptyDir($base);
        $dir = opendir($from);
        while (false !== ($file = readdir($dir))) {
            if ($file == '.' OR $file == '..') {continue;}
    
            if (is_dir($from . '/' . $file)) {
                zip_r($from . '/' . $file, $zip, $base . '/' . $file);
            } else {
                $zip->addFile($from . '/' . $file, $base . '/' . $file);
            }
        }
        return $zip;
    }
    $from = "/path/to/folder";
    $base = "basezipfolder";
    $zip = new ZipArchive();
    $zip->open('zipfile.zip', ZIPARCHIVE::CREATE);
    $zip = zip_r($from, $zip, $base);
    $zip->close();
    
  12. from https://stackoverflow.com/questions/1334613/how-to-recursively-zip-a-directory-in-php by cc-by-sa and MIT license