Отдача изображения с подменой URL
К примеру есть изображение:
http://imgur.com/3vwoV
Адрес к картинке:
http://i.imgur.com/3vwoV.jpg
А картинка лежит на сервере по такому пути:
site.ru/images/2011/09/3vwoV.jpg
Собственно, вопрос:
Как правильно отдавать картинку ?
Как сделал я:
В папке /images/ создал файл .htaccess с таким содержанием:
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .csharp.geshi_code {font-family:monospace;} .csharp.geshi_code .imp {font-weight: bold; color: red;} .csharp.geshi_code .kw1 {color: #0600FF;} .csharp.geshi_code .kw2 {color: #FF8000; font-weight: bold;} .csharp.geshi_code .kw3 {color: #008000;} .csharp.geshi_code .kw4 {color: #FF0000;} .csharp.geshi_code .kw5 {color: #000000;} .csharp.geshi_code .co1 {color: #008080; font-style: italic;} .csharp.geshi_code .co2 {color: #008080;} .csharp.geshi_code .co3 {color: #008080;} .csharp.geshi_code .coMULTI {color: #008080; font-style: italic;} .csharp.geshi_code .es0 {color: #008080; font-weight: bold;} .csharp.geshi_code .es_h {color: #008080; font-weight: bold;} .csharp.geshi_code .br0 {color: #000000;} .csharp.geshi_code .sy0 {color: #008000;} .csharp.geshi_code .st0 {color: #666666;} .csharp.geshi_code .st_h {color: #666666;} .csharp.geshi_code .nu0 {color: #FF0000;} .csharp.geshi_code .me1 {color: #0000FF;} .csharp.geshi_code .me2 {color: #0000FF;} .csharp.geshi_code span.xtra { display:block; }
RewriteRule ^([a-zA-z0-9]{6}).jpg$ show.image.php?&key=$1 [L]
show.image.php
Тут скрипт делает запрос в базу, получает верный путь и отдает картинку через GD (а значит, каждый раз катинка будет генерироваться, подгружаться в память и т.д).
Как можно сделать лучше, не нагружая озу ?
1 ответов
Отдачу картинки естественно лучше сделать без запросов к базе и PHP. Это нагружает сервер.
Но когда нужно сделать запрос к базе и какие-то изменения в картинке есть два способа, как это сделать лучше.
Первый более правильный:
Перед Apache поставить Nginx (вообще он всегда должен стоять перед апачем) и указать, что запросы по определённому url должны складываться в кеш Nginx на несколько часов.
Второй - без правки конфигов веб-сервера:
Пользователь делает запрос к картинке. Если картинка не найдена, то запрос переадресуется к PHP (такое легко делается на mod_rewrite), PHP делает нужные манипуляции с картинкой и создаёт её по нужному адресу. При следующем запросе картинка будет отдаваться напрямую. Но тут большая проблема с тем, что могут сто раз одновременно запросить картинку, когда её нет и она в сто потоков будет пересоздаваться.
И главное помнить, что если нехороший пользователь подставит какие-то символы (например, после вопросильного знака ?example=primer), то картинка всёравно должна браться из кеша.
И ещё. Много встречал сайтов, где при отдаче картинке в url передаётся нужный размер, например example.org/images/100x100/image.png - тут главное не дать пользователю подменять размер. У Вас должен быть список разрешённых рамеров, а то так Вам сервер повесят.
После генерации картинки через GD - сохранить результат в файл и при повторном обращении отдавать уже готовую картинку без ГД. Другое дело в том, что в любом случае, если картинка будет отдаваться через ПХП, то она не будет считаться статикой (а значит на ее отдачу нельзя будет настроить тот же nginx) и будет жраться больше ресурсов. Вообще, такое есть смысл делать только если нужно на 100% запретить доступ к картине (то есть отдельным юзерам разрешаем, а всем остальным запрещаем, в том числе и по прямой ссылке). Но такое не делают даже всякие вконтакте, гугл+ и т.д. То есть ссылку по прямой кратинке всегда можно показать кому угодно.
По поводу GD.
Я так понимаю ты GD используешь чисто чтоб открыть картинку и отобразить ее на экран или все же ресайзишь как-то? Если не ресайзишь или будешь кешироват ресайзенную картинку то лучше заюзать какой-то такой скрипт:
<?
$fullPath = $_SERVER["DOCUMENT_ROOT"]."/test/test.jpg";
if ($fd = fopen ($fullPath, "r")) {
$fsize = filesize($fullPath);
header("Content-type: image/jpg"); // не забываем тут контент тайп менять, если картинка не JPG
header("Content-length: $fsize");
header("Cache-control: private");
while(!feof($fd)) {
$buffer = fread($fd, 2048);
echo $buffer;
}
}
fclose ($fd);
exit;
?>
Т.е. у вас задача изначально подразумевает неудачную архитектуру.
Храните файлы по другому :)