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

如何基于PHP的curl_multi_exec实现多文件并行上传?含Request类框架

PHP多文件并行上传实现方案

我来帮你完善这个基于cURL多句柄实现的PHP多文件并行上传方案!你的Request类框架已经搭好了核心结构,下面是补全后的完整实现:

完整的Request类代码

class Request {
    protected $curlHandlers = [];
    protected $curlMultiHandle = null;

    public function register($url, $file = []) {
        if (empty($file) || !is_array($file)) {
            return false;
        }

        // 仅初始化一次多cURL句柄
        if (is_null($this->curlMultiHandle)) {
            $this->curlMultiHandle = curl_multi_init();
        }

        // 为每个待上传文件创建独立cURL句柄
        foreach ($file as $fieldName => $filePath) {
            if (!file_exists($filePath)) {
                trigger_error("文件 {$filePath} 不存在,跳过上传", E_USER_WARNING);
                continue;
            }

            $curlHandler = curl_init($url);
            
            // 配置POST上传参数(使用CURLFile符合PHP5.5+安全规范)
            $postData = [
                $fieldName => new CURLFile(realpath($filePath))
            ];
            curl_setopt($curlHandler, CURLOPT_POST, true);
            curl_setopt($curlHandler, CURLOPT_POSTFIELDS, $postData);
            
            // 设置返回结果不直接输出,后续统一收集
            curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, true);
            
            // 可选:设置上传超时时间(单位:秒)
            curl_setopt($curlHandler, CURLOPT_TIMEOUT, 30);
            
            // 将单个句柄添加到多句柄队列
            curl_multi_add_handle($this->curlMultiHandle, $curlHandler);
            $this->curlHandlers[] = $curlHandler;
        }

        return true;
    }

    public function executeAll() {
        if (is_null($this->curlMultiHandle) || empty($this->curlHandlers)) {
            return [];
        }

        $activeHandles = null;
        // 启动多cURL请求执行
        do {
            $execStatus = curl_multi_exec($this->curlMultiHandle, $activeHandles);
        } while ($execStatus == CURLM_CALL_MULTI_PERFORM);

        // 等待所有请求完成
        while ($activeHandles && $execStatus == CURLM_OK) {
            if (curl_multi_select($this->curlMultiHandle) == -1) {
                usleep(100); // 避免CPU空转
            }
            do {
                $execStatus = curl_multi_exec($this->curlMultiHandle, $activeHandles);
            } while ($execStatus == CURLM_CALL_MULTI_PERFORM);
        }

        // 收集所有上传结果并清理资源
        $uploadResults = [];
        foreach ($this->curlHandlers as $handler) {
            $uploadResults[] = [
                'response' => curl_multi_getcontent($handler),
                'error_msg' => curl_error($handler),
                'error_code' => curl_errno($handler)
            ];
            // 移除并关闭单个cURL句柄
            curl_multi_remove_handle($this->curlMultiHandle, $handler);
            curl_close($handler);
        }

        // 关闭多cURL句柄并重置属性
        curl_multi_close($this->curlMultiHandle);
        $this->curlMultiHandle = null;
        $this->curlHandlers = [];

        return $uploadResults;
    }
}

关键细节说明

  • CURLFile替代旧语法:放弃了不安全的@符号文件上传方式,符合PHP5.5及以上版本的安全规范
  • 多句柄并行机制:每个文件对应独立的cURL句柄,通过curl_multi系列函数实现真正的并行上传,比串行上传效率提升明显
  • 资源清理:执行完成后必须关闭所有句柄,避免内存泄漏
  • 错误处理:收集每个文件的上传错误信息,方便后续排查问题

使用示例

// 初始化上传实例
$uploader = new Request();

// 注册需要上传的文件(支持多个文件同时上传到同一接口)
$uploader->register('https://your-upload-api.com/upload', [
    'avatar' => '/home/user/avatar.jpg',
    'document' => '/home/user/resume.pdf',
    'attachment' => '/home/user/log.zip'
]);

// 执行并行上传并获取结果
$results = $uploader->executeAll();

// 遍历处理结果
foreach ($results as $idx => $result) {
    if ($result['error_code'] === 0) {
        echo "第{$idx+1}个文件上传成功:{$result['response']}\n";
    } else {
        echo "第{$idx+1}个文件上传失败:{$result['error_msg']}\n";
    }
}

额外提示

  • 若需要上传到不同接口,可多次调用register方法,每次传入不同的URL和对应文件
  • 可根据需求添加更多cURL配置,比如自定义HTTP头、SSL证书验证、进度回调等
  • 确保服务器的max_execution_time和upload_max_filesize配置足够应对大文件上传

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:25:04