Como crear un archivo Zip y forzar su descarga en PHP

Hola a todos:

Hoy vamos a ver cómo podemos generar una archivo zip, añadirle los archivos que queramos y forzar su descarga con php.

Desde la versión 5.2.0 de PHP está disponible la clase  ZipArchive.

Para ilustrar su funcionamiento como siempre lo mejor es crear un pequeño ejemplo.

Vamos a crear un pequeño script que genere un archivo zip con dos archivos de imagen png, aunque se puede hacer con cualquier tipo de archivo. Una imagen se creará en la raiz de la carpeta comprimida y la otra en un directorio que crearemos dentro de esta carpeta.

Vayamos por partes:

Primero creamos la carpeta donde alojaremos  este pequeño ejemplo, por ejemplo podemos llamar prueba_zip a la carpeta.

Para este ejemplo vamos a descargar de internet (o copiar desde cualquier sitio) dos archivos, por ejemplo dos imagenes.

Copiamos los dos archivos en la carpeta prueba_zip, imaginemos que se llaman imagen1.png e imagen2.png.

Ahora debemos crear un archivo php que va a contener el código de ejemplo para crear un archivo.zip.

Vamos a llamarle index.php.

Editamos el archivo que acabamos de crear y copiamos en el el siguiente código:

<?php
// Creamos un instancia de la clase ZipArchive
 $zip = new ZipArchive();
// Creamos y abrimos un archivo zip temporal
 $zip->open("miarchivo.zip",ZipArchive::CREATE);
 // Añadimos un directorio
 $dir = 'miDirectorio';
 $zip->addEmptyDir($dir);
 // Añadimos un archivo en la raid del zip.
 $zip->addFile("imagen1.jpg","mi_imagen1.jpg");
 //Añadimos un archivo dentro del directorio que hemos creado
 $zip->addFile("imagen2.jpg",$dir."/mi_imagen2.jpg");
 // Una vez añadido los archivos deseados cerramos el zip.
 $zip->close();
 // Creamos las cabezeras que forzaran la descarga del archivo como archivo zip.
 header("Content-type: application/octet-stream");
 header("Content-disposition: attachment; filename=miarchivo.zip");
 // leemos el archivo creado
 readfile('miarchivo.zip');
 // Por último eliminamos el archivo temporal creado
 unlink('miarchivo.zip');//Destruye el archivo temporal
?>

Aunque en los comentarios del propio código se explican los pasos vamos a verlos más detenidamente:

Primero creamos una instancia de la clase ZipArchive:

$zip = new ZipArchive();

Después creamos un archivo zip temporal que llamamos miarchivo.zip y que eliminaremos después de descargarlo.

$zip->open("miarchivo.zip",ZipArchive::CREATE);

Para indicarle que tiene que crearlo ya que no existe utilizamos el valor ZipArchive::CREATE.

Conviene recordar que tenemos que tener permisos de escritura en la carpeta para poder crear el archivo.

En este ejemplo vamos a crear dentro del archivo comprimido una carpeta a la que hemos llamado miDirectorio.

$zip->addEmptyDir('miDirectorio');

Como podemos observar con el método addEmptyDir creamos un directorio vacío dentro del archivo zip que acabamos de crear.

Después añadimos el archivo imagen1.jpg que hemos copiado en nuestra carpeta. Para ello utilizamos el método addFile.

El método addFile recibe como primer parámetro la ruta donde se encuentra el archivo que vamos a añadir, en este caso como se encuentra en la misma carpeta solo es necesario especificar el nombre del archivo.
El segundo parámetro es opcional y es la ruta final dentro del archivo zip y el nombre final que tendrá el archivo al comprimirlo, si no se especifica se creará en la raíz del archivo zip con el mismo nombre.

En este caso lo colocamos en la raíz del archivo zip por lo que solo especificamos su nombre final que en este caos es mi_imagen1.jpg.

$zip->addFile("imagen1.jpg","mi_imagen1.jpg");

Ahora vamos añadimos otro archivo, pero esta vez en lugar de crearlo en la raíz del zip le decimos que lo añada a la carpeta miDirectorio que hemos creado anteriormente:

 $zip->addFile("imagen2.jpg",$dir."/mi_imagen2.jpg");

Ahora solo nos queda cerrar el archivo zip que hemos creado:

 $zip->close();

Y forzar su descarga:

 header("Content-type: application/octet-stream");
 header("Content-disposition: attachment; filename=miarchivo.zip");
 // leemos el archivo creado
 readfile('comprimido.zip');

Para forzar su descarga creamos las cabeceras necesarias indicando que es un archivo de tipo zip y especificando su nombre, en este caso le hemos llamado miarchivo.zip, pero podéis poner el nombre que queráis.

Como último paso eliminamos el archivo zip temporal que hemos creado:

unlink('miarchivo.zip');//Destruye el archivo temporal

Y esto es todo.

Espero que os sirva de ayuda.

Un saludo, y si aún no lo has hecho no olvides suscribirte a mi blog para no perderte los próximos posts  :-),

También puedes seguirme en Twitter en ‎@revigames y no olvides que me ayudas mucho si compartes este post en las redes sociales.

17 comentarios en “Como crear un archivo Zip y forzar su descarga en PHP

    1. Hola,
      La linea es $zip->open(“miarchivo.zip”,ZipArchive::CREATE); ¿Puede ser que la veas incompleta por el navegador/dispositivo donde estás leyendo?.
      Yo la veo completa.
      Gracias por comentar

  1. Tengo una web que la gente se descarga grupos de imagenes en archivos zip, pero los clientes que usan Mac tienen problemas a la hora de descomprimir el archivo resultante y les aparece vacio.

    Como se puede solucionar?

  2. Hola, estoy siguiendo tu codigo y en lugar de abrirse el cuadro de dialogo para descargar el zip, el mismo se descarga directamente en la pantalla.
    ¿alguna ayuda?
    Muchas gracias!!!

    1. Encontré el problema y lo quería comentar por si a alguien le pasa algo similar.
      El asunto es que había “algo” que estaba enviando una salida antes que la serie de header, con lo cual PHP no era capaz de modificar las cabeceras.
      Incluyo un config.php para poder conectarme a la base de datos, resulta que luego de cerrar el php, había tres lineas en blanco…. ahí estaba el problema
      Espero que mi torpeza le sirva a alguien.

      Saludos!!

  3. hola necesito ayuda es para crear y descargar archivos no me genera nada paso codigo eso es en parte de mi boton
    $(document).on(‘click’,’.descargar’,function(){
    var img=$(this);
    $.ajax({
    url: ‘querys.php’,
    type: ‘POST’,
    data: {query: ‘dwn_file_contratista’, id_contratista: $(img).data(“id_contratista”)},
    success: function(){

    }
    });
    });

    y esto ya es parte del archivo querys.php

    case ‘dwn_file_contratista’:

    $contratista=$_POST[‘id_contratista’];

    $sql_contratista_files=mysql_query(“SELECT * FROM contratista_files WHERE id_contratista=’$_POST[id_contratista]’ AND status=’0′”) or die(mysql_error());
    $sql_contratista_auditoria=mysql_query(“SELECT * FROM contratista_auditoria WHERE id_contratista=’$_POST[id_contratista]'”) or die(mysql_error());
    $sql_contratista_amonesta=mysql_query(“SELECT * FROM contratista_amonestacion WHERE id_contratista=’$_POST[id_contratista]'”) or die(mysql_error());

    $zip = new ZipArchive();

    $filename = ‘files_’.$contratista.’.zip’;
    $zip->open($filename,ZipArchive::CREATE);

    while($file = mysql_fetch_array($sql_contratista_files))
    {
    $zip->addFile($file[url]);
    }
    while($auditoria= mysql_fetch_array($sql_contratista_auditoria))
    {
    $zip->addFile($auditoria[url_archivo]);
    }
    while($amonesta=mysql_fetch_array($sql_contratista_amonesta))
    {
    $zip->addFile($amonesta[url_archivo]);
    }

    $zip->close();

    header(“Content-type: application/octet-stream”);
    header(“Content-Disposition: attachment; filename=”.$filename);
    readfile($filename);
    unlink($filename);

    break;

    1. Hola Jorge Luis, estás haciendo una llamada Ajax para descargar el archivo zip, esto no te va a funcionar, tienes que acceder a la url donde vas a generar el archivo directamente (sin peticiones Ajax) mediante un link en html o si lo vas ha hacer desde javascript con window.location.href=url_donde_generas_el_archivo_comprimido.

  4. ¿Tengo un problema, deseo agregar bastantes archivos y los temporales no alcanzan como puedo solucionar eso?

    Saludos y gracias

  5. Hola, tengo un problema, me genera el archivo pero me da un error: “se produjo un error cargando el archivo”, ¿se sabe a qué es debido? muchas gracias!

    Un saludo!

      1. Hola, ya sé que es antiguo, jeje, lo siento pero era por si se sabía el motivo. No es Mac, pero trabajo con máquina virtual Linux. Gracias por responder.

  6. Como se pueden agregar archivos que son generados por el mismo sistema, solo tengo la ruta donde se genera dicho archivo, alguien que pudiera ayudarme

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.