在PHP中使用水印和存储以及显示图像的正确方法

Emi*_*oni 4 php image server-load

我正在构建一个基于Web的系统,它将承载高负荷图像的负载和负载,并且它们将可供出售.当然我永远不会显示高分辨率图像,而是在浏览时人们只能看到低分辨率的水印图像.目前的工作流程如下:

PHP脚本处理高图像上传,当图像上传时,它会自动调整为低分辨率图像和缩略图图像,并且两个文件都保存在服务器上(不添加水印).

当人们浏览时,页面显示图像的缩略图,点击时,它会放大并显示带有水印的低图像.目前,每当打开低位图像时,我都会动态应用水印.

我的问题是,正确的方法是什么:

1)我是否应该使用缩略图保存低级图像的第二个副本,只有在第一次访问时?我的意思是如果有人访问图像,我会动态添加水印,然后显示图像并将其存储在服务器上.如果存在水印副本,则下次访问相同图像时只显示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);
Run Code Online (Sandbox Code Playgroud)

所有低图像都是1024x1024,JPG,质量设置为45%,并且删除了所有不必要的滤镜,因此低图像的文件大小约为40Kb-80Kb.

它在某种程度上与这个问题有关,只是规模和情景有点不同.

我在专用服务器(Xeon E3-1245v2)cpu,32 GB RAM,2 TB存储),该网站整体流量不大,但它不时有巨大的峰值.当图像发布时,我们每小时可以获得几千次点击,人们可以通过图像浏览,下载,购买等等.因此,在正常使用情况下,我确信即时生成是正确的方法,我有点担心关于穗期.

需要提一下,我正在使用ImageMagick库进行图像处理,而不是GD.

感谢您的输入.

UPDATE

没有一个完整的完整解决方案的答案,但这是好的,因为我从来没有寻找过.这是一个艰难的决定,哪一个接受谁和谁给予赏金.

@ Ambroise-Maupate解决方案很好,但它继续在PHP上完成这项工作.

@Hugo Delsing建议使用Web服务器来提供缓存文件,降低对PHP脚本的调用,这意味着使用更少的资源,另一方面,它不是真正的存储友好.

我将使用2个答案的混合合并解决方案,转发CRON作业以删除垃圾.

谢谢你的指示.

小智 5

我建议你在飞行中创建水印图像,并在每个人建议的同时缓存它们.

然后你可以创建一个垃圾收集器 PHP脚本,每天都会执行(使用cron).此脚本将浏览您的缓存文件夹以读取每个图像访问时间.这可以使用fileatime()PHP方法完成.然后,当在24或48小时内未访问缓存的wm图像时,只需将其删除即可.

使用此方法,您可以处理峰值周期,因为图像在第一次请求时被缓存.并且您将节省您的硬盘空间,因为您的垃圾收集器脚本将为您删除未使用的图像.

仅当您的服务器分区启用了atime更新时,此方法才有效.

http://php.net/manual/en/function.fileatime.php


Hug*_*ing 5

我个人将以CDN类创建静态/无cookie子域来处理此类图像。主要原因是:

  1. 图像仅创建一次
  2. 仅创建访问的图像
  3. 创建后,就可以从缓存中提供图片,并且速度更快。

第一步是在一个指向空文件夹的子域上创建一个网站。使用IIS / Apache的设置或禁用此新网站的会话的设置。还要在网站上设置一些长缓存标题,因为内容不应更改

第二步是创建一个.htaccess包含以下内容的文件。

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

这将确保如果有人访问现有图像,它将直接显示图像而不会产生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;
}
?>
Run Code Online (Sandbox Code Playgroud)