Правильный способ создания водяных знаков, хранения и отображения изображений в 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, чтобы обрабатывать изображения такого типа. Основными причинами являются:
- Изображения создаются только один раз
- Созданы только доступные изображения
- После создания изображение подается из кэша и работает намного быстрее.
Первым шагом будет создание веб-сайта на поддомене, который указывает на пустую папку. Используйте настройки 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 часов, просто удалите его.
С помощью этого метода вы можете обрабатывать периоды скачков, поскольку изображения кэшируются при первом запросе. И вы сэкономите место на жестком диске, так как ваш скрипт сборки мусора удалит неиспользуемые изображения для вас.
Этот метод будет работать только в том случае, если на вашем серверном разделе включены временные обновления.
Для большинства сценариев ленивое применение водяного знака, вероятно, имело бы смысл (генерировать изображение с водяными знаками на лету по запросу и затем кэшировать результат), однако, если у вас есть большие всплески спроса, вы сами создаете механизм для DOS: создайте версию с водяным знаком на загрузить.
Учитывая емкость вашего жесткого диска и количество пиков.
Я бы создал изображение с водяными знаками только в том случае, если оно просматривается (так что да, на лету). Таким образом, вы не используете много места с кучей файлов, которые можно просматривать или не просматривать.
Я бы не стал использовать миниатюры водяных знаков, я бы сделал фильтр, который имитирует водяные знаки и защищает от сохранения. Этот фильтр будет применяться ко всем эскизам без создания второго изображения.
Таким образом, все ваши пиктограммы с водяными знаками (подделка с другим элементом сверху).
Затем, если один из этих эскизов просматривается, он создает изображение с водяным знаком (только один раз), поскольку после его создания вы загружаете новое изображение с водяным знаком.
Это был бы самый эффективный способ справиться с вашим жестким диском и Pikes.
Другой вариант - обновить хостинг. Godaddy предлагает неограниченное хранилище и пропускную способность около 50$ в год.