【问题标题】:PHP File Upload + Form ValidationPHP文件上传+表单验证
【发布时间】:2015-10-31 09:47:09
【问题描述】:

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

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

我当前的实现大致如下:

我有一个这样的简单表格:

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

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

【问题讨论】:

  • 您希望输入选择相同的文件吗?
  • imo,这样做的一种方法是:1) 文件被上传,然后您将其移动到“临时暂存区”,直到您验证所有其他信息。 1 a] 您告诉用户文件上传正常,但正在等待您需要的任何许可。 2)您将其移至“永久区域”。你告诉用户数据验证是好的。这些都是服务器端验证检查。您每隔几个小时清理一次“临时暂存区”。
  • @phplover 是的,但这是不可能的还是我错了?
  • @Ryan 好的,所以我必须将文件移动到临时暂存区域或直接移动到永久区域,但例如当用户忘记设置名字时,文件将是上传到临时或永久登台,用户必须再次检查表单,到目前为止一切顺利。但是我怎样才能防止用户之后上传另一个文件呢?我应该使用像 $fileIsUploaded 这样的布尔标志并检查这个标志是真还是假?
  • 如果表单没有发现错误,为什么不直接上传文件?

标签: php validation file-upload


【解决方案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>

如果字段未填写,浏览器将不允许用户发送表单

【讨论】:

  • 请注意,一般情况下,不应使用此客户端验证来代替服务器端验证,因为如果人们尝试直接向服务器发帖,这会给您带来各种麻烦。跨度>
  • @Gnarlywhale 当然,您需要保持服务器端验证,但这有助于用户检查他的输入
  • 该评论仅针对 Fox,因为最初的问题暗示他们是开发新手,可能不了解最佳实践。
  • @Gnarlywhale 好的,对不起
  • 是的,我也可以在客户端使用 html5 或 js 验证,但我也想要一个服务器端工作解决方案:)
【解决方案2】:

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

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

此外,cronjob 会在特定的时间间隔内刷新临时目录,并且将删除未使用的文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    • 2012-09-08
    • 2012-11-02
    • 2014-09-06
    • 2011-06-29
    • 2013-03-13
    相关资源
    最近更新 更多