Team LiB
Previous Section Next Section

Working with Form Submissions in PHP

Now that you have been introduced to all the different HTML widgets (or if you happened to skip ahead because you knew of them already) it's time to get into the real PHP-related materials of the chapter. The remainder of this chapter will be focused on accessing and working with form (and related) data.

Retrieving Form Values

After a form has been submitted back to the Web server, if the ACTION attribute of the form is a PHP script, that script is executed and is provided the data that was submitted. But how is this data accessed from within PHP? Thankfully, there are a number of very convenient methods to use when retrieving data.

Depending on what method was used to submit the form data to the PHP script (GET or POST), PHP has two superglobal arrays, called $_GET and $_POST, respectively, that will be used to store this data. These variables are associate arrays containing a list of keys (representing the names of the form elements as specified by their NAME attribute) and their associated values. Hence, the value of the $_GET['mytext'] variable will contain the value of the HTML widget whose NAME attribute is mytext:

The HTML widget:

<INPUT TYPE="text" NAME="mytext" VALUE="This is my text!">

The PHP code:

<?php echo $_GET['mytext']; ?>

Output when the form is submitted:

This is my text!

NOTE

The term superglobal was introduced in Chapter 1 and indicates that regardless of the current scope (in a function, for example) the variables $_GET and $_POST will always be available without having to use the global statement to bring them into the current scope. See Chapter 1 for more information.


Using the $_GET array assumes that the form was submitted via the GET method. If the submission was done via the POST method, the data would be stored in the $_POST variable instead. For those circumstances when the method that the data was submitted through is irrelevant (or could be either), a third superglobal array, $_REQUEST, is provided, which combines $_GET, $_POST, $_COOKIE (the superglobal containing cookie variablessee Chapter 5, "Advanced Form Techniques"), and $_FILES (discussed later in the chapter).

For those who have worked with PHP in the past (prior to PHP version 4.1.0), by default, PHP created standard variable names such as $myvalue to represent the value contained within the $_GET['myvariable'] superglobal. Although it is still possible to turn this behavior on by default (by setting the register_globals directive to on), doing so is highly discouraged because of security issues. A much safer approach (accomplishing the same end result) is to use the import_request_variables() function. This function will create global-scope variables such as $myvalue for the values stored in the relevant superglobal arrays. The syntax for this function is as follows:

import_request_variables($types [, $prefix])

When using this function, $types represents a string indicating the types of variables to import and should consist of any combination (not case sensitive) of the letters P, G, and C. These letters represent $_POST, $_GET, and $_COOKIE, respectively. The second optional parameter, $prefix, if provided, should be a string representing what to prefix to the start of every variable created.

In Listing 4.11, assuming that $_GET['myvalue'] exists, you can use the import_request_variables() function to create a local copy of it, as shown:

Listing 4.11. Using the import_request_variables() Function
<?php
    /* Assume $_GET['myvalue'] exists */
    import_request_variables("G", "myget_");
    echo "The value of the 'myvalue' field is: $myget_myvalue";
?>

NOTE

import_request_variables() is recommended over the use of the register_globals configuration directive; however, note that it does not protect you from the security risks associated with working with user data. It is always recommended that data received from the user be sanitized before use. It is also important to note that the import_request_variables() function imports variables into the global scope only. Thus, it should never be used from within a function.


Data-Access "Gotchas"

Now that you have an understanding of how to access external input from your PHP script, a number of small issues may arise in your attempts to work with this knowledge. To save you time, I'll outline these issues, starting with HTML widgets whose name contains a period.

In HTML, it is perfectly acceptable to have a form widget named myvar.email (the value set for the widget's NAME tag). However, recalling the restrictions placed on variable names described in Chapter 1, such a variable name is invalid in PHP. As a consequence, when PHP is provided a form submission that contains a period in one or more of the widget's names, they are converted to an underscore character automatically.

Therefore, this widget's value

<INPUT TYPE="text" NAME="myform.email">

would be accessed in PHP as the following:

<?php
    echo $_GET['myform_email']; 
?>

Although every form can be designed in such a way that no widget is given a name with a period in it, this behavior in PHP is important when dealing with image submission widgets. If an image widget has a NAME attribute, when clicked, it sends as part of the form data the X,Y coordinate of where the user clicked the image. Specifically, the image widget will send these values in the variables AAAAAA.x and AAAAAA.y, where AAAAAA represents the value of the NAME attribute. Thus, to access these values in PHP, the period must be substituted with an underscore as shown:

The image submission widget:

<INPUT TYPE="image" SRC="images/myimagemap.gif" NAME="mymap">

How to access the coordinates from PHP:

<?php echo "X Coordinate: {$_GET['mymap_x']}<BR>
            Y Coordinate: {$_GET['mymap_y']}"; ?>

While I am discussing using the image widget in PHP scripts, I want to point out another common coding mistake in its use. In situations where it would be desirable to have multiple submission widgets for the same form, each submission widget must be given a unique value for its NAME attribute to distinguish each from the other. If the image submission widget is used, often either one or the other X,Y variable is checked to determine which submission image was clicked, using a facility such as if($_GET['myimagename_x']). Unfortunately, this method is the incorrect way to do things. As you know, an image submit widget returns the X,Y values where the user clicked the image to the PHP script. The problem is that the preceding if statement example will fail if the X value returned is 0 (if using a text-based browser, the X,Y coordinate will always be returned as 0,0 when clicked). A much more reliable method is to use the isset() function, as shown in Listing 4.12:

Listing 4.12. Properly Checking for Submission Using Image Widgets

The HTML image submission widgets:

<INPUT TYPE="image" NAME="submit_one" SRC="/images/button1.gif">
<INPUT TYPE="image" NAME="submit_two" SRC="/images/button2.gif">

Properly determining which submission button was clicked in PHP:

<?php
     if(isset($_GET['submit_one_x'])) {

          /* code if the first submit button was pressed */ 

     } elseif(isset($_GET['submit_two_x'])) {
               /* code if the second submit button was pressed */
     } else {

          /* Code if neither submit was pressed */
     }
?>

NOTE

In Listing 4.12, notice that I have included a third case (the last else statement). If there are only two Submit buttons (such as in this example) and both are checked, will the code in the else statement ever be executed? Yes! In Microsoft Internet Explorer, pressing the Enter key while focused on certain widgets (such as a text field) will cause the form to be submitted without either image submit widget being used.


Using Arrays as Widget Names

As I described in the first section of this chapter, the <SELECT> widget can potentially be used to select multiple items and thus have multiple values to pass to PHP. Unfortunately, setting the NAME attribute to something such as myselect will create a variable $_GET['myselect'], which will contain only the last item selected from the list. Obviously, this is not the desired result and another method must be used. To solve this problem, PHP allows you to dynamically create arrays based on form submissions by appending a set of square brackets [] to the end of the name of the widget. Thus, myselect would become myselect[], causing PHP to create an additional item in the array $_GET['myselect'] instead of overwriting the previous value. This concept is illustrated in Listing 4.13:

Listing 4.13. Using Arrays with Form Data in PHP

The HTML code:

<SELECT NAME="myselect[]" MULTIPLE SIZE=3>
<OPTION VALUE="value1">Pick Me!</OPTION>
<OPTION VALUE="value2">No, Pick Me!</OPTION>
<OPTION VALUE="value3">Forget them, pick me!</OPTION>
<OPTION VALUE="value4">Pick me, I'm the best</OPTION>
</SELECT>

The PHP code to access which value(s) were selected:

<?php
     foreach($_GET['myselect'] as $val) {
          echo "You selected: $val<BR>";
     }
     echo "You selected ".count($_GET['myselect'])." Values.";
?>

This technique is not limited to <SELECT> widgets or, for that matter, integer-based arrays. If you would like to provide a string key for a given form widget, specify it (without quotes) within the square brackets:

<INPUT TYPE="text" NAME="data[email]" VALUE="joe.doe@joe.doe.com">

When submitted, the preceding text field's value could be accessed by using $_GET['data']['email'].

Handling File Uploads

NOTE

For file uploading to work properly in PHP, a number of configuration directives should be appropriately set in the php.ini file. Specifically, the file_uploads, uploads_max_filesize, upload_tmp_dir, and post_max_size directives affect PHP's capability to receive uploaded files. For information on these directives, please consult the PHP manual.


As I alluded to in the first section of this chapter, PHP is capable of accepting file uploads from HTML forms via the file widget. When uploading files from an HTML form, some special consideration must be taken regarding the <FORM> tag itself. Specifically, for the file upload to succeed, the ENCTYPE attribute of the <FORM> tag must be set to the MIME value multipart/form-data and the METHOD attribute must be set to POST. An example of an HTML form that uploads a file to the script upload.php is shown in Listing 4.14:

Listing 4.14. Setting Up the HTML to Upload a File via HTTP
<FORM METHOD="POST" ACTION="upload.php" ENCTYPE="multipart/form-data">
<INPUT TYPE="file" NAME="myfile"><BR>
<INPUT TYPE="submit" VALUE="Upload the file">
</FORM>

NOTE

A special hidden form widget with the name MAX_FILE_SIZE may be used to specify the maximum file size accepted for the file upload. This size restriction is enforced on the client side and may not work for all clients. This check along with the upload_max_filesize configuration directive should be used.


When the form in Listing 4.14 is submitted, the file will be uploaded to the Web server and stored in a temporary directory specified by the upload_tmp_dir php.ini directive. PHP then creates a superglobal variable, $_FILES, and, in this case, populates the $_FILES array with a key myfile. The value of this key is another array populated with information about the file that was uploaded. Specifically, the array stored in $_FILES['myfile'] has the keys shown in Table 4.7.

Table 4.7. Keys Created for a File When Uploaded

name

The name of the file as it was on the client machine

type

The MIME type for the file if known

size

The size of the uploaded file in bytes

tmp_name

The temporary name given to the file by PHP when it was uploaded to the server

error

An integer value representing the error that occurred while uploading the file


NOTE

The following array keys may or may not contain a value, depending on the circumstances under which the file was uploaded. For instance, the type key may be empty if the browser did not provide any MIME information.


If an error has occurred during the uploading of the file, $_FILES['myfile']['error'] will be set to an integer representing the error that occurred and representing one of the following constants:

Table 4.8. File Uploading Error Constants in PHP

UPLOAD_ERR_OK

No error occurred.

UPLOAD_ERR_INI_SIZE

The uploaded file exceeds the maximum value specified in the php.ini file.

UPLOAD_ERR_FORM_SIZE

The uploaded file exceeds the maximum value specified by the MAX_FILE_SIZE hidden widget.

UPLOAD_ERR_PARTIAL

The file upload was canceled and only part of the file was uploaded.

UPLOAD_ERR_NOFILE

No file was uploaded.


Assuming the file was uploaded successfully, it must be moved from its current location (the temporary directory) to its permanent location. If the file is not moved, it will be deleted when the PHP script's execution is complete.

Because of security issues, prior to moving the file from its temporary location to a new one, the is_uploaded_file() should be used to confirm that the file was actually uploaded through PHP. After the file has been confirmed, the move_uploaded_file() can be used to move the uploaded file from its current location to a new one. To move the file to the destination directory, PHP must also have write permission for that directory. See Chapter 21, "Working with Streams and the File System," for detailed information on the use of file-uploading related functions and working with permissions.

NOTE

The move_uploaded_file() function assumes the file is stored in the directory specified by the upload_tmp_dir configuration directive.


Listing 4.15 processes the file uploaded in the example described in Listing 4.14:

Listing 4.15. Processing a File Upload in PHP
<?php
     if(is_uploaded_file($_FILES['myfile']['tmp_name'])) {
          move_uploaded_file($_FILES['myfile']['tmp_name'], 
          "/path/to/dir/newname");
     }
?>

    Team LiB
    Previous Section Next Section