it-swarm.com.de

Wie [rekursiv] Zip ein Verzeichnis in PHP?

Verzeichnis ist so etwas wie:

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

Ich verwende die gleiche PHP Zip-Klasse, die in PHPMyAdmin verwendet wird http://trac.seagullproject.org/browser/branches/0.6-bugfix/lib/other/Zip.php . Ich bin mir nicht sicher, wie ich ein Verzeichnis komprimieren soll und nicht nur eine Datei.

$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

aber wenn ich versuche, die entsprechende heruntergeladene Zip-Datei zu entpacken, erhalte ich "Operation nicht erlaubt"

Dieser Fehler tritt nur auf, wenn ich versuche, auf meinem Mac zu dekomprimieren. Wenn ich über die Befehlszeile dekomprimiere, wird die Datei in Ordnung dekomprimiert. Muss ich beim Herunterladen einen bestimmten Inhaltstyp senden, aktuell "application/Zip"?

117
ed209

Hier ist eine einfache Funktion, die jede Datei oder jedes Verzeichnis rekursiv komprimieren kann. Es muss nur die Zip-Erweiterung geladen werden.

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

Nenne es so:

Zip('/folder/to/compress/', './compressed.Zip');
249
Alix Axel

Eine weitere rekursive Verzeichnisbaumarchivierung, die als Erweiterung von ZipArchive implementiert wurde. Als Bonus ist eine Hilfefunktion für die Komprimierung einzelner Anweisungen enthalten. Optionaler lokaler Name wird wie in anderen ZipArchive-Funktionen unterstützt. Fehlerbehandlung Code hinzugefügt werden ...

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);
15

Ich habe Alix Axel s Antwort bearbeitet, um ein drittes Argument zu verwenden, wenn dieses dritte Argument auf true gesetzt wird. Alle Dateien werden unter dem Hauptverzeichnis und nicht direkt in der Zip-Datei hinzugefügt Mappe.

Wenn die Zip-Datei existiert, wird die Datei ebenfalls gelöscht.

Beispiel:

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

Drittes Argument true Zip-Struktur:

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

Drittes Argument false oder fehlende Zip-Struktur:

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

Bearbeiteter Code:

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

VERWENDUNG: thisfile.php? Dir = ./path/to/folder (Nach dem Zippen startet es download also :)

<?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']);
}
?>
4
T.Todua

Versuchen Sie diesen Link <- MEHR QUELLENCODE HIER

/** 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');
?>;
2
Phill Pafford

Hier ist mein Code für Zip die Ordner und deren Unterordner und deren Dateien und machen es im Zip-Format herunterladbar

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);
}

Wenn Probleme mit dem Code auftreten, lassen Sie es mich wissen.

1
nitin

Dieser Code funktioniert sowohl für Windows als auch für 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();
}
0
Ammar Qala

Hier ist die einfache, leicht zu lesende, rekursive Funktion, die sehr gut funktioniert:

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();
0
Tarik

Hier ist meine Version, die auf Alix basiert, unter Windows und hoffentlich auch auf * nix funktioniert:

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();
}
0
Ohad Schneider

Tolle Lösung, aber für mein Windows muss ich noch Änderungen vornehmen. Unterhalb des Änderungscodes

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();
}
0
Juan

Ich musste diese Zip-Funktion unter Mac OS X ausführen

also ich würde immer diesen nervigen .DS_Store zip.

Ich habe https://stackoverflow.com/users/2019515/user2019515 angepasst, indem ich additionalIgnore-Dateien hinzugefügt habe.

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

SO, um den .DS_Store von Zip zu ignorieren, führen Sie aus

zipIt ('/ path/to/folder', '/path/to/compressed.Zip', false, array ('. DS_Store'));

0
Kim Stacks