Лучший способ кэшировать изображения с измененным размером с помощью PHP и MySQL
Вопрос
Как лучше всего обрабатывать кэширование изображений с помощью PHP.
Имя файла в настоящее время хранится в базе данных MySQL, которая при загрузке переименовывается в GUID вместе с исходным именем файла и тегом alt.
Когда изображение помещается на HTML-страницы, это делается с использованием URL-адреса, например '/images/get/200x200/{guid}.jpg, который перезаписывается в PHP-скрипт.Это позволяет моим дизайнерам указывать (грубо говоря, исходное изображение может быть меньше) размер файла.
Затем сценарий php создает хэш размера (200x200 в URL-адресе) и имени файла GUID и, если файл был сгенерирован ранее (файл с именем хеша существует в каталоге TMP), отправляет файл из каталога TMP приложения.Если хешированное имя файла не существует, оно создается, записывается на диск и обслуживается таким же образом.
Насколько это эффективно?(Он также поддерживает нанесение водяных знаков на изображения, и настройки водяных знаков также сохраняются в хеше, но это выходит за рамки этого.)
Решение
В примере перезаписи Дэна Уди есть две опечатки (и я не могу это комментировать), скорее должно быть так:
RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]
С уважением.
Другие советы
Я бы сделал это по-другому.
Проблемы:1.Обработка файлов PHP менее эффективна, чем могла бы быть.2.PHP должен проверять наличие файлов каждый раз, когда образуется изображение 3.Apache в этом гораздо лучше, чем когда-либо будет PHP.
Здесь есть несколько решений.
Вы можете использовать mod_rewrite
на Апаче.Можно использовать mod_rewrite, чтобы проверить, существует ли файл, и если да, то вместо этого использовать этот файл.Это полностью обходит PHP и делает работу намного быстрее.Однако реальный способ сделать это — создать определенную схему URL-адресов, которая должна существовать всегда, а затем перенаправить ее на PHP, если она не существует.
Например:
RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]
Итак, если клиент запрашивает /images/cached/<something>
и этот файл еще не существует, Apache перенаправит запрос на /images/generate.php?/images/cached/<something>
.Затем этот скрипт может сгенерировать изображение, записать его в кеш, а затем отправить клиенту.В дальнейшем скрипт PHP никогда не будет вызываться, за исключением новых изображений.
Используйте кэширование.Как сказал другой автор, используйте такие вещи, как mod_expires
, заголовки Last-Modified и т. д.для ответа на условные запросы GET.Если клиенту не придется повторно запрашивать изображения, загрузка страниц резко ускорится, а нагрузка на сервер уменьшится.
В случаях, когда вам нужно отправить изображение с PHP, вы можете использовать mod_xsendfile
сделать это с меньшими накладными расходами.Видеть отличный пост в блоге от Арнольда Дэниелса по этому вопросу, но учтите, что его пример предназначен для скачивания.Чтобы отображать встроенные изображения, удалите заголовок Content-Disposition (третий вызов header()).
Надеюсь, это поможет, особенно после того, как моя мигрень пройдет.
Стоит добавить одно замечание: убедитесь, что ваш код не генерирует «несанкционированные» размеры этих изображений.
Таким образом, следующий URL-адрес создаст версию изображения 1234 размером 200x200, если она еще не существует.Идентификатор высоко Советуем вам убедиться, что запрошенный URL-адрес содержит поддерживаемые вами размеры изображения.
/images/get/200x200/1234.jpg
Злоумышленник может начать запрашивать случайные URL-адреса, всегда изменяя высоту и ширину изображения.Это может вызвать у вашего сервера серьезные проблемы, поскольку он будет находиться там, по сути, под атакой, генерируя изображения размеров, которые вы не поддерживаете.
/images/get/0x1/1234.jpg
/images/get/0x2/1234.jpg
...
/images/get/0x9999999/1234.jpg
/images/get/1x1/1234.jpg
...
etc
Вот случайный фрагмент кода, иллюстрирующий это:
<?php
$pathOnDisk = getImageDiskPath($_SERVER['REQUEST_URI']);
if(file_exists($pathOnDisk)) {
// send header with image mime type
echo file_get_contents($pathOnDisk);
exit;
} else {
$matches = array();
$ok = preg_match(
'/\/images\/get\/(\d+)x(\d+)\/(\w+)\.jpg/',
$_SERVER['REQUEST_URI'], $matches);
if(! $ok) {
// invalid url
handleInvalidRequest();
} else {
list(, $width, $height, $guid) = $matches;
// you should do this!
if(isSupportedSize($width, $height)) {
// size is supported. all good
// generate the resized image, save it & output it
} else {
// invalid size requested!!!
handleInvalidRequest();
}
}
}
// snip
function handleInvalidRequest() {
// do something w/ invalid request
// show a default graphic, log it etc
}
?>
Кажется, отличный пост, но моя проблема все еще остается нерешенной.У меня нет доступа к htaccess у моего хост-провайдера, поэтому не может быть и речи о настройке Apache.Есть ли действительно способ установить заголовок Cace-Control для изображений?
Ваш подход кажется вполне разумным - я бы добавил, что необходимо создать какой-то механизм, чтобы проверить, что дата создания кэшированной версии была после последней измененной временной метки исходного (исходного) файла изображения, и, если нет, восстановить кэшированную/измененную версию. .Это гарантирует, что если дизайнеры изменят изображение, кеш будет обновлен соответствующим образом.
Это звучит как надежный способ сделать это.Следующим шагом может стать выход за рамки PHP/MySQL.
Возможно, настройте свои заголовки:
Если вы используете PHP для отправки типов MIME, вы также можете использовать заголовки «Keep-alive» и «Cache-control», чтобы продлить срок службы ваших изображений на сервере и снять часть нагрузки с PHP/MySQL.
Также рассмотрите плагины Apache для кэширования.Нравиться mod_expires.
И еще: насколько вы контролируете свой сервер?Стоит ли нам ограничить этот разговор только PHP/MySQL?
Мне удалось сделать это, просто используя заголовок перенаправления в PHP:
if (!file_exists($filename)) {
// *** Insert code that generates image ***
// Content type
header('Content-type: image/jpeg');
// Output
readfile($filename);
} else {
// Redirect
$host = $_SERVER['HTTP_HOST'];
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = $filename;
header("Location: http://$host$uri/$extra");
}
Вместо того, чтобы хранить адрес файла в базе данных, я предпочитаю добавлять случайное число к имени файла всякий раз, когда пользователь входит в систему.Что-то вроде этого для пользователя 1234:image/picture_1234.png?rnd=6534122341
Если пользователь отправляет новое изображение во время сеанса, я просто обновляю случайное число.
GUID решает проблему кэша на 100%.Однако из-за этого становится сложнее отслеживать файлы изображений.При использовании этого метода существует вероятность, что пользователь снова увидит ту же картинку при следующем входе в систему.Однако шансы невелики, если вы генерируете случайное число из миллиарда чисел.
phpThumb — это фреймворк, который на лету генерирует изображения/миниатюры с измененным размером.Он также реализует кэширование, и его очень легко реализовать.
Код для изменения размера изображения:
<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&h=200" alt="thumbnail"/>
предоставит вам миниатюру размером 200 х 200;
Он также поддерживает водяные знаки.
Проверьте это по адресу:http://phpthumb.sourceforge.net/