Section 11.3. File Manipulation


11.3. File Manipulation

There may be times when you don't want to store information in a database and may want to work directly with a file instead. An example is a logfile that tracks when your application can't connect to the database. It'd be impossible to keep this information in the database, since it's not available at exactly the time you'd need to write to it. PHP provides functions for file manipulation that can perform the following:

  • Check the existence of a file

  • Create a file

  • Append to a file

  • Rename a file

  • Delete a file

We've already discussed the include and require functions for pulling information directly into a PHP script. At this junction, we'll focus on working with file content.

Since working directly with files from your PHP code can create security risks, it's a good idea to find solutions to problems that don't use files directly if possible; for example, storing information in a database instead of file. You must be very careful to not allow misuse of your PHP programs to either read or destroy the contents of important files either accidentally or as part of an attack.


11.3.1. Functions and Precautions

To check for the existence of a file, use the function file_exists, which takes the name of the file to check for its parameter, as shown in Example 11-20. If the file exists, it returns trUE; otherwise, it returns FALSE.

Example 11-20. The file_exists.php script checks to see if the file is there

 <?php   $file_name="file_exists.php";   if(file_exists($file_name)) {     echo ("$file_name does exist.");   }   else {     echo ("$file_name does not exist.");   } ?> 

As you would expect, the file does exist:

 The file exists.php does exist. 

PHP provides several functions to tell you about various file attributes. PHP has the ability to read data from, and write data to, files on your system. However, it doesn't just stop there. It comes with a full-featured file-and-directory-manipulation API that allows you to:

  • View and modify file attributes

  • Read and list directory contents

  • Alter file permissions

  • Retrieve file contents into a variety of native data structures

  • Search for files based on specific patterns

All of this file manipulation through the API is robust and flexible. These characteristics are why we're writing this book. PHP has a lot of great commands, including all the file manipulation ones.

11.3.1.1. Permissions

Now that you know a file exists, you may think you're done, but you're not. Just because it's there doesn't mean you can read, write, or execute the file. To check for these attributes, use is_readable to check for read access, is_writable to check for write access, and is_executable to check for the ability to execute the file. Each function takes a filename as its parameter. Unless you know the file is in the same directory as your script, you must specify a full path to the file in the filename. You can use concatenation to put the path and filename together, as in:

 $file_name = $path_to_file . $file_name_only; 

Let's go ahead and expand the last example to also check for these details. Example 11-21 assumes the script is saved as permissions.php.

Example 11-21. Checking the permissions of a file

 <?php   $file_name="permissions.php";   if(is_readable($file_name)) {     echo ("The file $file_name is readable.<br>");   }   else {     echo ("The file $file_name is not readable.<br>");   }   if(is_writeable($file_name)) {     echo ("The file $file_name is writeable.<br>");   }   else {     echo ("The file $file_name is not writeable.<br>");   }   if(is_executable($file_name)) {     echo ("The file $file_name is executable.<br>");   }   else {     echo ("The file $file_name is not executable.<br>");   } ?> 

The code tells you the many details regarding permissions on the file in Figure 11-17.

Figure 11-17. This file is readable but not executable or writable to PHP


11.3.1.2. Creating files

Files can be created with the touch command. This command takes a filename as its parameter. If a file doesn't already exist, it's created as an empty zero length file. If the file does exist, only its modification time is updated.

11.3.1.3. Deleting files

Files can be deleted with the unlink command. This command, shown in Example 11-22, takes a filename as its parameter. If a file exists and PHP has adequate permission, it'll delete the file. You must be very careful when deleting files not to accidentally delete a file that you still want. If you're using a filename that is derived from user input, you must also be very careful that the filename hasn't been crafted by the user to delete a different file than you intended. Example 11-22 shows how to use file_exists, touch, and unlink.

Always be careful when deleting files, as you won't be able to retrieve your data!


Example 11-22. Using file_exists, touch, and unlink together

 <?php   $file_name="test.txt";   if(file_exists($file_name)) {     echo ("$file_name does exist.<br>");   }   else {     echo ("The file $file_name does not exist.<br>");     touch($file_name);   }   if(file_exists($file_name)) {     echo ("The file $file_name does exist.<br>");     unlink($file_name);   }   else {     echo ("The file $file_name does not exist.<br>");   }   if(file_exists($file_name)) {     echo ("The file $file_name does exist.<br>");   }   else {     echo ("The file $file_name does not exist.<br>");   } ?> 

The output looks like Figure 11-18.

Figure 11-18. The test.txt file is created and removed


11.3.1.4. Moving files

To move a file, you should use the rename function. It renames files or directories and takes the old name and the new name as its parameters. As of PHP 5.0, rename can also be used with some URL wrappers, and context support has been added. Example 11-23 assumes that you've recreated the test.txt file.

Example 11-23. Renaming a file

 <?php   $file_name="test.txt";   $new_file_name="production.txt";   $status=rename($file_name,$new_file_name);   if ($status) {     echo ("Renamed file.");   } ?> 

The file has been renamed, as is demonstrated in the report from Example 11-23.

 Renamed file. 

11.3.2. URL Wrappers

Two URL protocols that PHP has built in for use with the filesystem functions include fopen and copy. In addition to these two wrappers, as of PHP 4.3.0, you can write your own wrappers using a PHP script and stream_wrapper_register. The default wrapper is file://, used with PHP, and it is the local filesystem. If you specify a relative path, which is one that doesn't begin with /, \, \\, or a Windows drive letter, such as C://, the path provided applies against the current working directory. Usually this is where the script resides, unless of course, it's been changed.

With some functions, such as fopen and file_get_contents, include_path can be used to search for relative paths as well. Table 11-3 provides a URL wrapper summary for reference.

Table 11-3. URL wrappers

Attribute

Supported

Restricted by allow_url_fopen

No

Allows reading

Yes

Allows simultaneous reading and writing

Yes

Allows writing

Yes

Allows appending

Yes

Supports stat

Yes

Supports rename

Yes

Supports mkdir

Yes

Supports rmdir

Yes


11.3.3. Uploading Files

It's a fairly common requirement for a PHP-based site to allow file uploads. For example, on a blog site, a user may want to upload an image to go with her post. We'll walk through the steps to upload a file, because you'll be designing a blog in Chapter 16. PHP allows you to do this with the help of forms input.

When you use the file upload form field, the client's browser pulls up a file selection dialog, so you don't have to worry about doing that. The code to include in the file upload field is <input type="file" name="file">. You must also add enctype="multipart/form" to the form tag. This allows a file to be sent with the form submission. Finally, because of the increased size of the form submission, you must use the POST type submission instead of GET.

The php.ini configuration file has a setting that globally limits the size of file upload, called upload_max_filesize. The default value is 2 MB. This helps prevent denial-of-service attacks in which an attacker uploads many huge files to slow your connection or fill up your server's storage.


Once the user selects a file from the HTML form produced by Example 11-24 and clicks Submit, Apache does some of the hard work by handling the upload and placing it into a temporary directory with a temporary filename. It's now up to you to validate the upload and move it if it passes validation.

Example 11-24. Prompting to upload a file

 <html> <head></head> <body> <form action="<?=$PHP_SELF?>" method="post" enctype="multipart/form-data"> <br><br> Choose a file to upload:<br> <input type="file" name="upload_file"> <br> <input type="submit" name="submit" value="submit"> </form> </body> </html> 

11.3.3.1. Accessing the file

Access the uploaded file like you access other attribute form submissions, by their name, which in this case is upload_file. The difference is that file upload variables are arrays that contain several attributes about the upload.

The attributes in Table 11-4 provide you with enough information to analyze the file.

Table 11-4. File upload attribute

Attribute

Meaning

$HTTP_POST_FILES['upload_file']

The array; replace upload_file with the name of your upload file submission variable

$HTTP_POST_FILES[' upload_file']['name']

The original name of the file

$HTTP_POST_FILES[' upload_file']['tmp_name']

The temporary name assigned during the upload process

$HTTP_POST_FILES[' upload_file']['type']

The file's mime type

$HTTP_POST_FILES[' upload_file']['size']

The file's size in bytes


11.3.3.2. Validation

You need to validate the file to ensure that it's not too big orworse yetin a file format that isn't allowed, such as a .zip file when you allow only .jpg files. You validate in this order:

  1. Was a file actually sent?

  2. Is it too big?

  3. Is it the wrong type?

We'll start with the is_uploaded_file function to check that a file was indeed uploaded.

Example 11-25 verifies that the file exists in the temporary directory with the proper temporary name. If it doesn't, stop processing the file and warn the user that he needs to try again.

Example 11-25. Checking for the existence of an uploaded file

 <?php if (!is_uploaded_file($HTTP_POST_FILES['upload_file']['tmp_name'])) {   $error = "You must upload a file!";   unlink($HTTP_POST_FILES['upload_file']['tmp_name']); } else {   //proceed to process the file } ?> 

Now in Example 11-26, we make sure the file isn't too big.

Example 11-26. Checking the file size

 <?php $maxsize=28480; if ($HTTP_POST_FILES['upload_file']['size'] > $maxfilesize) {   $error = "Error, file must be less than $maxsize bytes.";   unlink($HTTP_POST_FILES['upload_file']['tmp_name']); } else {   // proceed to process the file. } ?> 

To validate the size of a file, assign the maximum allowed file size in bytes to the variable $maxsize. In this case, you are checking for 28,480 bytes. You already have the file size stored in the $HTTP_POST_FILES array, so it's easy to check. If the file is too big, you need to tell the user about the problem and make him upload a different file. You also need to remove the file using the unlink function so that you don't end up with a million files sitting in the temporary directory.

You might be tempted to validate the type of file by simply looking at its file extension, but this isn't a good idea, since it's trivial to modify the file extension of a file before uploading it.


Next, Example 11-27 checks the file type to make sure it's either a JPEG or a GIF file.

Example 11-27. Checking the file type

 <?php if($HTTP_POST_FILES['upload_file']['type'] != "image/gif" AND $HTTP_POST_FILES['upload_file']['type'] != "image/pjpeg" AND $HTTP_POST_FILES['upload_file']['type'] !="image/jpeg") {   $error = "You may only upload .gif or .jpeg files";   unlink($HTTP_POST_FILES['upload_file']['tmp_name']); } else {    //the file is the correct format } ?> 

Use the $HTTP_POST_FILES['file']['type'] variable to compare the mime type against the types expected. This is much harder to alter than the file extension. If you find that the file type doesn't match, warn the user that he'll need to upload a different file and remove the temporary file.

The following line copies the file from the temporary directory into the uploads directory using the same filename:

 copy($HTTP_POST_FILES['upload_file']['tmp_name'],"uploads/". $HTTP_POST_FILES['upload_file']['name']); 

Using unlink, let's remove the temporary file:

 unlink($HTTP_POST_FILES['upload_file']['tmp_name']); 

To help prevent misuse of the upload processing script, validate that the submit button was pressed. Take a look at the entire script in Example 11-28.

Example 11-28. Processing an uploaded file

 <?php $maxsize=28480; //set the max upload size in bytes if (!$HTTP_POST_VARS['submit']) {   //print_r($HTTP_POST_FILES);   $error=" "; //this will cause the rest of the processing to be skipped //and the upload form displays } if (!is_uploaded_file($HTTP_POST_FILES['upload_file']['tmp_name']) AND !isset($error)) {   $error = "<b>You must upload a file!</b><br><br>";   unlink($HTTP_POST_FILES['upload_file']['tmp_name']); } if ($HTTP_POST_FILES['upload_file']['size'] > $maxsize AND !isset($error)) {   $error = "<b>Error, file must be less than $maxsize bytes.</b><br><br>";   unlink($HTTP_POST_FILES['upload_file']['tmp_name']); } if($HTTP_POST_FILES['upload_file']['type'] != "image/gif" AND $HTTP_POST_FILES['upload_file']['type'] != "image/pjpeg" AND $HTTP_POST_FILES['upload_file']['type'] !="image/jpeg" AND !isset($error)) {   $error = "<b>You may only upload .gif or .jpeg files.</b><br><br>";   unlink($HTTP_POST_FILES['upload_file']['tmp_name']); } if (!isset($error)) { copy($HTTP_POST_FILES['upload_file']['tmp_name'],"uploads/".$HTTP_POST_FILES ['upload_file']['name']);   unlink($HTTP_POST_FILES['upload_file']['tmp_name']);   print "Thank you for your upload.";   exit; } else {   echo ("$error"); } ?> <html> <head></head> <body> <form action="<?=$PHP_SELF?>" method="post" enctype="multipart/form-data"> Choose a file to upload:<br> <input type="file" name="upload_file" size="80"> <br> <input type="submit" name="submit" value="submit"> </form> </body> </html> 

Each validation checks to see whether a prior step failed; if so, it doesn't continue the validation. When you reach the end of the validation section, you print out the value in the $error variable. If there were no errors, no error message displays and you move the image to its final destination. If you encountered an error, or if this is the first time the script has been called, you display the file upload form.

Figure 11-19 shows what the form looks like.

Figure 11-19. The upload form with an invalid file selected


When this file is submitted, you should see an error, shown in Figure 11-20, since it's not a .jpg or .gif file.

Figure 11-20. The .ini file was caught by the validation


Next, we'll try sending in a 506K image. Remember, the limit is 20K, so this is much larger than what you're allowing. Figure 11-21 shows what happens.

Figure 11-21. We caught the file size error, too


OK, now we'll try a file that meets the validation criteria, to get the happier result shown in Figure 11-22.

Figure 11-22. A successful upload!


There's now a file called logo.jpg in the uploads directory on your server. To increase security slightly, you could pick your own filenames instead of using a user-supplied name.



Learning PHP and MySQL
Learning PHP and MySQL
ISBN: 0596101104
EAN: 2147483647
Year: N/A
Pages: 135

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net