
Теперь рассмотрим второй вариант решения задачи.
И, прежде всего, разберем взаимодействие между посетителем, сервером и PHP скриптом в этом случае.
Сравните его с предыдущим способом решения. С первого взгляда видно, что этот при этом варианте обращений к PHP будет гораздо меньше, т.к. всю работу по проверке прав доступа к файлу мы переложили на Apache.
Чтобы скачать файл, как и в предыдущем случае, посетителю нужно зайти на сайт, выбирать файл и ввести captcha. После этого PHP скрипт создает запись в специальном файле (templinks.txt), в которой указываются:
1) IP адрес посетителя;
2) имя файла, который он хочет скачать;
3) время окончания действия этой записи (т.е. время до которого разрешается скачивание).
Примечание. В отличие от предыдущего варианта сейчас мы используем текстовый файл, а не БД, для хранения данных о загрузках посетителей. Дело в том, что mod_rewrite может работать с текстовым файлом без использования дополнительных скриптов, а с БД – нет.
Если кто-то обратиться к файлу напрямую (без ввода captcha), а сервер не найдет в файле templinks.txt
записи для этого посетителя, то, как и в предыдущем случае, к запросу будет добавлен index.php
, и вместо файла посетитель получит страницу с 404-ой ошибкой.
Теперь посмотрим, как рассказать серверу, как проверять запросы к файлам.
Для этого открываем файл httpd.conf и добавляем в него следующие настройки.
<IfModule mod_rewrite.c> # загружаем файл со списком временных ссылок # ключ в массиве - ip_ссылка, значение - название файла и время жизни ссылки RewriteMap temp-links "txt:/your_path/templinks.txt" </IfModule>
Здесь у нас только одна директива – RewriteMap
. Именно она читает данные из файла templinks.txt
и помещает их в ассоциативный массив temp-links
.
Примечание. К сожалению, директиву RewriteMap
нельзя размещать в файлах .htaccess
, поэтому доступ к конфигу сервера обязателен.
Я сразу хочу отметить, что mod_rewrite очень чувствителен к ошибкам, поэтому будьте особенно внимательны когда записываете директивы.
Переходим к формату записей в файле templinks.txt.
Напомню, для каждой загрузки нам нужно хранить три значения: IP адрес посетителя, название файла и время окончания доступа к нему. Но mod_rewrite требует, чтобы каждая строка состояла из двух слов, разделенных пробелом.
Первое слово используется в качестве ключа ассоциативного массива (temp-links
), второе – в качестве значения.
Поэтому я решил использовать следующий формат:
IPадрес-ИмяФайла Дата
Например, запись:
127.0.0.1-file4.txt 20090111234431
означает, что посетитель с IP адресом 127.0.0.1 может скачивать файл file4.txt до 23:44:31 11 января 2009 года.
Теперь в корне сайта создаем .htaccess с такими директивами.
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase /path_to_site/ # если не найдена запись для данного посетителя и файла (IP-ИмяФайла) RewriteCond ${temp-links:%{REMOTE_ADDR}-$2|DENIED} =DENIED [OR] # или время работы этой записи закончилось # (время в формате ГодМесяцДеньЧасыМинутыСекунды (например, 20090111213503)) RewriteCond ${temp-links:%{REMOTE_ADDR}-$2|0} <${TIME} # и если это не запрос к статическому файлу сайта (картинки, css и т.п., естественно, archive сюда не входит) RewriteCond $1/$2 !^(index\.php|images|robots\.txt|css) # перенаправляем запрос RewriteRule ^(.*)/([a-zA-Z0-9-_.]+)$ index.php/$1/$2 [L] </IfModule> <IfModule !mod_rewrite.c> ErrorDocument 404 /index.php </IfModule>
Это, наверное, самая сложная часть 😉
С помощью директив RewriteCond
(строки 6 и 10) мы определяем есть ли подходящая запись в массиве temp-links
для данного запроса или нет. Разберем их по частям.
Выражение
${temp-links:%{REMOTE_ADDR}-$2|DENIED}
обрабатывается следующим образом.
1) Получаем IP адрес (%{REMOTE_ADDR}
).
2) Добавляем к нему дефис и вторую часть адреса $2. Это интересный момент. Директивы RewriteCond
не существуют сами по себе, они всегда связаны с RewriteRule
(строка 16), в которой мы разбираем адрес с помощью регулярного выражения. Т.е. $2 соответствует второй подмаске этого выражения (тому что находится во второй паре круглых скобок).
3) С помощью полученного ключа (IPадрес-ИмяФайла) ищем подходящее значение в массиве temp-links
.
4) Если значение с таким ключем отсутствует в массиве, то будет использовано DENIED
.
Вторая директива RewriteCond
выполняет проверку времени. Ключ массива составляется точно так же как и в предыдущем случае, но в качестве значения по-умолчанию используется не DENIED
, а ноль. Значение найденного элемента в массиве сравнивается с текущим временем.
Если доступ к файлу на данный момент разрешен, то директива RewriteRule
не выполняется и посетитель получает нужный ему файл.
В противном случае в начало запроса добавляем index.php
и таким образом управление передается движку CodeIgniter.
Теперь посмотрим какие изменения нужно сделать в движке сайта.
Как вы понимаете, благодаря тому, что проверками и передачей файлов теперь занимается web сервер, наш сайт немного упрощается.
Нам нужны выполнить только три операции:
1) создать страницу с общим списком файлов;
2) добавить форму с captcha;
3) если captcha заполнена правильно, то добавить запись в файл templinks.txt
.
Я не вижу смысла приводить здесь код контроллера. Он остался практически без изменений, только убраны методы download
и _sendFile
. Да и в любом случае, вы можете скачать архив с примером.
А вот код модели изменился более существенно. Теперь мы работаем с текстовым файлом, а не базой данных, да и метод checkFileLink
уже не нужен.
class MFileLink extends Model { function MFileLink() { parent::Model(); } /** * Создает временную ссылку и добавляет ее в текстовый файл * * @param $fileName - имя файла * @return ссылку, если она создана, false - если возникла ошибка */ function createLink($fileName) { $userIP = $_SERVER['REMOTE_ADDR']; //проверяем существование файла if (!get_file_info($this->config->item('filesdir').'/'.$fileName)) { return false; } if (write_file('templinks.txt', $userIP.'-'.$fileName.' ' .date('YmdHis', time() + $this->config->item('linktime')).PHP_EOL, 'a')) { return 'archive/'.$fileName; } else { return false; } } }
Удаление устаревших ссылок и записей.
Думаю, очевидно, что если нашим сайтом будут активно пользоваться, то количество записей со временными ссылками будет быстро расти. Причем основная их масса будет просто занимать место и тормозить работу сайта. Поэтому все устаревшие записи нужно периодически удалять.
Эту операцию лучше всего сделать с помощью отдельного скрипта, который будет запускаться планировщиком.
Приводить его код я здесь не буду, статья и так получилась довольно объемной. К тому же, я уверен, что вы без особого труда и сами сможете его написать 😉
Скачать:
1) Архив с первым вариантом (отправка файлов PHP скриптом).
2) Архив со вторым вариантом (отправка с помощью Apache).
Примечание. Я хочу подчеркнуть, что эту статью нельзя рассматривать как руководство для создания сервисов файлового хостинга (file share). Т.к. остались не рассмотренными вопросы вроде распределения нагрузки между серверами, да и сам Apache потребляет довольно много ресурсов (связка nginx + Apache скорее всего будет более удачным выбором для такого сервиса).
Если вы заметили ошибку, хотите рассказать о других вариантах решения задачи или просто высказаться, не стесняйтесь, комментарии открыты 😉
Интересно почитать
Интернет-магазин предлагает множество уникальных сортов чая продажа чая.
Не с чем идти на день рожденья? Плюшевые игрушки идеально подойдут любому ребенку в качестве подарка.
Что выбрать: платный хостинг или бесплатный? Все просто, в первом случае – хостинг будет действительно ваш.