Crear archivos zip con PHP: agregar archivos y directorios, descargar zip y proteger con contraseña

Desde hace tiempo he querido hacer un post completo sobre cómo trabajar con archivos ZIP en PHP.

Como sabemos, los archivos ZIP son unos paquetes que permiten tener dentro múltiples archivos para su posterior transporte.

Tutorial de creación de archivos zip con PHP

PHP tiene soporte nativo para los archivos ZIP en la clase ZipArchive y permite comprimir o empaquetar archivos de una manera fácil.

Hoy vamos a ver cómo:

  1. Crear un archivo zip  y agregarle contenido
  2. Forzar la descarga de un archivo zip, es decir, crear un zip y mostrarlo en el navegador
  3. Agregar archivos a un zip a partir de un patrón glob
  4. Agregar todo el contenido de un directorio de manera recursiva. Es decir, agregar todo el contenido y si hay un directorio agregar el contenido de ese directorio, así recursivamente.
  5. Proteger un archivo ZIP con contraseña

Todavía no vamos a ver cómo descomprimir o desempaquetar, eso es de otro post.

Comprimir archivos con PHP: primer ejemplo

Aviso: si al leer el post no sabes de dónde salen los archivos comprimidos, quieres ver la relación del código o te pierdes, te invito a ver y clonar el repositorio en GitHub 😉

Veamos el primer ejemplo. En el mismo creamos una nueva instancia de ZipArchive. Abrimos el archivo zip con el método open.

Al método open le pasamos la ruta absoluta del zip y el modo de apertura. Lo estamos abriendo de modo que se cree si no existe y que se sobrescriba si ya existe.

Si no lo sobrescribimos y ya existe, se irán agregando más archivos al zip, ya que guardará los anteriores.

La parte importante para agregar un archivo es el método addFile. Recibe dos argumentos: la ruta absoluta de la ubicación del archivo y su nombre. Ese nombre es el que tendrá dentro del zip.

Utilizamos basename para limpiar el nombre, ya que algo como C:\fotos\perro.png se convierte en perro.png

De esta manera en el zip se añade el archivo con perro.png, aquí bien podrías cambiar el nombre del archivo.

Puedes llamar a addFile cuantas veces quieras, solo recuerda que al final debes llamar al método close; el cual devuelve un booleano indicando si la escritura del archivo fue exitosa.

Al cerrar el archivo se habrá creado un zip en el directorio indicado.

Comprimir y descargar ZIP

En ocasiones vamos a necesitar crear un zip y mandarlo de regreso al usuario a través del navegador web.

Para ello utilizamos la función readfile en conjunto de algunos encabezados HTTP para forzar la descarga.

Primero creamos el archivo zip como normalmente se hace, y una vez que tenemos el archivo lo mandamos a través del navegador web.

Por cierto, si quieres eliminar el archivo al final simplemente invoca a unlink.

3 – Utilizar patrón GLOB para agregar muchos archivos

La clase ZipArchive también permite agregar archivos basados en un patrón glob. Por ejemplo, para agregar todas las imágenes con extensión png podríamos indicarlas con el patrón *.png

De la misma manera todos los archivos de código fuente de Golang podrían agregarse con el patrón *.go

También soporta directorios: ./fotos/*.psd

Para agregar archivos basados en glob usamos el método llamado addGlob:

Agregar un directorio y todo su contenido a un archivo zip, de manera recursiva, usando PHP

Veamos algo interesante, se trata de agregar todo el contenido de un directorio recursivamente.

Es decir, si tenemos una carpeta y la misma tiene archivos todos los archivos son agregados.

Si dentro de la carpeta tenemos otra carpeta con contenido también se agrega. Y así infinitamente, por eso se dice que es de manera recursiva.

Para ello no existe un método como addDirRecursivePlease, pero sí podemos recorrer manualmente un directorio de manera recursiva y llamar a addFile en un ciclo.

Podemos recorrer un directorio de distintas maneras, en el ejemplo se utiliza un RecursiveDirectoryIterator con un RecursiveIteratorIterator.

No te preocupes ni compliques, simplemente vamos a iterar por un directorio de manera recursiva. Y dentro del ciclo agregar archivos.

En el ejemplo agregamos todo el contenido de imágenes, que a su vez tiene otros directorios. En cada iteración obtenemos la ruta absoluta del archivo.

Utilizamos substr para agregar un nombre bonito o limpio como vimos anteriormente, pero no usamos basename porque queremos respetar la profundidad de directorios.

Proteger archivo zip con contraseña

Para terminar con los ejemplos veamos cómo agregar una contraseña al archivo zip y proteger los archivos con la misma.

Te aviso de una vez que esto de la contraseña y la protección de archivos funciona en PHP 7.2 y adelante.

Hay librerías y trucos para hacerlo funcionar en otras versiones, pero nosotros no vamos a ver eso. Te recomiendo encarecidamente que actualices tu versión de PHP en Windows, Android o Linux.

Lo que hay que notar aquí es el uso de setPassword en el zip después de haberlo abierto, (solo se necesita una vez) así como el método setEncryptionName que recibe el título del archivo (no su ruta absoluta) y el método de cifrado que es AES 256.

Fíjate en que setEncryptionName es llamado después de agregar cada archivo.

Conclusión

Puedes combinar todos los ejemplos y adecuarlos a tus necesidades. Por ejemplo, descargar el archivo zip después de ponerle contraseña, agregar con glob y después agregar recursivamente, etcétera.

Los archivos que prestaron sus servicios para ser comprimidos son de otros posts como el de cron con Go, los fondos de escritorio de lenguajes de programación, la lectura y escritura de archivos Excel con PHP o el conversor de bases numéricas.

Recuerda que el código completo está en mi GitHub.

Referencias

Muchas cosas presentes aquí fueron tomadas, inspiradas e investigadas de los siguientes enlaces (en serio, eran todas las pestañas que tenía mi navegador mientras hacía los ejemplos)

https://www.php.net/manual/es/book.zip.php

https://www.php.net/manual/es/ziparchive.setpassword.php

https://www.php.net/manual/es/ziparchive.addglob.php

https://github.com/parzibyte/marca_de_agua_php_personal/blob/master/marcar.php

https://stackoverflow.com/questions/39833496/zip-a-file-and-protect-with-a-password-in-php

https://php.net/manual/en/ziparchive.setencryptionname.php

 

Deja un comentario

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