Как я могу сгенерировать и загрузить файл с одним действием пользователя в PHP? - PullRequest
0 голосов
/ 28 октября 2019

Мое PHP-приложение должно предоставлять моим пользователям одну кнопку, при нажатии которой:

  1. Выполняет функцию, которая генерирует файл .csv и сохраняет его на сервере.
  2. Загружает этот файл в клиент пользователя.
  3. Повторно отображает ту же страницу, на которой находится кнопка.

Для лучшего, что я сделал до сих пор, требуются две кнопки. К вашему сведению, они выглядят так:

enter image description here

Кнопка «Создать файл экспорта» выдает POST, который выполняет функцию генератора файлов. HTML-код для этого:

<form enctype="multipart/form-data" action="season.php?#19" method="POST" name="export_meals_form">
  <input type="hidden" name="export_meals" value="docs/meals.csv">
  <p><input type="submit" value="Generate Export File" />
</form>

Кнопка «Загрузить файл экспорта» на самом деле является ссылкой. Вот код HTML:

<p><a href="docs/meals.csv" download><button type="button">Download Export File</button></a></p>

Если пользователь нажимает эти две кнопки в правильном порядке, все работает нормально. Но нет никаких причин, по которым пользователь должен сделать два клика (и, возможно, ошибиться);эти два действия всегда должны происходить вместе и в таком порядке.

Мне кажется, проблема в том, что я не знаю, как начать загрузку из кода PHP. Единственный способ загрузки, который я нашел, состоит в том, чтобы пользователь щелкнул ссылку с модификатором «download», как указано выше.

Несколько других задали этот вопрос, и обычный ответ выглядит так:использовать функцию PHP readfile (), встроенную в такой код (из Как загрузить файл из базы данных / папки с помощью php ):

    header('Content-Description: File Transfer');
    header('Content-Type: application/force-download');
    header("Content-Disposition: attachment; filename=\"" . basename($name) . "\";");
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($name));
    ob_clean();
    flush();
    readfile("your_file_path/".$name); //showing the path to the server where the file is to be download
    exit;

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

Я думаю, что здесь есть что-то базовое, чего я не понимаю.

Ответы [ 2 ]

0 голосов
/ 31 октября 2019

Спасибо, Расклатт - ваше решение стало прорывом. Сложная часть заключалась в том, чтобы получить код загрузки в нужном месте в последовательности выполнения PHP.

В случае моего последнего кода, который обобщал часть генератора для поддержки запросов на загрузку, отличных от файла "экспорта еды", который былнеотложная необходимость, может быть полезна другим, вот она:

<?php
if($_POST['file_to_download']) {
    // $filepath = "docs/meals.csv";
    $filepath = $_POST['file_to_download'];
    $parameters = $_POST['download_parameters'];
    $season_id = sqlSelect("id", SEASONS_TABLE, "current_season=1","")[0]['id'];

    // Call the generator function (if any)
    switch ($filepath) {
        case MEALS_EXPORT_FILE:
            exportMealsCSV($season_id, $filepath, $parameters);
            break;
    }

    // Put out the file
    // Code from the PHP manual: https://www.php.net/manual/en/function.readfile.php
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($filepath).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($filepath)); 
    readfile($filepath);
    exit;
}
>

PHP, который создает форму, которая делает этот конкретный запрос на загрузку, выглядит следующим образом:

function renderExportMealsForm($season, $action) {
    if (!$season) return;
    $form = '';
    $form .= '<form enctype="multipart/form-data" action="' . makeURI("season.php", PREVIOUS_CRUMBS_IDS, "", EXPORT_MEALS_ID) . '" method="POST" name="export_meals_form">';
        $form .= '<input type="hidden" name="file_to_download" value="' . MEALS_EXPORT_FILE . '">'; 
        $form .= '<input type="hidden" name="download_parameters" value="' . $action . '">'; 
    $form .= '<p><input type="submit" value="Download Export File" />';
    $form .= '</form>';
    if (0) deb("form = " , $form);
    return $form; 
}
0 голосов
/ 28 октября 2019

Вы разместили скрипт, который является производным от руководства (я считаю, что версия руководства является очень надежным примером загрузки) , должно быть вышеhtml любой вашей страницы (или другой вывод из браузера), поэтому пример будет:

<?php
# I would still put session at the top
session_start();

# To create the file, use 
# Make this anywhere above any possible browser output
if(!empty($_POST['action']) && $_POST['action'] == 'export_meals') {
    # I would make the file noted on the php side, not sent by the form
    $file = "docs/meals.csv";
    # This would be the data to save to file
    $data = getDataFromSomePlace();
    # This will save the file to disk–not sure where you get the data...
    file_put_contents($file, $data);
    # Check if the file is really there and can be read
    if(!is_file($file) || !is_readable($file))
        die('File does not exists. Check path again.');
    # Do the default from-the-manual download script
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);
    exit;
}
# Now you can start all your other scripts and html
?><!doctype html>
<html>
...etc
<body>

<form action="season.php" method="POST" id="export_meals_form">
    <!-- I would just make this an "action" name, not the actual file path -->
    <input type="hidden" name="action" value="export_meals" />
    <input type="submit" value="Generate Export File" />
</form>

</body>
</html>

ПРИМЕЧАНИЕ: Я немного изменил вашу форму, а также загрузкусценарий, но если вы делаете это так, он должен работать. На самом деле, я бы создал новую пустую страницу, без стилей или другого пуха, и посмотрел бы, сможете ли вы заставить ее работать только с этими основами. Этот сценарий протестирован и работает, поэтому в случае его сбоя вы неправильно его реализовали или каким-то образом неправильно настроен ваш сервер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...