Raikkon
12/08/2008, 10:27
¡Muchas gracias!
function enviar_archivo($archivo, $speed = 100) {
// Veamos.. existe el fichero ?
if (!is_file($archivo)) {
die("404 Archivo no encontrado");
}
// Recolectamos información sobre el archivo
$archivo_nombre = basename($archivo);
$archivo_extension = strtolower(substr(strrchr($archivo_nombre,"."),1));
// Asignamos el Content-Type adecuado a cada tipo de archivo, esto se
// puede configurar al gusto, yo he incluído los más comunes para los
// ebooks: exe, zip, lit, pdf, mp3, html, html
switch($archivo_extension) {
case "exe":
$ctype="application/octet-stream";
break;
case "zip":
$ctype="application/zip";
break;
case "lit":
$ctype="application/lit";
break;
case "pdf":
$ctype="application/pdf";
break;
case "mp3":
$ctype="audio/mpeg3";
break;
case "htm":
case "html":
$ctype="text/html";
break;
case "txt":
$ctype="text/plain";
break;
// Debemos tener cuidado con no dejar descargar por este
// método ficheros sensibles tales como ficheros .php, .inc, etc...
case "php":
case "inc":
die("No te dejo bajar ficheros ". $archivo_extension ."");
break;
default:
$ctype="application/force-download";
}
// Empezamos con los headers
header("Cache-Control:");
header("Cache-Control: public");
header("Content-Type: $ctype");
// Meramente estético, sustituímos los posibles guiones bajos ( _ )
// por espacios en el nombre del fichero para bajar archivos más
// legibles. Ej: "fichero_a_bajar.pdf" se convierte en "fichero a bajar.pdf"
$archivo_nombre_limpio = str_replace("_", " ", $archivo_nombre);
// Forzamos la descarga en lugar de la apertura
$header='Content-Disposition: attachment; filename='.$archivo_nombre_limpio;
header($header);
header("Accept-Ranges: bytes");
$tamano = filesize($archivo);
// Si el navegador nos solicita el http_range...
if(isset($_SERVER['HTTP_RANGE'])) {
// entonces le enviamos sólo el trozo que falta.
// (Mundialmente conocido como "resume")
list($a, $rango)=explode("=",$_SERVER['HTTP_RANGE']);
str_replace($rango, "-", $rango);
$tamano2=$tamano-1;
$nueva_longitud=$tamano2-$rango;
header("HTTP/1.1 206 Partial Content");
header("Content-Length: $nueva_longitud");
header("Content-Range: bytes $rango$tamano2/$tamano");
} else {
// Si no le enviamos todo el pack
$tamano2=$tamano-1;
header("Content-Range: bytes 0-$tamano2/$tamano");
header("Content-Length: ".$tamano2);
}
// Una vez tomadas estas decisiones, sólo queda abrir el archivo...
$puntero_al_fichero = fopen("$archivo","rb");
// localizar el inicio de la parte que queremos enviar...
fseek($puntero_al_fichero,$posicion_inicio);
// y empezar a enviar. Aqui es donde se produce la magia... en base
// a la variable de velocidad, leemos ese número de Ks del archivo,
// lo enviamos... y nos "dormimos" un segundo. Esta forzada chapuza
// produce exactamente el efecto deseado... ralentizar la descarga a
// los X k/s que deseemos por cada envío.
while(!feof($puntero_al_fichero)) {
// Nos aseguramos de no producir un timeout por sobrepasar el
// tiempo máximo de ejecución de PHP en caso de archivos
// demasiado grandes.
set_time_limit(0);
// Ponemos los datos en el buffer...
print(fread($puntero_al_fichero,1024*$speed));
// Lanzamos el contenido del buffer...
flush();
// Y a dormir...
sleep(1);
}
// Proceso completado, archivo descargado,
// todo el "pescao vendío"
fclose($puntero_al_fichero);
exit;
}
// Y finalmente un ejemplo tonto de uso de la función
enviar_archivo("fichero.pdf",100);
?>