Принудительно скачать с PHP, затем перенаправить - PullRequest
4 голосов
/ 07 апреля 2011

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

Мне нужно найти способ принудительно загрузить файл, а затем, после начала загрузки, перенаправить на страницу «Спасибо за загрузку».

Пока у меня есть:

<?php
ob_start();

$token = $_POST['validationCode'];

if(isset($token)){

    $connect = mysql_connect('localhost', 'root', 'root');
    $db = mysql_select_db('mydb');

    if (!$connect || !$db){
        die('Connect Error (' . mysql_connect_errno() . ') '
                . mysql_connect_error());
    }

    $sql = mysql_query("SELECT * FROM emailaddresses WHERE token='$token'");
    $result = mysql_fetch_array($sql);
    if($result){
        header('Location: complete.php');
        header('Content-type: application/mp3');
        header('Content-Disposition: attachment; filename=track.mp3');
        $f = file_get_contents('downloads/track.mp3');
        print $f;
        $sql = "UPDATE emailaddresses SET download=1 WHERE token='$token'";
        $result = mysql_query($sql);
    }
    else{
        echo "There was a problem downloading the file" . mysql_error();
    }
}

ob_end_flush();

?>

Важно скрыть местоположение загружаемого файла, иначе я бы просто создал HTML-ссылку на файл.

Я, очевидно, не могу поместить заголовок перенаправления ниже других заголовков, поскольку он просто не будет работать. Я действительно не вижу, куда идти, кроме как открыть это во всплывающем окне и направить главное окно на страницу «спасибо», но это ПОСЛЕДНИЙ курорт.

Кто-нибудь может дать какие-нибудь предложения?

Приветствия

Rich

Ответы [ 3 ]

5 голосов
/ 07 апреля 2011
  1. Вы не можете скрыть местоположение файла.Это будет ясно видно любому, кто достаточно определен, чтобы найти его, по той самой причине, что браузеру нужно знать URL для загрузки файла.
  2. Вы не можете сделать это с двумя перенаправлениями заголовка подряд,как вы сказали.Вы можете перенаправить на другую страницу только через некоторое время, используя Javascript.

Выбор действительно невелик.Если ваша основная цель - скрыть URL-адрес, это в любом случае потеряно.Для удобства использования вы все равно обычно указываете на странице простую ссылку ( "Загрузка не начинается? Нажмите здесь ..." ), поскольку пользователь может случайно отменить перенаправлениев неподходящее время, чтобы безвозвратно уничтожить загрузку.


Вы не можете вывести ничего, кроме самого файла, в том же запросе / ответе.Вы можете попробовать составные HTTP-ответы, как предложено @netcoder, но я не совсем уверен, насколько хорошо это поддерживается.Просто начните с предположения, что есть один «потерянный» запрос / ответ, в котором загружается только файл, и больше ничего не происходит.С этим ограничением обычно работают следующие вещи:

  • Пользователь нажимает ссылку «загрузить» или отправляет форму со своим адресом электронной почты или всем, что требуется для запуска процесса загрузки.
  • Сервер возвращает «Благодарим Вас за загрузку от нас! Ваша загрузка начнется в ближайшее время ...» страница.
  • Эта страница содержит Javascript или <meta> refresh или HTTP Refresh headerэто вызывает задержку перенаправления на URL-адрес файла.
  • Страница "Спасибо" будет "перенаправлять" к расположению файла, но так как это вызываетфайл для загрузки, страница не будет видимо изменяться, будет инициирована только загрузка.

Посмотрите на http://download.com пример этого в действии.

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

1 голос
/ 07 апреля 2011

Хорошо, во-первых, браузер должен знать местоположение файла, чтобы загрузить его. Любой, кто откроет стандартный инструмент разработки браузера, такой как Firebug, сможет увидеть в текстовом виде URL-адрес вашего файла.

Теперь, я полагаю, вы хотите защитить свой файл от несанкционированной загрузки. Если это то, что вы хотите, есть способ использовать сеанс.

На первой странице вы разместите свой код, чтобы проверить, разрешена ли загрузка. Затем вы включите текущую сессию с чем-то, что идентифицирует файл Все, что является уникальным для файла, будет делать, например, идентификатор базы данных.

$_SESSION['download_key'] = time();

Затем вы перенаправляете на страницу с html-мета как это

<meta http-equiv="refresh" content="5;/download.php?file=download_key" />

На этой странице вы скажете: «Спасибо, парень, что скачали мой потрясающий файл». Обратите внимание, что вы также можете поместить содержимое атрибута «content» в заголовочный файл, если хотите, например,

header('Refresh: 5;/download.php?file=download_key');

Обратите внимание, что 5 - это число секунд до появления диалогового окна загрузки файла.

Затем на download.php вы сделаете следующее:

1- Проверьте, какой файл был запрошен, используя $ _GET ['file'].

2- Затем вы проверяете, существует ли в сеансе ключ download_key. Если нет, то вы выходите из сценария вот так

if (!isset($_SESSION['download_key'])) die('Unauthorized');

3- Затем вы проверяете, старше ли отметки времени, чем произвольный лимит времени. Здесь с 30 сек

if ($_SESSION['download_key'] - time() > 30) die('Unauthorized');

4- Наконец, если все проверено, вы отправляете файл вот так

header('Content-disposition: attachment; filename=myfile.ext');
header('Content-type: bin/x-file-type'); //Change for the correct mimetype
readfile('myfile.ext');

После чтения файла вы поместите код для установки загрузки в базу данных равной 1.

И это все, защищенная загрузка файлов, и любой, кто использует URL-адрес напрямую, будет встречен большим «неавторизованным» текстом.

Я также хотел бы добавить, что если у вас большой файл (скажем, несколько килобайт), вам лучше отключить буферизацию вывода, так как это будет означать, что php будет хранить копию файла в памяти на весь срок загрузки. С функцией readfile php отправит его в браузер, когда он читает его на диске, и, следовательно, будет использовать меньше памяти (и начнет отправлять данные раньше).

РЕДАКТИРОВАТЬ: Что заставляет его работать следующее

Я фактически перевернул последовательность: посетитель сначала перенаправляется на страницу благодарности, которая содержит заголовок / тег Обновить. Волшебство заголовка Refresh заключается в том, что он перенаправляет ПОСЛЕ загрузки контента. На странице благодарности браузер, увидев этот заголовок, затем ждет указанное время, пока показывает страницу, , а затем перенаправляют на загрузку. После перенаправления браузер видит, что это файл для загрузки, и вместо изменения страницы просто показывает диалог загрузки файла. Как только пользователь нажмет OK, загрузка начнется, но он останется на той же странице.

Короче говоря, вам не нужно перенаправлять после загрузки файла, поскольку вы уже находитесь на странице благодарности! Я не думаю, что это даже возможно перенаправить после загрузки файла. Просто посмотрите, что происходит, когда вы нажимаете на ссылку, которая указывает на прямой файл на веб-сервере. Браузер запрашивает загрузку, но не отключает вашу навигацию. Как только загрузка начнется, вы можете счастливо щелкнуть мышью на странице со ссылкой. К тому времени, когда загрузка закончится, вы можете быть на совершенно другом веб-сайте. Вот почему вы можете только показать страницу благодарности раньше. Но если вы установите ноль для заголовка / тега обновления, приглашение на загрузку появится, как только страница загрузится, так что это почти так, как если бы они были одновременными (на взгляд посетителя)

1 голос
/ 07 апреля 2011

Единственный известный мне в PHP способ (загрузить, а затем перенаправить) - это использовать HTTP-ответ из нескольких частей.Примерно так:

define('MP_BOUNDARY', '--'.sha1(microtime(true)));

header('Content-Type: multipart/x-mixed-replace; boundary="'.MP_BOUNDARY.'"');
flush();

echo "Content-Type: application/zip\r\n";
echo "Content-Disposition: attachment; filename=foo.zip\r\n";
echo "\r\n";
readfile('foo.zip');
echo MP_BOUNDARY;
flush();

echo "Content-Type: text/html\r\n";
echo "\r\n";
echo '<html><script type="text/javascript">location.href="http://www.google.ca";</script></html>';
echo MP_BOUNDARY.'--';
flush();

В вашем случае вы могли бы просто вывести содержимое страницы "Спасибо за загрузку" вместо перенаправления JavaScript.

Я не уверен, работает ли он во всех основных браузерах или нет.

...