• Aucun résultat trouvé

Rejecting large files

Dans le document DAVID POWERS Y (Page 182-186)

The ability to upload files is not enough on its own: you need to make your form more secure. The first step is to set a maximum size for file uploads. Even if your hosting com-pany sets a lower limit than the 2MB default, you may want to set a much lower limit your-self. At the same time, it’s a good idea to make your form more user-friendly by reporting whether the upload was successful. You can do this easily by checking the error level reported by the $_FILESarray (see Table 6-2).

Continue working with the previous file. Alternatively, use upload05.phpfrom the down-load files. The final code for this PHP Solution is in updown-load06.php.

1.In addition to the automatic limits set in the PHP configuration (see Table 6-1), you can also specify a maximum size for an upload file in your XHTML form. Add the following line highlighted in bold immediately before the file input field:

<label for="image">Upload image:</label>

<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo ➥ MAX_FILE_SIZE; ?>" />

<input type="file" name="image" id="image" />

This is a hidden form field, so it won’t be displayed onscreen. However, it is vital that you place it before the file input field; otherwise, it won’t work. The value attribute sets the maximum size of the upload file in bytes. Instead of specifying a numeric value, I have used a constant, which needs to be defined next.

PHP Solution 6-3: Setting a size limit and displaying outcome

6

2.Scroll up to the top of upload.php, and define the value of MAX_FILE_SIZE imme-diately after the opening PHP tag like this:

<?php

// define a constant for the maximum upload size define ('MAX_FILE_SIZE', 3000);

if (array_key_exists('upload', $_POST)) {

I have deliberately chosen a very small size (3,000 bytes) for testing purposes.

3.Save upload.phpand load it in a browser. Select a file bigger than 2.9KB to upload.

Click the Uploadbutton, and check the upload folder. The file shouldn’t be there. If you’re in the mood for experimentation, move the MAX_FILE_SIZE hidden field below the file input field, and try it again. This time the file should be copied to your upload folder. Move the hidden field back to its original position before continuing.

The advantage of using MAX_FILE_SIZEis that PHP abandons the upload if the file is bigger than the stipulated value, avoiding unnecessary delay if the file is too big.

4.Unfortunately, users can get around this restriction by faking the value of MAX_FILE_SIZEin the hidden field, so it’s important to check the actual size of the file on the server side, too. Add the code shown here in bold immediately after the line that removes spaces from filenames.

$file = str_replace(' ', '_', $_FILES['image']['name']);

// convert the maximum size to KB

$max = number_format(MAX_FILE_SIZE/1024, 1).'KB';

// begin by assuming the file is unacceptable

$sizeOK = false;

// check that file is within the permitted size

if ($_FILES['image']['size'] > 0 && $_FILES['image']['size'] <= ➥ MAX_FILE_SIZE) {

$sizeOK = true;

}

// move the file to the upload folder and rename it

The first line of new code is typical of the concise way PHP is often written:

$max = number_format(MAX_FILE_SIZE/1024, 1).'KB';

It converts MAX_FILE_SIZEfrom bytes to kilobytes and formats it all in one pass.

The number_format()function normally takes two arguments: a number that you want nicely formatted with commas as the thousands-separator and the number of decimal places to be displayed. To get the number of kilobytes, you need to divide MAX_FILE_SIZEby 1,024; and PHP takes that calculation as the first argument. It’s also perfectly happy for you to tag KB on the end with the concatenation operator (a period). If you find this difficult to follow, the following three lines do exactly the same:

$kilobytes = MAX_FILE_SIZE/1024;

$formatted = number_format($kilobytes, 1);

$max = $formatted.'KB';

After converting MAX_FILE_SIZE, the script assumes that the file is too big by set-ting a variable $sizeOKto false. The guilty until proven innocent approach may seem harsh, but it’s wise on the Web.

Finally, an ifstatement checks whether $_FILES['image']['size']is greater than 0 and less than or equal to MAX_FILE_SIZE. You need to check both conditions, because $_FILES['image']['size']is set to 0 if PHP detects that the file is larger than the maximum permitted by the hidden field or the server configuration. If the size is within the acceptable range, $sizeOKis set to true.

5.You can now use $sizeOKto control whether the file is moved to the upload folder.

PHP Solutions 6-1 and 6-2 assume that the upload is successful, but that may not always be the case. It’s a good idea to check the error level (see Table 6-2) reported by the $_FILESarray, so you can inform users what happens to their upload.

This means that you need to create a series of nested decisions. One way is to nest lots of if... else statements inside each other. The code is more readable, though, if you use a switchstatement (see “Using the switch statement for deci-sion chains” in Chapter 3) in combination with if... else. Amend the remaining part of the PHP code above the DOCTYPEdeclaration like this (new code is in bold):

// check that file is within the permitted size

if ($_FILES['image']['size'] > 0 && $_FILES['image']['size'] <= ➥ MAX_FILE_SIZE) {

// move the file to the upload folder and rename it

$success = move_uploaded_file($_FILES['image']['tmp_name'], ➥

$result = "Error uploading $file. Please try again.";

} break;

case 3:

$result = "Error uploading $file. Please try again.";

default:

$result = "System error uploading $file. Contact webmaster.";

}

$result = "$file cannot be uploaded. Maximum size: $max.";

} }

6

The basic structure here is an if... elsestatement, which determines whether the size of the uploaded file is acceptable. If it is, the switch statement examines the value of $_FILES['image']['error'].

Error level 0 indicates the file was uploaded successfully, so it’s OK to move it to the upload folder. As long as the folder has the correct permissions, and there’s suffi-cient disk space, this operation should succeed. However, move_uploaded_file() returns a Boolean value, so you can verify the outcome of the operation by captur-ing the result in $success. If $successis true, you can report the successful upload.

Otherwise, inform the user of a problem.

Error levels 1 and 2 both indicate that the file exceeds the maximum size. You don’t need to check for either of these, because the code in step 4 already takes care of files that are too big. Error level 3 indicates that the upload was incomplete, so a suitable message is stored in $result.

Using defaultat the end of the switchstatement covers any remaining possibili-ties. Since the $_FILESarray reports a size of 0 when no file is selected, $sizeOK remains false, so the switchstatement never encounters error level 4, which is handled separately in the elseifclause. That leaves error levels 6 (no temporary folder) and 7 (cannot write file). These are system errors that the user cannot over-come by trying again, so a suitable catchall message is used.

Finally, if the file is too big, a message is prepared, saying that the file can’t be uploaded and reporting the maximum permitted size.

6.The common feature of every branch of this decision chain is that a message reporting the outcome of the upload is stored in $result. All that’s needed now is to display the contents of $resultafter the form is submitted. Insert the following code between the opening <body>and <form>tags:

<body>

<?php

// if the form has been submitted, display result if (isset($result)) {

Since $resultis set only after the form has been submitted, this new code block is ignored when the form first loads, but displays the outcome of any upload operation.

7.Let’s test the page. Save upload.phpand select an image that’s bigger than 2.9KB.

Click Upload. You should see an error message like the following:

8.Change MAX_FILE_SIZE to something more reasonable—say, 51200 (50KB)—like this:

// define a constant for the maximum upload size define ('MAX_FILE_SIZE', 51200);

9.Save output.phpand test the file again, mak-ing sure you choose an image that’s smaller than MAX_FILE_SIZE. This time you should see a message like the one shown to the right.

10.Check inside the upload folder. Your image should be there. You can compare your code with upload06.phpif you run into any prob-lems. Change the value of MAX_FILE_SIZEto suit your particular needs.

Dans le document DAVID POWERS Y (Page 182-186)