Create resized image cache but prevent abuse

2019-04-14 07:51发布

Okay so I have an idea on how I want to serve and cache my images. I don't know if this is the right way to do it but if it is, I'd like to know how to go about preventing abuse.

Situation:

index.php

<img src="images/cache/200x150-picture_001.jpg" />

images/cache/.htaccess

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ images/image.php?f=$1 [L]

The above checks if the image exists, if not it will be rewritten to image.php

image.php PSEUDO code

get height and width from filename

resize and save image to cache folder

serve the image with content-type and readfile.

This way I'm trying to reduce HTTP requests and PHP load with readfiles. The browser gets the image/jpeg if it exists and if not it will be generated.

Eventually all images will be cached and served in the right height and width so browsers won't be downloading oversized images.

The only catch.. if you change the image url to different dimensions, you can fill up the server.

Am I doing it right, what's the right way to do it. Is there any chance of stopping this from happening?

I know this whole concept of caching has been refined a million times, please enlighten me.

4条回答
来,给爷笑一个
2楼-- · 2019-04-14 08:05

I just do:

<img src="/thumbnail.php?thumb=mybigpicture.ext" ... />

And here's how I do it. Note that this implementation scales images whether they're wider than taller or vice-versa, and does a decent job of scaling unlike most PHP attempts.

<?php

function thumb_image($request = "") {
  $cfgthumb['folder'] = "/images/cache";
  $cfgthumb['height'] = 150;
  $cfgthumb['width'] = 200;
  $cfgthumb['error'] = "/images/error.jpg";
  $cfgthumb['default'] = "/images/notfound.jpg";

  $thumb = $cfgthumb['folder'] . "/" . md5($request);
  header("Content-Type: image/jpeg");
  if (is_readable($thumb)) echo file_get_contents($thumb);
  elseif (is_readable($request)) {
    $extension = strtolower(end(explode(".", $request)));
    switch ($extension) {
    case "gif":
      $simage = imagecreatefromgif($request);
      break;
    case "jpeg":
    case "jpg":
      $simage = imagecreatefromjpeg($request);
      break;
    case "png":
      $simage = imagecreatefrompng($request);
      break;
    }
    if ($simage) {
      $simage_width = imagesx($simage);
      $simage_height = imagesy($simage);
      if (($simage_width > $cfgthumb['width']) || ($simage_height > $cfgthumb['height'])) {
        if ($simage_width > $simage_height) {
          $dimage_width = $cfgthumb['width'];
          $dimage_height = floor($simage_height * ($cfgthumb['width'] / $simage_width));
        } else {
          $dimage_width = floor($simage_width * ($cfgthumb['height'] / $simage_height));
          $dimage_height = $cfgthumb['height'];
        }
      } else {
        $dimage_width = $simage_width;
        $dimage_height = $simage_height;
      }
      $dimage = imagecreatetruecolor($dimage_width, $dimage_height);
      imagegammacorrect($simage, 2.2, 1.0);
      imagecopyresampled($dimage, $simage, 0, 0, 0, 0, $dimage_width, $dimage_height, $simage_width, $simage_height);
      imagegammacorrect($dimage, 1.0, 2.2);
      imagejpeg($dimage, $thumb, 100);
      imagejpeg($dimage, NULL, 100);
      imagedestroy($simage);
      imagedestroy($dimage);
    } else echo file_get_contents($cfgthumb['error']);
  } else echo file_get_contents($cfgthumb['default']);
}

?>
查看更多
成全新的幸福
3楼-- · 2019-04-14 08:09

Caching is a distinctly non-trivial issue - your solution seems reasonable, but is indeed open to intentional and unintentional denial of service attacks. It also doesn't address what happens when the image changes - how do you remove all the resized images from the cache? It doesn't set cache headers to allow "downstream" caches. It doesn't deal with the risk of the entire cache being flushed at the same time, requiring all images to be re-generated in the context of an HTTP request, which could be a major performance drain..

Have you looked at "off the shelf" solutions such as Apache's caching module?

查看更多
Rolldiameter
4楼-- · 2019-04-14 08:19

Not sure if I'm not too late with the answer, but why don't you simple use SLIR (Smart Lencioni Image Resizer) for that? It can do whatever you need (include caching and cache management), so you simple drop it in and use.

查看更多
Viruses.
5楼-- · 2019-04-14 08:21

Some approaches:

  • Maintain an array of allowed resolutions, and check whether the requested resolution is in that array. Downside: you can't quickly add a resolution without editing the array.

  • If this is in a CMS context: allow the creation of new images (that are not in the cache yet) only by authenticated users; refuse the request otherwise. When an authenticated user adds an image in the CMS, they preview it, and doing that generates the resized image. Downside: not entirely easy to implement.

查看更多
登录 后发表回答