• Aucun résultat trouvé

Uploading Files

Dans le document Learning PHP, MySQL, JavaScript, and CSS (Page 170-175)

Uploading files to a web server is a subject area that seems daunting to many people, but it actually couldn’t be much easier. All you need to do to upload a file from a form is choose a special type of encoding called multipart/form-data; your browser will han-dle the rest. To see how this works, type in the program in Example 7-15 and save it as upload.php. When you run it, you’ll see a form in your browser that lets you upload a file of your choice.

Example 7-15. Image uploader (upload.php)

Select File: <input type='file' name='filename' size='10' />

$name = $_FILES['filename']['name'];

move_uploaded_file($_FILES['filename']['tmp_name'], $name);

echo "Uploaded image '$name'<br /><img src='$name' />";

}

echo "</body></html>";

?>

Let’s examine this program a section at a time. The first line of the multiline echo statement starts an HTML document, displays the title, and then starts the document’s body.

Next we come to the form that selects the POST method of form submission, sets the target for posted data to the program upload.php (the program itself), and tells the web browser that the data posted should be encoded using the content type multipart/form-data.

With the form set up, the next lines display the prompt “Select File:” and then request two inputs. The first input being asked for is for a file, which is done by using an input type of file and a name of filename. This input field has a width of 10 characters.

The second requested input is just a Submit button that is given the label “Upload”

(replacing the default button text of “Submit Query”). And then the form is closed.

This short program shows a common technique in web programming in which a single program is called twice: once when the user first visits a page, and again when the user presses the Submit button.

The PHP code to receive the uploaded data is fairly simple, because all uploaded files are placed into the associative system array $_FILES. Therefore, a quick check to see whether $_FILES has anything in it is sufficient to determine whether the user has up-loaded a file. This is done with the statement if ($_FILES).

The first time the user visits the page, before uploading a file, $_FILES is empty, so the program skips this block of code. When the user uploads a file, the program runs again and discovers an element in the $_FILES array.

Once the program realizes that a file was uploaded, the actual name, as read from the uploading computer, is retrieved and placed into the variable $name. Now all that’s necessary is to move the uploaded file from the temporary location in which PHP stored it to a more permanent one. This is done using the move_uploaded_file function, passing it the original name of the file, with which it is saved to the current directory.

File Handling | 149

Finally, the uploaded image is displayed within an <IMG> tag, and the result should look like the screen grab in Figure 7-2.

Figure 7-2. Uploading an image as form data

If you run this program and receive warning messages such as “Permis-sion denied” for the move_uploaded_file function call, you may not have the correct permissions set for the folder in which the program is running.

Using $_FILES

Five things are stored in the $_FILES array when a file is uploaded, as shown in Ta-ble 7-6 (where file is the file upload field name supplied by the submitting form).

Table 7-6. The contents of the $_FILES array

Array element Contents

$_FILES['file']['name'] The name of the uploaded file (e.g., smiley.jpg)

$_FILES['file']['type'] The content type of the file (e.g., image/jpeg)

$_FILES['file']['size'] The file’s size in bytes

$_FILES['file']['tmp_name'] The name of the temporary file stored on the server

$_FILES['file']['error'] The error code resulting from the file upload

Content types used to be known as MIME (Multipurpose Internet Mail Extension)

Table 7-7. Some common Internet media content types

Hopefully it now goes without saying (although I’ll do so anyway) that form data val-idation is of the utmost importance, due to the possibility of users attempting to hack into your server.

In addition to maliciously formed input data, some of the things you also have to check are whether a file was actually received and, if so, whether the right type of data was sent.

Taking all these things into account, Example 7-16, upload2.php, is a rewrite of up-load.php.

Example 7-16. A more secure version of upload.php

<?php // upload2.php echo <<<_END

<html><head><title>PHP Form Upload</title></head><body>

<form method='post' action='upload2.php' enctype='multipart/form-data'>

Select a JPG, GIF, PNG or TIF File:

<input type='file' name='filename' size='10' />

<input type='submit' value='Upload' /></form>

_END;

if ($_FILES) {

$name = $_FILES['filename']['name'];

switch($_FILES['filename']['type'])

move_uploaded_file($_FILES['filename']['tmp_name'], $n);

echo "Uploaded image '$name' as '$n':<br />";

echo "<img src='$n' />";

}

else echo "'$name' is not an accepted image file";

}

else echo "No image has been uploaded";

File Handling | 151

echo "</body></html>";

?>

The non-HTML section of code has been expanded from the half-dozen lines of Ex-ample 7-15 to more than 20 lines, starting at: if ($_FILES).

As with the previous version, this if line checks whether any data was actually posted, but there is now a matching else near the bottom of the program that echoes a message to screen when nothing has been uploaded.

Within the if statement, the variable $name is assigned the value of the filename as retrieved from the uploading computer (just as before), but this time we won’t rely on the user having sent us valid data. Instead, a switch statement is used to check the uploaded content type against the four types of images this program supports. If a match is made, the variable $ext is set to the three-letter file extension for that type.

Should no match be found, the file uploaded was not of an accepted type and the variable $ext is set to the empty string "".

The next section of code then checks the variable $ext to see whether it contains a string and, if so, creates a new filename called $n with the base name image and the extension stored in $ext. This means that the program is in full control over the name of the file to be created, as it can be only one of image.jpg, image.gif, image.png, or image.tif.

Safe in the knowledge that the program has not been compromised, the rest of the PHP code is much the same as in the previous version. It moves the uploaded temporary image to its new location and then displays it, while also displaying the old and new image names.

Don’t worry about having to delete the temporary file that PHP creates during the upload process, because if the file has not been moved or renamed, it will be automatically removed when the program exits.

After the if statement there is a matching else, which is executed only if an unsup-ported image type was uploaded, in which case it displays an appropriate error message.

When you write your own file uploading routines, I strongly advise you to use a similar approach and have pre-chosen names and locations for uploaded files. That way no attempts to add pathnames and other malicious data to the variables you use can get through. If this means that more than one user could end up having a file uploaded with the same name, you could prefix such files with the user’s name, or save them to individually created folders for each user.

If, however, you must use a supplied filename, you should sanitize it by allowing only

$name = preg_replace("/[^A-Za-z0-9.]/", "", $name);

This leaves only the characters A–Z, a–z, 0–9 and . in the string $name, and strips out everything else.

Even better, to ensure that your program will work on all systems (regardless of whether they are case-sensitive or case-insensitive), instead use the following command, which changes all uppercase characters to lowercase at the same time:

$name = strtolower(preg_replace("/[^A-Za-z0-9.]/", "", $name));

Sometimes you may encounter the media type image/pjpeg, which in-dicates a progressive JPEG. You can safely add this to your code as an alias of image/jpeg, like this:

case 'image/pjpeg':

case 'image/jpeg': $ext = 'jpg'; break;

Dans le document Learning PHP, MySQL, JavaScript, and CSS (Page 170-175)