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

StackOverflow https://stackoverflow.com/questions/140734

  •  02-07-2019
  •  | 
  •  

Вопрос

Как лучше всего обрабатывать кэширование изображений с помощью 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&amp;h=200" alt="thumbnail"/>

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

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

Проверьте это по адресу:http://phpthumb.sourceforge.net/

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top