open - ¿Cómo[recursivamente] Zip un directorio en PHP?
un zip php (11)
Aquí está la función recursiva simple, fácil de leer que funciona muy bien:
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();
El directorio es algo así como:
home/
file1.html
file2.html
Another_Dir/
file8.html
Sub_Dir/
file19.html
Estoy usando la misma clase de PHP Zip utilizada en PHPMyAdmin http://trac.seagullproject.org/browser/branches/0.6-bugfix/lib/other/Zip.php . No estoy seguro de cómo comprimir un directorio en lugar de solo un archivo. Esto es lo que tengo hasta ahora:
$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
pero cuando intento descomprimir el archivo zip descargado correspondiente obtengo "operación no permitida"
Este error solo ocurre cuando intento descomprimir en mi mac, cuando descomprimo a través de la línea de comando el archivo se descomprime bien. ¿Debo enviar un tipo de contenido específico en la descarga, actualmente ''aplicación / zip''?
Aquí está mi código para comprimir las carpetas y sus subcarpetas y sus archivos y hacer que se pueda descargar en formato 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);
}
Si surge un problema con el código, hágamelo saber.
Aquí está mi versión base en Alix, funciona en Windows y con suerte en * nix también:
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();
}
Aquí hay una función simple que puede comprimir cualquier archivo o directorio recursivamente, solo necesita la extensión zip para ser cargada.
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();
}
Llámalo así:
Zip(''/folder/to/compress/'', ''./compressed.zip'');
Este código funciona tanto para Windows como para 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();
}
Gran solución, pero para mi Windows necesito hacer modificaciones. Debajo del código de modificación
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();
}
He editado la respuesta de para tomar un tercer texto, cuando establezco este tercer argumento como true
todos los archivos se agregarán en el directorio principal en lugar de directamente en la carpeta zip.
Si el archivo zip existe, el archivo también se eliminará.
Ejemplo:
Zip(''/path/to/maindirectory'',''/path/to/compressed.zip'',true);
Tercer argrumento con true
estructura zip:
maindirectory
--- file 1
--- file 2
--- subdirectory 1
------ file 3
------ file 4
--- subdirectory 2
------ file 5
------ file 6
Tercer argrumento estructura postal false
o faltante:
file 1
file 2
subdirectory 1
--- file 3
--- file 4
subdirectory 2
--- file 5
--- file 6
Código editado:
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();
}
Necesitaba ejecutar esta función Zip en Mac OSX
así que siempre comprimiría esa molesta .DS_Store.
He adaptado incluyendo archivos adicionales de Ignore.
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 para ignorar .DS_Store de zip, ejecutas
zipIt (''/ path / to / folder'', ''/path/to/compressed.zip'', false, array (''. DS_Store''));
Otro archivo de árbol de directorios recursivo más, implementado como una extensión de ZipArchive. Como beneficio adicional, se incluye una función auxiliar de compresión de árbol de declaración única. El nombre local opcional es compatible, como en otras funciones de ZipArchive. Error al manejar el código que se agregará ...
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);
Pruebe este enlace <- MÁS CÓDIGO FUENTE AQUÍ
/** 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'');
?>;
USO: thisfile.php? Dir =. / Ruta / a / carpeta (Después de comprimir, comienza la descarga también :)
<?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'']);
}
?>