Лучший способ кэширования измененных изображений с использованием 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&amp;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%. Однако это делает сложнее отслеживать файлы изображений. Благодаря этому методу пользователь может увидеть то же изображение снова при следующем входе в систему. Однако шансы низкие, если вы генерируете свое случайное число из миллиарда чисел.