Come comprimere un'intera cartella usando PHP


132

Ho trovato qui su Stackoveflow alcuni codici su come ZIP un file specifico, ma che ne dici di una cartella specifica?

Folder/
  index.html
  picture.jpg
  important.txt

dentro dentro My Folder, ci sono file. dopo aver zippato il My Folder, voglio anche eliminare l'intero contenuto della cartella tranne important.txt.

Ho trovato questo qui in pila

Ho bisogno del tuo aiuto. Grazie.


Per quanto posso vedere, il link stackoverflow che hai fornito in realtà comprime più file. Con quale parte hai problemi?
Lasse Espeholt,

@lasseespeholt Il link che ti ho dato zip solo un file specifico, non la cartella e il contenuto della cartella ..
woninana,

Prende una matrice di file (essenzialmente una cartella) e aggiunge tutti i file al file zip (il ciclo). Vedo che una bella risposta è stata pubblicata ora +1 :) che è lo stesso codice, l'array è solo un elenco di file da una directory ora.
Lasse Espeholt,


Risposte:


321

Codice aggiornato il 2015/04/22.

Comprimi un'intera cartella:

// Get real path for our folder
$rootPath = realpath('folder-to-zip');

// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);

// Create recursive directory iterator
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($rootPath),
    RecursiveIteratorIterator::LEAVES_ONLY
);

foreach ($files as $name => $file)
{
    // Skip directories (they would be added automatically)
    if (!$file->isDir())
    {
        // Get real and relative path for current file
        $filePath = $file->getRealPath();
        $relativePath = substr($filePath, strlen($rootPath) + 1);

        // Add current file to archive
        $zip->addFile($filePath, $relativePath);
    }
}

// Zip archive will be created only after closing object
$zip->close();

Comprimi un'intera cartella + elimina tutti i file tranne "important.txt":

// Get real path for our folder
$rootPath = realpath('folder-to-zip');

// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);

// Initialize empty "delete list"
$filesToDelete = array();

// Create recursive directory iterator
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($rootPath),
    RecursiveIteratorIterator::LEAVES_ONLY
);

foreach ($files as $name => $file)
{
    // Skip directories (they would be added automatically)
    if (!$file->isDir())
    {
        // Get real and relative path for current file
        $filePath = $file->getRealPath();
        $relativePath = substr($filePath, strlen($rootPath) + 1);

        // Add current file to archive
        $zip->addFile($filePath, $relativePath);

        // Add current file to "delete list"
        // delete it later cause ZipArchive create archive only after calling close function and ZipArchive lock files until archive created)
        if ($file->getFilename() != 'important.txt')
        {
            $filesToDelete[] = $filePath;
        }
    }
}

// Zip archive will be created only after closing object
$zip->close();

// Delete all files from "delete list"
foreach ($filesToDelete as $file)
{
    unlink($file);
}

2
Devi impostare chmod (scrivibile) su dir (dove si trova questo script) su 777. Ad esempio: se lo script si trova in /var/www/localhost/script.php, allora devi impostare chmod 0777 su dir / var / www / localhost /.
Dador,

3
L'eliminazione dei file prima della chiamata $zip->close()non funzionerà. Controlla la mia risposta qui
hek2mgl

10
@alnassre è un requisito della domanda: "Voglio anche cancellare l'intero contenuto della cartella tranne important.txt". Inoltre ti consiglio di leggere sempre il codice prima di eseguirlo.
Dador,

1
@alnassre hahahaha ... scusa :) ... hahaha
Ondrej Rafaj,

1
@ nick-newman, sì, per calcolare la percentuale puoi usare php.net/manual/ru/function.iterator-count.php + counter all'interno del loop. Per quanto riguarda il livello di compressione - non è possibile con ZipArchive in questo momento: stackoverflow.com/questions/1833168/...
dador

54

Esiste un utile metodo non documentato nella classe ZipArchive: addGlob ();

$zipFile = "./testZip.zip";
$zipArchive = new ZipArchive();

if ($zipArchive->open($zipFile, (ZipArchive::CREATE | ZipArchive::OVERWRITE)) !== true)
    die("Failed to create archive\n");

$zipArchive->addGlob("./*.txt");
if ($zipArchive->status != ZIPARCHIVE::ER_OK)
    echo "Failed to write files to zip\n";

$zipArchive->close();

Ora documentato su: www.php.net/manual/en/ziparchive.addglob.php


2
@netcoder - i vantaggi di aver scritto il phpt per testarlo ... fondamentalmente, leggere il sorgente per la classe ZipArchive e trovarlo lì .... c'è anche un metodo addPattern () non documentato che prende un modello di stile regexp, ma non sono mai riuscito a farlo funzionare (potrebbe essere un bug in classe)
Mark Baker

1
@kread - puoi usarlo con qualsiasi elenco di file che può essere estratto usando glob (), quindi l'ho trovato estremamente utile da quando l'ho scoperto.
Mark Baker,

@MarkBaker So che questo commento arriva anni dopo che hai pubblicato, sto solo tentando la fortuna qui. Ho pubblicato anche qui una domanda su zippare. Sto per provare il metodo glob che hai pubblicato qui, ma il mio problema principale è che non riesco ad usare addFromString e ho usato addFile, che non funziona in modo silenzioso. Hai forse idea di cosa potrebbe andare storto o cosa potrei fare di sbagliato?
Skytiger

@ user1032531 - l'ultima riga del mio post (modificata il 13 dicembre 2013) indica proprio questo, con un link alla pagina dei documenti
Mark Baker

6
È addGlobricorsivo?
Vincent Poirier,

20

Prova questo:

$zip = new ZipArchive;
$zip->open('myzip.zip', ZipArchive::CREATE);
foreach (glob("target_folder/*") as $file) {
    $zip->addFile($file);
    if ($file != 'target_folder/important.txt') unlink($file);
}
$zip->close();

Questo non comprimerà in modo ricorsivo però.


Certamente cancella alcuni file My folder, ma ho anche una cartella all'interno di una cartella My folderche mi dà un errore di: Autorizzazione negata scollegando la cartella con inMy folder
woninana

@Stupefy: prova if (!is_dir($file) && $file != 'target_folder...')invece. O controlla la risposta di @kread se vuoi comprimere ricorsivamente, è il modo più efficiente.
netcoder,

La cartella all'interno di My foldernon viene ancora eliminata, ma non ci sono più errori comunque.
woninana,

Ho anche dimenticato di dire che non ci sono file .zip creati.
woninana,

1
L'eliminazione dei file prima della chiamata $zip->close()non funzionerà. Controlla la mia risposta qui
hek2mgl

19

Presumo che questo sia in esecuzione su un server in cui l'applicazione zip si trova nel percorso di ricerca. Dovrebbe essere vero per tutti i sistemi basati su Unix e credo che la maggior parte dei server basati su Windows.

exec('zip -r archive.zip "My folder"');
unlink('My\ folder/index.html');
unlink('My\ folder/picture.jpg');

L'archivio risiederà successivamente in archive.zip. Tieni presente che gli spazi vuoti nei nomi di file o cartelle sono una causa comune di errori e dovrebbero essere evitati ove possibile.


15

Ho provato con il codice qui sotto e funziona. Il codice è autoesplicativo, per favore fatemi sapere se avete domande.

<?php
class FlxZipArchive extends ZipArchive 
{
 public function addDir($location, $name) 
 {
       $this->addEmptyDir($name);
       $this->addDirDo($location, $name);
 } 
 private function addDirDo($location, $name) 
 {
    $name .= '/';
    $location .= '/';
    $dir = opendir ($location);
    while ($file = readdir($dir))
    {
        if ($file == '.' || $file == '..') continue;
        $do = (filetype( $location . $file) == 'dir') ? 'addDir' : 'addFile';
        $this->$do($location . $file, $name . $file);
    }
 } 
}
?>

<?php
$the_folder = '/path/to/folder/to/be/zipped';
$zip_file_name = '/path/to/zip/archive.zip';
$za = new FlxZipArchive;
$res = $za->open($zip_file_name, ZipArchive::CREATE);
if($res === TRUE) 
{
    $za->addDir($the_folder, basename($the_folder));
    $za->close();
}
else{
echo 'Could not create a zip archive';
}
?>

Soluzione eccellente Funziona anche in laravel 5.5. mi è davvero piaciuto. (y)
Web Artisan

1
Ottimo codice! Pulito, semplice e perfettamente funzionante! ;) Mi sembra la risposta migliore. Se può aiutare qualcuno: l'ho appena aggiunto ini_set('memory_limit', '512M');prima dell'esecuzione dello script e ini_restore('memory_limit');alla fine. Era necessario evitare la mancanza di memoria in caso di cartelle pesanti (era una cartella più grande di 500 MB).
Jacopo Pace,

1
Nel mio ambiente (PHP 7.3, Debian) è stato creato un archivio ZIP senza un elenco di directory (file grande, vuoto). Ho dovuto cambiare la seguente riga: $ name. = '/'; in $ name = ($ name == '.'? '': $ name. '/');
Gerfried

Questo funziona per me. Grazie per la condivisione. Saluti!
Sathiska,

8

Questa è una funzione che comprime un'intera cartella e il suo contenuto in un file zip e puoi usarlo in questo modo:

addzip ("path/folder/" , "/path2/folder.zip" );

funzione :

// compress all files in the source directory to destination directory 
    function create_zip($files = array(), $dest = '', $overwrite = false) {
    if (file_exists($dest) && !$overwrite) {
        return false;
    }
    if (($files)) {
        $zip = new ZipArchive();
        if ($zip->open($dest, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
            return false;
        }
        foreach ($files as $file) {
            $zip->addFile($file, $file);
        }
        $zip->close();
        return file_exists($dest);
    } else {
        return false;
    }
}

function addzip($source, $destination) {
    $files_to_zip = glob($source . '/*');
    create_zip($files_to_zip, $destination);
    echo "done";
}

Come includere automaticamente anche sottocartelle nel backup con questo script? @Alireza
floCoder

2

Perché non provare EFS PhP-ZiP MultiVolume Script ... Ho zippato e trasferito centinaia di concerti e milioni di file ... ssh è necessario per creare in modo efficace archivi.

Ma credo che i file risultanti possano essere usati con exec direttamente da php:

exec('zip -r backup-2013-03-30_0 . -i@backup-2013-03-30_0.txt');

Non so se funziona. Non ho provato ...

"il segreto" è che il tempo di esecuzione per l'archiviazione non deve superare il tempo consentito per l'esecuzione del codice PHP.


1

Questo è un esempio funzionante di creazione di ZIP in PHP:

$zip = new ZipArchive();
$zip_name = time().".zip"; // Zip name
$zip->open($zip_name,  ZipArchive::CREATE);
foreach ($files as $file) {
  echo $path = "uploadpdf/".$file;
  if(file_exists($path)){
  $zip->addFromString(basename($path),  file_get_contents($path));---This is main function  
  }
  else{
   echo"file does not exist";
  }
}
$zip->close();

1

Ho trovato questo post su Google come secondo miglior risultato, in primo luogo ho usato exec :(

Comunque, sebbene ciò non soddisfacesse esattamente le mie esigenze .. Ho deciso di pubblicare una risposta per gli altri con la mia versione rapida ma estesa di questo.

CARATTERISTICHE SCRIPT

  • Denominazione dei file di backup giorno per giorno, PREFIX-YYYY-MM-DD-POSTFIX.EXTENSION
  • Segnalazione file / mancante
  • Elenco dei backup precedenti
  • Non comprime / include i backup precedenti;)
  • Funziona su Windows / Linux

Ad ogni modo, sullo script .. Anche se può sembrare molto .. Ricorda che c'è un eccesso qui .. Quindi sentiti libero di eliminare le sezioni di segnalazione secondo necessità ...

Inoltre può sembrare disordinato e alcune cose potrebbero essere ripulite facilmente ... Quindi non commentare, è solo uno script veloce con commenti di base inseriti .. NON PER USO LIVE .. Ma facile da pulire per uso live !

In questo esempio, viene eseguito da una directory che si trova all'interno della cartella principale www / public_html. Quindi, per arrivare alla radice deve solo spostarsi su una cartella.

<?php
    // DIRECTORY WE WANT TO BACKUP
    $pathBase = '../';  // Relate Path

    // ZIP FILE NAMING ... This currently is equal to = sitename_www_YYYY_MM_DD_backup.zip 
    $zipPREFIX = "sitename_www";
    $zipDATING = '_' . date('Y_m_d') . '_';
    $zipPOSTFIX = "backup";
    $zipEXTENSION = ".zip";

    // SHOW PHP ERRORS... REMOVE/CHANGE FOR LIVE USE
    ini_set('display_errors',1);
    ini_set('display_startup_errors',1);
    error_reporting(-1);




// ############################################################################################################################
//                                  NO CHANGES NEEDED FROM THIS POINT
// ############################################################################################################################

    // SOME BASE VARIABLES WE MIGHT NEED
    $iBaseLen = strlen($pathBase);
    $iPreLen = strlen($zipPREFIX);
    $iPostLen = strlen($zipPOSTFIX);
    $sFileZip = $pathBase . $zipPREFIX . $zipDATING . $zipPOSTFIX . $zipEXTENSION;
    $oFiles = array();
    $oFiles_Error = array();
    $oFiles_Previous = array();

    // SIMPLE HEADER ;)
    echo '<center><h2>PHP Example: ZipArchive - Mayhem</h2></center>';

    // CHECK IF BACKUP ALREADY DONE
    if (file_exists($sFileZip)) {
        // IF BACKUP EXISTS... SHOW MESSAGE AND THATS IT
        echo "<h3 style='margin-bottom:0px;'>Backup Already Exists</h3><div style='width:800px; border:1px solid #000;'>";
            echo '<b>File Name: </b>',$sFileZip,'<br />';
            echo '<b>File Size: </b>',$sFileZip,'<br />';
        echo "</div>";
        exit; // No point loading our function below ;)
    } else {

        // NO BACKUP FOR TODAY.. SO START IT AND SHOW SCRIPT SETTINGS
        echo "<h3 style='margin-bottom:0px;'>Script Settings</h3><div style='width:800px; border:1px solid #000;'>";
            echo '<b>Backup Directory: </b>',$pathBase,'<br /> ';
            echo '<b>Backup Save File: </b>',$sFileZip,'<br />';
        echo "</div>";

        // CREATE ZIPPER AND LOOP DIRECTORY FOR SUB STUFF
        $oZip = new ZipArchive;
        $oZip->open($sFileZip,  ZipArchive::CREATE | ZipArchive::OVERWRITE);
        $oFilesWrk = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathBase),RecursiveIteratorIterator::LEAVES_ONLY);
        foreach ($oFilesWrk as $oKey => $eFileWrk) {
            // VARIOUS NAMING FORMATS OF THE CURRENT FILE / DIRECTORY.. RELATE & ABSOLUTE
            $sFilePath = substr($eFileWrk->getPathname(),$iBaseLen, strlen($eFileWrk->getPathname())- $iBaseLen);
            $sFileReal = $eFileWrk->getRealPath();
            $sFile = $eFileWrk->getBasename();

            // WINDOWS CORRECT SLASHES
            $sMyFP = str_replace('\\', '/', $sFileReal);

            if (file_exists($sMyFP)) {  // CHECK IF THE FILE WE ARE LOOPING EXISTS
                if ($sFile!="."  && $sFile!="..") { // MAKE SURE NOT DIRECTORY / . || ..
                    // CHECK IF FILE HAS BACKUP NAME PREFIX/POSTFIX... If So, Dont Add It,, List It
                    if (substr($sFile,0, $iPreLen)!=$zipPREFIX && substr($sFile,-1, $iPostLen + 4)!= $zipPOSTFIX.$zipEXTENSION) {
                        $oFiles[] = $sMyFP;                     // LIST FILE AS DONE
                        $oZip->addFile($sMyFP, $sFilePath);     // APPEND TO THE ZIP FILE
                    } else {
                        $oFiles_Previous[] = $sMyFP;            // LIST PREVIOUS BACKUP
                    }
                }
            } else {
                $oFiles_Error[] = $sMyFP;                       // LIST FILE THAT DOES NOT EXIST
            }
        }
        $sZipStatus = $oZip->getStatusString();                 // GET ZIP STATUS
        $oZip->close(); // WARNING: Close Required to append files, dont delete any files before this.

        // SHOW BACKUP STATUS / FILE INFO
        echo "<h3 style='margin-bottom:0px;'>Backup Stats</h3><div style='width:800px; height:120px; border:1px solid #000;'>";
            echo "<b>Zipper Status: </b>" . $sZipStatus . "<br />";
            echo "<b>Finished Zip Script: </b>",$sFileZip,"<br />";
            echo "<b>Zip Size: </b>",human_filesize($sFileZip),"<br />";
        echo "</div>";


        // SHOW ANY PREVIOUS BACKUP FILES
        echo "<h3 style='margin-bottom:0px;'>Previous Backups Count(" . count($oFiles_Previous) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
        foreach ($oFiles_Previous as $eFile) {
            echo basename($eFile) . ", Size: " . human_filesize($eFile) . "<br />";
        }
        echo "</div>";

        // SHOW ANY FILES THAT DID NOT EXIST??
        if (count($oFiles_Error)>0) {
            echo "<h3 style='margin-bottom:0px;'>Error Files, Count(" . count($oFiles_Error) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
            foreach ($oFiles_Error as $eFile) {
                echo $eFile . "<br />";
            }
            echo "</div>";
        }

        // SHOW ANY FILES THAT HAVE BEEN ADDED TO THE ZIP
        echo "<h3 style='margin-bottom:0px;'>Added Files, Count(" . count($oFiles) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
        foreach ($oFiles as $eFile) {
            echo $eFile . "<br />";
        }
        echo "</div>";

    }


    // CONVERT FILENAME INTO A FILESIZE AS Bytes/Kilobytes/Megabytes,Giga,Tera,Peta
    function human_filesize($sFile, $decimals = 2) {
        $bytes = filesize($sFile);
        $sz = 'BKMGTP';
        $factor = floor((strlen($bytes) - 1) / 3);
        return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
    }
?>

CHE COSA FA??

Semplicemente comprimerà l'intero contenuto della variabile $ pathBase e memorizzerà lo zip nella stessa cartella. Fa un semplice rilevamento per i backup precedenti e li salta.

BACKUP CRON

Questo script che ho appena testato su Linux e ha funzionato bene da un cron job usando un url assoluto per pathBase.


Ho anche escluso lo script di eliminazione, puoi vedere la risposta accettata per questo
Angry 84

Devo amare quei voti negativi casuali senza un commento che spieghi il perché.
Arrabbiato, 84

1

Usa questa funzione:

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 . '/'));
            } elseif (is_file($file) === true) {
                $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
            }
        }
    } elseif (is_file($source) === true) {
        $zip->addFromString(basename($source), file_get_contents($source));
    }

    return $zip->close();
}

Esempio di utilizzo:

zip('/folder/to/compress/', './compressed.zip');

1

Utilizzare questo funziona bene.

$dir = '/Folder/';
$zip = new ZipArchive();
$res = $zip->open(trim($dir, "/") . '.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
if ($res === TRUE) {
    foreach (glob($dir . '*') as $file) {
        $zip->addFile($file, basename($file));
    }
    $zip->close();
} else {
    echo 'Failed to create to zip. Error: ' . $res;
}

1

Crea una cartella zip in PHP.

Metodo di creazione zip

   public function zip_creation($source, $destination){
    $dir = opendir($source);
    $result = ($dir === false ? false : true);

    if ($result !== false) {

        
        $rootPath = realpath($source);
         
        // Initialize archive object
        $zip = new ZipArchive();
        $zipfilename = $destination.".zip";
        $zip->open($zipfilename, ZipArchive::CREATE | ZipArchive::OVERWRITE );
         
        // Create recursive directory iterator
        /** @var SplFileInfo[] $files */
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY);
         
        foreach ($files as $name => $file)
        {
            // Skip directories (they would be added automatically)
            if (!$file->isDir())
            {
                // Get real and relative path for current file
                $filePath = $file->getRealPath();
                $relativePath = substr($filePath, strlen($rootPath) + 1);
         
                // Add current file to archive
                $zip->addFile($filePath, $relativePath);
            }
        }
         
        // Zip archive will be created only after closing object
        $zip->close();
        
        return TRUE;
    } else {
        return FALSE;
    }


}

Chiama il metodo zip

$source = $source_directory;
$destination = $destination_directory;
$zipcreation = $this->zip_creation($source, $destination);

0

Ho apportato alcuni piccoli miglioramenti alla sceneggiatura.

  <?php
    $directory = "./";
    //create zip object
    $zip = new ZipArchive();
    $zip_name = time().".zip";
    $zip->open($zip_name,  ZipArchive::CREATE);
    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($directory),
        RecursiveIteratorIterator::LEAVES_ONLY
    );
    foreach ($files as $file) {
        $path = $file->getRealPath();
        //check file permission
        if(fileperms($path)!="16895"){
            $zip->addFromString(basename($path),  file_get_contents($path)) ;
            echo "<span style='color:green;'>{$path} is added to zip file.<br /></span> " ;
        }
        else{
            echo"<span style='color:red;'>{$path} location could not be added to zip<br /></span>";
        }
    }
    $zip->close();
    ?>

In questo modo i file vengono compressi ma l'elenco delle directory è sparito, la dose non ha più directory
Sujay sreedhar,

0

Questo risolverà il tuo problema. Per favore, provalo

$zip = new ZipArchive;
$zip->open('testPDFZip.zip', ZipArchive::CREATE);
foreach (glob(APPLICATION_PATH."pages/recruitment/uploads/test_pdf_folder/*") as $file) {
    $new_filename = end(explode("/",$file));
    $zip->addFile($file,"emp/".$new_filename);
}           
$zip->close();

0

Per chiunque legga questo post e cerchi un perché comprimere i file usando addFile invece di addFromString, che non comprime i file con il loro percorso assoluto (basta comprimere i file e nient'altro), vedi la mia domanda e rispondi qui

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.