Archive

Posts Tagged ‘cache’

A Simple Introduction To Zend_Cache

April 2nd, 2009 No comments

The Zend_Cache class is part of the Zend Framework and is used (as its name suggests) to cache things. This can be anything from the front end browser output to the outcome of a complex calculation or even the results of database queries. Zend_Cache is an enormous topic, not just how the class works, but what the best practices are for caching.

The best place to start with caching is one of the simpler topics of caching database queries. Normally, a call to a database table in Zend Framework might be done like this.

$houses    = new Houses();
$result      = $houses->fetchAll();

The result would then be processed. To use Zend_Cache instead of calling the database we first need to set up our Zend_Cache object so that we can use it. To do this we need to call the Zend_Cache static function factory() with a few parameters, which will give us a cache object. Here is a typical example.

$query_cache = Zend_Cache::factory('Core', 'File', $frontendoptions, $backendoptions);

The parameters are as follows:

  • 'Core' – This can be a number of different options which dictate what sort of things are cached on the frontend, the value here is mapped to a class. In this case the class is Zend_Cache_Core, but other classes are mapped to Zend_Cache_Frontend_*. The Zend_Cache_Core class is best used for database calls because there is no specific frontend class that deals with database calls.
  • 'File' – This indicates where the cache is to be stored in the backend. Again this value maps to a class, in this case Zend_Cache_Backend_File. In most cases the Zend_Cache_Backend_File class is the simplest and easiest option to use.
  • $frontendoptions – This is an array of options that relates to the frontend class you have chosen.
  • $backendoptions – This is an array of options that relates to the backend class you have chosen.

The following code sets up an instance of Zend_Cache using some common parameters. Note that different frontend and backend classes have a different set of parameters, but the parameters used below are for the Core frontend and the File backend. The APPLICATION_PATH constant just points to our application folder.

$frontendoptions = array(
    'lifetime' => 60 * 5, // 5minutes
    'automatic_serialization'=>true
);
$backendoptions = array(
    'cache_dir'=> APPLICATION_PATH . '/cache/',
    'file_name_prefix' => 'zend_cache_query',
    'hashed_directory_level' => 2
);
$query_cache = Zend_Cache::factory('Core', 'File', $frontendoptions, $backendoptions);

Here is an explanation of the frontend options used.

  • lifetime – This is self explanatory. If the cache created is greater than the number of seconds for this parameter then the cache is deleted. This can be set to null if we wan’t the cache to last forever.
  • automatic_serialization – If set to true this will automatically serialise the cache data. This allows you to store complex data like objects and arrays. If you are storing a numeric value or text string only then you can set this to false.

Here is an explanation of the backend options used.

  • cache_dir – This is the directory that the cache is to be kept in. The default to this is /tmp/ but it is best to keep the cache within the application folder so that you can manage the files manually if need be.
  • file_name_prefix – This sets the start of the filename to be used, because I want to cache database queries I have selected zend_cache_query as my prefix.
  • hashed_directory_level – Some file systems have great difficulty handling lots of files in a single directory. This option splits the cache into different levels or directories. The default is 0, but for this example I have selected 2. This means that our cache files will be stored inside 2 levels of directories.

To load a cache we use the load() function. This function takes a parameter that identifies the cache, but because we are getting all data from the houses table we don’t need to worry too much about this. If there is no cache with that name present then the function returns false. If this occurs we run our normal database query but in each case the $result variable will contain our data.

if ( !($result = $query_cache->load('allhouses')) ) {
    $houses    = new Houses();
    $result      = $houses->fetchAll();
    $query_cache->save($result, 'allhouses');
}

Once we have run the normal query we save the result to the cache using the save() function. This contains the data we want to save in the first parameter and the same cache name as the load() function in the second parameter. The next time the page is loaded the cache is loaded instead of calling the database.

We can also cache single data rows in the same way by using a unique identifier for our cache name. Assuming that have our house id we can do the following:

$cacheName = 'house'.$id;
if ( !($result = $query_cache->load($cacheName )) ) {
    $houses    = new Houses();
    $result      = $houses->fetchRow($houses->select()->where('id = ?', $id));
    $query_cache->save($result, $cacheName );
}

Note that if you want to do anything more than display the results of the query then you will need to access the database directly. It is not possible to interact with a database through the cached object.

Google Ajax Libraries

March 13th, 2009 No comments

Strictly speaking the Google Ajax libraries don’t contain only Ajax libraries, but they are very useful for a variety of reasons. Google host a variety of different JavaScript libraries which you can link to on your pages rather than download the library and host it on your server. You can use MooTools, JQuery, Prototype/Scriptaculous, Dojo and even the Yahoo! User Interface Library.

How To Use Them

Using the Google Ajax libraries on your own site is quite easy, and you can do it in a number of different ways.

Normally, you would download the latest and greatest version of your chosen library and upload it to your site. Here is an example using the MooTools.

<script type='text/javascript' src='http://www.talkincode.com/'></script>

You can include this via Google using the following.

<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools-yui-compressed.js'></script>

If you are working on a development server you can also include the uncompressed version so that you can see where any errors are coming from.

<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools.js'></script>

If you want to download version 1.11 instead of version 1.2.1 by changing the folder:

<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/mootools/1.11/mootools.js'></script>

You can also use the google.load() function to include the library you want with a single function call.

<script src="http://www.google.com/jsapi"></script>
<script>
  google.load("mootools", "1.2.1");
</script>

Ease Of Use

You have to admit that this method of including JavaScript is much easier than downloading the library manually, uploading it and then sorting the script tags out.

Quick Downloads

The first benefit of using this service is that users will not have to wait very long in order to download the JavaScript libraries that your site relies on to work. This is because they are downloading it from Google and not your site.

Concurrent Connections

Your browser can only open a certain number of connections to a domain; this is partly due to how browsers work but also due to how servers work. If you host your JavaScript libraries with Google then your browser will be able to run off and get them whilst it is downloading your page making the page load a little faster.

Better Caching

Rather than repeatedly downloading files from a site over and over again a browser will try to minimise this by only downloading what it hasn’t downloaded already. This is fine if you spend all of your time on a single site, but most people don’t and they will therefore download the same version of the same JavaScript library over and over again. This happens even if the server has aggressive caching turned on. By hosting your libraries with Google you basically allow a user who has visited a site using the same library as you to reuse the file they downloaded there on your site.

Don’t Use On Your Intranet

There is one small issue if you are using this sort of thing on an Intranet system in that it will create unnecessary network traffic from your network. This method can also leave Intranet systems utterly useless if your Internet connection goes down for whatever reason. Holding your JavaScript libraries locally will mean that your systems can continue to work, even if you are cut off from the outside world.

Word Of Warning

Some countries actively block connections to some sites; especially Google. So if you do include JavaScript libraries like this then the chances are that someone in Iran or China will certainly not be able to view any JavaScript components and might even get a load of authentication errors.

More Information

For more information on the different libraries available take a look at the Google Ajax Libraries page.

Force Browser To Refresh All Content Using PHP

January 6th, 2009 No comments

One issue, especially when creating AJAX applications, is that the browser can cache the contents of the page so that when a similar request is made the same content is presented.

To force the browser to present the content you want it to without caching you can add the following headers to your page.

header("HTTP/1.1 202 Accepted");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, proxy-revalidate, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Cache-Control: max-age=10000000, s-maxage=1000000");
header("Pragma: no-cache");

Remember to put this before you print out any content as you will get some nice looking errors otherwise.

Also, I wouldn’t put this on every page on the site as it can create an overhead that just isn’t needed.

Some browsers, like IE, will still not work as expected here. If the browser is still not giving the content you want then try to add a random number to your GET or POST request. This makes the browser think that the content will be different.

Create Images Thumbnails And Cache Them In PHP

November 14th, 2008 No comments

Creating image thumbnails is a pretty common practice, and there are a few scripts available that allow you to do this in PHP using the GD2 library. However, they are normally overkill for what should be a simple task, so after a bit of searching and testing I found the following ImageResize class, which is taken from http://shiege.com/scripts/thumbnail/. I have modified the code to be PHP5, but if you want the PHP4 version then you can get it from the site.

class ImageResize{
  public $img;
 
  public function ImageResize($imgfile){
    //detect image format
    $this->img["format"] = ereg_replace(".*\.(.*)$","\\1",$imgfile);
    $this->img["format"] = strtoupper($this->img["format"]);
    if($this->img["format"] == "JPG" || $this->img["format"] == "JPEG"){
      //JPEG
      $this->img["format"] = "JPEG";
      $this->img["src"] = ImageCreateFromJPEG ($imgfile);
    }elseif($this->img["format"] == "PNG"){
      //PNG
      $this->img["format"] = "PNG";
      $this->img["src"] = ImageCreateFromPNG ($imgfile);
    }elseif($this->img["format"] == "GIF"){
      //GIF
      $this->img["format"] = "GIF";
      $this->img["src"] = ImageCreateFromGif($imgfile);
    }elseif($this->img["format"] == "WBMP"){
      //WBMP
      $this->img["format"] = "WBMP";
      $this->img["src"] = ImageCreateFromWBMP ($imgfile);
    }else{
      //DEFAULT
      echo "Not Supported File";
      exit();
    };
    $this->img["lebar"] = imagesx($this->img["src"]);
    $this->img["tinggi"] = imagesy($this->img["src"]);
    //default quality jpeg
    $this->img["quality"] = 75;
  }
 
  public function size_height($size = 100){
    //height
    $this->img["tinggi_thumb"] = $size;
    $this->img["lebar_thumb"] = ($this->img["tinggi_thumb"]/$this->img["tinggi"])*$this->img["lebar"];
  }
 
  public function size_width($size = 100){
    //width
    $this->img["lebar_thumb"] = $size;
    $this->img["tinggi_thumb"] = ($this->img["lebar_thumb"]/$this->img["lebar"])*$this->img["tinggi"];
  }
 
  public function size_auto($size = 100){
    //size
    if($this->img["lebar"]> = $this->img["tinggi"]){
      $this->img["lebar_thumb"] = $size;
      $this->img["tinggi_thumb"] = ($this->img["lebar_thumb"]/$this->img["lebar"])*$this->img["tinggi"];
    }else{
      $this->img["tinggi_thumb"] = $size;
      $this->img["lebar_thumb"] = ($this->img["tinggi_thumb"]/$this->img["tinggi"])*$this->img["lebar"];
    };
  }
 
  public function jpeg_quality($quality = 75){
    //jpeg quality
    $this->img["quality"] = $quality;
  }
 
  public function show(){
    //show thumb
    header("Content-Type: image/".$this->img["format"]);
 
    /* change ImageCreateTrueColor to ImageCreate if your GD not supported ImageCreateTrueColor function*/
    $this->img["des"] = ImageCreateTrueColor($this->img["lebar_thumb"],$this->img["tinggi_thumb"]);
    imagecopyresampled($this->img["des"], $this->img["src"], 0, 0, 0, 0, $this->img["lebar_thumb"], $this->img["tinggi_thumb"], $this->img["lebar"], $this->img["tinggi"]);
 
    if($this->img["format"] == "JPG" || $this->img["format"] == "JPEG"){
      //JPEG
      imageJPEG($this->img["des"],"",$this->img["quality"]);
    }elseif($this->img["format"] == "PNG"){
      //PNG
      imagePNG($this->img["des"]);
    }elseif($this->img["format"] == "GIF"){
      //GIF
      imageGIF($this->img["des"]);
    }elseif($this->img["format"] == "WBMP"){
      //WBMP
      imageWBMP($this->img["des"]);
    };
  }
 
  public function save($save = ""){
    //save thumb
    if(empty($save)){
      $save = strtolower("./thumb.".$this->img["format"]);
    }
    /* change ImageCreateTrueColor to ImageCreate if your GD not supported ImageCreateTrueColor function*/
    $this->img["des"] = ImageCreateTrueColor($this->img["lebar_thumb"],$this->img["tinggi_thumb"]);
    imagecopyresampled($this->img["des"], $this->img["src"], 0, 0, 0, 0, $this->img["lebar_thumb"], $this->img["tinggi_thumb"], $this->img["lebar"], $this->img["tinggi"]);
 
    if($this->img["format"] == "JPG" || $this->img["format"] == "JPEG"){
      //JPEG
      imageJPEG($this->img["des"],"$save",$this->img["quality"]);
    }elseif($this->img["format"] == "PNG"){
      //PNG
      imagePNG($this->img["des"],"$save");
    }elseif($this->img["format"] == "GIF"){
      //GIF
      imageGIF($this->img["des"],"$save");
    }elseif($this->img["format"] == "WBMP"){
      //WBMP
      imageWBMP($this->img["des"],"$save");
    };
  }
}

Put this into a file called class.ImageResize.php and you can use it to resize and show any image you want.

include('class.ImageResize.php');
// create ImageResize object
$originalImage = new ImageResize("anImage.jpg");
// use the show function to print this image to screen
$originalImage->show();
// use the save function to save this image to another file - leave empty to save as thumb.anImage.jpg
$originalImage->save("anotherFile.png");
// use one of the size functions to resize the image
$originalImage->size_width(120);
// save it again...
$originalImage->save("thumb_anotherFile.png");

If you want to create a simple thumbnail caching function then you can use the following code. It checks to see if the image exists and if it is older than 30 days. If it is then the file is deleted and because the file no longer exists (or if it never existed) the next part of the code where the thumbnail is created is run.

$imageName = str_replace(dirname("./images/", "" , "http://www.example.com/images/an_image.jpg");
 
if ( file_exists("./thumb_cache".$imageName) ) {
  // 2592000 = 30 days
  if ( time() - filemtime("./thumb_cache".$imageName) > 2592000 ) {
    unlink("./thumb_cache".$imageName);
  }
}
if ( !file_exists("./thumb_cache".$imageName) ) {
  include('class.ImageResize.php');
  // if cache file does not exist then create it.
  $originalImage = new ImageResize("./images/".$_result['image_path']);
  $originalImage->size_width(120);
  $originalImage->save("./thumb_cache".$imageName);
}

Categories: PHP Tags: , , , ,