Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Закешировать скрипт, создающий изображение на лету
 
 автор: tAleks   (18.01.2011 в 19:37)   письмо автору
 
 

Есть скрипт, который бетер изображение, накладывает на него водяной знак, и выдает. На сколько я понимаю (могу ошибаться) эта процедура достаточно затратная, чтобы каждый раз генерировать изображение на лету. Есть идея, как-то это закешировать. Вопрос как?

Скрипт выглядит так:


<?php
// Скрипт get_file.php

$id_file intval(@$_GET['id_file']);

$wmark 'watermark.png'// Файл с водяным знаком

/*
Метод files::get_image_wmark берет изображение из БД по id_file
Накладывает на него водяной знак средсвтами GD, и выдает в браузер
*/
files::get_image_wmark($id_file$wmark);
?>


Далее, если мне нужно изображение на страице, я делаю так:


<img src="get_file.php?id_file=34" />


И вот, хотелось бы скрипт get_file.php как-то закешировать, чтобы он постоянно одни и те же изображения не создавал снова и снова, а брались эти изображения из кэша.

С кэшами раньше никогда не работал. Прочитал пару статей на эту тему, честно говоря не очень понял.

Подскажите конкретным примером. Буду благодарен.

  Ответить  
 
 автор: psychomc   (18.01.2011 в 20:00)   письмо автору
 
   для: tAleks   (18.01.2011 в 19:37)
 

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

  Ответить  
 
 автор: tAleks   (18.01.2011 в 20:03)   письмо автору
 
   для: psychomc   (18.01.2011 в 20:00)
 

Дело в том, что в БД хранятся файлы БЕЗ водяных знаков. И эти файлы используются на разных проектах, и на наих в разных местах нужно накладывать разные водяные знаки.

  Ответить  
 
 автор: psychomc   (18.01.2011 в 20:06)   письмо автору
 
   для: tAleks   (18.01.2011 в 20:03)
 

что если сделать флаг, уникально идентифицирующий водяной знак? или так не катит?
(может быть я не вник)

  Ответить  
 
 автор: cheops   (18.01.2011 в 20:43)   письмо автору
 
   для: tAleks   (18.01.2011 в 20:03)
 

>Дело в том, что в БД хранятся файлы БЕЗ водяных знаков. И эти файлы используются на разных
>проектах, и на наих в разных местах нужно накладывать разные водяные знаки.
Добавьте пустое поле рядом с тем, которое указывает на файлы без водяных знаков. При первом обращении, пусть скрипт создает изображение и сохраняет к нему путь в этом пустом поле. При следующих обращениях проверяйте состояние поля - если оно заполнено, берите скрипт из кэша (любая папка, куда сохраняются изображения с водяным знаком), если незаполненно, вы будете знать, что это первое обращение.

  Ответить  
 
 автор: tAleks   (18.01.2011 в 21:03)   письмо автору
 
   для: cheops   (18.01.2011 в 20:43)
 

Нет, я бы хотел сделать так, чтобы сгенерированная картинка хранилась в кэше у пользователя, или где-нибудь на промежуточных серверах. Т.е. чтобы когда пользователь по сайту гулял, и заходил дважды на одну и ту же страницу, чтобы ему это изображение не с сайта качалось, а бралось из его кэша, или из кэша промежуточного сервера. Примерно так.

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

  Ответить  
 
 автор: cheops   (18.01.2011 в 21:16)   письмо автору
 
   для: tAleks   (18.01.2011 в 21:03)
 

Заставить пользователя и промежуточные сервера кэшировать данные невозможно, можно им только рекомендовать это, добавив, в META-данные время последнего обновления страницы
<META HTTP-EQUIV="Expires" CONTENT="Tue, 02 Jan 2011 01:00:00 GMT">

Если время не будет меняться, теоретически информация будет извлекаться из кэша (если она там есть). Но сильного эффекта я бы не ожидал.

  Ответить  
 
 автор: tAleks   (18.01.2011 в 21:35)   письмо автору
 
   для: cheops   (18.01.2011 в 21:16)
 

В книге "PHP5 Практика создания WEB-сайтов", на странице 147, есть пример "Управление кэшированием".
И там, пример с посылкой заголовков когда изображение берется из БД.

Если кратко, то такой (Урезан мной, набирать долго не хочется):


// Запрос к БД
$doc = mysql_query("Запрос");

// отпраялвем закголовки
header("Cach-Control: public, must-revalidate");
header("Vari: Content-ID");
header("Content-ID: ".md5(mysql_result($doc, 0, 'docs')));
header("Content-type: ".mysql_result($doc, 0, 'type'));

// Выводим картинку в окно браузера
echo mysql_result($doc, 0, 'docs');



Как я понял, при таких заголовках, если изображение есть в кэше (где либо) то повторный запрос к БД (обращение к этому скрипту) не происходит, изображение просто берется из кэша. Так? Но тогда, как браузер пользователя узнает что изображение обновилось, и его снова нужно запросить с сервера, если оно всегда берется из кэша? Или я че-то не так понял?

Вот хотелось бы разобраться в принципе действия данного метода кэширования. Поясните плиз.

  Ответить  
 
 автор: cheops   (18.01.2011 в 21:57)   письмо автору
 
   для: tAleks   (18.01.2011 в 21:35)
 

Да, если кэш есть в принципе - его может и не быть, только must-revalidate уберите.

  Ответить  
 
 автор: tAleks   (18.01.2011 в 21:58)   письмо автору
 
   для: cheops   (18.01.2011 в 21:57)
 

Поясните, плиз, как это работает? И какой от этого будет эффект, если я эти заголовки пропишу в своем скрипте?

  Ответить  
 
 автор: cheops   (18.01.2011 в 21:59)   письмо автору
 
   для: tAleks   (18.01.2011 в 21:58)
 

По сути тут один HTTP-заголовок, управления кэшем "Cach-Control: public", который всем встречным говорит - кэшируйте, если можете, нечего беспокоить изначальный сервер.

  Ответить  
 
 автор: tAleks   (18.01.2011 в 22:04)   письмо автору
 
   для: cheops   (18.01.2011 в 21:59)
 

А когда изображение на сервере изменится? Как об этом узнают все те, кто закешировали предыдущее изображение?

  Ответить  
 
 автор: cheops   (18.01.2011 в 22:06)   письмо автору
 
   для: tAleks   (18.01.2011 в 22:04)
 

У них стоят свои тайм-лимиты (хотя вы можете сами его рекомендовать при помощи специальных HTTP-заголовков), они обязательно перепроверят через некоторое время, можете сами тайм-лимиты выставлять, или посылать HTTP-заголовок со временем создания документа (в данном случае изображения), поменялся документ - меняйте время создания.

  Ответить  
 
 автор: tAleks   (18.01.2011 в 22:23)   письмо автору
 
   для: cheops   (18.01.2011 в 22:06)
 

Покажите пример, плиз.

И в моем, вышеописанном, случае, какие лучше заголовки послать?

  Ответить  
 
 автор: cheops   (18.01.2011 в 22:39)   письмо автору
 
   для: tAleks   (18.01.2011 в 22:23)
 

Можно поступить следующим образом
// Запрос к БД 
$doc = mysql_query("Запрос"); 

// отпралявем заголовки 
header("Cach-Control: public");
header("Expires: Tue, 18 Jan 2011 01:00:00 GMT");
header("Vari: Content-ID"); 
header("Content-ID: ".md5(mysql_result($doc, 0, 'docs'))); 
header("Content-type: ".mysql_result($doc, 0, 'type')); 

// Выводим картинку в окно браузера 
echo mysql_result($doc, 0, 'docs');

  Ответить  
 
 автор: naxa   (18.01.2011 в 21:37)   письмо автору
 
   для: tAleks   (18.01.2011 в 21:03)
 

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

смысл кэшировать изображение только у одного юзера, а для других по новой её генерировать?

при кэшировании на этом же сервере - у вас место на харде будет заниматься картинками в 2 раза больше, трафика будет потребляться столько же как раньше, а процессорное время и память разгрузите...

чем решение не понравилось? :)

или вам не решение надо, а просто разобраться с кэшированием на стороне клиента? :)

надеяться на то, что у клиента (причём 1-го) что-то закешируется и тем самым это разгрузит сервер - это надеяться на "авось" (имхо)....

  Ответить  
 
 автор: naxa   (18.01.2011 в 20:44)   письмо автору
 
   для: tAleks   (18.01.2011 в 20:03)
 

если скрипты разнесены отдельно по доменам, то на каждом домене создайте папку photwithwmark или типа того, если с разных доменов обращение к одним и тем же скриптам - создаёте либо папку
с началом домена что-то вроде ( str_replace('www.', '', strtolower($_SERVER['HTTP_HOST'])) . photwithwmark )

( либо можно в принципе всё в одну папку скинуть, и префикс на картинки ставить, но лучше по папкам, т.к. если будет много ф-лов в одной папке - я так не люблю :) ).

дальше выбираете имя файла

if ( file_exists( str_replace('www.', '', strtolower($_SERVER['HTTP_HOST'])) . 'photwithwmark/' . $filename ) ) {
    выводите файл    str_replace('www.', '', strtolower($_SERVER['HTTP_HOST'])) . 'photwithwmark/' . $filename;
} else {
   накладываете водяной знак и сохраняете изображение 
   $fp = fopen(str_replace('www.', '', strtolower($_SERVER['HTTP_HOST'])) . 'photwithwmark/' . $filename, 'w' );
    fwrite($fp,  <текст изображение с вотемарком>);
   fclose($fp);
}


ну я бы так бы сделал :)


p.s.
описал не как "Закешировать скрипт", а как закешировать ф-лы с вотемарками ...

  Ответить  
 
 автор: Trianon   (18.01.2011 в 21:48)   письмо автору
 
   для: tAleks   (18.01.2011 в 19:37)
 

Где я?
Кто здесь?
Какая БД?
Вы о чем все?


tests/imgref.php
<?php

  
for($i 0$i 10$i++)
  { 
$j $i.$i.$i.$i;
    
printf("<img src=img/%s.gif >%s</a><br>"$j$j);
  }




tests/img/.htaccess
php_value error_reporting 32767
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteBase /tests/img/
RewriteRule ^([0-9]+).gif$ /tests/imgcreator.php?id=$1 [L]



tests/imgcreator.php

<?php

    $text 
sprintf("%04d", @$_GET['id']);
    
$name "img/$text.gif";

    
$w 40$h 16;
    
$im imagecreate($w$h);
    
$cw imagecolorallocate($im255255255);
    
$cb imagecolorallocate($im000);

    
imagestring($im530$text$cb);

    
imagegif($im$name);
    
$mt filemtime($name);

    
$gmt gmdate("r"$mt);
    
$l fopen("imglog.txt"'a+');
    
fputs($l"nm=$name, gmt=$gmt\r\n");
    
fclose($l);

    
header("Last-Modified: $gmt");
    
header("Content-Type: image/gif");
    
readfile($name);

  Ответить  
 
 автор: tAleks   (18.01.2011 в 21:53)   письмо автору
 
   для: Trianon   (18.01.2011 в 21:48)
 

Что это? Ниче не понял. Буду очень благодарен за коментарии.

  Ответить  
 
 автор: Trianon   (18.01.2011 в 22:00)   письмо автору
 
   для: tAleks   (18.01.2011 в 21:53)
 

Я о том, что кешированием должен заниматься http-сервер (apache), а не php-интерпретатор.
Что если файл уже есть (уже создан php-интерпретатором в процессе обработки некоторого запроса, который был ранее), то на php вообще управление передаваться не должно.

  Ответить  
 
 автор: tAleks   (18.01.2011 в 22:06)   письмо автору
 
   для: Trianon   (18.01.2011 в 22:00)
 

>Я о том, что кешированием должен заниматься http-сервер (apache), а не php-интерпретатор.
>Что если файл уже есть (уже создан php-интерпретатором в процессе обработки некоторого запроса, который был ранее), то на php вообще управление передаваться не должно.

И я примерно так думаю. Вопрос в том, как это реализовать в моем, вышеописанном, случае?

  Ответить  
 
 автор: Trianon   (18.01.2011 в 22:11)   письмо автору
 
   для: tAleks   (18.01.2011 в 22:06)
 

я привел пример.
imgref.php порождает страницу с несколькими картинками.
по запросу картинки apache либо берет уже построенную ранее картинку, либо по условию отсутствия файла через Mod Rewrite сваливается в скрипт imgcreator.php с требованием создать файл с картинкой и выбросить его содержимое в поток браузеру, предварив причитающимися заголовками.

  Ответить  
 
 автор: kosta_in_net   (28.01.2011 в 17:45)   письмо автору
 
   для: tAleks   (18.01.2011 в 22:06)
 

Я вообще считаю, что хранить изображения в базе - извращение. Если нужно иметь несколько вариантов водяных знаков, нужно создать несколько папок в которые складывать рисунки уже с нужными водяными знаками (при загрузке изображения сразу обрабатываются, получая несколько нужных копий).
Вопрос о том, как их кешировать отпадает сам собой. Ведь даже анализ того, есть ли файл и какова его дата - это уже некоторая нагрузка на сервер. А так - файлы заранее созданы. Просто бери и передавай их браузеру

  Ответить  
 
 автор: bab-nike   (30.01.2011 в 01:18)   письмо автору
 
   для: tAleks   (18.01.2011 в 19:37)
 

Сказать честно прочитал только вопрос, понял одно -нужно кешировать изображение....
вот тема, я сделал через htaccess и работает отлично.
http://softtime.ru/forum/read.php?id_forum=2&id_theme=75115&page=1

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования