Estoy intentando servir archivos zip grandes a los usuarios. Cuando hay 2 conexiones concurrentes, el servidor se queda sin memoria (RAM). Aumenté la cantidad de memoria de 300MB a 4GB (Dreamhost VPS) y luego funcionó bien.Cómo forzar la descarga de archivos grandes sin utilizar demasiada memoria?
Necesito permitir mucho más de 2 conexiones simultáneas. Los 4GB reales permitirían algo así como 20 conexiones simultáneas (muy mal).
Bueno, el código actual que estoy usando, necesita el doble de memoria que el tamaño real del archivo. Eso es muy malo. Quiero algo como "transmitir" el archivo al usuario. Por lo tanto, no asignaría más que el fragmento que se está sirviendo a los usuarios.
El siguiente código es el que estoy usando en CodeIgniter (framework PHP):
ini_set('memory_limit', '300M'); // it was the maximum amount of memory from my server
set_time_limit(0); // to avoid the connection being terminated by the server when serving bad connection downloads
force_download("download.zip", file_get_contents("../downloads/big_file_80M.zip"));exit;
La función force_download es el siguiente (CodeIgniter función auxiliar por defecto):
function force_download($filename = '', $data = '')
{
if ($filename == '' OR $data == '')
{
return FALSE;
}
// Try to determine if the filename includes a file extension.
// We need it in order to set the MIME type
if (FALSE === strpos($filename, '.'))
{
return FALSE;
}
// Grab the file extension
$x = explode('.', $filename);
$extension = end($x);
// Load the mime types
@include(APPPATH.'config/mimes'.EXT);
// Set a default mime if we can't find it
if (! isset($mimes[$extension]))
{
$mime = 'application/octet-stream';
}
else
{
$mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
}
// Generate the server headers
if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
header("Content-Length: ".strlen($data));
}
else
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".strlen($data));
}
exit($data);
}
Probé algunos códigos basados en fragmentos que encontré en Google, pero el archivo siempre se entregó dañado. Probablemente debido al mal código.
¿Alguien podría ayudarme?
¿Ha tratado de redirigir a un archivo usando cabecera 'Location'? – Dani
Me parece que está mucho mejor si solo le da a los usuarios un enlace directo a los archivos ... – NotMe
Olvidé decir que los archivos están en una carpeta a la que no se puede acceder a través de la web. Esto es por razones de seguridad. Solo sirvo el archivo si el usuario pasa un proceso de autenticación. Probaré las sugerencias a continuación y volveré a votar para obtener la mejor respuesta. –