1

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.

6
  • You want the input to have the same file selected? Commented Aug 7, 2015 at 20:47
  • imo, One way of doing this is: 1) the file gets uploaded and you move it to a 'temporary staging area' until you have all the other information validated. 1 a] You tell the user that the file upload was ok but are waiting for whatever clearances you need. 2) you move it to the 'permanent area'. You tell the user that the data validation is good. These are all server side validation checks. You cleanup the 'temporary staging area' every few hours. Commented Aug 7, 2015 at 21:31
  • @phplover yes, but this is impossible or am I wrong? Commented Aug 8, 2015 at 8:36
  • @Ryan ok, so I have to move the file into a temporary staging area or directly to the permanent area, but for example what is when the user forgot to set the firstname, so the file would be uploaded to the temporary or permanent staging and the user have to check the form again, so far so good. But how can I prevent that the user upload a another file afterwards? Should I use a boolean flag like $fileIsUploaded and check if this flag is true or false? Commented Aug 8, 2015 at 8:36
  • Why dont you just make the file upload if no errors were found in the form? Commented Aug 8, 2015 at 8:37

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

10 Comments

Note that in general, this client side validation should not be used instead of the server side validation, since that opens you up to all sorts of trouble if people attempt to post to the server directly.
@Gnarlywhale Of course, you need to keep server side validation, but this helps user to check his input
The comment was just for Fox, since the original question implies they are new to development and may not know best practices.
@Gnarlywhale OK, Sorry
yeah I can use html5 or js validation for client side, too, but I want a server side working solution, too :)
|
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.