Я создаю сайт для видеообработки для клиента в облаке RackSpace, используя традиционный стек LAMP (облако RackSpace имеет как стеки Windows, так и LAMP). Видео и другие мультимедийные файлы, которые я обслуживаю на этом сайте, должны быть защищены, так как мой клиент взимает деньги за доступ к ним. У нас нет DRM или смешного бизнеса, в основном мы храним файлы за пределами корня веб-сайта и используем PHP для аутентификации пользователя, прежде чем они смогут получить доступ к файлам с помощью mod_rewrite для запуска запроса через PHP.
Итак, скажем, пользователь запрашивает файл по этому URL-адресу:
http://www.example.com/uploads/preview_image/29.jpg
Я использую mod_rewrite, чтобы переписать этот URL-адрес:
http://www.example.com/files.php?path=%2Fuploads%2Fpreview_image%2F29.jpg
Вот упрощенная версия скрипта files.php:
<?php // Setups the environment and sets $logged_in // This part requires $_SESSION require_once('../../includes/user_config.php'); if (!$logged_in) { // Redirect non-authenticated users header('Location: login.php'); } // This user is authenticated, continue $content_type = "image/jpeg"; // getAbsolutePathForRequestedResource() takes // a Query Parameter called path and uses DB // lookups and some string manipulation to get // an absolute path. This part doesn't have // any bearing on the problem at hand $file_path = getAbsolutePathForRequestedResource($_GET['path']); // At this point $file_path looks something like // this: "/path/to/a/place/outside/the/webroot" if (file_exists($file_path) && !is_dir($file_path)) { header("Content-Type: $content_type"); header('Content-Length: ' . filesize($file_path)); echo file_get_contents($file_path); } else { header('HTTP/1.0 404 Not Found'); header('Status: 404 Not Found'); echo '404 Not Found'; } exit(); ?>
в<?php // Setups the environment and sets $logged_in // This part requires $_SESSION require_once('../../includes/user_config.php'); if (!$logged_in) { // Redirect non-authenticated users header('Location: login.php'); } // This user is authenticated, continue $content_type = "image/jpeg"; // getAbsolutePathForRequestedResource() takes // a Query Parameter called path and uses DB // lookups and some string manipulation to get // an absolute path. This part doesn't have // any bearing on the problem at hand $file_path = getAbsolutePathForRequestedResource($_GET['path']); // At this point $file_path looks something like // this: "/path/to/a/place/outside/the/webroot" if (file_exists($file_path) && !is_dir($file_path)) { header("Content-Type: $content_type"); header('Content-Length: ' . filesize($file_path)); echo file_get_contents($file_path); } else { header('HTTP/1.0 404 Not Found'); header('Status: 404 Not Found'); echo '404 Not Found'; } exit(); ?>
Позвольте мне начать с того, что это прекрасно работает для меня. На местных тестовых машинах это работает как шарм. Однако после его развертывания в облаке он перестает работать. После некоторой отладки выясняется, что если запрос к облаку имеет определенные расширения файлов, такие как .JPG, .PNG или .SWF (т.е. расширения обычно статических файлов мультимедиа.), Запрос направляется в систему кэширования под названием Varnish. Конечным результатом этой маршрутизации является то, что к тому моменту, когда весь этот процесс превратится в мой скрипт PHP, сеанса нет.
Если я изменю расширение в URL-адресе на .PHP, или если я даже добавлю параметр запроса, то Varnish обходит и скрипт PHP может получить сеанс. Нет проблем? Я просто добавлю бессмысленный параметр запроса к моим запросам!
Вот трюк: файлы мультимедиа, которые я обслуживаю через эту систему, запрашиваются через скомпилированные SWF-файлы, которые у меня отсутствуют. Они создаются сторонним программным обеспечением, и я не надеюсь добавить или изменить URL-адреса, которые они запрашивают.
Есть ли другие варианты, которые я имею на это?
Обновление: я должен отметить, что я проверил это поведение с поддержкой RackSpace, и они сказали, что они ничего не могут с этим поделать.
Если запрашивающее флэш-приложение выполняет следующие переадресации, я бы попытался ответить с переадресацией на первый запрос и переписать второй, например
GET .../29.jpg
в
header("Status: 302 Moved temporarily"); header("Location: .../r.php?i=29.jpg&random=872938729348");
Затем ваш r.php доставляет файл по второму запросу.
Если нет (btw. Always), я бы явно отправлял заголовки вместе с доставкой статических файлов, которые Varnish принимает и действует соответственно, что-то вроде
header("Cache-Control: no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0"); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
И: я бы поставил exit();
после первого оператора header()
чтобы убедиться, что остальная часть скрипта не выполнена. header()
отправляет только заголовки.
Я считаю более надежным использование ob_start()
поскольку пробелы в вашем PHP-файле могут приводить к раздражающим ошибкам при добавлении заголовков.
У меня такая же ситуация, и я связался с Rackspace, надеясь на лучший ответ.
Я получил один! Они собрали FAQ, в котором изложено полдюжины способов обойти / изменить кеширование:
http://cloudsites.rackspacecloud.com/index.php/How_can_I_bypass_the_cache%3F