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.