首页 > 解决方案 > 在 PHP 中使用 Curl 进行异步上传 - curl_multi_exec()

问题描述

几天来,我一直在试图弄清楚如何使用 PHP 并行上传多个文件。

假设我有一个名为 Request 的类,它有 2 个方法 register() 和 executeAll():

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

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

        // Register the curl multihandle only once.
        if (is_null($this->curlMultiHandle)) {
            $this->curlMultiHandle = curl_multi_init();
        }

        $curlHandler = curl_init($url);

        $options = [
            CURLOPT_ENCODING => 'gzip',
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => 1,
            CURLOPT_POSTFIELDS => $file,
            CURLOPT_USERAGENT => 'Curl',
            CURLOPT_HTTPHEADER => [
                'Content-Type' => 'multipart/form-data; boundry=-------------'.uniqid()
            ]
        ];

        curl_setopt_array($curlHandler, $options);

        $this->curlHandlers[] = $curlHandler;
        curl_multi_add_handle($this->curlMultiHandle, $curlHandler);
    }

    public function executeAll() 
    {
        $responses = [];

        $running = null;

        do {
            curl_multi_exec($this->curlMultiHandle, $running);
        } while ($running > 0);

        foreach ($this->curlHandlers as $id => $handle) {
            $responses[$id] = curl_multi_getcontent($handle);
            curl_multi_remove_handle($this->curlMultiHandle, $handle);
        }

        curl_multi_close($this->curlMultiHandle);

        return $responses;
    }
}

$request = new Request;

// For this example I will keep it simple uploading only one file.
// that was posted using a regular HTML form multipart
$resource = $_FILES['file'];
$request->register('http://localhost/upload.php', $resource);

$responses = $request->executeAll(); // outputs an empty subset of array(1) { 0 => array(0) { } }

问题:

无法弄清楚为什么在 upload.php 上(脚本是我在注册方法上的端点 url) $_FILES 始终是一个空数组:

上传.php:

<?php

    var_dump($_FILES); // outputs an empty array(0) { }

我已经尝试过的事情:

在数据前加上 @ 前缀,如下所示:

    $options = [
        CURLOPT_ENCODING => 'gzip',
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => 1,
        CURLOPT_POSTFIELDS => ['file' => '@'.$file['tmp_name']],
        CURLOPT_USERAGENT => 'Curl',
        CURLOPT_HTTPHEADER => [
            'Content-Type' => 'multipart/form-data; boundry=-------------'.uniqid()
        ]
    ];

不幸的是,这没有用。

我究竟做错了什么 ?

如何在已发布的脚本 (upload.php) 上获取存储在全局 $_FILES 中的文件资源?

更多调试信息:

在 upload.php print_r 上,我得到以下响应的标题:

array(1) {
  [0]=>
  string(260) "Array
(
    [Host] => localhost
    [User-Agent] => Curl
    [Accept] => */*
    [Accept-Encoding] => gzip
    [Content-Length] => 1106
    [Content-Type] => multipart/form-data; boundary=------------------------966fdfac935d2bba
    [Expect] => 100-continue
 )
"
}

upload.php 上的 print_r($_POST) 返回以下响应:

array(1) {
  [0]=>
  string(290) "Array
(
    [name] => example-1.jpg
    [encrypted_name] => Nk9pN21IWExiT2VlNnpHU3JRRkZKZz09.jpg
    [type] => image/jpeg
    [extension] => jpg
    [tmp_name] => C:\xampp\tmp\php77D7.tmp
    [error] => 0
    [size] => 62473
    [encryption] => 1
    [success] => 
    [errorMessage] => 
)
"
}

我很感激任何答案。

谢谢,

伊甸园

标签: phpcurlasynchronousupload

解决方案


Can't figure out why on upload.php (the script which is my endpoint url on the register method) $_FILES is always an empty array- 你的第一个问题是你用你自己的覆盖了 libcurl 的边界字符串,但是你让 curl 自动生成 multipart/form-data 正文,这意味着 curl 在实际的请求正文中生成另一个与你自己不同的随机边界字符串,这意味着服务器将无法解析文件。从标题中删除自定义边界字符串(如果您不覆盖它,curl 将插入它自己的)。您的第二个问题是您使用 $_FILES 错误,如果您希望将其提供给 curl,则需要提取上传名称,并且您需要将文件名转换为 CURLFile 对象以让 curl 为您上传它们。另一个问题是您的脚本在执行多句柄时将无缘无故地使用 100% cpu,您应该添加 curl_multi_select 以防止阻塞整个 cpu 核心。http://php.net/manual/en/features.file-upload.post-method.php ,有关如何使用 CURLFile,请参阅http://php.net/manual/en/curlfile.construct.php和如何使用 curl_multi_select,参见http://php.net/manual/en/function.curl-multi-select.php


推荐阅读