PhpRiot
Become Zend Certified

Prepare for the ZCE exam using our quizzes (web or iPad/iPhone). More info...


When you're ready get 7.5% off your exam voucher using voucher CJQNOV23 at the Zend Store

Storing Images in MySQL Revisited

Handling The File Upload

Now that users can select a file and upload it, we must implement the form processor. We will do this in the process.php script that the upload form points to.

As discussed on the PHP manual, the details of the uploaded file are stored in the $_FILES superglobal.

One of the fields included in the upload data is an error code. This helps you determined if the file was successfully uploaded. You can find a list of the error codes at http://www.php.net/manual/en/features.file-upload.errors.php.

The following listing shows a function we can use to check that a file was successfully uploaded based on its error. If the file was not successfully uploaded an exception is thrown with a relevant error message. If successful, nothing happens.

Listing 6 Asserting a file upload was successful (listing-6.php)
<?php
    function assertValidUpload($code)
    {
        if ($code == UPLOAD_ERR_OK) {
            return;
        }
 
        switch ($code) {
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                $msg = 'Image is too large';
                break;
 
            case UPLOAD_ERR_PARTIAL:
                $msg = 'Image was only partially uploaded';
                break;
 
            case UPLOAD_ERR_NO_FILE:
                $msg = 'No image was uploaded';
                break;
 
            case UPLOAD_ERR_NO_TMP_DIR:
                $msg = 'Upload folder not found';
                break;
 
            case UPLOAD_ERR_CANT_WRITE:
                $msg = 'Unable to write uploaded file';
                break;
 
            case UPLOAD_ERR_EXTENSION:
                $msg = 'Upload failed due to extension';
                break;
 
            default:
                $msg = 'Unknown error';
        }
 
        throw new Exception($msg);
    }
?>

Once we know the upload was successful, we must perform some other validation on the upload. We are checking the following things:

  • Ensuring the file saved on the server was in fact from a PHP upload and not tampered with on the server. This is done using is_uploaded_file().
  • Ensuring the uploaded file is an image. We can use the getImageSize() function to determine this.

To make checking of all of these conditions simpler, we wrap the validation in try/catch block. We can then handle the exception to retrieve any error messages.

The following listing shows how we validate the uploaded file. This includes firstly ensuring the upload data is in $_FILES, then making use of the assertValidUpload() function.

Listing 7 Validating the uploaded file (listing-7.php)
<?php
    $errors = array();
 
    try {
        if (!array_key_exists('image', $_FILES)) {
            throw new Exception('Image not found in uploaded data');
        }
 
        $image = $_FILES['image'];
 
        // ensure the file was successfully uploaded
        assertValidUpload($image['error']);
 
        if (!is_uploaded_file($image['tmp_name'])) {
            throw new Exception('File is not an uploaded file');
        }
 
        $info = getImageSize($image['tmp_name']);
 
        if (!$info) {
            throw new Exception('File is not an image');
        }
    }
    catch (Exception $ex) {
        $errors[] = $ex->getMessage();
    }
?>

Once we know the uploaded file is valid we can insert it into the database. The following listing shows the entire upload.php script. When validating the upload we used the getImageSize() function. This is useful not only to determine if a file is an image, but also what kind of image it is. We use the returned mime value to fill the mime_type column in the database.

Listing 8 The full upload script (process.php)
<?php
    require_once('globals.php');
 
    function assertValidUpload($code)
    {
        if ($code == UPLOAD_ERR_OK) {
            return;
        }
 
        switch ($code) {
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                $msg = 'Image is too large';
                break;
 
            case UPLOAD_ERR_PARTIAL:
                $msg = 'Image was only partially uploaded';
                break;
 
            case UPLOAD_ERR_NO_FILE:
                $msg = 'No image was uploaded';
                break;
 
            case UPLOAD_ERR_NO_TMP_DIR:
                $msg = 'Upload folder not found';
                break;
 
            case UPLOAD_ERR_CANT_WRITE:
                $msg = 'Unable to write uploaded file';
                break;
 
            case UPLOAD_ERR_EXTENSION:
                $msg = 'Upload failed due to extension';
                break;
 
            default:
                $msg = 'Unknown error';
        }
 
        throw new Exception($msg);
    }
 
    $errors = array();
 
    try {
        if (!array_key_exists('image', $_FILES)) {
            throw new Exception('Image not found in uploaded data');
        }
 
        $image = $_FILES['image'];
 
        // ensure the file was successfully uploaded
        assertValidUpload($image['error']);
 
        if (!is_uploaded_file($image['tmp_name'])) {
            throw new Exception('File is not an uploaded file');
        }
 
        $info = getImageSize($image['tmp_name']);
 
        if (!$info) {
            throw new Exception('File is not an image');
        }
    }
    catch (Exception $ex) {
        $errors[] = $ex->getMessage();
    }
 
    if (count($errors) == 0) {
        // no errors, so insert the image
 
        $query = sprintf(
            "insert into images (filename, mime_type, file_size, file_data)
                values ('%s', '%s', %d, '%s')",
            mysql_real_escape_string($image['name']),
            mysql_real_escape_string($info['mime']),
            $image['size'],
            mysql_real_escape_string(
                file_get_contents($image['tmp_name'])
            )
        );
 
        mysql_query($query, $db);
 
        $id = (int) mysql_insert_id($db);
 
        // finally, redirect the user to view the new image
        header('Location: view.php?id=' . $id);
        exit;
    }
?>
<html>
    <head>
        <title>Error</title>
    </head>
    <body>
        <div>
            <p>
                The following errors occurred:
            </p>
 
            <ul>
                <?php foreach ($errors as $error) { ?>
                    <li>
                        <?php echo htmlSpecialChars($error) ?>
                    </li>
                <?php } ?>
            </ul>
 
            <p>
                <a href="upload.php">Try again</a>
            </p>
        </div>
    </body>
</html>

If the upload is successful we redirect the user to the view.php script. We'll implement this script shortly. We pass the ID stored in the database of the newly uploaded image. We retrieve this using the mysql_insert_id() method.

If the upload is not successful, the reason for the failure is displayed and the user can go back and try another upload.

In This Article



Bonus listings: 1 available