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.
<?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.
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.
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')?>">
It is somewhat slower to generate an image than to send a static image. For buttons that will always look the same when called with the same text argument, a simple cache mechanism can be implemented.
Example 9-8 generates the button only when no cache file for that button is found. The $path variable holds a directory, writable by the web server user, where buttons can be cached. The filesize( ) function returns the size of a file, and readfile( ) sends the contents of a file to the browser. Because this script uses the text form parameter as the filename, it is very insecure (Chapter 12 explains why and how to fix it).
<?php header('Content-Type: image/png'); $path = "/tmp/buttons"; // button cache directory $text = $_GET['text']; if($bytes = @filesize("$path/$text.png")) { // send cached version header("Content-Length: $bytes"); readfile("$path/$text.png"); } else { // build, send, and cache $font = 'times'; if (!$_GET['size']) $_GET['size'] = 12; $im = ImageCreateFromPNG('button.png'); $tsize = ImageTTFBBox($size, 0, $font, $text); $dx = abs($tsize[2]-$tsize[0]); // center text $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, $_GET['size'], 0, $x, $y, -$black, $font, $text); ImagePNG($im); // send image to browser ImagePNG($im,"$path/$text.png"); // save image to file } ?>
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.
<?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.
Copyright © 2003 O'Reilly & Associates. All rights reserved.