2011-04-08 27 views
16

Estoy utilizando el sencillo script Descargar:php, descarga de archivos

if (file_exists($file)) { 
    header('Content-Description: File Transfer'); 
    header('Content-Type: application/octet-stream'); 
    header('Content-Disposition: attachment; filename='.basename($file)); 
    header('Content-Transfer-Encoding: binary'); 
    header('Expires: 0'); 
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
    header('Pragma: public'); 
    header('Content-Length: ' . filesize($file)); 
    ob_clean(); 
    flush(); 
    readfile($file); 
    exit; 
} 

Se está trabajando en mi LocalServer hasta 200 MB.

Cuando intento este código en su página web que descarga en lugar de 173KB archivo de 200MB.

I comprobado todo, escribió algo de código personalizado (usando funciones ob y fread en lugar de readfile), pero no puede descargar archivos de gran tamaño.

Gracias por su respuesta.

  • estoy usando Apache 2.2, PHP 5.3
  • configuración Todo PHP para trabajar con archivos grandes están bien. (Tiempos de ejecución, los límites de memoria, ...
+0

mi hosting, dreamhost a veces mata scripts que consumen mucha CPU o recursos. Ese podría ser tu caso. – nerkn

Respuesta

19

Un problema que tengo con el siguiente código es que no tiene control sobre el flujo de salida, su PHP arrendamiento manejarlo sin saber exactamente lo que está pasando en el fondo:

Lo que debe hacer es crear una sistema de salida que puede controlar y replicar servidores acros.

Por ejemplo:

if (file_exists($file)) 
{ 
    if (FALSE!== ($handler = fopen($file, 'r'))) 
    { 
     header('Content-Description: File Transfer'); 
     header('Content-Type: application/octet-stream'); 
     header('Content-Disposition: attachment; filename='.basename($file)); 
     header('Content-Transfer-Encoding: chunked'); //changed to chunked 
     header('Expires: 0'); 
     header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
     header('Pragma: public'); 
     //header('Content-Length: ' . filesize($file)); //Remove 

     //Send the content in chunks 
     while(false !== ($chunk = fread($handler,4096))) 
     { 
      echo $chunk; 
     } 
    } 
    exit; 
} 
echo "<h1>Content error</h1><p>The file does not exist!</p>"; 

Esto sólo es básico, pero darle una oportunidad!

también leer mi respuesta aquí: file_get_contents => PHP Fatal error: Allowed memory exhausted

+0

Gracias. El envío fragmentado está funcionando en todos los servidores sin problemas. También estoy enviando el tamaño del archivo, realmente enviando un tamaño de archivo completo y enviando el fragmento del archivo por partes puede ser trivial pero funciona bien por ahora. De lo contrario, para grandes descargas, el usuario no verá el tamaño completo del archivo y esto puede no ser útil. – jsonx

+0

Depende totalmente de cómo se transfieran los datos; por ejemplo, la transmisión y la descarga requieren 2 métodos distintos de entrega de contenido. Me complace ayudar – RobertPitt

+0

¿No debería estar codificado el 'nombre base ($ file)'? ¿Qué pasa si contiene caracteres que se atornillan con http? – 735Tesla

0

se ha asegurado de su script can run long suficiente y tiene suficiente memoria?

lo que realmente necesita búfer de salida?

3

Parece readfile puede tener problemas con archivos largos. Como pidió @Khez, podría ser que la secuencia de comandos se ejecuta durante mucho tiempo. Una rápida búsqueda en Google resultó en un par de ejemplos de fragmentación del archivo.

http://teddy.fr/blog/how-serve-big-files-through-php http://www.php.net/manual/en/function.readfile.php#99406

+0

todas las configuraciones están bien para trabajar con archivos grandes, tiempos de ejecución, límites de memoria, ... – jsonx

+0

en la función read_chunked() del primer enlace resolvió el problema. – jsonx

+0

read_chunked() se comporta de forma inconsistente en algunos servidores – jsonx

0

La verdadera solución es evitar el uso de un script PHP para el envío de un solo archivo al cliente, que es una exageración y su servidor web es más adecuado para la tarea.

Es de suponer que tenga una razón para enviar los archivos a través de PHP, tal vez los usuarios deben autenticarse primero? Si ese es el caso, entonces debe usar X-Accel-Redirect (si está usando nginx) o X-Sendfile (anteriormente X-LightTPD a enviar en archivos) en lighttpd.

Si está utilizando Apache, he encontrado algunas referencias al mod_xsendfile pero nunca lo he usado personalmente, y dudo que esté instalado para usted si tiene un hosting administrado.

Si estas soluciones son insostenibles Me disculpo, pero realmente necesitan más información sobre el problema real: ¿Por qué está enviando estos archivos a través de PHP en el primer lugar?

+0

Gracias Zofrex, sí, debe hacerse alguna autenticación y algunas otras operaciones antes de enviar archivos. mod_xsendfile se ve bien, lo intentaré. Tal vez la solución más clara. – jsonx

3

Una solución para ciertos escenarios es que puede usar PHP-script para decidir de forma inteligente qué archivo descargar, pero en lugar de enviar el archivo directamente desde PHP, puede devolver una redirección al cliente que contiene el enlace que procesa solo el servidor web.

Esto se puede hacer al menos de dos maneras: PHP-script copia el archivo en una "zona de descarga" que por ejemplo podría limpiarse de archivos "viejos" regularmente por algún otro script de fondo/servicio o exponer el ubicación permanente real para los clientes.

Por supuesto, existen inconvenientes como en el caso de cada solución. En este caso, dependiendo de los clientes (curl, wget, navegador GUI) que soliciten el archivo, es posible que no admitan la redirección y, en el otro, los archivos están muy expuestos al mundo exterior y pueden leerse en todo momento sin el control (de acceso) del script PHP.

Cuestiones relacionadas