© Frank M. Kromann 2018
Frank M. KromannBeginning PHP and MySQLhttps://doi.org/10.1007/978-1-4302-6044-8_15

15. Handling File Uploads

Frank M. Kromann1 
(1)
Aliso Viejo, CA, USA
 
Most people know that the Web’s HTTP protocol is primarily involved in the transfer of web pages from a server to the user’s browser. However, it’s actually possible to transfer of any kind of file via HTTP, including images, Microsoft Office documents, PDFs, executables, MPEGs, ZIP files, and a wide range of other file types. Although FTP historically has been the standard means for uploading files to a server, file transfers are becoming increasingly prevalent via a web-based interface. In this chapter, you’ll learn all about PHP’s file upload handling capabilities, including the following topics:
  • PHP’s file upload configuration directives

  • PHP’s $_FILES superglobal array, used to handle file-upload data

  • PHP’s built-in file-upload functions: is_uploaded_file() and move_uploaded_file()

  • A review of possible error messages returned from an upload script

Several real-world examples are offered throughout this chapter, providing you with applicable insight into this topic.

Uploading Files via HTTP

The way files are uploaded via a web browser was officially formalized in November 1995 when Ernesto Nebel and Larry Masinter of the Xerox Corporation proposed a standardized methodology for doing so within RFC 1867, “Form-Based File Upload in HTML” ( https://www.ietf.org/rfc/rfc1867.txt ). This memo, which formulated the groundwork for making the additions necessary to HTML to allow for file uploads (subsequently incorporated into HTML 3.0), also offered the specification for a new Internet media type, multipart/form-data. This new media type was desired because the standard type used to encode “normal” form values, application/x-www-form-urlencoded, was considered too inefficient to handle large quantities of binary data that might be uploaded via such a form interface. An example of a file-uploading form follows, and a screenshot of the corresponding output is shown in Figure 15-1:
<form action="uploadmanager.html" enctype="multipart/form-data" method="post">
  <label form="name">Name:</label><br>
  <input type="text" name="name" value=""><br>
  <label form="email">Email:</label><br>
  <input type="text" name="email" value=""><br>
  <label form="homework">Class notes:</label>
  <input type="file" name="homework" value=""><br>
  <input type="submit" name="submit" value="Submit Homework">
</form>
../images/314623_5_En_15_Chapter/314623_5_En_15_Fig1_HTML.jpg
Figure 15-1

HTML form incorporating the file input type tag

Understand that this form offers only part of the desired result; whereas the file input type and other upload-related attributes standardize the way files are sent to the server via an HTML page, no capabilities are available for determining what happens once that file gets there. The reception and subsequent handling of the uploaded files are a function of an upload handler, created using some server process or capable server-side language such as Perl, Java, or PHP. The remainder of this chapter is devoted to this aspect of the upload process.

Uploading Files with PHP

Successfully managing file uploads via PHP is the result of cooperation between various configuration directives, the $_FILES superglobal, and a properly coded web form. In the following sections, all three topics are introduced, concluding with a number of examples.

PHP’s File Upload/Resource Directives

Several configuration directives are available for fine-tuning PHP’s file-upload capabilities. These directives determine whether PHP’s file-upload support is enabled, as well as the maximum allowable uploadable file size, the maximum allowable script memory allocation, and various other important resource benchmarks.

file_uploads = On | Off

Scope: PHP_INI_SYSTEM; Default value: On

The file_uploads directive determines whether PHP scripts on the server can accept file uploads.

max_input_time = integer

Scope: PHP_INI_ALL; Default value: -1

The max_input_time directive determines the maximum amount of time, in seconds, that a PHP script will spend attempting to parse input before registering a fatal error. The default value of -1 indicates unlimited time if the time is counted from the start of execution and not from the time input is available. This is relevant because particularly large files can take some time to upload, eclipsing the time limit set by this directive. Note that if you create an upload feature that handles large documents or high-resolution photos, you may need to increase the limit set by this directive accordingly.

max_file_uploads = integer

Scope: PHP_INI_SYSTEM; Default value: 20

The max_file_uploads directive sets an upper limit on the number of files that can be simultaneously uploaded.

memory_limit = integer

Scope: PHP_INI_ALL; Default value: 16M

The memory_limit directive sets a maximum allowable amount of memory in megabytes that a script can allocate, (Thevalue is provided in bytes but you can use shorthand by adding k, M, or G for kilo, Mega, and Giga bytes.) When you are uploading files, PHP will allocate memory to hold the content of the POST data in memory. The memory limit should be set to a vaue larger than post_max_size. Use this to prevents runaway scripts from monopolizing server memory and even crashing the server in certain situations.

post_max_size = integer

Scope: PHP_INI_PERDIR; Default value: 8M

The post_max_size places an upper limit on the size of data submitted via the POST method. Because files are uploaded using POST, you may need to adjust this setting upward along with upload_max_filesize when working with larger files. The post_max_size should be at least as big as upload_max_filesize.

upload_max_filesize = integer

Scope: PHP_INI_PERDIR; Default value: 2M

The upload_max_filesize directive determines the maximum size of an uploaded file. This limit is for a single file. If your upload multiple files with a single post request, this values sets the maximum size for each file. This directive should be smaller than post_max_size because it applies only to information passed via the file input type and not to all information passed via the POST instance. Like memory_limit.

upload_tmp_dir = string

Scope: PHP_INI_SYSTEM; Default value: NULL

Because an uploaded file must be successfully transferred to the server before subsequent processing on that file can begin, a staging area of sorts must be designated for such files where they can be temporarily placed until they are moved to their final location. This staging location is specified using the upload_tmp_dir directive . For example, suppose you want to temporarily store uploaded files in the /tmp/phpuploads/ directory. You would use the following:
upload_tmp_dir = "/tmp/phpuploads/"

Keep in mind that this directory must be writable by the user owning the server process. Therefore, if user nobody owns the Apache process, user nobody should be made either the owner of the temporary upload directory or a member of the group owning that directory. If this is not done, user nobody will be unable to write the file to the directory (unless world write permissions are assigned to the directory). If upload_tmp_dir is undefined or set to null the system defined tmp dir will be used. On most Linux systems this will be /tmp.

The $_FILES Array

The $_FILES superglobal stores a variety of information pertinent to a file uploaded to the server via a PHP script. In total, five items are available in this array, each of which is introduced here.

Note

Each of the array elements introduced in this section makes reference to userfile. This term is simply a placeholder for the name assigned to the file-upload form element and is not related to the file name on the user’s hard drive. You will probably change this name in accordance with your chosen name assignment.

  • $_FILES['userfile']['error']: This array value offers important information pertinent to the outcome of the upload attempt. In total, five return values are possible: one signifying a successful outcome and four others denoting specific errors that arise from the attempt. The name and meaning of each return value is introduced in the “Upload Error Messages” Section.

  • $_FILES['userfile']['name']: This variable specifies the original name of the file, including the extension, as declared on the client machine. Therefore, if you browse to a file named vacation.png and upload it via the form, this variable will be assigned the value vacation.png.

  • $_FILES['userfile']['size']: This variable specifies the size, in bytes, of the file uploaded from the client machine. For example, in the case of the vacation.png file, this variable could plausibly be assigned a value such as 5253, or roughly 5KB.

  • $_FILES['userfile']['tmp_name']: This variable specifies the temporary name assigned to the file once it has been uploaded to the server. This value is generated automatically by PHP when the file is saved to the temporary directory (specified by the PHP directive upload_tmp_dir).

  • $_FILES['userfile']['type']: This variable specifies the MIME type of the file uploaded from the client machine. Therefore, in the case of the vacation.png image file, this variable would be assigned the value image/png. If a PDF was uploaded, the value application/pdf would be assigned. Because this variable sometimes produces unexpected results, you should explicitly verify it yourself from within the script.

PHP’s File-Upload Functions

In addition to the number of file-handling functions made available via PHP’s file system library (see Chapter 10 for more information), PHP offers two functions specifically intended to aid in the file-upload process, is_uploaded_file() and move_uploaded_file() .

Determining Whether a File Was Uploaded

The is_uploaded_file() function determines whether a file specified by the input parameter filename is uploaded using the POST method. Its prototype follows:
boolean is_uploaded_file(string filename)
This function is intended to prevent a potential attacker from manipulating files not intended for interaction via the script in question. The function checks if the file was uploaded via HTTP POST and not just any file on the system. The following example shows how a simple check is done before the uploaded file is moved to its final location.
<?php
if (is_uploaded_file($_FILES['classnotes']['tmp_name'])) {
     copy($_FILES['classnotes']['tmp_name'],
              "/www/htdocs/classnotes/".$_FILES['classnotes']['name']);
} else {
     echo "<p>Potential script abuse attempt detected.</p>";
}
?>

Moving an Uploaded File

The move_uploaded_file() function provides a convenient means for moving an uploaded file from the temporary directory to a final location. Its prototype follows:
boolean move_uploaded_file(string filename, string destination)

Although copy() works equally well, move_uploaded_file() offers one additional feature: it will check to ensure that the file denoted by the filename input parameter was in fact uploaded via PHP’s HTTP POST upload mechanism. If the file has not been uploaded, the move will fail and a FALSE value will be returned. Because of this, you can forgo using is_uploaded_file() as a precursor condition to using move_uploaded_file() .

Using move_uploaded_file() is simple. Consider a scenario in which you want to move the uploaded class notes file to the directory /www/htdocs/classnotes/ while also preserving the file name as specified on the client:
move_uploaded_file($_FILES['classnotes']['tmp_name'],
                        "/www/htdocs/classnotes/".$_FILES['classnotes']['name']);

Of course, you can rename the file to anything you wish after it’s been moved. It’s important, however, that you properly reference the file’s temporary name within the first (source) parameter.

Upload Error Messages

Like any other application component involving user interaction, you need a means to assess the outcome, successful or otherwise. How do you know with certainty that the file-upload procedure was successful? And if something goes awry during the upload process, how do you know what caused the error? Happily, sufficient information for determining the outcome (and in the case of an error, the reason for the error) is provided in $_FILES['userfile']['error']:
  • UPLOAD_ERR_OK: A value of 0 is returned if the upload is successful.

  • UPLOAD_ERR_INI_SIZE: A value of 1 is returned if there is an attempt to upload a file whose size exceeds the value specified by the upload_max_filesize directive .

  • UPLOAD_ERR_FORM_SIZE: A value of 2 is returned if there is an attempt to upload a file whose size exceeds the value of the max_file_size directive , which can be embedded into the HTML form

Note

Because the max_file_size directive is embedded within the HTML form, it can easily be modified by an enterprising attacker. Therefore, always use PHP’s server-side settings (upload_max_filesize , post_max_filesize ) to ensure that such predetermined absolutes are not surpassed.

  • UPLOAD_ERR_PARTIAL: A value of 3 is returned if a file is not completely uploaded. This might happen if a network error causes a disruption of the upload process.

  • UPLOAD_ERR_NO_FILE: A value of 4 is returned if the user submits the form without specifying a file for upload.

  • UPLOAD_ERR_NO_TMP_DIR: A value of 6 is returned if the temporary directory does not exist.

  • UPLOAD_ERR_CANT_WRITE: A value of 7 is returned if the file can’t be written to the disk.

  • UPLOAD_ERR_EXTENSION: A value of 8 is returned if one of the installed PHP extensions caused the upload to stop.

A Simple Example

Listing 15-1 (uploadmanager.php) implements the class notes example referred to throughout this chapter. To formalize the scenario, suppose that a professor invites students to post class notes to his website, the idea being that everyone might have something to gain from such a collaborative effort. Of course, credit should nonetheless be given where credit is due, so each file upload should be renamed to the include the last name of the student. In addition, only PDF files are accepted.
<form action="listing15-1.php" enctype="multipart/form-data" method="post">
  <label form="email">Email:</label><br>
  <input type="text" name="email" value=""><br>
  <label form="lastname">Last Name:</label><br>
  <input type="text" name="lastname" value=""><br>
  <label form="classnotes">Class notes:</label><br>
  <input type="file" name="classnotes" value=""><br>
  <input type="submit" name="submit" value="Submit Notes">
</form>
<?php
// Set a constant
define ("FILEREPOSITORY","/var/www/5e/15/classnotes");
// Make sure that the file was POSTed.
If ($_FILES['classnotes']['error'] == UPLOAD_ERR_OK) {
    if (is_uploaded_file($_FILES['classnotes']['tmp_name'])) {
        // Was the file a PDF?
        if ($_FILES['classnotes']['type'] != "application/pdf") {
            echo "<p>Class notes must be uploaded in PDF format.</p>";
        } else {
            // Move uploaded file to final destination.
            $result = move_uploaded_file($_FILES['classnotes']['tmp_name'],
                      FILEREPOSITORY . $_POST['lastname'] . '_' . $_FILES['classnotes']['name']);
           if ($result == 1) echo "<p>File successfully uploaded.</p>";
               else echo "<p>There was a problem uploading the file.</p>";
        }
    }
}
else {
    echo "<p>There was a problem with the upload. Error code {$_FILES['classnotes']['error']}</p>”;
}
?>
Listing 15-1

A Simple File-Upload Example

Caution

Remember that files are both uploaded and moved under the guise of the web server daemon owner. Failing to assign adequate permissions to both the temporary upload directory and the final directory destination for this user will result in failure to properly execute the file-upload procedure.

Although it’s quite easy to manually create your own file-upload mechanism, the HTTP_Upload PEAR package truly renders the task a trivial affair.

Summary

Transferring files via the Web eliminates a great many inconveniences otherwise posed by firewalls, FTP servers, and clients. There is no need for additional applications and security can be managed within the web application. It also enhances an application’s ability to easily manipulate and publish nontraditional files. In this chapter, you learned just how easy it is to add such capabilities to your PHP applications. In addition to offering a comprehensive overview of PHP’s file-upload features, several practical examples were discussed.

The next chapter introduces in great detail the highly useful Web development topic of tracking users via session handling.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.72.224