如何为PHP视频上传表单做安全防护?已有图片校验方案
解决MP4视频上传的安全校验问题
嘿,这个问题我之前也遇到过!要防止伪装成MP4的恶意文件上传,光靠扩展名和MIME类型肯定不够——就像你用getimagesize()校验图片那样,得从文件内容层面去验证视频的有效性。下面给你几个靠谱的方案,以及对现有代码的优化建议:
一、先修正现有代码的逻辑问题
你当前的代码里有个明显的逻辑错误:在判断$_FILES["fileToUpload"]["type"] == "image/png"的分支里,又嵌套了video/mp4的判断,这会导致MP4文件根本不会进入视频校验的分支。先把这个逻辑理顺,区分图片和视频的处理流程:
$target_file = "你的目标存储路径"; // 记得替换成实际路径 $imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION)); $allowed_extensions = ["jpg", "png", "jpeg", "gif", "mp4"]; // 第一步:校验扩展名 if (!in_array($imageFileType, $allowed_extensions)) { echo "no way"; exit; } $tmp_file = $_FILES["fileToUpload"]["tmp_name"]; // 第二步:分类型校验内容 if (in_array($imageFileType, ["jpg", "png", "jpeg", "gif"])) { // 图片校验:用你已有的getimagesize $check = getimagesize($tmp_file); if ($check === false) { echo "no way"; exit; } } elseif ($imageFileType === "mp4") { // 这里放视频校验的逻辑,下面给你具体实现 } // 校验通过后再移动文件 move_uploaded_file($tmp_file, $target_file);
二、视频内容校验的可靠方案
方案1:用FFprobe解析视频元数据(最推荐)
FFprobe是FFmpeg套件的一部分,它能真正读取视频文件的编码信息,判断是否为有效的MP4视频。这是最可靠的方法,因为恶意文件很难伪造完整的视频编码流。
步骤:
- 确保服务器上安装了FFmpeg(大部分Linux服务器可以通过
apt install ffmpeg或yum install ffmpeg安装,Windows服务器需要手动下载配置)。 - 在PHP中调用FFprobe命令,解析视频的编码信息:
// MP4视频常见的有效编码(h264、h265、mpeg4) $valid_codecs = ['h264', 'hevc', 'mpeg4']; // 构造安全的FFprobe命令,用escapeshellcmd避免命令注入 $command = escapeshellcmd( "ffprobe -v error -select_streams v:0 -show_entries stream=codec_name " . "-of default=noprint_wrappers=1:nokey=1 " . $tmp_file ); // 执行命令并获取输出 $codec = trim(shell_exec($command)); // 判断编码是否有效 if (empty($codec) || !in_array($codec, $valid_codecs)) { echo "no way"; exit; }
注意:如果你的服务器禁用了shell_exec或exec函数,可以考虑用PHP的FFmpeg扩展(比如php-ffmpeg),不过安装和配置相对麻烦一些。
方案2:检查文件头(魔术字节)
MP4文件的开头几个字节有固定的标识(称为“魔术字节”),可以读取文件的前几个字节来判断是否为MP4格式。这种方法不需要额外安装工具,但可靠性略低于FFprobe(恶意文件可能伪造文件头)。
// 打开临时文件读取前8个字节 $handle = fopen($tmp_file, "rb"); $file_header = fread($handle, 8); fclose($handle); // MP4常见的文件头标识(对应ftyp字段) $valid_headers = [ "\x00\x00\x00\x18\x66\x74\x79\x70", "\x00\x00\x00\x0C\x66\x74\x79\x70" ]; // 判断文件头是否匹配 if (!in_array($file_header, $valid_headers)) { echo "no way"; exit; }
三、额外的安全加固措施
除了内容校验,还有几个关键措施能提升上传安全:
- 重命名上传文件:永远不要使用用户提供的文件名,上传后用随机字符串(比如
uniqid()+ 扩展名)重命名,避免路径遍历和文件名注入。 - 存储路径隔离:把上传的文件放在Web根目录之外,或者配置Web服务器禁止执行该目录下的脚本(比如Apache的
<Directory>配置中添加php_flag engine off)。 - 限制文件大小:通过
$_FILES["fileToUpload"]["size"]限制最大上传大小,防止超大文件占用服务器资源。 - 不要依赖MIME类型:
$_FILES["fileToUpload"]["type"]是客户端提供的,可以被篡改,完全不要用它作为校验依据。
内容的提问来源于stack exchange,提问作者hameds1
相关产品推荐
相关产品推荐

