php - force - Encabezados HTTP para descargas de archivos
php force download pdf (3)
He escrito un script PHP que maneja las descargas de archivos, determina qué archivo se solicita y establece los encabezados HTTP adecuados para que el navegador descargue el archivo (en lugar de mostrarlo en el navegador).
Ahora tengo un problema donde algunos usuarios informaron que ciertos archivos se identificaron incorrectamente (por lo que independientemente de la extensión, el navegador la considerará una imagen GIF). Supongo que esto se debe a que no configuré el "tipo de contenido" en el encabezado de respuesta. ¿Es este el caso más probable? Si es así, ¿existe un tipo bastante genérico que podría usarse para todos los archivos, en lugar de tratar de dar cuenta de todos los tipos de archivos posibles?
Actualmente solo estoy configurando el valor "Content-disposition: attachment; filename = arandomf.ile"
Actualización: seguí esta guía aquí para crear un proceso más sólido para la descarga de archivos ( http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/ ) , pero hay un retraso significativo entre el momento en que se ejecuta el script y cuando aparece el cuadro de diálogo de descarga del navegador. ¿Alguien puede identificar el cuello de botella que está causando esto?
Aquí está mi implementación:
/**
* Outputs the specified file to the browser.
*
* @param string $filePath the path to the file to output
* @param string $fileName the name of the file
* @param string $mimeType the type of file
*/
function outputFile($filePath, $fileName, $mimeType = '''') {
// Setup
$mimeTypes = array(
''pdf'' => ''application/pdf'',
''txt'' => ''text/plain'',
''html'' => ''text/html'',
''exe'' => ''application/octet-stream'',
''zip'' => ''application/zip'',
''doc'' => ''application/msword'',
''xls'' => ''application/vnd.ms-excel'',
''ppt'' => ''application/vnd.ms-powerpoint'',
''gif'' => ''image/gif'',
''png'' => ''image/png'',
''jpeg'' => ''image/jpg'',
''jpg'' => ''image/jpg'',
''php'' => ''text/plain''
);
$fileSize = filesize($filePath);
$fileName = rawurldecode($fileName);
$fileExt = '''';
// Determine MIME Type
if($mimeType == '''') {
$fileExt = strtolower(substr(strrchr($filePath, ''.''), 1));
if(array_key_exists($fileExt, $mimeTypes)) {
$mimeType = $mimeTypes[$fileExt];
}
else {
$mimeType = ''application/force-download'';
}
}
// Disable Output Buffering
@ob_end_clean();
// IE Required
if(ini_get(''zlib.output_compression'')) {
ini_set(''zlib.output_compression'', ''Off'');
}
// Send Headers
header(''Content-Type: '' . $mimeType);
header(''Content-Disposition: attachment; filename="'' . $fileName . ''"'');
header(''Content-Transfer-Encoding: binary'');
header(''Accept-Ranges: bytes'');
// Send Headers: Prevent Caching of File
header(''Cache-Control: private'');
header(''Pragma: private'');
header(''Expires: Mon, 26 Jul 1997 05:00:00 GMT'');
// Multipart-Download and Download Resuming Support
if(isset($_SERVER[''HTTP_RANGE''])) {
list($a, $range) = explode(''='', $_SERVER[''HTTP_RANGE''], 2);
list($range) = explode('','', $range, 2);
list($range, $rangeEnd) = explode(''-'', $range);
$range = intval($range);
if(!$rangeEnd) {
$rangeEnd = $fileSize - 1;
}
else {
$rangeEnd = intval($rangeEnd);
}
$newLength = $rangeEnd - $range + 1;
// Send Headers
header(''HTTP/1.1 206 Partial Content'');
header(''Content-Length: '' . $newLength);
header(''Content-Range: bytes '' . $range - $rangeEnd / $size);
}
else {
$newLength = $size;
header(''Content-Length: '' . $size);
}
// Output File
$chunkSize = 1 * (1024*1024);
$bytesSend = 0;
if($file = fopen($filePath, ''r'')) {
if(isset($_SERVER[''HTTP_RANGE''])) {
fseek($file, $range);
while(!feof($file) && !connection_aborted() && $bytesSend < $newLength) {
$buffer = fread($file, $chunkSize);
echo $buffer;
flush();
$bytesSend += strlen($buffer);
}
fclose($file);
}
}
}
Como se explica en el enlace de Alex, probablemente le falte el encabezado Content-Disposition
sobre Content-Type
.
Entonces algo como esto:
Content-Disposition: attachment; filename=MyFileName.ext
Puedes probar este script de descarga de fuerza . Incluso si no lo usa, probablemente lo guiará en la dirección correcta:
<?php
$filename = $_GET[''file''];
// required for IE, otherwise Content-disposition is ignored
if(ini_get(''zlib.output_compression''))
ini_set(''zlib.output_compression'', ''Off'');
// addition by Jorg Weske
$file_extension = strtolower(substr(strrchr($filename,"."),1));
if( $filename == "" )
{
echo "<html><title>eLouai''s Download Script</title><body>ERROR: download file NOT SPECIFIED. USE force-download.php?file=filepath</body></html>";
exit;
} elseif ( ! file_exists( $filename ) )
{
echo "<html><title>eLouai''s Download Script</title><body>ERROR: File not found. USE force-download.php?file=filepath</body></html>";
exit;
};
switch( $file_extension )
{
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
// change, added quotes to allow spaces in filenames, by Rajkumar Singh
header("Content-Disposition: attachment; filename=/"".basename($filename)."/";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
exit();
Según RFC 2046 (extensiones multipropósito de correo de Internet) :
La acción recomendada para una implementación que recibe un
La entidad "application / octet-stream" es simplemente ofrecer poner los datos en un archivo
Así que iría por eso.