У меня есть CSV-файл на моем сервере. Если пользователь нажимает на ссылку, он должен загрузиться, но вместо этого он открывается в окне моего браузера.
Мой код выглядит следующим образом:
<a href="files/csv/example/example.csv">
Нажмите здесь, чтобы загрузить пример файла CSV
</a>
Это обычный веб-сервер, на котором хранятся все мои разработки. Теперь содержимое моего файла csv.php:
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=example.csv');
header('Pragma: no-cache');
Теперь моя проблема в том, что он загружает, но не мой CSV-файл. Он создает новый файл. Как решить данную проблему?
Ответ 1
.htaccess решение:
Чтобы перебрать все файлы CSV на вашем сервере для загрузки, добавьте в файл .htaccess:
AddType application/octet-stream csv
Решение PHP:
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=example.csv');
header('Pragma: no-cache');
readfile("/path/to/yourfile.csv");
Ответ 2
Это невозможно сделать надежно, так как браузер должен решить, что делать с URL-адресом, который его попросили получить.
Вы можете сообщить браузеру сразу предложить «сохранить на диск», отправив заголовок Content-disposition:
header("Content-disposition: attachment");
Я не уверен, насколько хорошо это поддерживается различными браузерами. Альтернативой является отправка Content-type of application/octet-stream, но это хак (по сути, вы говорите браузеру:«Я не говорю тебе, что это за файл», и в зависимости от того, что большинство браузеров затем предложит диалог загрузки) и, как утверждается, вызывает проблемы с Internet Explorer. Подробнее об этом читайте в FAQ по веб-авторингу.
Вы уже перешли на PHP-файл для доставки данных — это необходимо для установки заголовка Content-disposition (если только нет каких-то заумных настроек Apache, которые также могут это сделать). Теперь остается, чтобы этот PHP-файл прочитал содержимое CSV-файла — filename=example.csv, и в заголовке нужно указать браузеру, какое имя использовать для файла.
Ответ 3
Вот более безопасное для браузера решение:
$fp = @fopen($yourfile, 'rb');
if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) {
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="yourname.file"');
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: ".filesize($yourfile));
} else {
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="yourname.file"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".filesize($yourfile));
}
fpassthru($fp);
fclose($fp);
Ответ 4
В предыдущем ответе описывается, как использовать .htaccess для принудительной загрузки всех файлов определенного типа. Однако решение не работает со всеми типами файлов во всех браузерах. Вот более надежный способ:
<FilesMatch "\.(?i:csv)$">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
Возможно, вам придется очистить кэш браузера, чтобы убедиться, что это работает правильно.
Ответ 5
Хорошее чистое решение:
<?php
header('Content-Type: application/download');
header('Content-Disposition: attachment; filename="example.csv"');
header("Content-Length: " . filesize("example.csv"));
$fp = fopen("example.csv", "r");
fpassthru($fp);
fclose($fp);
?>
Ответ 6
Если вы делаете это с самим приложением ... Надеюсь, этот код поможет.
HTML
В href — вы должны добавить download_file.php вместе с вашим URL:
<a class="download" href="'/download_file.php?fileSource='+http://www.google.com/logo_small.png" target="_blank" title="YourTitle">
PHP
/* Здесь находится файл Download.php для принудительной загрузки */
<?php
$fullPath = $_GET['fileSource'];
if($fullPath) {
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
switch ($ext) {
case "pdf":
header("Content-Disposition: attachment; filename=\"" . $path_parts["basename"]."\""); // Используйте 'attachment' для принудительной загрузки
header("Content-type: application/pdf"); // Добавьте сюда дополнительные заголовки для различных расширений.
break;
default;
header("Content-type: application/octet-stream");
header("Content-Disposition: filename=\"" . $path_parts["basename"]."\"");
}
if($fsize) { // Проверяем, существует ли размер файла
header("Content-length: $fsize");
}
readfile($fullPath);
exit;
}
?>
Ответ 7
Для принудительной загрузки вы можете использовать заголовок Content-Type: application/force-download, который поддерживается большинством браузеров:
function downloadFile($filePath) {
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
}
Загрузка файлов таким способом — не лучшая идея, особенно для больших файлов. PHP потребует дополнительный процессор/память для чтения и вывода содержимого файла, а при работе с большими файлами может достигнуть ограничений по времени/памяти.
Лучшим способом было бы использовать PHP для аутентификации и предоставления доступа к файлу, а фактическое обслуживание файлов должно быть делегировано веб-серверу с использованием метода X-SENDFILE (требуется определенная конфигурация веб-сервера):
X-SENDFILE изначально поддерживается
Apache требует модуль mod_xsend. В Ubuntu можно установить: apt install libapache2-mod-xsendfile
У Nginx похожий заголовок X-Accel Redirect
После настройки веб-сервера для обработки X-SENDFILE просто замените его readfile($filePath) на header('X-SENDFILE: ' . $filePath),и веб-сервер позаботится об обслуживании файлов, что потребует меньше ресурсов, чем при использовании PHP readfile.
(Для Nginx используйте заголовок X-Accel-Redirect вместо X-SENDFILE)
Примечание. Если вы в конечном итоге загружаете пустые файлы, это означает, что вы не настроили свой веб-сервер для обработки X-SENDFILE заголовков.
Web