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. 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. 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.1. Caching the Dynamically Generated Buttons
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).
Example 9-8. Caching dynamic buttons
<?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
}
?>
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.
 |  |  | 9.5. Images with Text |  | 9.7. Scaling Images |
Copyright © 2003 O'Reilly & Associates. All rights reserved.
|
|