home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Programming PHPProgramming PHPSearch this book

9.6. Dynamically Generated Buttons

A popular use for dynamically generated images is to create images for buttons on the fly. Normally, a blank button background image is used and text is overlaid on top of it, as shown in Example 9-7.

Example 9-7. Creating a dynamic button

<?php
 $font = 'times';
 if (!$size) $size = 12;
 $im = ImageCreateFromPNG('button.png');
 // calculate position of text
 $tsize = ImageTTFBBox($size,0,$font,$text);
 $dx = abs($tsize[2]-$tsize[0]);
 $dy = abs($tsize[5]-$tsize[3]);
 $x = ( ImageSx($im) - $dx ) / 2;
 $y = ( ImageSy($im) - $dy ) / 2 + $dy;
 // draw text
 $black = ImageColorAllocate($im,0,0,0);
 ImageTTFText($im, $size, 0, $x, $y, $black, $font, $text);
 header('Content-Type: image/png');
 ImagePNG($im);
?>

In this case, the blank button (button.png) looks as shown in Figure 9-6.

Figure 9-6

Figure 9-6. Blank button

Note that if you are using GD 2.0.1, antialiased TrueType fonts work only if the background image is indexed. If you are having problems with your text looking terrible, load your background image into any image-editing tool and convert it from a true color image to one with an 8-bit indexed palette. Alternatively, upgrade from GD 2.0.1 to GD 2.0.2 or later.

The script in Example 9-7 can be called from a page like this:

<img src="button.php?text=PHP+Button">

This HTML generates the button shown in Figure 9-7.

Figure 9-7

Figure 9-7. Generated button

The + character in the URL is the encoded form of a space. Spaces are illegal in URLs and must be encoded. Use PHP's urlencode( ) function to encode your button strings. For example:

<img src="button.php?text=<?php echo urlencode('PHP Button')?>">

9.6.2. A Faster Cache

Example 9-8 is still not quite as quick as it could be. There is a more advanced caching technique that completely eliminates PHP from the request once an image has been generated.

First, create a buttons directory somewhere under your web server's DocumentRoot and make sure that your web server user has permissions to write to this directory. For example, if the DocumentRoot directory is /var/www/html, create /var/www/html/buttons.

Second, edit your Apache httpd.conf file and add the following block:

<Location /buttons/>
  ErrorDocument 404 /button.php
</Location>

This tells Apache that requests for nonexistent files in the buttons directory should be sent to your button.php script.

Third, save Example 9-9 as button.php. This script creates new buttons, saving them to the cache and sending them to the browser. There are several differences from Example 9-8, though. We don't have form parameters in $_GET, because Apache handles error pages as redirections. Instead, we have to pull apart values in $_SERVER to find out which button we're generating. While we're at it, we delete the '..' in the filename to fix the security hole from Example 9-8.

Once button.php is installed, when a request comes in for something like http://your.site/buttons/php.png, the web server checks whether the buttons/php.png file exists. If it does not, the request is redirected to our button.php script, which creates the image (with the text "php") and saves it to buttons/php.png. Any subsequent requests for this file are served up directly without a line of PHP being run.

Example 9-9. More efficient caching of dynamic buttons

<?php
 // bring in redirected URL parameters, if any
 parse_str($_SERVER['REDIRECT_QUERY_STRING']);

 $button_dir = '/buttons/';
 $url = $_SERVER['REDIRECT_URL'];
 $root = $_SERVER['DOCUMENT_ROOT'];

 // pick out the extension
 $ext = substr($url,strrpos($url,'.'));

 // remove directory and extension from $url string
 $file = substr($url,strlen($button_dir),-strlen($ext));

 // security - don't allow '..' in filename
 $file = str_replace('..','',$file);

 // text to display in button
 $text = urldecode($file);

 // build image
 if(!isset($font)) $font = 'times';
 if(!isset($size)) $size = 12;
 $im = ImageCreateFromPNG('button.png');
 $tsize = ImageTTFBBox($size,0,$font,$text);
 $dx = abs($tsize[2]-$tsize[0]);
 $dy = abs($tsize[5]-$tsize[3]);
 $x = ( ImageSx($im) - $dx ) / 2;
 $y = ( ImageSy($im) - $dy ) / 2 + $dy;
 $black = ImageColorAllocate($im,0,0,0);
 ImageTTFText($im, $size, 0, $x, $y, -1*$black, $font, $text);

 // send and save the image
 header('Content-Type: image/png');
 ImagePNG($im);
 ImagePNG($im,$root.$button_dir."$file.png");
 ImageDestroy($im);
?>

The only drawback to the mechanism in Example 9-9 is that the button text cannot contain any characters that are illegal in a filename. Nonetheless, this is the most efficient way to cache such dynamically generated images. If you change the look of your buttons and you need to regenerate the cached images, simply delete all the images in your buttons directory, and they will be recreated as they are requested.

You can also take this a step further and get your button.php script to support multiple image types. Simply check $ext and call the appropriate ImagePNG( ), ImageJPEG( ), or ImageGIF( ) function at the end of the script. You can also parse the filename and add modifiers such as color, size, and font, or pass them right in the URL. Because of the parse_str( ) call in the example, a URL such as http://your.site/buttons/php.png?size=16 displays "php" in a font size of 16.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.