Принуждение загрузить файл с помощью PHP

У меня есть файл CSV на моем сервере. Если пользователь нажимает на ссылку, он должен скачать, но вместо этого он открывается в окне моего браузера.

Мой код выглядит следующим образом

<a href="files/csv/example/example.csv">
    Click here to download an example of the "CSV" file
</a>

Это обычный веб-сервер, на котором у меня есть все мои разработки.

Я попробовал что-то вроде:

<a href="files/csv/example/csv.php">
    Click here to download an example of the "CSV" file
</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

Или вы можете сделать это с помощью HTML5. Просто с

<a href="example.csv" download>download not open it</a>

Ответ 3

Это нельзя сделать надежно, так как это зависит от браузера, чтобы решить, что делать с URL-адресом, который он запрашивал.

Вы можете предложить браузеру, что он должен немедленно предложить "сохранить на диск", отправив заголовок Content-disposition:

header("Content-disposition: attachment");

Я не уверен, насколько это поддерживается различными браузерами. Альтернативой является отправка Content-типа приложения/октетного потока, но это взлом (вы в основном говорите в браузере "Я не говорю вам, что это за файл", и в зависимости от того, что большинство браузеры затем предложит диалог загрузки) и предположительно вызывает проблемы с Internet Explorer.

Подробнее об этом читайте в Часто задаваемые вопросы по веб-авторингу.

Изменить. Вы уже переключились на PHP файл для доставки данных, что необходимо для установки заголовка Content-disposition (если не установлены некоторые тайные настройки Apache, которые также могут это сделать). Теперь все, что осталось сделать, - это то, что этот PHP файл читает содержимое файла CSV и печатает его. filename=example.csv в заголовке только указывает браузеру клиента, какое имя использовать для файла, оно фактически не извлекает данные из файла на сервере.

Ответ 4

Вот более безопасное для браузера решение:

    $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);

Ответ 5

Настройте сервер для отправки файла с типом носителя application/octet-stream.

Ответ 6

Это означает, что ваш браузер может обрабатывать этот тип файла.

Если вам это не нравится, самый простой способ - предложить ZIP файлы. Каждый может работать с файлами ZIP, и они доступны для загрузки по умолчанию.

Ответ 7

Хорошее чистое решение:

<?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);
?>

Ответ 8

Предыдущий ответ на этой странице описывает, как использовать .htaccess, чтобы принудительно загрузить все файлы определенного типа. Однако решение не работает со всеми типами файлов во всех браузерах. Это более надежный способ:

<FilesMatch "\.(?i:csv)$">
  ForceType application/octet-stream
  Header set Content-Disposition attachment
</FilesMatch>

Вам может потребоваться очистить кеш браузера, чтобы убедиться, что он работает правильно.

Ответ 9

Если вы делаете это с самим приложением... Надеюсь, этот код поможет.

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

/* Here is the Download.php file to force download stuff */

<?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"]."\""); // Use 'attachment' to force a download
                header("Content-type: application/pdf"); // Add here more headers for diff. extensions
                break;

            default;
                header("Content-type: application/octet-stream");
                header("Content-Disposition: filename=\"" . $path_parts["basename"]."\"");
        }

        if($fsize) { // Checking if file size exist
            header("Content-length: $fsize");
        }
        readfile($fullPath);
        exit;
    }
?>

Ответ 10

Для принудительной загрузки вы можете использовать заголовок 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 просто замените readfile($filePath) на header('X-SENDFILE: '. $filePath) и веб-сервер позаботится о обслуживании файлов, что потребует меньше ресурсов, чем при использовании PHP- readfile.

(Для Nginx используйте заголовок X-Accel-Redirect вместо X-SENDFILE)

Примечание. Если в итоге вы загружаете пустые файлы, это означает, что вы не настроили свой веб-сервер для обработки заголовка X-SENDFILE. Проверьте ссылки выше, чтобы увидеть, как правильно настроить ваш веб-сервер.