es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Error de PDF al descargar/guardar, pero no al ver en el navegador (primera página en blanco)

Tenemos un sitio desde hace muchos años, PHP en Ubuntu, donde los clientes pueden descargar formularios/cartas en formato PDF, luego cargarlos cuando se completan.

Ahora, al volver a descargar el PDF con varias páginas que cargó el cliente, la primera página (portada) está en blanco y Adobe Acrobat muestra el mensaje “Error en la página…”. Cuando cargamos el documento a través de FTP, el archivo está bien y sin errores, por lo que el problema debe estar en el proceso de descarga de archivos / readfile().

Este error ocurre tanto en Chrome como en Firefox (todos actualizados). Si solo visualiza el PDF en el navegador, la portada parece estar bien y ser legible, sin embargo, si lo descarga, obtiene el mismo error de Adobe y la primera página en blanco. Estoy sin ideas sobre cómo diagnosticar esto.

A continuación se muestra el código PHP que usamos para obtener el archivo.

Tenga en cuenta que, por razones de seguridad, no permitimos enlaces directos a ningún archivo. El enlace es una página PHP que valida una solicitud de archivo codificada para obtener permiso para leer un archivo, luego extrae la información correcta del archivo de la base de datos para ese usuario, luego lee el archivo y lo sirve al cliente. No he incluido el código de validación o relacionado con la base de datos, solo el código de readfile relevante:

header(“Content-Length: ” . filesize(‘/filestore/’ . $doc[‘filename’]));
header(“Expires: Sat, 26 Jul 1997 05:00:00 GMT”); // Fecha en el pasado
header(‘Content-type: application/pdf’);
header(‘Content-Disposition: attachment; filename=”‘ . $docname . ‘.’ . strtolower(end(explode(‘.’, $doc[‘filename’]))) . ‘”‘);
header(“Pragma: private”);
readfile(‘/filestore/’ . $doc[‘filename’]);

Información adicional basada en preguntas en comentarios:

Para evitar el enlace directo y el raspado de documentos por fuerza bruta, el almacenamiento de archivos no se encuentra en una carpeta pública (por lo que no hay enlace directo).

Los enlaces de usuario son similares a este Mi archivo con la ID codificada con la información del archivo y las comprobaciones de token CSRF y token de sesión como parte de la validación. El archivo download.php valida al usuario y el archivo para asegurarse de que tengan permiso para el documento, luego llama al código anterior para obtener y “servir” el archivo al navegador.

$docname es el nombre de archivo original del cliente para el archivo almacenado en la base de datos. Guardamos archivos con nuestro propio nombre de archivo generado para evitar conflictos de nombres cuando los clientes usan el mismo nombre de archivo, esto se almacena en la DB como $doc[‘filename’]. Restauramos el nombre de archivo del cliente al descargar.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Tenemos un sitio desde hace muchos años en PHP en Ubuntu donde los clientes pueden descargar formularios y cartas como archivos PDF, para luego subirlos una vez completados. Ahora, al volver a descargar archivos PDF de varias páginas subidos por el cliente, la primera página (portada) está en blanco y Adobe Acrobat dice “existe un error en la página…”. Cuando FTP el documento, el archivo está bien sin errores, por lo que el problema debe estar en el proceso de descarga y lectura de archivos. Este error ocurre en Chrome y Firefox (todos actualizados). Si solo se ve el PDF en el navegador, la portada parece ser correcta y legible, sin embargo, si se descarga, se obtiene el mismo error de Adobe y la primera página está en blanco. No sé cómo diagnosticar esto.

    A continuación, se muestra el código PHP que utilizamos para extraer el archivo:

    header("Content-Length: " . filesize('/filestore/' . $doc['filename']));
    header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Fecha en el pasado
    header('Content-type: application/pdf');
    header('Content-Disposition: attachment; filename="' . $docname . '.' . strtolower(end(explode('.', $doc['filename']))) . '"');
    header("Pragma: private");
    readfile('/filestore/'  . $doc['filename']);
    

    Información adicional basada en preguntas en los comentarios:

    • Para evitar el enlace directo y la obtención intensiva de documentos, el almacén de archivos no se encuentra en una carpeta pública (por lo que no hay enlace directo).
    • Los enlaces de usuario se ven así: <a href="download.php?id=dkljfsdjoiweoiq">Mi Archivo</a> con la identificación codificada con la información del archivo y comprobaciones de token CSRF y de sesión como parte de la validación. El archivo download.php valida al usuario y el archivo para asegurarse de que tengan permiso para el documento, luego llama al código anterior para obtener y “servir” el archivo en el navegador.
    • $docname es el nombre de archivo original del cliente para el archivo almacenado en la base de datos. Guardamos los archivos con nuestro propio nombre generado para evitar conflictos de nombres cuando los clientes usan el mismo nombre de archivo, esto se almacena en la base de datos como $doc['filename']. Restauramos el nombre del archivo del cliente al descargar.

Comments are closed.