Detección inteligente de tipo de archivo usando PHP

En la mayoría de las aplicaciones web actuales, existe la necesidad de permitir a los usuarios cargar archivos de imágenes, audio y video. A veces, también necesitamos restringir la carga de ciertos tipos de archivos; un archivo ejecutable es un ejemplo obvio.

Dejando a un lado la seguridad, es posible que también desee evitar que los usuarios usen mal la instalación de carga, por ejemplo ¡subir ilegalmente archivos de música con derechos de autor y usar el servicio para promover la piratería! En este artículo, veremos algunas maneras en las que podemos lograr esto.

Detección de tipo de archivo usando extensión y tipos MIME

No voy a hablar de esto con demasiados detalles, ya que, después de todo, esto es lo que normalmente hacemos cuando queremos restringir ciertos archivos. Simplemente obtenemos el tipo MIME del archivo usando $ _FILES ['myFile'] ['type'] y verifica si es de un tipo válido.

O podemos escanear los últimos caracteres del nombre del archivo y rechazar los archivos que terminan con cierta extensión. Desafortunadamente, estos métodos no son suficientes, ya que uno puede cambiar fácilmente la extensión de un archivo para evitar esta restricción. Además, la información de tipo MIME es proporcionada por el navegador y la mayoría de los navegadores, si no todos, determinan el tipo de mime según la extensión del archivo. Por lo tanto, los tipos MIME también pueden ser fácilmente falsificados.

Ahora exploremos algunas otras formas que ofrecen una mejor infalibilidad.

Usando Magic Bytes

La mejor manera de determinar el tipo de archivo es mediante el examen de los primeros bytes de un archivo, denominado "bytes mágicos". Los bytes mágicos son esencialmente firmas que varían en longitud entre 2 y 40 bytes en los encabezados de archivo, o al final de un archivo. Hay varios cientos de tipos de archivos, y muchos de ellos tienen varias firmas de archivos asociadas con ellos. Puedes ver una lista de firmas de archivos aquí.

Aunque es inconsistente, esta es nuestra mejor apuesta para detectar tipos de archivos de manera confiable. Esta tarea aparentemente difícil se ha hecho realmente fácil con una extensión PECL llamada Fileinfo. A partir de PHP 5.3, Fileinfo se entrega con la distribución principal y está habilitada de forma predeterminada, por lo que definitivamente es una forma robusta y sencilla de detectar e imponer restricciones en los tipos de archivos cargados.

Veamos ahora cómo podemos detectar un tipo de archivo usando Fileinfo:

Manejo de subidas de imágenes

Si pretende permitir solo la carga de imágenes, entonces puede usar la función incorporada getimagesize () función para asegurar que el usuario esté cargando un archivo de imagen válido. Esta función devuelve falso, si el archivo no es un archivo de imagen válido.

Leyendo e interpretando bytes mágicos manualmente.

Si, por algún motivo, no puede instalar Fileinfo, puede seguir determinando manualmente el tipo de archivo leyendo los primeros bytes de un archivo y comparándolos con los bytes mágicos conocidos asociados con el tipo de archivo en particular. Este proceso definitivamente tiene un elemento de prueba y error, porque aún existe la posibilidad de que haya algunos bytes mágicos no documentados asociados con formatos de archivo legítimos. Como resultado, los archivos válidos podrían ser rechazados por su sistema. Sin embargo, no es imposible como hace un par de años, me pidieron que trabajara en una secuencia de comandos que solo permitiera cargar archivos mp3 originales, y como no podíamos usar Fileinfo, recurrimos a este escaneo manual. Me tomó un tiempo dar cuenta de algunos de los bytes mágicos no documentados para mp3, pero muy pronto obtuve un script de carga estable.

Antes de terminar, me gustaría desprenderme de una advertencia general: asegúrese de no llamar a un incluir() con un archivo que se cargó, ya que el código PHP puede estar oculto como parte de la imagen, y la imagen pasaría sus pruebas para la validación de archivos muy bien, solo para causar estragos cuando los ejecute el servidor.