Mecha CMS

Mecha CMS blog and documentation.

Dynamic Image Resizer with Cache Feature

Updated: Sunday, 07 August 2016

Creating dynamic image resizer via URL path.

Table of Content

Update: The plugin version of this tutorial is now available. This plugin will also store the generated images in the browser’s cache, so it will not affect the hosting quota.

Previously, we have created a dynamic image resizer using the Route method. Now we are going to make it even better by adding ability to cache the thumbnails. It is useful to speed up the image loading process due to the image size that changed dynamically, we need more CPU usage for dynamic images compared to just load the images directly, so it will require more time and more energy in the absence of image caching ability. Here is the route declaration for dynamic image resizer with cache feature:

Route::get('t/(:num)/(:num)/(:num)/(:num)/(:all)', function($x = 0, $y = 0, $width = 0, $height = 0, $path = "") {
    $path = str_replace('/', '__', $path);
    // Use thumbnail cache if available
    if($cache = File::exist(CACHE . DS . $x . '.' . $y . '.' . $width . '.' . $height . '.' . $path)) {
        Image::take($cache)->draw();
    }
    // Otherwise, create the thumbnail cache
    $x = (int) $x;
    $y = (int) $y;
    $width = (int) $width;
    $height = (int) $height;
    if($file = File::exist(ASSET . DS . str_replace('__', DS, $path))) {
        Image::take($file)->crop($x, $y, $width, $height)->draw(CACHE . DS . $x . '.' . $y . '.' . $width . '.' . $height . '.' . $path);
    }
});

Route::get('t/(:num)/(:all)', function($width = 0, $path = "") {
    $path = str_replace('/', '__', $path);
    // Use thumbnail cache if available
    if($cache = File::exist(CACHE . DS . $width . '.' . $path)) {
        Image::take($cache)->draw();
    }
    // Otherwise, create the thumbnail cache
    $width = $height = (int) $width;
    if($file = File::exist(ASSET . DS . str_replace('__', DS, $path))) {
        Image::take($file)->resize($width, $height)->draw(CACHE . DS . $width . '.' . $path);
    }
});

How it Works?

I will explain about how this route works:

Route::get('t/(:num)/(:all)', function($width = 0, $path = "") { … });

First of all, we will check whether the cached image file already exists, if it does, then load the cached image instead:

// Create a valid file name by replacing nested image path with a `__`
$path = str_replace('/', '__', $path);
// Use thumbnail cache if available
if($cache = File::exist(CACHE . DS . $width . '.' . $path)) {
    Image::take($cache)->draw();
}

If not, we will create the image cache using the dynamic image resizer function we created before. The cache file will be stored in the lot\scraps folder:

// Otherwise, create the thumbnail cache
$width = $height = (int) $width;
if($file = File::exist(ASSET . DS . str_replace('__', DS, $path))) {
    // Example file name: `20.my-image.jpg`, `100.path__another-path__my-image.jpg`
    Image::take($file)->resize($width, $height)->draw(CACHE . DS . $width . '.' . $path);
}

Warning!

This route will automatically create image cache via URL if they are not available, so this will allow any visitor to change the image width parameter in the image URL either manually or automatically. There are no limit that can be given, so if there are particular robots or rogue applications want to try to access your thumbnail URL continuously through the URL parameters in different sizes, then the worst possibility is that you will be met with a lot of images cache in your web storage with different sizes. Limiting the allowed image dimensions may be useful for you:

if( ! Mecha::walk(array(300, 600, 1024, 1280))->has($width)) {
    exit('This image dimension is not available.');
}

Or you could also create another function separately which has an ability to remove the cached images automatically within a certain period.

Donation and Email Subscription