Я написал сценарий PHP, который обрабатывает загрузку файлов, определяет, какой файл запрашивается, и устанавливает правильные заголовки HTTP, чтобы браузер действительно загрузил файл (а не отображал его в браузере).
Теперь у меня проблема, когда некоторые пользователи сообщают, что определенные файлы идентифицируются неправильно (поэтому, независимо от расширения, браузер будет считать это изображением в формате GIF). Я предполагаю, что это потому, что я не установил «Content-type» в заголовке ответа. Так ли это, скорее всего? Если да, то существует ли достаточно общий тип, который можно было бы использовать для всех файлов, вместо того, чтобы пытаться учитывать все возможные типы файлов?
В настоящее время я устанавливаю только значение «Content-disposition: attachment; filename = arandomf.ile»
Обновлять: Я следовал этому руководству здесь, чтобы создать более надежный процесс загрузки файлов (http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/), но существует значительная задержка между выполнением сценария и появлением диалогового окна загрузки браузера. Может ли кто-нибудь определить узкое место, вызывающее это?
Вот моя реализация:
/**
* 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);
}
}
}






Согласно RFC 2046 (многоцелевые расширения почты Интернета):
The recommended action for an implementation that receives an
"application/octet-stream" entity is to simply offer to put the data in a file
Так что я бы выбрал это.
Я согласен - application / octet-stream сообщает браузеру, что это общий двоичный файл, который приведет к его сохранению на диск
Но Content-disposition вернее. stackoverflow.com/questions/20508788/…
Вы можете попробовать это скрипт принудительной загрузки. Даже если вы не используете его, он, вероятно, укажет вам правильное направление:
<?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/octet-stream";
}
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();
Обратите внимание, что Content-Type: application/force-download и Content-Transfer-Encoding: binary не являются стандартами HTTP. Они могут работать, но здесь бесполезны. RFC2616: w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
"приложение / принудительная загрузка" - не лучший вариант по умолчанию; "application / octet-stream" было бы лучше
Как объясняется ссылкой Алекса, вам, вероятно, не хватает заголовка Content-Disposition поверх Content-Type.
Так что-то вроде этого:
Content-Disposition: attachment; filename = "MyFileName.ext"
Думаю должен быть attachment; filename = "MyFileName.ext". См. w3.org/Protocols/rfc2616/rfc2616-sec19.html.
Аналогичная проблема здесь stackoverflow.com/questions/33946612/…