PHP文件上传+表单验证

时间:2015-08-07 20:45:25

标签: php validation file-upload

我想验证其他输入字段验证旁边的文件上传。这听起来不是那么困难,但如果我选择一个文件然后提交表单,那么当存在其他输入的错误时,该文件也将被临时上传。

因此,用户必须修复此错误,然后必须再次选择该文件:(。有没有一种用户友好的实现方式?

我目前的实施情况如下:

我有一个这样的简单形式:

<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>

因此,在提交此表单后,所有用户数据(如姓名,姓氏和条款)都将设置和验证,如:

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");
        }
    }
}

因此,如果不存在表单错误,则文件将被正确上载,并且用户将重定向到成功页面,但如果由于用户错过了必需的输入字段(如firstname)而发生错误,则该文件将通过提交上载动作也是如此,但未保存,因此用户必须更正错误的输入并再次选择文件。

2 个答案:

答案 0 :(得分:1)

使用HTML5属性required,如下所示:

<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>

如果字段未填写

,浏览器将不允许用户发送表单

答案 1 :(得分:0)

好的,我已经实现了Ryan Vincent在上面的评论中描述的解决方案,并且只使用服务器端验证。

所以如果存在其他表单错误,我会让上传的文件通过,并将其上传到临时目录。之后,我用成功消息和包含临时文件名的隐藏字段替换表单的文件输入字段,因此如果发生其他表单错误,文件仍然在临时目录中持久存在,不得重新上载。如果没有出现表单错误,则将文件从临时目录移动到目标目录。

另外,cronjob会刷新特定intervall中的temp目录,并且将删除未使用的文件。