PHP Lessons - Lesson 4 - Working with Images, GD2 Library
In the previous lessons, we learned how to write database queries, so now we'll focus less on writing queries and more on practicing them. We'll also combine writing queries with learning other PHP features, starting with image processing. In one of the previous lessons, we already uploaded files and even created a Files table for uploaded files. Now, let’s upload images to the same table. But first, we need to add a photo upload field to the content creation form.
$content .= '<label for="bodytext">Message:</label><br />'; $content .= '<textarea name="bodytext" id="bodytext"></textarea><br />'; $content .= '<label for="bodytext">Attach a file:</label><br /><input type="file" name="filename"><br />'; $content .= '<label for="bodytext">Attach an image:</label><br /><input type="file" name="image">';
Now we need to write file handling logic, but first let’s add a new column to the Messages table, where we'll store the image file ID (fid). We'll store the image metadata in the Files table, just like other files. The new column is named image_fid
, with type INT(11), and defaults to NULL. Let’s insert the form processing code in the write()
method:
if($_FILES["image"]["size"] > 1024*3*1024){ echo ("File size exceeds three megabytes"); exit; } if(is_uploaded_file($_FILES["image"]["tmp_name"])){ move_uploaded_file($_FILES["image"]["tmp_name"], "./files/".$_FILES["filename"]["name"]); } else { echo("File upload error"); } $sql = 'INSERT INTO Files (filename, filepath, filemime, filesize, timestamp) VALUES ("'. $_FILES['image']['name'] . '", "files/' . $_FILES['image']['name'] . '", "'. $_FILES['image']['type'] .'", '. $_FILES['image']['size'] .', '. time() . ')'; mysql_query($sql);
This processing is no different from uploading regular files, although in a future lesson, we’ll look at how to validate file types to prevent uploading, for example, PDF files disguised as images.
Now both files will be uploaded, one of them an image. Here’s the $_POST
and $_FILES
arrays printed with print_r()
:
Array ( [title] => test [bodytext] => asdfasf ) Array ( [filename] => Array ( [name] => ip.txt [type] => text/plain [tmp_name] => Y:\tmp\php2C5.tmp [error] => 0 [size] => 13 ) [image] => Array ( [name] => Coat_of_arms_of_Vladimiri_Oblast.png [type] => image/png [tmp_name] => Y:\tmp\php2C6.tmp [error] => 0 [size] => 393743 ) )
Now change the insert query for the message:
$sql = 'INSERT INTO Messages (title, bodytext, created, fid, image_fid) VALUES ("'. $p["title"] . '", "' . $p["bodytext"] . '", ' . time() . ',LAST_INSERT_ID()-1, LAST_INSERT_ID())';
To identify the fid of the regular file and the image, we use LAST_INSERT_ID()
. Since the regular file is inserted before the image, we subtract one from the last ID.
Now that images are inserted into the database, we can display them. To handle images, we’ll create a stub class called simpleImage
. Create a new file simpleImage.php
in the class
folder and write the following:
<?php class simpleCMS { } ?>
Now that we’ve created a new class for image processing, we need to define methods. But first, let’s talk about variable visibility in PHP classes.
PHP 5 Class Properties
In PHP4 everything was simple—class properties were declared with var
. But in PHP5, you have more control using public
, protected
, and private
.
Public
The public
keyword declares a property accessible from outside the class. For example:
<?php $obj = new simpleCMS(); $obj->db='newDB'; ?>
Protected
protected
means the property is accessible only within the class and its subclasses (we’ll cover inheritance later). If you try to access a protected
property from outside, you’ll get an error.
simpleCMS.php ... protected $db = 'testDB'; ... index.php ... $obj = new simpleCMS(); $obj->db='newDB'; ...
Now let’s add a protected variable $path
and use a constructor to set it when creating an image object.
Class Constructor
The constructor initializes the object’s state. We’ll pass the file path to the constructor and store it:
class simpleCMS { protected $path; public function __construct($image){ $this->path = $image; } }
Now update the public_display()
method of simpleCMS
to output image data:
if(!empty($row['image_fid'])){ $sql = "SELECT * FROM Files WHERE fid=".$row['image_fid']; $image_query = mysql_query($sql) or die(mysql_error()); $image = mysql_fetch_array($image_query); $content .= '<div class="image">'; $image = new simpleImage($image['filepath']); $content .= $image->scale(100,100); $content .= '</div>'; unset($image); }
This code retrieves the file path from the database. Let’s now write the scale()
method:
public function scale($width, $height){ ... return '<img src="'. $newImagePath . '" width="'. $destWidth.'" height="'. $destHeight . '" />'; }
Make sure the files/presets
folder exists and has write permissions (777).
Now for the scale_and_crop()
method, which works similarly:
public function scale_and_crop($width, $height){ ... return '<img src="'. $newImagePath . '" />'; }
Also change the display method output:
$content .= '<div class="image">'; $image = new simpleImage($image['filepath']); $content .= $image->scale_and_crop(100,100); $content .= '</div>';
This makes the images square and cropped proportionally.
In both cases, images are generated on the fly. Since image processing takes time, their paths are often saved in the database to skip regeneration. We won’t cover this optimization here, because in the CMS build we'll eventually use Zend Framework. These PHP lessons are intended to teach you the basics of PHP.