PHP, X-SendFile: Отправка файла вместе с выводом текста в браузер (через эхо)

Я использую модуль X-SendFile Apache для загрузки больших файлов с сервера. Загрузки работают хорошо. Однако, когда начинается загрузка, мне нужно вывести в браузер какой-то текст, например: «Спасибо за загрузку файла…».

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

Пожалуйста, как выполнить обе задачи в одном php-скрипте - загрузку файла и отправку текстового содержимого в браузер/веб-страницу? Проблема, вероятно, возникает в выходных заголовках HTTP, но я не знаю, как ее решить.

Это пример кода, который я использую для загрузки файлов через X-SendFile (работает правильно сам по себе):

                header('Content-Description: File Transfer');
                header("Content-Disposition: attachment; filename=\"". basename($filePath) . "\"");
                header('Content-Transfer-Encoding: binary');
                header('Expires: 0');
                header('Cache-Control: no-store, no-cache, must-revalidate');
                header('Pragma: no-cache');
                header('Content-Length: ' . filesize($filePath));
                header("X-Sendfile: $filePath");

Для завершения, это моя тестовая строка echo"". Если он размещен над кодом X-Sendfile, он выводится, но загрузка не начинается. Если он указан ниже кода X-Sendfile, файл загружается, но ничего не отображается в браузере:

echo "SUCCESS!!!";
ob_flush();

Ограничение:

Мне нужно иметь возможность легко загрузить файл через URL. Пример, www.mydomain.com/?fileID=asl523n53twteHLfga. Другими словами, скрипт загрузки PHP находится в пределах index.php. Когда пользователь вводит www.mydomain.com, отображается целевая страница домена. Однако при передаче дополнительной переменной $_GET скрипт PHP распознает это и должен отображать Спасибо за загрузку... вместо целевой страницы.

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


person Bunkai.Satori    schedule 27.11.2013    source источник
comment
Невозможно. Многокомпонентность HTTP вообще не поддерживается (или поддерживается хорошо) большинством браузеров. ответ обычно состоит из ОДНОГО потока данных. большинство людей обходятся, открывая промежуточную страницу с благодарностью, а затем мета-обновление, указывающее на реальную ссылку для скачивания.   -  person Marc B    schedule 27.11.2013
comment
Марк Б., спасибо за ответ. Я понимаю, что вы имеете в виду. Это необходимое выполнимое решение. Я подожду, чтобы собрать еще несколько ответов, и если не будет ничего лучше, я пойду в указанном вами направлении. Спасибо и +1.   -  person Bunkai.Satori    schedule 27.11.2013


Ответы (2)


Как насчет того, чтобы добавить отдельную страницу загрузки, которая будет загружать файл (например, download.php?fileID=XYZ), и чтобы на вашей странице индекса отображалось следующее сообщение:

<?php

function homeScreen() {
  // your home content
}

function downloadFileScreen ($id) {
?>
<h2>Thank you for your download!</h2>
Your download should start automatically, if it does not, click 
<a href="download.php?fileID=<?php print $id; ?>">here</a>
<script type="text/javascript">
window.setTimeout('location.href="download.php?fileID=<?php print $id; ?>"',3000);
</script>
<?php
}

if (isset($_GET['fileID'])) {
  $id= $_GET['fileID'];
  downloadFileScreen ($id);
?>
} else {
  // no ID passed, show home screen
  homeScreen();
}
?>

Я не слышал ни о каком браузере, поддерживающем смешивание загрузки и отображения HTTP-контента в одном запросе, но я посмотрю, можно ли этого добиться с помощью ob_start() и ob_flush().

person SaschaM78    schedule 27.11.2013
comment
Привет, Саша, я реализовал твое решение (так, как это работает только для меня), и оно работает хорошо. Позвольте мне поблагодарить вас за ваш ответ и отметить его как принятый ответ. Спасибо. - person Bunkai.Satori; 28.11.2013
comment
Большое спасибо, рад, что это может помочь вам начать! - person SaschaM78; 28.11.2013

Есть обходной путь. Вы можете создать iframe, внутри которого загрузите файл. Подробности смотрите в коде.

Страница благодарности: (например, www.mydomain.com/?fileID=asl523n53twteHLfga)

<p>Thank you!</p>
<?php
$fileID = $_REQUEST['fileID'];
// csrf code individual for visitor, so visitor can's send direct link to friend
$csrf = md5(uniqid(rand(), true));
$_SESSION['csrf'] = $csrf;
// with iframe file will be downloaded 'in background'
echo '<iframe src="downloadFile.php?fileID=' . urlencode($fileID) . '&csrf=' . urlencode($csrf) . '" width="0" height="0"></iframe>';
?>

downloadFile.php (например, www.mydomain.com/downloadFile.php?fileID=asl523n53twteHLfga)

<?php
$fileID = $_REQUEST['fileID'];
if ($_REQUEST['csrf'] == $_SESSION['csrf'])
{
    // download file
    header('Content-Description: File Transfer');
    header("Content-Disposition: attachment; filename=\"". basename($filePath) . "\"");
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('Pragma: no-cache');
    header('Content-Length: ' . filesize($filePath));
    header("X-Sendfile: $filePath");
    die();
}
else
{
    // csrf from request not equal csrf saved in session, so probably this is direct link to file received from other user
    // redirect to 'thank you' page
    header('Location: /?fileID=' . urlencode($fileID));
    die();
}
?>
person Dador    schedule 27.11.2013
comment
Привет и спасибо за ваш ответ. Ваш ответ содержит отличный пример, я считаю, что он будет работать идеально. Приведенное выше решение от Sascha — еще один отличный пример. Я попробовал решение Саши, и оно сработало для меня хорошо. Поскольку я должен принять решение, какой ответ я отмечу как принятый ответ, я решу за Сашу, так как его ответ я фактически реализовал. Я дам вам +1 за ваш отличный совет. Спасибо. - person Bunkai.Satori; 28.11.2013