PHP文件上传功能忽略已设3项校验限制规则问题咨询
问题原因
- 文件名大写校验逻辑存在缺陷
ctype_lower()函数的判断规则是:仅当字符串中所有字母都是小写且至少包含1个字母时才返回true。如果文件名不含任何字母、或者全小写字母,要么会误判通过校验,要么会触发错误的提示信息。 - 校验分支的错误提示逻辑不匹配
文件名校验的else分支统一输出“文件名不能超过50字符”的提示,当文件名长度符合要求但全小写时,用户看不到正确的错误提示,也会误以为规则未生效。 - 超大文件的大小校验逻辑失效
如果上传的文件大小超过php.ini中upload_max_filesize或表单MAX_FILE_SIZE的限制,PHP会直接将$_FILES["uploadedFile"]["size"]置为0,此时会通过你写的$_FILES["uploadedFile"]["size"] < 3000000判断,不会触发你写的大小超限逻辑。 - 错误码校验顺序错位
你把$_FILES["uploadedFile"]["error"]的判断放在了MIME校验之后,上传出错的文件(比如大小超限的文件)会先走完前面的大小、文件名、MIME校验,才会报错,逻辑顺序不合理。
修复后的完整代码
<?php // 先判断文件字段是否正常上传 if (!isset($_FILES["uploadedFile"]) || $_FILES["uploadedFile"]["error"] != UPLOAD_ERR_OK) { $errorMap = [ UPLOAD_ERR_INI_SIZE => '文件大小超过服务器限制', UPLOAD_ERR_FORM_SIZE => '文件大小超过表单限制', UPLOAD_ERR_PARTIAL => '文件仅部分被上传', UPLOAD_ERR_NO_FILE => '没有文件被上传', UPLOAD_ERR_NO_TMP_DIR => '找不到临时文件夹', UPLOAD_ERR_CANT_WRITE => '文件写入失败', UPLOAD_ERR_EXTENSION => '文件上传被扩展中断' ]; $errorCode = $_FILES["uploadedFile"]["error"] ?? -1; echo "上传错误:" . ($errorMap[$errorCode] ?? '未知错误'); exit; } // 1. 校验文件大小 3MB = 3*1024*1024 = 3145728字节,也可保留你原有的3000000数值 $maxSize = 3145728; if ($_FILES["uploadedFile"]["size"] >= $maxSize) { echo "Invalid file size. Must be less than 3MB."; exit; } $fileName = $_FILES["uploadedFile"]["name"]; // 2. 校验文件名长度 if (strlen($fileName) > 50) { echo "The file name must not exceed 50 characters"; exit; } // 3. 校验文件名至少包含1个大写字母 if (!preg_match('/[A-Z]/', $fileName)) { echo "The file name must contain at least one uppercase letter"; exit; } // 4. 校验文件MIME类型 $acceptedFileTypes = ["image/gif", "image/jpg", "image/jpeg","image/png"]; $fileinfo = finfo_open(FILEINFO_MIME_TYPE); $uploadedFileType = finfo_file($fileinfo, $_FILES["uploadedFile"]["tmp_name"]); if (!in_array($uploadedFileType, $acceptedFileTypes)) { echo "Invalid file type. Must be gif, jpg or jpeg."; exit; } // 校验upload目录是否存在,不存在则创建 $uploadDir = "upload/"; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); } $targetPath = $uploadDir . $fileName; // 校验文件是否已存在 if (file_exists($targetPath)) { echo $fileName . " already exists. "; exit; } // 移动文件 if (move_uploaded_file($_FILES["uploadedFile"]["tmp_name"], $targetPath)) { echo "Upload: " . $fileName . "<br />"; echo "Type: " . $uploadedFileType . "<br />"; echo "Size: " . ($_FILES["uploadedFile"]["size"] / 1024) . " Kb<br />"; echo "Stored"; } else { echo "Something went wrong while uploading."; } ?>
修复说明
- 调整了校验顺序,优先判断上传错误码,再依次校验大小、文件名、MIME类型,只要任意校验不通过就直接终止程序,避免多层嵌套逻辑出错
- 用正则
/[A-Z]/替换ctype_lower()做大写字母校验,只要文件名中存在任意一个大写字母就通过,完美匹配需求,也兼容含数字、特殊字符的文件名 - 拆分了各个校验分支的错误提示,每个规则不通过都会返回对应的提示,方便排查问题
- 补充了upload目录的自动创建逻辑,避免目录不存在导致上传失败
内容的提问来源于stack exchange,提问作者Zack Fair
相关产品推荐
相关产品推荐

