Web

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

У меня есть 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

Для laravel требуется расширение Mcrypt PHP

Web

Как использовать PHPMailer для массовой рассылки писем

Web

Tailwind CSS — что это такое и какие возможности он дает?

Web

Как сделать так, чтобы все значения PHP echo попадали в таблицу HTML

×