You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现MP4视频上传Windows正常 iOS Safari提示无效文件

问题说明

在Linux环境下基于PHP开发MP4视频上传、自动生成缩略图功能,通过FFmpeg组件截取视频指定帧生成缩略图。代码在所有Windows端浏览器下均可正常运行,但在iOS端Safari浏览器上传时,会直接返回「INVALID FILE」错误提示,无法完成上传,原实现代码如下:

ini_set('display_errors', 'On'); error_reporting(E_ALL);
require_once '../../vendor/autoload.php' ;

if($_FILES["upload_file"]["name"] != '')
{
 $data = explode(".", $_FILES["upload_file"]["name"]);
 $extension = $data[1];
 $allowed_extension = array("mp4");
 if(in_array($extension, $allowed_extension))
 {
  $name_only = pathinfo($_FILES["upload_file"]['name'], PATHINFO_FILENAME) ; // Main Name Only 
  $new_video_name = $name_only.'.mp4';
  $new_img_name = $name_only.'.jpg';

  $path = $_POST["hidden_folder_name"] .'/'. $new_video_name;
  $img_path = $_POST["hidden_folder_name"] .'/'.$new_img_name ;
  if(move_uploaded_file($_FILES["upload_file"]["tmp_name"], $path))
  {

    $ffmpeg = FFMpeg\FFMpeg::create(array(
    'ffmpeg.binaries'  => '/usr/local/bin/ffmpeg',
    'ffprobe.binaries' => '/usr/local/bin/ffprobe',
    'timeout'          => 3600, 
    'ffmpeg.threads'   => 12, 
));
            
    $video = $ffmpeg->open($path);
    $video->filters()->resize(new FFMpeg\Coordinate\Dimension(320, 180))->synchronize();
    $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(5))->save($img_path);

   echo 'FILE UPLOADED';
  }
  else
  {
   echo 'THERE IS AN ERROR';
  }
 }
 else
 {
  echo 'INVALID FILE';
 }
}
else
{
 echo 'PLEASE SELECT FILE';
}
故障原因
  • 后缀获取逻辑存在硬伤:原代码用explode(".", 文件名)取下标1的元素作为文件后缀,只要文件名包含多个.(比如iOS设备生成的IMG_2024.05.20.mp4这类命名),取到的就不是真实后缀mp4,直接触发后缀校验失败返回错误。
  • 未兼容后缀大小写:iOS Safari可能上传后缀为大写.MP4的视频文件,原代码严格匹配小写mp4,也会导致校验不通过。
  • 隐藏隐患:固定截取第5秒帧的逻辑,遇到iOS端上传的时长不足5秒的短视频时,FFmpeg会直接报错导致流程中断。
修复方案
  1. 替换后缀获取逻辑,使用PHP原生pathinfo()的PATHINFO_EXTENSION常量获取真实后缀,完全兼容文件名带多个.的场景。
  2. 后缀校验前统一转小写,兼容大写后缀的上传场景。
  3. 增加MIME类型校验,避免仅靠后缀判断带来的恶意文件上传风险。
  4. 截取缩略图前先判断视频总时长,不足5秒时取第0秒帧,避免短视频处理报错。
修复后代码
ini_set('display_errors', 'On'); 
error_reporting(E_ALL);
require_once '../../vendor/autoload.php' ;

if(!empty($_FILES["upload_file"]["name"]))
{
    // 安全获取文件后缀,兼容多.文件名,统一转小写
    $extension = strtolower(pathinfo($_FILES["upload_file"]["name"], PATHINFO_EXTENSION));
    $allowed_extension = array("mp4");
    // 校验文件MIME类型,拦截非法文件
    $allowed_mime = ["video/mp4"];
    $file_mime = mime_content_type($_FILES["upload_file"]["tmp_name"]);
    
    if(in_array($extension, $allowed_extension) && in_array($file_mime, $allowed_mime))
    {
        $name_only = pathinfo($_FILES["upload_file"]['name'], PATHINFO_FILENAME);
        $new_video_name = $name_only.'.mp4';
        $new_img_name = $name_only.'.jpg';

        $path = $_POST["hidden_folder_name"] .'/'. $new_video_name;
        $img_path = $_POST["hidden_folder_name"] .'/'.$new_img_name ;
        if(move_uploaded_file($_FILES["upload_file"]["tmp_name"], $path))
        {
            $ffmpeg = FFMpeg\FFMpeg::create(array(
                'ffmpeg.binaries'  => '/usr/local/bin/ffmpeg',
                'ffprobe.binaries' => '/usr/local/bin/ffprobe',
                'timeout'          => 3600, 
                'ffmpeg.threads'   => 12, 
            ));
            $ffprobe = FFMpeg\FFProbe::create();
            $video = $ffmpeg->open($path);
            $video->filters()->resize(new FFMpeg\Coordinate\Dimension(320, 180))->synchronize();
            // 适配短视频场景,时长不足5秒取首帧
            $duration = $ffprobe->format($path)->get('duration');
            $capture_time = $duration >= 5 ? 5 : 0;
            $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds($capture_time))->save($img_path);

            echo 'FILE UPLOADED';
        }
        else
        {
            echo 'THERE IS AN ERROR';
        }
    }
    else
    {
        echo 'INVALID FILE';
    }
}
else
{
    echo 'PLEASE SELECT FILE';
}

内容的提问来源于stack exchange,提问作者robotron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 23:54:15