Cómo almacenar archivos en una base de datos MySQL

Un clásico problema de una aplicación web es el almacenamiento de archivos subidos por los usuarios (Sus fotos por ejemplo).

Si bien teóricamente se puede realizar sin mayores inconvenientes (Al fin y al cabo, un archivo digital no es más que una colección de datos binarios), es sumamente ineficiente hacerlo.

Veamos cómo sería esto:

Primero que nada, habría que manejar de alguna forma el upload de archivos, pero, asumiendo que el archivo ya está disponible para php se podría pensar en almacenarlo dentro de la base de datos utilizando algún campo tipo BLOB.

Un problema inmediato que surge de tomar esta opción es que la base de datos crecerá mucho si el sistema es muy utilizado, lo cual impactará negativamente en su rendimiento, hará más costozos los backups, etc…

Una alternativa simple es guardar, en lugar del contenido del archivo, su localización (Puede ser la ruta al archivo, si está guardado en algún medio de almacenamiento, ya sea el disco local o alguno externo, como S3 por ejemplo).

De esa forma se logra aislar a la base de datos del manejo de información que, por otro lado, tampoco será sencilla de consultar y, a la vez, permite aprovechar capacidades del medio de almacenamiento elegido (Incluso hace mucho más simple la introducción de alguna capa de caché como ser un CDN).

Si lo que buscas es realizar búsquedas dentro del contenido de archivos de texto, lo mejor que puedes hacer es usar alguna otra herramienta como Solr, ElasticSearch o Sphinx (Por nombrar sólo algunos).

Si, de cualquier forma decides guardar el contenido del archivo directo en la base de datos, te recomiendo guardarlo con alguna forma de codificación que prevenga problemas con los caracteres especiales (acentos, eñes, etc…), por ejemplo base64 o algún formato comprimido (Zip por ejemplo).

En general diría que los datos que se almacenan en la base deberían ser (al menos en su gran mayoría) de naturaleza dinámica (Es decir, que pueden cambiar a lo largo del tiempo). Aquellos datos que permanecerán estáticos probablemente tengan un mejor lugar donde residir.

Por último, ¿pensaste en cómo mostrarías la foto si lo que está guardado en la base es el contenido del archivo en lugar de su ruta?.

En el caso de que tomes mi sugerencia es bien fácil, basta con algo como:

<img src="<?php echo $usuario['foto']; ?>"/>

Si en cambio lo que está guardado en la base es el contenido del archivo… no es que sea imposible, claro, pero seguro que es algo más complicado (Tal vez tengas que hacer un script que devuelva los datos binarios de la foto o algo así)… ¿para qué hacer las cosas más difíciles de lo que debe ser?

mchojrin

Por mchojrin

Ayudo a desarrolladores PHP a acceder mercados y clientes más sofisticados y exigentes

12 comentarios

  1. Hola, tengo una pagina web con un botón y quiero mandar un archivo adjunto y que ese archivo me llegue a mi mail.
    No estoy pudiendo configurar la base de datos con el PHP, no entiendo bien como hacerlo.
    Tengo un PHP el cual me saca todos los datos de un formulario HTML, pero el archivo adjunto no se como manejarlo, como guardar la ruta en la base de datos y como indicarle a que base apuntar, etc.
    Si podrías orientarme un poco te lo agradecería.

    1. Hola Alexis:

      ¿Cómo estás? Son varias preguntas en una, intentaré responder. Por el tema del envío de correos te recomiendo leer este artículo.

      Por el tema de la base de datos, lo que debes ver primero que nada es cómo y dónde se está almacenando el archivo que estás recibiendo.

      Seguramente estás usando el mecanismo de subida de archivos de PHP.

      En ese caso, deberás usar la función move_uploaded_file para guardar el archivo en alguna ubicación propia de tu aplicación.

      Esa ubicación la puedes crear del modo que te sea más cómodo (Por ejemplo concatenando la constante __DIR__ con algún directorio de tu aplicación (uploads podría ser).

      Lo importante es que guardes esa ubicación en alguna variable para luego poder usarla en tu sentencia INSERT en el campo donde guardarás la ruta al archivo.

      Respecto al problema que tienes de configuración de la base de datos, ¿podrías darme algún detalle más? ¿Qué error ves?

      Saludos!

    2. Hola,
      Primero que nada te quiero agradecer por tu tiempo y dedicación en la respuesta.
      Vos sabes que estuve indagando un poco mas y pude hacer esto con PHPMailer para enviar el mail y como tu decís use la función move_uploaded_file para guardar el archivo, el problema que estoy teniendo ahora es que los archivos adjuntos que envió me llegan vacíos, mi teoría es que lo estoy enviando antes de que se carguen en mi ruta.
      En la ruta quedan bien guardados, están llegando mal al mail que me envía el PHPMailer, tenes idea como podre solucionar esto?

      1. $postData = $uploadedFile = $statusMsg = »;
        $directorio = ‘archivos/’;
        $nombre = $_POST[‘nombre’];
        $telefono = $_POST[‘telefono’];
        $mailDestino = $_POST[‘email’];
        $cuerpo = ‘cuerpo’;

        if(!empty($nombre) && !empty($telefono) && !empty($_FILES[«adjunto»][«name»])){
        $archivo = basename($_FILES[«adjunto»][«name»]);
        $targetFilePath = $directorio . $archivo;
        $fileType = pathinfo($targetFilePath, PATHINFO_EXTENSION);

        //tipos de archivos posibles
        $allowTypes = array('pdf', 'doc', 'docx', 'jpg', 'png', 'jpeg');

        if(in_array($fileType, $allowTypes)){
        $subir_archivo = $directorio.$archivo;
        if(move_uploaded_file($_FILES['adjunto']['tmp_name'], $subir_archivo)){
        $uploadedFile = $targetFilePath;
        }else{
        $statusMsg = "Ocurrio un error, intente nuevamente.";
        echo $statusMsg;
        }
        }else{
        $statusMsg = 'Lo sentimos, solo archivos con extensión PDF, DOC, JPG, JPEG, & PNG se pueden cargar.';
        echo $statusMsg;
        }

        }else{
        $statusMsg = ‘Los campos con (*) son obligatorios.’;
        echo $statusMsg;
        }

        if(!empty($uploadedFile) && file_exists($uploadedFile)){
        $email = new PHPMailer();
        $email->SetFrom($mailDestino, $nombre);
        $email->isHTML(true);
        $email->Subject = $asunto;
        $email->Body = $cuerpo;
        $email->AltBody = $cuerpo;
        $email->AddAddress( ‘mimail@gmail.com’ );
        $file_to_attach = $directorio;
        $email->AddAttachment( $file_to_attach , $_FILES[‘adjunto’][‘name’] );

        return $email->Send();

        }

          1. En la línea:

            $email->AddAttachment( $file_to_attach , $_FILES[‘adjunto’][‘name’] );

            Estás adjuntando el contenido de $file_to_attach.

            $file_to_attach está definido como $directorio y $directorio está definido como ‘archivos/’.

            Fijate eso, en todo caso, lo mejor que podés hacer es ir mirando el contenido de las variables a lo largo de la ejecución para ver exactamente qué es lo que está tratando de adjuntar.

  2. Hola mira tengo este problema guarde la ruta en la base de datos, ahora como puedo visualizar el archivo ya sea imagen o pdf

    1. Hola Edgar!

      La visualización del archivo la realizará el cliente. Lo que tú puedes hacer es generar el código HTML que corresponda según el tipo de archivo.

      Si se trata de una imagen puedes usar un tag «img», si se trata de un pdf deberías usar un «a» para que se abra en otra ventana por ejemplo.

      Saludos!

  3. Entonces es mas recomendable guardar la ruta en la base de datos o el archivo a la base de datos?

    1. Hola Mike:

      Definitivamente lo más recomendable es guardar la ruta. De esa forma:

      1. Ahorras espacio en la base de datos (Que igualmente no serviría de mucho ya que hacer búsquedas por el contenido de un archivo sería sumamente ineficiente)
      2. Te reservas el derecho de modificar el modo de almacenar los archivos posteriormente (Por ejemplo, en una primera instancia puedes guardarlos en el mismo servidor donde está tu aplicación pero luego podrías preferir usar otro tipo de almacenamiento como S3)

¿Te quedó alguna duda? Publica aca tu pregunta

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