Правильный способ создания водяных знаков, хранения и отображения изображений в PHP

Я создаю веб-систему, которая будет размещать множество изображений высокого разрешения, и они будут доступны для продажи. Конечно, я никогда не буду отображать изображение высокого разрешения, вместо этого при просмотре люди увидят только изображение с низким разрешением и водяными знаками. В настоящее время рабочий процесс выглядит следующим образом:

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

Когда люди просматривают, страница отображает миниатюру изображения, при щелчке она увеличивает и отображает низкое изображение с водяным знаком. В настоящее время я применяю водяной знак на лету, когда открывается низкое изображение.

Мой вопрос, как правильно:

1) Должен ли я сохранить 2-ю копию изображения с низким разрешением с миниатюрой, только при первом доступе к нему? Я имею в виду, что если кто-то получит доступ к изображению, я добавлю водяной знак на лету, затем отобразю изображение и сохраню его на сервере. В следующий раз, когда к копии с водяным знаком будет добавлено то же изображение, просто отобразите копию wm, в противном случае нанесите водяной знак на лету. (в случае изменения watermark.png просто удалите изображения с водяными знаками, и они будут воссозданы при доступе).

2) Должен ли я продолжать наносить водяные знаки на лету, как я делаю сейчас.

Мой самый большой вопрос, насколько велика разница между PHP file_exists()и добавление водяного знака к изображению, что-то вроде:

$image = new Imagick();
$image->readImage($workfolder.$event . DIRECTORY_SEPARATOR . $cat . DIRECTORY_SEPARATOR .$mit);
$watermark = new Imagick();
$watermark->readImage($workfolder.$event . DIRECTORY_SEPARATOR . "hires" . DIRECTORY_SEPARATOR ."WATERMARK.PNG");
$image->compositeImage($watermark, imagick::COMPOSITE_OVER, 0, 0);

Все изображения с низким разрешением имеют размер 1024x1024, JPG с настройкой качества 45%, и все ненужные фильтры удалены, поэтому размер файла изображения с низким разрешением составляет около 40–80 КБ.

Это как-то связано с этим вопросом, просто масштаб и сценарии немного отличаются.

Я работаю на выделенном сервере (Xeon E3-1245v2), 32 ГБ оперативной памяти, 2 ТБ хранилища), сайт не имеет большого трафика в целом, но время от времени имеет ОГРОМНЫЕ скачки. Когда изображения выпускаются, мы получаем несколько тысяч обращений в час, когда люди просматривают изображения, скачивают, покупают и т. Д. Поэтому, при обычном использовании я уверен, что генерация на лету - это правильный подход, я немного волнуюсь о пиковом периоде.

Необходимо отметить, что я использую библиотеку ImageMagick для обработки изображений, а не GD.

Спасибо за ваш вклад.

ОБНОВИТЬ

Ни в одном из ответов нет полного комплексного решения, но это хорошо, так как я никогда не искал этого. Это было трудное решение, кого принять, а кого назначить награду.

Решение @Ambroise-Maupate - это хорошо, но, тем не менее, это работа на PHP.

@Hugo Delsing предлагает использовать веб-сервер для обслуживания кэшированных файлов, уменьшая количество обращений к PHP-сценарию, что будет означать меньшее использование ресурсов, с другой стороны, это не очень удобно для хранения.

Я буду использовать решение смешанного слияния из 2 ответов, передавая задание CRON для удаления мусора.

Спасибо за указания.

4 ответа

Решение

Лично я бы создал поддомен / поддомен без cookie в CDN, чтобы обрабатывать изображения такого типа. Основными причинами являются:

  1. Изображения создаются только один раз
  2. Созданы только доступные изображения
  3. После создания изображение подается из кэша и работает намного быстрее.

Первым шагом будет создание веб-сайта на поддомене, который указывает на пустую папку. Используйте настройки IIS/Apache или что-то еще, чтобы отключить сеансы для этого нового веб-сайта. Также установите несколько длинных заголовков кэширования на сайте, потому что контент не должен меняться

Вторым шагом будет создание .htaccess файл, содержащий следующее.

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)   /create.php?path=$1  [L]

Это гарантирует, что если кто-то получит доступ к существующему изображению, он покажет изображение напрямую без PHP мешая. Каждый несуществующий запрос будет обработан create.php скрипт, который является следующей вещью, которую вы должны добавить.

<?php
function NotFound()
{
    if (!headers_sent()) {
        $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
        header($protocol . ' 404 Not Found');
        echo '<h1>Not Found</h1>';
        exit;
    }
}

$p = $_GET['path'];

//has path
if (strlen($p)<=1)
    NotFound();

$clean = explode('?', $p);
$clean = explode('#', $clean[0]);
$params = explode('/', substr($clean[0], 1)); //drop first /

//I use a check for two, because I dont allow images in the root folder
//I also use the path to determine how it should look
//EG: thumb/125/90/imagecode.jpg
if (count($params)<2)
    NotFound();

$type = $params[0];

//I use the type to handle different methods. For this example I only used the full sized image
//You could use the same to handle thumbnails or cropped/watermarked
switch ($type) {
    //case "crop":if (Crop($params)) return; else break;
    //case "thumb":if (Thumb($params)) return; else break;
    case "image":if (Image($params)) return; else break;
}
NotFound();
?>
<?php
/*
Just some example to show how you could create a responds
Since you already know how to create thumbs, I'm not going into details

Array
(
    [0] => image
    [1] => imagecode.JPG
)
*/
function Image($params) {
    $tmp = explode('.', $params[1]);
    if (count($tmp)!=2)
        return false;

    $code = $tmp[0];


    //WARNING!! SQL INJECTION
    //USE PROPER DB METHODS TO GET REALPATH, THIS IS JUST EXAMPLE
    $query = "SELECT realpath FROM images WHERE Code='".$code."'";
    //exec query here to $row
    $realpath = $row['realpath'];


    $f = file_get_contents($realpath);

    if (strlen($f)<=0)
        return false;

    //create folder structure
    @mkdir($params[0]);

    //if you had more folders, continue creating the structure
    //@mkdir($params[0].'/'.$params[1]);

    //store the image, so a second request won't access this script
    file_put_contents($params[0].'/'.$params[1], $f);

    //you could directly optimize the image for web to make it even better
    //optimizeImage($params[0].'/'.$params[1]);

    //now serve the file to the browser, because even the first request needs to show the image
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    header('Content-Type: '.finfo_file($finfo, $params[0].'/'.$params[1]));

    echo $f;

    return true;
}
?>

Я бы посоветовал вам создавать изображения с водяными знаками на лету и кэшировать их в то же время, что и все.

Затем вы можете создать PHP-скрипт для сборщика мусора, который будет выполняться каждый день (используя cron). Этот скрипт просматривает вашу папку кеша, чтобы прочитать каждый раз доступ к изображению. Это можно сделать с помощью fileatime() PHP метод. Затем, если кэшированное wm- изображение не было доступно в течение 24 или 48 часов, просто удалите его.

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

Этот метод будет работать только в том случае, если на вашем серверном разделе включены временные обновления.

Смотрите http://php.net/manual/en/function.fileatime.php

Для большинства сценариев ленивое применение водяного знака, вероятно, имело бы смысл (генерировать изображение с водяными знаками на лету по запросу и затем кэшировать результат), однако, если у вас есть большие всплески спроса, вы сами создаете механизм для DOS: создайте версию с водяным знаком на загрузить.

Учитывая емкость вашего жесткого диска и количество пиков.

Я бы создал изображение с водяными знаками только в том случае, если оно просматривается (так что да, на лету). Таким образом, вы не используете много места с кучей файлов, которые можно просматривать или не просматривать.

Я бы не стал использовать миниатюры водяных знаков, я бы сделал фильтр, который имитирует водяные знаки и защищает от сохранения. Этот фильтр будет применяться ко всем эскизам без создания второго изображения.

Таким образом, все ваши пиктограммы с водяными знаками (подделка с другим элементом сверху).

Затем, если один из этих эскизов просматривается, он создает изображение с водяным знаком (только один раз), поскольку после его создания вы загружаете новое изображение с водяным знаком.

Это был бы самый эффективный способ справиться с вашим жестким диском и Pikes.

Другой вариант - обновить хостинг. Godaddy предлагает неограниченное хранилище и пропускную способность около 50$ в год.

Другие вопросы по тегам