Лучший способ кэшировать изображения с измененным размером с помощью PHP и MySQL


Каков наилучший практический способ обработки кэширования изображений с использованием PHP.

Имя файла в настоящее время хранится в базе данных MySQL, которая при загрузке переименовывается в идентификатор GUID вместе с исходным именем файла и тегом alt.

Когда изображение помещается на HTML-страницы, это делается с помощью URL-адреса, такого как '/images/get/200x200/{guid}.jpg, который переписывается в php-скрипт. Это позволяет моим дизайнерам указывать (примерно - исходное изображение может быть меньше) размер файла.

Затем php-скрипт создает хэш размером (200x200 в URL-адресе) и имя файла GUID, и если файл был сгенерирован ранее (файл с именем хэша существует в каталоге TMP), отправляет файл из каталога TMP приложения. Если хэшированное имя файла не существует, то оно создается, записывается на диск и подается таким же образом,

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

Author: Chris Hawes, 2008-09-26

9 answers

В примере переписывания Дэна Удея есть две опечатки (и я не могу это прокомментировать), скорее это должно быть:

RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]

С уважением.

 10
Author: Sensi, 2009-12-29 15:02:58

Я бы сделал это по-другому.

Проблемы: 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>. Этот скрипт может затем сгенерировать изображение, записать его в кэш, а затем отправить клиенту. В будущем PHP-скрипт никогда не вызывается, за исключением новых изображений.

Используйте кэширование. Как другой плакат гласил: используйте такие вещи, как mod_expires, Последние измененные заголовки и т. Д. для ответа на условные запросы GET. Если клиенту не придется повторно запрашивать изображения, загрузка страниц значительно ускорится, а нагрузка на сервер уменьшится.

В случаях, когда вам действительно нужно отправить изображение с PHP, вы можете использовать mod_xsendfile, чтобы сделать это с меньшими затратами. Смотрите отличное сообщение в блоге Арнольда Дэниелса по этому вопросу, но обратите внимание, что его пример предназначен для загрузки. Чтобы подавать изображения встраиваемыми, выньте заголовок Размещения содержимого (третий вызов заголовка()).

Надеюсь, это поможет - больше после того, как моя мигрень пройдет.

 30
Author: Dan Udey, 2010-03-02 22:27:15

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

Таким образом, следующий 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
    }
?>
 5
Author: phatduckk, 2008-09-27 18:12:22

Кажется отличным постом, но моя проблема все еще остается нерешенной. У меня нет доступа к htaccess у моего хост-провайдера, так что о настройке apache не может быть и речи. Есть ли на самом деле способ установить заголовок cace-control для изображений?

 1
Author: , 2009-03-01 23:51:23

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

 0
Author: sgibbons, 2008-09-26 17:22:09

Это звучит как надежный способ сделать это. Следующим шагом может быть выход за рамки PHP/MySQL.

Возможно, измените свои заголовки:

Если вы используете PHP для отправки типов MIME, вы также можете использовать заголовки 'Keep-alive' и 'Cache-control', чтобы продлить срок службы ваших изображений на сервере и снять часть нагрузки с PHP/MySQL.

Кроме того, рассмотрите также плагины apache для кэширования. Как mod_экспирирует.

О, еще одна вещь, насколько ты контролируешь есть над вашим сервером? Должны ли мы ограничить этот разговор только PHP/MySQL?

 0
Author: Pete Karl II, 2008-09-26 17:29:20

Мне удалось сделать это просто с помощью заголовка перенаправления в 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");
}
 0
Author: , 2009-03-05 17:01:28

Вместо сохранения адреса файла в бд я предпочитаю добавлять случайное число к имени файла всякий раз, когда пользователь входит в систему. Что-то вроде этого для пользователя 1234: изображение/picture_1234.png?rnd=6534122341

Если пользователь отправляет новое изображение во время сеанса, я просто обновляю случайное число.

Идентификатор GUID решает проблему кэша на 100%. Однако это в некотором роде затрудняет отслеживание файлов изображений. С помощью этого метода есть вероятность, что пользователь может увидеть ту же картинку снова при следующем входе в систему. Однако шансы невелики, если вы сгенерируете свое случайное число из миллиарда чисел.

 0
Author: Haluk, 2010-04-04 00:18:37

PhpThumb - это фреймворк, который генерирует изображения/миниатюры с измененным размером на лету. Он также реализует кэширование, и его очень легко реализовать.

Код для изменения размера изображения:

<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&amp;h=200" alt="thumbnail"/>

Даст вам миниатюру размером 200 х 200;

Он также поддерживает водяные знаки.

Проверьте это на: http://phpthumb.sourceforge.net/

 0
Author: user18334, 2016-01-22 11:15:11