|
|
|
| Доброго времени суток. Вот, пришёл к ВАМ с очередной проблемой, с которой столкнулся только что... Сделать необходимо следующее: "Есть на сервере файлы, которые можно скачать, но доступ к самим файлам (исходным) ограничен (сам файл называться может, ну, допустим, ммм, по id, согласно id в таблице БД)... Т.е. пользователю должен выдаваться с нормальным именем... (Надеюсь меня поймут :) )". Так сказать должна быть разовая ссылка В общем сделать то такое нетрудно:
<?php
header('Content-type: application/pdf');
header('Content-Length: ' . filesize("original.pdf"));
header('Content-Disposition: attachment; filename="downloaded.pdf"');
readfile('original.pdf');
?>
|
, но тогда создаётся проблема с докачкой.
Или же просто-напросто копировать файлы в папки с неопределённым названием (т.е. хэш-код какой-нить). И удалять их через сутки (или меньше)... | |
|
|
|
|
|
|
|
для: Aid
(16.05.2007 в 10:09)
| | Хеши можно хранить в БД, а при обращении к файлу например по ссылке ?id=23&code=ekfjwhfc784fj7tnw93rfhw48 проверять соответствие хеша и ip, ну и конечно через некоторое время удалять запись с хешем из БД. | |
|
|
|
|
|
|
|
для: golovdinov
(16.05.2007 в 14:56)
| | Не, не то... Надо, чтоб пользователи не знали настоящего имени файла... Да, я конечно понимаю, что хэши необходимо хранить в БД, там же и дату создания ссылки... Но вопрос остаётся тот же... Как сделать так, чтоб пользователь не знал настоящего имени файла (т.е. не знал, откуда его можно скачать), но при этом, чтоб мог его закачивать и докачивать :) | |
|
|
|
|
|
|
|
для: Aid
(16.05.2007 в 10:09)
| | Если у вас здоровые файлы и большая посещаемость, то этих временных файлов быстро накопится изрядное количество. Но если это не так, то я бы не стал отдавать файл через скрипт.
Если у вас юниксовый сервер, то можно использовать ссылки на файлы - их-то можно плодить без счета:) | |
|
|
|
|
|
|
|
для: Aid
(16.05.2007 в 10:09)
| | Проблема с докачкой решается генерацией поля заголовка Accept-Ranges: в откликах, обработкой полей Range: в http-запросе и применением связки fopen, fseek,fpassthru вместо readfile | |
|
|
|
|
|
|
|
для: Trianon
(16.05.2007 в 15:57)
| | Да, конечно интересно, но есть небольшое "но"... Клиент при этом должен указать что-либо (может позицию курсора, в файле)? Я пытался посмотреть и GET и POST, но там глухо, как в танке... пусто, клиент ничего не передаёт... Мож подскажешь тогда, как узнать куда fseek'oм переходить? | |
|
|
|
|
|
|
|
для: Aid
(17.05.2007 в 12:35)
| | print_r(getallheaders());
$_SERVER тоже имеет смысл смотреть. | |
|
|
|
|
|
|
|
для: Trianon
(17.05.2007 в 12:44)
| | СПАСИБО!!!
Знаешь, я и не думал, что там всё так просто... Хотя это пока что только Mozilla была при проверке (т.е. FireFox), но докачивает без fseek... Посмотрим на остальные...
и ещё раз СПАСИБО!!! | |
|
|
|
|
|
|
|
для: Aid
(17.05.2007 в 13:14)
| | если у Вас не применяется fseek, значит где-то Вы облажались.... | |
|
|
|
|
|
|
|
для: Trianon
(17.05.2007 в 13:16)
| | стоп... Вы используете $_SERVER['HTTP_RANGE'] ? | |
|
|
|
|
|
|
|
для: Aid
(17.05.2007 в 14:12)
| | Откуда именно вытягивать конкретное поле заголовка запроса - не столь важно.
Можно из getallheaders(), можно из $_SERVER, можно из переменной окружения.
Суть от этого не меняется. fseek при обработке запроса диапазона всё равно необходим. | |
|
|
|
|
|
|
|
для: Trianon
(17.05.2007 в 14:20)
| |
<?php
$tmp = trim($_SERVER['HTTP_RANGE'], "-");
$wr = intval(substr($tmp, 6));
$name = "1.rar";
$fp = fopen($name, 'rb');
header("Accept-Ranges: bytes");
header("Content-Type: application/rar");
header("Content-Length: " . filesize($name));
fseek($fp, $wr);
fpassthru($fp);
?>
|
Здесь что-то не так... А я что именно -- понять не могу... | |
|
|
|
|
|
|
|
для: Aid
(17.05.2007 в 14:21)
| | кошмар.
Боже, какой кошмар.
$tmp = trim($_SERVER['HTTP_RANGE'], "-");
в этом поле указывается ПозицияНачала-ПозицияКонца
Позиция начала - это позиция первого байта, который нужно передать.
Позиция конца - это позиция последнего байта, который нужно передать.
причем и то и другое число может отсутствовать. Отсюда и минус сбоку.
Если отсутствует позиция начала - она равна нулю.
Если отсутствует позиция конца - она равна длине файла без единицы.
Исправляйте это $wr = intval(substr($tmp, 6));
header("Accept-Ranges: acceptable-ranges");
в этом поле никаких acceptable-ranges быть не должно.
Должно быть none , если Вы не умеете обрабатывать диапазонные запросы
либо должно быть bytes, если умеете.
header("Content-Type: application/rar");
header("Content-Length: " . filesize($name));
fseek($fp, $wr);
fpassthru($fp);
кроме того нужно выдавать статус 206 Partial Content и
поле заголовка отклика Content-Range
И вообще: http://zeus.sai.msu.ru:7000/nets/semenov/4/45/http4561.shtml
либо оригинальный RFC по HTTP/1.1... чтоб не соврать RFC-2616....
да. именно он.http://www.faqs.org/rfcs/rfc2616.html | |
|
|
|
|
|
|
|
для: Trianon
(17.05.2007 в 14:37)
| | По-моему мне пора вешаться... :)
Да уж, что-то я смотрю на это всё, как баран на новые ворота... Ну явно не моя тема... На С++ было гораздо проще с этим всем | |
|
|
|
|
|
|
|
для: Trianon
(17.05.2007 в 14:37)
| | как-то не могу сегодня, не взглянув хотя бы на кусочек кода (нормального)... | |
|
|
|
|
|
|
|
для: Trianon
(17.05.2007 в 14:37)
| | Уважаемый, Trianon, не могшли бы Вы дать кусочек кода?
А то, хоть убейте, понять принцип работы не могу... Т.е., не понимаю... Хоть бы глазком на такое взглянуть... | |
|
|
|
|
|
|
|
для: Aid
(21.05.2007 в 13:47)
| | Честно скажу, написано только что, и на одном дыхании, так что корректность не проверял.
Но то, что вспомнил - учел.
<?php
$handle = fopen($fullname, 'rb');
fseek($handle, 0, SEEK_END);
$size = ftell($handle);
if(isset($_SERVER['HTTP_RANGE']))
{
$range = explode('-', $_SERVER['HTTP_RANGE']);
if(!$range[0])$range[0] = 0;
if($range[1]) ++ $range[1];
else $range[1] = $size;
}
else $range = array(0, $size);
if($range[0] < 0) $range[0] = 0;
if($range[1] > $size) $range[1] = $size;
$part_size = $range[1]-$range[0];
$range_start = $range[1];
if($range[0] > 0 || $range[1] < $size)
{
$range_stop = $range[1]-1;
header("206 HTTP/1.0 Partial content");
header("Content-Length: $part_size");
header("Content-Range: bytes $range_start-$range_stop/$size");
}else
header("Content-Length: $size");
header("Accept-Ranges: bytes");
header("Content-Type: application/octet-stream; name=\"$name\"");
header("Content-Disposition: attachment; filename=\"$name\"");
fseek($handle, $range_start, SEEK_SET);
if($arnge[1] == $size)
fpassthru($handle);
else
for($blklen = 16384, $pos = $range_start; $pos < $range[1]; $pos += $buflen)
{
if($range[1]-$pos < $blklen)
$blklen = intval($range[1]-$pos);
$buffer = fread($handle, $blklen);
$buflen = strlen($buffer);
echo $buffer;
}
?>
|
| |
|
|
|
|
|
|
|
для: Trianon
(21.05.2007 в 14:43)
| | Trianon, не сочтите за труд, пожалуйста, прокоментируйте ваш пример, как для новичков. | |
|
|
|
|
|
|
|
для: tAleks
(12.06.2007 в 10:40)
| | Пример расчитан на человека а) прочитавшего разделы 9.2.7, 13.5, 13.36 документа RFC-2616 или его перевода, и б) представляющего, что делают функции explode, ftell, fpassthru.
Кстати, пример, похоже, содержит ошибку.
Ненамеренно, конечно, так получилось.
В ближайшее время попытаюсь её исправить. | |
|
|
|
|
|
|
|
для: Trianon
(12.06.2007 в 15:22)
| | >Пример расчитан на человека
> а) прочитавшего разделы 9.2.7, 13.5, 13.36 документа RFC-2616 или его перевода, и
Дайте пожалуйста ссылку на перевод.
> б) представляющего, что делают функции explode, ftell, fpassthru.
Знаю, только то, что написано о них в мануале.
>Кстати, пример, похоже, содержит ошибку.
>Ненамеренно, конечно, так получилось.
>В ближайшее время попытаюсь её исправить.
Жду. Надо позарез... | |
|
|
|
|
|
|
|
для: tAleks
(12.06.2007 в 19:12)
| | > Дайте пожалуйста ссылку на перевод.
Вам ее уже не раз давали...
Есть и в этой теме, ~10 постов наверх.
("Гипертекстный протокол HTTP") | |
|
|
|
|
|
|
|
для: kasmanaft
(12.06.2007 в 19:21)
| | "Гипертекстный протокол HTTP" и RFC-2616 это одно и то же?
Просто я думал что это разные вещи....
Если нет, тогда спасибо... два раза... :)
Седня целый день его читаю.... :) Голова уже квадратная... :) | |
|
|
|
|
автор: -=|NickK|=- (13.06.2007 в 15:50) |
|
|
для: Trianon
(21.05.2007 в 14:43)
| | На первый взгляд:
- Не совпадают имена переменных с именем файла
- очепятка: if($arnge[1] == $size) | |
|
|
|
|
автор: -=|NickK|=- (13.06.2007 в 15:57) |
|
|
для: Trianon
(21.05.2007 в 14:43)
| | Да, и еще чередование blklen / buflen ) | |
|
|
|
|
|
|
|
для: -=|NickK|=-
(13.06.2007 в 15:57)
| | очепятка - да.
Но не в ней суть.
Касательно blklen/buflen - тут всё чисто.
blklen - размер блока чтения.
buflen - размер прочтенного участка файла. | |
|
|
|
|
автор: -=|NickK|=- (13.06.2007 в 15:59) |
|
|
для: Trianon
(21.05.2007 в 14:43)
| | Чет туплю... Не дочитал до конца... | |
|
|
|