Лучший способ кэширования измененных изображений с использованием PHP и MySQL
Каким будет наилучший способ обработки кеширования изображений с помощью PHP.
В настоящее время имя файла хранится в базе данных MySQL, которая переименовывается в GUID при загрузке вместе с исходным именем файла и тегом alt.
Когда изображение помещается на страницы HTML, это делается с использованием URL-адреса, например "/images/get/200x200/{guid}.jpg", который переписывается на php script. Это позволяет моим дизайнерам указывать (грубо - исходное изображение может быть меньше) размер файла.
Затем php script создает хэш размера (200x200 в url) и имя файла GUID, и если файл был сгенерирован раньше (файл с именем хэша существует в каталоге TMP) отправляет файл из каталог приложения TMP. Если хэшированное имя файла не существует, оно создается, записывается на диск и подается таким же образом,
Насколько это эффективно? (Он также поддерживает водяные знаки изображений, а настройки водяного знака сохраняются также в хеше, но это выходит за рамки этого).
Ответы
Ответ 1
Существует два опечатка в примере перезаписи Dan Udey (и я не могу прокомментировать его), он должен быть:
RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]
С уважением.
Ответ 2
Я бы сделал это по-другому.
Проблемы:
1. Использование PHP для работы с файлами менее эффективно, чем могло бы быть.
2. PHP должен проверять наличие файлов каждый раз, когда изображение запрашивается
3. Apache намного лучше, чем PHP, когда-либо будет.
Здесь есть несколько решений.
Вы можете использовать mod_rewrite
в Apache. Можно использовать 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>
. Этот script может затем сгенерировать изображение, записать его в кэш и затем отправить его клиенту. В будущем PHP скрипт никогда не вызывается, кроме новых изображений.
Используйте кеширование. Как сказал другой плакат, используйте такие вещи, как mod_expires
, Last-Modified headers и т.д., Чтобы отвечать на условные запросы GET. Если клиенту не нужно повторно запрашивать изображения, загрузка страниц резко возрастет, а загрузка на сервере будет уменьшаться.
В случаях, когда вам нужно отправить изображение с PHP, вы можете использовать mod_xsendfile
для этого с меньшими затратами. См. отличное сообщение в блоге от Арнольда Дэниелса по этому вопросу, но обратите внимание, что его пример предназначен для загрузки. Для обслуживания встроенных изображений выньте заголовок Content-Disposition (третий вызов header()).
Надеюсь, что это поможет - больше после того, как моя мигрень прояснится.
Ответ 3
Следует отметить одно замечание: убедитесь, что код не генерирует "несанкционированные" размеры этих изображений.
Таким образом, следующий URL-адрес создаст версию 1234 с разрешением 200x200, если она еще не существует. Я бы предложил высоко предложить вам убедиться, что запрашиваемый URL-адрес содержит поддерживаемые размеры изображения.
/images/get/200x200/1234.jpg
Злоумышленник может начать запрашивать случайные URL-адреса, всегда изменяя высоту и ширину изображения. Это приведет к тому, что на вашем сервере возникнут серьезные проблемы b/c, которые он будет сидеть там, в основном под атакой, генерируя изображения размеров, которые вы не поддерживаете.
/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
}
?>
Ответ 4
Кажется, большой пост, но моя проблема все еще остается нерешенной. У меня нет доступа к htaccess в моем хост-провайдере, поэтому нет вопроса об настройке apache. Есть ли способ установить заголовок cace-control для изображений?
Ответ 5
Ваш подход кажется вполне разумным - я бы добавил, что должен быть установлен какой-то механизм, чтобы проверить, что дата, когда была создана кешированная версия, была после последней измененной метки времени исходного (исходного) файла изображения и, если не регенерировать кэшированную/измененная версия. Это гарантирует, что если изображение будет изменено дизайнерами, кеш будет соответствующим образом обновлен.
Ответ 6
Это звучит как надежный способ сделать это. Следующим шагом может быть выход за пределы PHP/MySQL.
Возможно, настроить заголовки:
Если вы используете PHP для отправки типов MIME, вы также можете использовать заголовки "Keep-alive" и "Cache-control", чтобы продлить срок службы ваших изображений на сервере и взять часть загрузки PHP/MySQL.
Также рассмотрим плагин apache для кеширования. Как mod_expires.
О, еще одна вещь, сколько у вас контроля над вашим сервером? Должны ли мы ограничивать этот разговор только PHP/MySQL?
Ответ 7
phpThumb - это структура, которая на лету генерирует измененные изображения/эскизы. Он также реализует кеширование и его очень легко реализовать.
Код для изменения размера изображения:
<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&h=200" alt="thumbnail"/>
даст вам миниатюру 200 x 200;
Он также поддерживает водяные знаки.
Проверьте это:
http://phpthumb.sourceforge.net/
Ответ 8
Мне удалось сделать это, просто используя заголовок redirect в 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");
}
Ответ 9
Вместо сохранения адреса файла в db я предпочитаю добавлять случайное число к имени файла всякий раз, когда пользователь входит в систему. Что-то вроде этого для пользователя 1234: image/picture_1234.png? rnd = 6534122341
Если пользователь отправляет новое изображение во время сеанса, я просто обновляю случайное число.
GUID решает проблему с кешем 100%. Однако это делает сложнее отслеживать файлы изображений. Благодаря этому методу пользователь может увидеть то же изображение снова при следующем входе в систему. Однако шансы низкие, если вы генерируете свое случайное число из миллиарда чисел.