正确的水印方式&存储&用PHP显示图像

时间:2015-01-19 10:50:09

标签: php image server-load

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

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);

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

它与this question有某种关系,只是规模和情景略有不同。

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

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

感谢您的意见。

更新

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

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

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

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

感谢您的指示。

4 个答案:

答案 0 :(得分:5)

我建议您即时创建水印图像,并在每个人建议的同时缓存它们。

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

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

此方法仅在您的服务器分区启用 atime 更新时才有效。

请参阅http://php.net/manual/en/function.fileatime.php

答案 1 :(得分:4)

我个人会在CDN中创建一个静态/无cookie的子域来处理这类图像。主要原因是:

  1. 图片仅创建一次
  2. 仅创建访问的图像
  3. 创建后,图像从缓存中提供,速度更快。
  4. 第一步是在子域上创建一个指向空文件夹的网站。使用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;
    }
    ?>
    

答案 2 :(得分:1)

对于大多数情况,懒洋洋地应用水印可能最有意义(在请求时动态生成带水印的图像然后缓存结果)但是如果你有需求大的尖峰你自己创建一个DOS机制:创建上传水印版本。

答案 3 :(得分:0)

考虑您的HDD存储容量和Pikes。

如果被查看,我只会创建一个带水印的图像。(所以是动态的)这样你就不会在很多空间中使用一堆可能被查看过的文件。

我不会水印缩略图我宁愿制作一个假水印的过滤器,以防止被保存。该过滤器将应用于所有缩略图,而不会创建第二个图像。

通过这种方式,所有的缩略图都会加水印(在顶部使用onther元素伪造)。

然后,如果查看其中一个缩略图,则会生成带水印的图像(仅一次),因为在生成之后,您将加载新的水印图像。

这将是处理硬盘存储和Pikes的最有效方式。

另一种选择是升级您的托管服务。 Godaddy提供无限存储和带宽,每年约50美元。