6

Resized Image URLs with Kohana 3

Posted (Updated ) in PHP

Have you ever wanted to generate a resized version of an image just using a HTML image tag and not worrying about entering large chunks of resizing code or storing cached images of various sizes? Today’s tutorial will show you exactly how to do that with Kohana 3. In this tutorial I will teach how to use the URL http://www.mysite.com/sized/image/<width>/<height>/<relative image path> to load a dynamically generated, resized image.

The trickiest concept to grasp in this tutorial are the URL segments. Imagine your site was located at http://www.mysite.com and you were browsing to this page http://www.mysite.com/archive/posts/my-post. In this instance, ‘segment 1’ would be archive, segment 2 posts and segment 3 my-post. Segments are split with the / character. In Kohana, URL segments take the following form: controller/method/method_arg_1/method_arg_2/etc. With this in mind, here’s the controller required for the above URL:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Controller_Archive extends Controller {
	public function action_posts( $post_name )
	{
		echo "You are viewing " . $post_name;
	}
}

How is this helpful to us and our resized image URLs? It’s not. Chances are our images won’t be in root directory and may not all be in the same directory as each other. We don’t want to add 50 method arguments in the hope that we capture all subdirectories of the possible image paths so what do we do? Let’s imagine our images were stored in the following folders:

assets/images/apple.jpg
assets/images/cars/honda.png

“But how do I do it!?” I hear you yell at your monitor. The answer lies in Kohana Routes. Routes allow you to override the default routing behaviour. In our case we want to have 3 arguments – width, height and image with the image argument grabbing its own URL segment and every segment thereafter in the URL. Time to begin.

Firstly set up your controller:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Controller_Sized extends Controller {
	public function action_image( $width, $height, $image )
	{
		//Generation code here
	}
}

and add the code to generate the image

<?php defined('SYSPATH') or die('No direct script access.');
 
class Controller_Sized extends Controller {
	public function action_image( $width, $height, $image )
	{
		//Let the browser know we're sending an image
		$filetype = explode('.', $image); $filetype = end($filetype);
		$this->request->headers = array('Content-Type: image/'.$type);
 
		//Send the resized image
		$this->request->response =
			Image::factory( $image )
				->resize($width, $height)->render(NULL, 75);
	}
}

This method extracts the file type from the provided image URL and sends the appropriate image header to the browser before finally sending the resized image using Kohana 3’s Image class. With the easy part out of the way – here’s the real core of this tutorial – the bootstrap route.

Open up your bootstrap file and enter this whopping chunk of code:

Route::set('dynamic_image', 'sized/image/<width>/<height>/<image>', array('image'=>'.+'))->defaults(array(
		'controller' => 'sized',
		'action' => 'image'
	));

That’s it! Wasn’t that easy? Now browse to http://www.mysite.com/sized/image/200/200/assets/images/cars/honda.png and view that 200px square Honda in all it’s glory.

  • Alex

    Hey, thanks for the post.

    If I may suggest some things for this otherwise good post…

    (a) You can use pathinfo($filename, PATHINFO_EXTENSION) to get the file extension natively.

    (b) To use this in a production environment, I think you’ll need to use caching so you don’t keep creating the image. Samsoir has a good module (http://github.com/samsoir/kohana-cache), or just save the image somewhere and check with file_exists() (take into account width and height).

    (c) It wouldn’t be a bad idea to force width and height as digits in your route. Simply add array(‘width’ => ‘\d+’, ‘height’ => ‘\d+’).

    Happy coding!

  • spinicrus

    nice post, although you might add this line, just after you set the headers:
    $this->request->send_headers();
    headers are not sent by default, so you must call send_headers() method for that.

    cheers!

  • Pingback: New Kohana 3 Resources @ Salient Digital Techno Blog()

  • Wiktor

    Hello.
    Unfortunately, above solution is not suitable with kohana 3.1

    It results with blank page (firebug says the response has 0 bytes).

    Any ideas how to solve it ?

    Thanks in advance.
    Wiktor

    • Flynsarmy

      The syntax in 3.1 is a little different. You’ll need to check the API on the Kohana website. The blank page you’re seeing is because there’s a fatal error occurring and you have display_errors turned off in your PHP settings. If you look at your apache error logs you’ll find the error.

  • Scifo

    like that –
    public function action_image() //$width, $height, $image
    {
    $width = $this->request->param(‘width’);
    $height = $this->request->param(‘height’);
    $image = $this->request->param(‘image’);
    $image = ‘.’.$this->config[‘pic_folder’].$image;
    $type = pathinfo($image, PATHINFO_EXTENSION);
    $this->response->headers(‘Content-Type’, ‘image/’.$type);
    $this->response->body(
    Image::factory($image)
    ->resize($width, $height)
    ->render(NULL, 75));
    }