11.3. File ManipulationThere 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:
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.
11.3.1. Functions and PrecautionsTo 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
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:
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. PermissionsNow 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
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 PHP11.3.1.2. Creating filesFiles 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 filesFiles 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.
Example 11-22. Using file_exists, touch, and unlink together
The output looks like Figure 11-18. Figure 11-18. The test.txt file is created and removed11.3.1.4. Moving filesTo 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
The file has been renamed, as is demonstrated in the report from Example 11-23. Renamed file. 11.3.2. URL WrappersTwo 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.
11.3.3. Uploading FilesIt'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.
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
11.3.3.1. Accessing the fileAccess 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.
11.3.3.2. ValidationYou 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:
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
Now in Example 11-26, we make sure the file isn't too big. Example 11-26. Checking the file size
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.
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
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
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 selectedWhen 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 validationNext, 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, tooOK, 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. |