Определение успешной загрузки с использованием php readfile - PullRequest
2 голосов
/ 07 января 2012

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

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

Это касается защиты интеллектуальной собственности, поскольку файлы являются собственностью пользователя, который их загрузил, и мне нужно вести учет того, что именно другие участники загрузили файл, в случае, если они начнут распространяться по Интернету. Но если функция readfile всегда отражает размер файла (то есть эти байты были каким-то образом переданы), я не могу узнать, был ли файл действительно загружен.

Я видел несколько постов на эту тему, но никаких реальных решений о том, что должно быть часто нужно, загружали или нет? Знание того, что они нажали кнопку загрузки, на самом деле не говорит, решили ли они пройти через нее, поскольку диалоговое окно «Сохранить как» позволяет кому-то отменить фактическое завершение загрузки.

Для полноты, вот мой код загрузки вплоть до функции readfile:

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header("Content-Disposition: attachment; filename=$download_name");
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . filesize("sub/$doc_file"));
    ob_clean();
    flush();
    $wasdownloaded = readfile("sub/$doc_file");

Ответы [ 3 ]

1 голос
/ 07 января 2012

Боюсь, что правильный ответ - «Невозможно» - позвольте мне объяснить: возможно, вы сможете правильно определить, когда файл перешел по проводам, но вы не можете точно определить, выбрасывал ли его клиент или нет.

Пример (хронологическая последовательность):

  • Пользователь MSIE нажимает кнопку «Загрузить» и получает диалоговое окно «Сохранить где».
  • Пока этот диалог открыт, загрузка начинается в фоновом режиме.
  • Пользователь перемещается по диалоговому окну или просто ничего не делает (зазвонил телефон, он говорит)
  • Фоновая загрузка завершена, ваш скрипт видит загрузку завершенной
  • Пользователь нажимает «отменить»
  • MSIE удаляет временный файл, загрузка никогда не сохраняется в доступной для пользователя форме

Результат:

  • Пользователь видит файл как "не загруженный" - и он прав
  • Ваше приложение видит файл как "правильно загруженный" - и это правильно
1 голос
/ 07 января 2012

Сначала вам понадобится ignore_user_abort () .

. Это позволит продолжить выполнение вашего сценария после того, как пользователь нажмет на кнопку отмены или выхода.

Затемдолжен print файл и постоянно проверять с помощью connection_aborted () .

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=$download_name");
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize("sub/$doc_file"));
ob_clean();
flush();

$fp=fopen("sub/$doc_file","rb");

while(!feof($fp))
{
    print(fread($fp,1024*8));

    flush();
    ob_flush();
    if( connection_aborted() )
    {
        //do code for handling aborts
    }
}
0 голосов
/ 07 января 2012

Используйте этот комментарий на php.net: http://www.php.net/manual/en/function.fread.php#72716 На fclose вы сможете определить, был ли файл загружен успешно, потому что вы проверяете, прервал ли пользователь соединение с connection_status()

...