Tải bản đầy đủ (.pdf) (10 trang)

Giải pháp thiết kế web động với PHP - p 24 pps

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (465.6 KB, 10 trang )

USING PHP TO MANAGE FILES

211

2. Remove any default code created by your script editor, and insert the following code:
<?php
// define error page
$error = 'http://localhost/phpsols/error.php';
// define the path to the download folder
$filepath = 'C:/xampp/htdocs/phpsols/images/';

$getfile = NULL;

// block any attempt to explore the filesystem
if (isset($_GET['file']) && basename($_GET['file']) == $_GET['file']) {
$getfile = $_GET['file'];
} else {
header("Location: $error");
exit;
}

if ($getfile) {
$path = $filepath . $getfile;
// check that it exists and is readable
if (file_exists($path) && is_readable($path)) {
// get the file's size and send the appropriate headers
$size = filesize($path);
header('Content-Type: application/octet-stream');
header('Content-Length: '. $size);
header('Content-Disposition: attachment; filename=' . $getfile);
header('Content-Transfer-Encoding: binary');


// open the file in read-only mode
// suppress error messages if the file can't be opened
$file = @fopen($path, 'r');
if ($file) {
// stream the file and exit the script when complete
fpassthru($file);
exit;
} else {
header("Location: $error");
}
} else {
header("Location: $error");
}
The only two lines that you need to change in this script are highlighted in bold type. The first
defines $error, a variable that contains the URL of your error page. The second line that
needs to be changed defines the path to the folder where the download file is stored.
The script works by taking the name of the file to be downloaded from a query string appended
to the URL and saving it as $getfile. Because query strings can be easily tampered with,
CHAPTER 7
212
$getfile is initially set to NULL. This is an important security measure. If you fail to do this,
you could give a malicious user access to any file on your server.
The opening conditional statement uses basename() to make sure that an attacker cannot
request a file, such as one that stores passwords, from another part of your file structure. As
explained in Chapter 4, basename() extracts the filename component of a path, so if
basename($_GET['file']) is different from $_GET['file'], you know theres an attempt to
probe your server, and you can stop the script from going any further by using the header()
function to redirect the user to the error page.
After checking that the requested file exists and is readable, the script gets the files size,
sends the appropriate HTTP headers, and opens the file in read-only mode using fopen().

Finally, fpassthru() dumps the file to the output buffer. But if the file cant be opened or
doesnt exist, the user is redirected to the error page.
3. Test the script by creating another page and add a couple of links to download.php. Add a
query string at the end of each link with file= followed by the name a file to be downloaded.
Youll find a page called getdownloads.php in the ch07 folder, which contains the following
two links:
<p><a href="download.php?file=maiko.jpg">Download image 1</a></p>
<p><a href="download.php?file=basin.jpg">Download image 2</a></p>
4. Click one of the links, and the browser should present you with a dialog box prompting you to
download the file or choose a program to open it, as shown in Figure 7-6.
Figure 7-6. The browser prompts the user to download the image, rather than opening it directly.
Download from Wow! eBook <www.wowebook.com>
USING PHP TO MANAGE FILES

213
5. Select Save File, and click OK, and the file should be saved rather than displayed. Click
Cancel to abandon the download. Whichever button you click, the original page remains in the
browser window. The only time download.php should load into the browser is if the file cannot
be opened. Thats why its important to send the user to an error page if theres a problem.
Ive demonstrated download.php with image files, but it can be used for any type of file because the
headers send the file as a binary stream.
This script relies on
header()
to send the appropriate HTTP headers to the browser. It is vital to
ensure that there are no new lines or whitespace ahead of the opening PHP tag. If you have removed
all whitespace and still get an error message saying “headers already sent,” your editor may have
inserted invisible control characters at the beginning of the file. Some editing programs insert the byte
order mark (BOM), which is known to cause problems with the ability to use the header() function.
Check your program preferences to make sure the option to insert the BOM is deselected.
Chapter review

The file system functions arent particularly difficult to use, but there are many subtleties that can turn a
seemingly simple task into a complicated one. Its important to check that you have the right permissions.
Even when handling files in your own website, PHP needs permission to access any folder where you want
to read files or write to them.
The SPL DirectoryIterator and RecursiveDirectoryIterator classes make it easy to examine the
contents of folders. Used in combination with the SplFileInfo methods and the RegexIterator, you
can quickly find files of a specific type within a folder or folder hierarchy.
When dealing with remote data sources, you need to check that allow_url_fopen hasnt been disabled.
One of the most common uses of remote data sources is extracting information from RSS news feeds or
XML documents, a task that takes only a few lines of code thanks to SimpleXML.
In the next two chapters, well put some of the PHP solutions from this chapter to further practical use
when working with images and building a simple user authentication system.
CHAPTER 7
214




215
Chapter 8
Generating Thumbnail Images
PHP has an extensive range of functions designed to work with images. Youve already met one of them,
getimagesize(), in Chapter 4. As well as providing useful information about an images dimensions, PHP
can manipulate images by resizing or rotating them. It can also add text dynamically without affecting the
original; it can even create images on the fly.
To give you just a taste of PHP image manipulation, Im going to show you how to generate a smaller copy
of an uploaded image. Most of the time, youll want to use a dedicated graphics program, such as
Photoshop or Fireworks, to generate thumbnail images because it gives you much better quality control.
However, automatic thumbnail generation with PHP can be very useful if you want to allow registered
users to upload images, but make sure they conform to a maximum size. You can save just the resized

copy, or the copy along with the original.
In Chapter 6, you built a PHP class to handle file uploads. In this chapter, youll create two classes: one to
generate thumbnail images, the other to upload and resize images in a single operation. Rather than build
the second class from scratch, youll base it on the Ps2_Upload class from Chapter 6. A great advantage
of using classes is that theyre extensible—a class based on another can inherit the functionality of its
parent class. Building the classes to upload images and generate thumbnails from them involves a lot of
code. But once you have defined the classes, using them involves only a few lines of script. If youre in a
rush or writing a lot of code makes you break out in a cold sweat, you can just use the finished classes.
Come back later to learn how the code works. It uses many basic PHP functions that youll find useful in
other situations.
In this chapter youll learn about the following:
• Scaling an image
• Saving a rescaled image
• Automatically resizing and renaming uploaded images
• Creating a subclass by extending an existing one
CHAPTER 8
216

Checking your servers capabilities
Working with images in PHP relies on the GD extension. Originally GD stood for GIF Draw, but problems
with the GIF patent led to support for GIF files being dropped in 1999, but the name GD stuck. The
problematic patent expired in 2004, and GIF is once again supported. The all-in-one PHP packages
recommended in Chapter 2 support GD by default, but you need to make sure the GD extension has also
been enabled on your remote web server.
As in previous chapters, run phpinfo() on your website to check the servers configuration. Scroll down
until you reach the section shown in the following screenshot (it should be about halfway down the page).

If you cant find this section, the GD extension isnt enabled, so you wont be able to use any of the scripts
in this chapter on your website. Ask for it to be enabled or move to a different host.
Strictly for abbreviation/acronym freaks: GIF stands for Graphics Interchange Format, JPEG is the

standard created by the Joint Photographic Experts Group, and PNG is short for Portable Network
Graphics. Although JPEG is the correct name for the standard, the “E” is frequently dropped,
particularly when used as a filename extension.
Manipulating images dynamically
The GD extension allows you to generate images entirely from scratch or work with existing images. Either
way, the underlying process always follows four basic steps:
1. Create a resource for the image in the servers memory while its being processed.
GENERATING THUMBNAIL IMAGES

217

2. Process the image.
3. Display and/or save the image.
4. Remove the image resource from the servers memory.
This process means that you are always working on an image in memory only and not on the original.
Unless you save the image to disk before the script terminates, any changes are discarded. Working with
images requires a lot of memory, so its vital to destroy the image resource as soon as its no longer
needed. If a script runs very slowly or crashes, it probably indicates that the original image is too large.
Making a smaller copy of an image
The aim of this chapter is to show you how to resize images automatically on upload. This involves
extending the Ps2_Upload class from Chapter 6. However, to make it easier to understand how to work
with PHPs image manipulation functions, I propose to start by using images already on the server, and
create a separate class to generate the thumbnail images.
Getting ready
The starting point is the following simple form, which uses PHP Solution 7-3 to create a drop-down menu of
the photos in the images folder. You can find the code in create_thumb_win01.php and
create_thumb_mac01.php in the ch08 folder. Copy it to a new folder called gd in the phpsols site root,
and rename it create_thumb.php.
<form id="form1" name="form1" method="post" action="">
<p>

<select name="pix" id="pix">
<option value="">Select an image</option>
<?php
$files = new DirectoryIterator(' /images');
$images = new RegexIterator($files, '/\.(?:jpg|png|gif)$/i');
foreach ($images as $image) {
?>
<option value="C:/xampp/htdocs/phpsols/images/<?php echo $image; ?>"> 
<?php echo $image; ?></option>
<?php } ?>
</select>
</p>
<p>
<input type="submit" name="create" id="create" value="Create Thumbnail">
</p>
</form>
The Win and Mac versions contain the fully qualified path to the images folder in default installations of
XAMPP and MAMP. If necessary, change the path (highlighted in bold) to match your setup. When loaded
into a browser, the drop-down menu should display the names of the photos in the images folder. This
makes it easier to pick images quickly for testing.
CHAPTER 8
218

Inside the upload_test folder that you created in Chapter 6, create a new folder called thumbs, and make
sure it has the necessary permissions for PHP to write to it. Refer to “Establishing an upload directory” in
Chapter 6 if you need to refresh your memory.
Building the Ps2_Thumbnail class
To generate a thumbnail image, the class needs to execute the following steps:
1. Get the dimensions of the original image.
2. Get the images MIME type.

3. Calculate the scaling ratio.
4. Create an image resource of the correct MIME type for the original image.
5. Create an image resource for the thumbnail.
6. Create the resized copy.
7. Save the resized copy to the destination folder using the correct MIME type.
8. Destroy the image resources to free memory.
In addition to generating a thumbnail image, the class automatically inserts _thb before the filename
extension, but a public method allows you to alter this value. The class also needs public methods to set
the destination folder and the maximum size of the thumbnail, and to retrieve messages generated by the
class. To keep the calculations simple, the maximum size controls only the larger of the thumbnails
dimensions.
Theres a lot to do, so Ill break up the code into sections. Theyre all part of the same class definition, but
presenting the script this way should make it easier to understand, particularly if you want to use some of
the code in a different context.
PHP Solution 8-1: Getting the image details
This PHP Solution describes how to get the dimensions and MIME type of the original image.
1. Create a new page called Thumbnail.php in the classes/Ps2 folder. The file will contain only
PHP, so strip out any HTML code inserted by your editing program.
2. The class needs to keep track of quite a few properties. Begin the class definition by listing
them like this:
<?php
class Ps2_Thumbnail {
protected $_original;
protected $_originalwidth;
protected $_originalheight;
protected $_thumbwidth;
protected $_thumbheight;
protected $_maxSize = 120;
protected $_canProcess = false;
protected $_imageType;

GENERATING THUMBNAIL IMAGES

219

protected $_destination;
protected $_name;
protected $_suffix = '_thb';
protected $_messages = array();
}
As in the Ps2_Upload class, all the properties have been declared as protected, which means
they cant be changed accidentally outside the class definition. Again, I have followed the
convention of beginning protected property names with an underscore. The names are
descriptive, so they need little explanation. The $_maxSize property has been given a default
value of 120 (pixels). This determines the maximum size of the thumbnails longer dimension.
The $_canProcess Boolean is initially set to false. This is to prevent the script from
attempting to process a file that isnt an image. The value will be reset to true if the MIME type
matches that of an image. You can also use it to prevent the generation of a thumbnail if
another error occurs.
3. The constructor takes one argument, the path to an image. Add the constructor definition after
the list of protected properties, but inside the the closing curly brace:
protected $_messages = array();

public function __construct($image) {
if (is_file($image) && is_readable($image)) {
$details = getimagesize($image);
} else {
$details = null;
$this->_messages[] = "Cannot open $image.";
}
// if getimagesize() returns an array, it looks like an image

if (is_array($details)) {
$this->_original = $image;
$this->_originalwidth = $details[0];
$this->_originalheight = $details[1];
// check the MIME type
$this->checkType($details['mime']);
} else {
$this->_messages[] = "$image doesn't appear to be an image.";
}
}
}
The constructor begins with a conditional statement that checks that $image is a file and is
readable. If it is, its passed to getimagesize() and the result is stored in $details.
Otherwise, $details is set to null, and an error message is added to the $_messages
property.
When you pass an image to getimagesize(), it returns an array containing the following
elements:
CHAPTER 8
220

• 0: width (in pixels)
• 1: height
• 2: an integer indicating the type of image
• 3: a string containing the correct width and height attributes ready for insertion
in an <img> tag
• mime: the images MIME type
• channels: 3 for RGB, and 4 for CMYK images
• bits: the number of bits for each color
If the value passed as an argument to getimagesize() isnt an image, it returns false.
Consequently, if $details is an array, you know youre dealing with an image. The images

path is stored in the $_original property, and its width and height are stored in
$_originalWidth and $_originalHeight respectively.
However, the image might not be a suitable type, so the final check is to pass its MIME type to
an internal method called checkType(), which youll define next.
4. The checkType() method compares the MIME type with an array of acceptable image types. If
it finds a match, it resets the $_canProcess property to true, and stores the type in the
$_imageType property. The method is used internally, so it needs to be declared as protected.
Add the following code to the class definition:
protected function checkType($mime) {
$mimetypes = array('image/jpeg', 'image/png', 'image/gif');
if (in_array($mime, $mimetypes)) {
$this->_canProcess = true;
// extract the characters after 'image/'
$this->_imageType = substr($mime, 6);
}
}
There are many types of images, but only JPEG, PNG, and GIF are used in web pages, so the
$_canProcess property is set to true only if the images MIME type matches one of those
listed in the $mimetypes array. If the MIME type isnt in the list $_canProcess remains false,
which later prevents the class from attempting to create a thumbnail.
All image MIME types begin with image/. To make the value easier to use later, the substr()
function extracts the characters after the slash and stores them in the $_imageType
property. When used with two arguments, substr() starts at the position (counting from 0)
specified in the second argument, and returns the rest of the string.
5. Its a good idea to test your code as you build the class. Catching errors early is much easier
than hunting for a problem in a long script. To test the code, create a new public method called
test() inside the class definition.

×