Как разрешить пользователям с необходимым разрешением скачивать файл через php? - PullRequest
6 голосов
/ 10 июня 2010

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

Код, который я использую для передачи файла пользователю:

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-disposition: attachment; filename=\"".$public_filename."\""); 
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: ".$f_filesize); 
readfile($file_path);

Большинство файлов довольно большие .... 400 МБ-10 ГБ.

Что было бы хорошим способом сделать это и сохранить в тайне истинные местоположения + имена файлов, чтобы люди не могли просто ссылаться на файлы напрямую, но ДОЛЖНЫ связываться через мой файл download.php?

Спасибо

РЕДАКТИРОВАТЬ: Я не спрашиваю, как сделать аутентификацию пользователя, все, что сделано.Я просто спрашиваю, является ли мой способ сделать это хорошей идеей в больших масштабах.Похоже, это может вызвать проблемы с памятью, если я продолжу читать файлы 10 ГБ.

Ответы [ 5 ]

10 голосов
/ 10 июня 2010

Хорошо, если php отправлять файлы размером около 400 МБ-10 ГБ, это не хорошо. Вам нужно каким-то образом разрешить любому используемому веб-серверу обслуживать файлы.

Это действительно сводится к тому, насколько безопасным вам это нужно. Самым простым решением, которое приходит на ум (но далеко не самым безопасным), является использование символических ссылок с длинными случайными именами, которые ссылаются на исходный файл. Через некоторое время символические ссылки истекают и удаляются. Каждый пользователь получает свою символическую ссылку (или «токен») на загружаемый файл. Я не уверен, как это работает в Windows-среде, но в Unix все равно довольно просто.

Вот некоторый псевдокод:

if($user->isAllowedToDownload($file)){
    $token = md5($user->name . $file->name . time() . $someGoodRandomValue);
    symlink($file, $download_path . $token);
    header("Location: $download_url$token"); 
}

Тогда вам нужна работа cron, которая очищает старые символические ссылки. Вам также необходимо убедиться, что веб-сервер настроен на переход по символическим ссылкам, желательно только для той папки, где создаются эти токены загрузки.

Поэтому, когда пользователь может запросить domain.com/download?file=bigfile.mp4, в публичном пространстве веб-сервера создается символическая ссылка, которая указывает на реальный файл за пределами публичного пространства веб-сервера. Пользователь перенаправляется на возможно domain.com/getFile/ab739babec890103bdbca72, что, в свою очередь, заставляет веб-сервер обслуживать файл. Теперь пользователям очень сложно угадать, что такое URL для файла, и это «безопасность».

2 голосов
/ 10 июня 2010

Вы уже делаете это - $public_filename - это то, что вам нужно, часть readfile ($ file_path) - это файл, его местоположение не публикуется. В прошлом это могло быть выше корня документа.

1 голос
/ 10 июня 2010

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

Более простое и лучшее решение - использовать тег заголовка "x-sendfile", поддерживаемый как apache, так и lighttpd через их модули.Все, что вам нужно сделать, это просто указать имя файла в заголовке, например:

header('X-Sendfile: filename-on-your-file-system');

Ссылка для lighttpd:

http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file

1 голос
/ 10 июня 2010
  1. Поместите файлы туда, где нет доступа по HTTP.
  2. Создать таблицу базы данных идентификаторов файлов с путями к файлам.
  3. Ссылка на файлы через идентификатор файла (как вы уже отмечали выше, download.php? FileID = 0000).
  4. ???
  5. Profit.

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

1 голос
/ 10 июня 2010

Вы захотите как-то аутентифицировать их (форма HTML, HTTP basic auth , что угодно), затем установить флаг session , который может проверить ваш скрипт download.php Обратите внимание, что это не мешает людям загружать файл, а затем распространять его самостоятельно.

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

Это само по себе не вызовет проблем с памятью. readfile не читает файл в память. Однако использование PHP создаст накладных расходов. Вы можете устранить эту задержку, используя X-Sendfile .

...