简体   繁体   中英

PHP File Upload + Form Validation

I want to validate a file upload beside a validation of other input fields. This sounds not so difficult but if I choose a file and then submit the form, the file would be also temporary uploaded when errors of other inputs exists.

So a user have to fix this errors and then have to choose the file again :(. Is there a way of an user friendly implementation?

My current implementation looks nearly as follows:

I have a simple form like this:

<form method="post" enctype="multipart/form-data">
    <input type="text" name="firstname" value="<?php echo $form->getFirstname() ?>" />
    <input type="text" name="lastname" value="<?php echo $form->getLastname() ?>" />
    <input type="file" name="file" />
    <input type="hidden" name="terms" value="false"/>
    <input type="checkbox" name="terms" value="terms" <?php if ($form->getTerms() === 'terms') echo 'checked' ?> />
    <input type="submit" name="send" value="send" />
</form>

So after submitting this form, all user data like firstname, lastname and terms would be set and validated like:

if ( isset($_POST['send']) && $_POST['send'] === 'send' ) {

    if ( !\Fox\Validator::isString($_POST['firstname']) ) {
        \Fox\Validator::setError(1, 'firstname required');
    } else {
        $form->setFirstname($_POST['firstname']);
    }

    // ... other unimportant validations

    // validate file upload
    if (!isset($_FILES['file']['error']) || is_array($_FILES['file']['error'])) {

        \Fox\Validator::setError(10, 'error occurred');

    } else {

        // check error value
        switch ($_FILES['file']['error']) {

            // file exists
            case UPLOAD_ERR_OK:

                // check filesize (max filesize 100mb)
                if ($_FILES['file']['size'] > 104857600) {

                    \Fox\Validator::setError(10, 'max filesize overridden');

                } else {

                    $finfo = new finfo(FILEINFO_MIME_TYPE);

                    // define allowed mime types
                    $allowedMimeTypes = array(
                        'jpg' => 'image/jpeg',
                        'png' => 'image/png',
                        'gif' => 'image/gif',
                        'bmp' => 'image/bmp',
                        'bmp' => 'image/x-ms-bmp',
                        'bmp' => 'image/x-windows-bmp',
                        'mov' => 'video/quicktime',
                        'avi' => 'video/avi',
                        'avi' => 'video/msvideo',
                        'avi' => 'video/x-msvideo',
                        'mp4' => 'video/mp4',
                        'mpeg' => 'video/mpeg',
                        'mkv' => 'video/x-matroska',
                        'flv' => 'video/x-flv',
                        'wmv' => 'video/x-ms-wmv',
                    );

                    if (false === $ext = array_search($finfo->file($_FILES['file']['tmp_name']), $allowedMimeTypes, true)) {

                        \Fox\Validator::setError(10, 'file not supported');

                    }
                }

                break;

            case UPLOAD_ERR_NO_FILE:

                \Fox\Validator::setError(10, 'no file selected');
                break;

            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:

                \Fox\Validator::setError(10, 'filesize overridden');
                break;

            default:

                \Fox\Validator::setError(10, 'error occurred');
        }

    }

    // check if form errors exists
    if (empty(\Fox\Validator::getError())) {

        // create unique filename
        $tmp = sha1_file($_FILES['file']['tmp_name']);

        // move file
        if (!move_uploaded_file($_FILES['file']['tmp_name'], sprintf('./Files/%s.%s', $tmp, $ext))) {

            \Fox\Validator::setError(10, 'error by uploading file');

        } else {

            header("Location: $successPage");
        }
    }
}

So if no form errors exists the file would be uploaded correctly and the user would be redirect to the success page, but if an error occurred because the user missed an required input field like firstname, the file would be uploaded through the submit action, too but not saved, so the user have to correct the input with errors and select a file again.

Use HTML5 attribute required , like this:

<form method="post" enctype="multipart/form-data">
    <input type="text" name="firstname" value="<?php echo $form->getFirstname() ?>" required/>
    <input type="text" name="lastname" value="<?php echo $form->getLastname() ?>" required/>
    <input type="file" name="file" required/>
    <input type="hidden" name="terms" value="false"/>
    <input type="checkbox" name="terms" value="terms" <?php if ($form->getTerms() === 'terms') echo 'checked' ?> required/>
    <input type="submit" name="send" value="send" />
</form>

Browser will not let user send form, if fields not filled

Ok, I have implemented a solution which Ryan Vincent has described in the comments above and is working with only server side validation.

So I let the uploaded file pass if other form errors exists and upload it to a temp directory. After that I replace the file input field of the form with a success message and a hidden field which contains the temporary filename, so if other form errors occur the file is still persistent in the temp directory and must not be reuploaded. If no form errors occur the file is moved from the temp directory to the target directory.

In Addition a cronjob flushes the temp directory in a specific intervall and unused files will be deleted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM