简体   繁体   English

在PHP中使用Curl异步上传-curl_multi_exec()

[英]Async Upload Using Curl in PHP - curl_multi_exec()

I'm trying to figure out for days how would it be possible if at all, to upload multiple files parallel using PHP. 我试图弄清楚几天,如果有的话,怎么可能用PHP并行上传多个文件。

given I have a class called Request with 2 methods register() and executeAll(): 给定我有一个名为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) { } }

Problem: 问题:

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: 无法弄清楚为什么在upload.php(该脚本是我在register方法上的端点网址)$ _FILES始终为空数组:

upload.php: upload.php:

<?php

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

Things I've already tried: 我已经尝试过的事情:

prefixing the data with @, like so: 给数据加上@前缀,如下所示:

    $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()
        ]
    ];

That unfortunately did not work. 不幸的是,这没有用。

What am I doing wrong ? 我究竟做错了什么 ?

how could I get the file resource stored in $_FILES global on the posted script (upload.php) ? 我如何才能在发布的脚本(upload.php)上获取存储在$ _FILES全局文件中的文件资源?

Further Debug Information: 更多调试信息:

on upload.php print_r the headers I get as response the following: 在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
 )
"
}

print_r($_POST) on upload.php gives the following response back: 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] => 
)
"
}

I appreciate any answer. 我感谢任何答案。

Thanks, 谢谢,

Eden 伊甸园

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 - your first problem is that you override libcurl's boundary string with your own, but you have curl generate the multipart/form-data body automatically, meaning curl generates another random boundary string, different from your own, in the actual request body, meaning the server won't be able to parse the files. 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 -您的第一个问题是您用自己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会在实际的请求主体中生成另一个不同于您自己的随机边界字符串,这意味着服务器将无法解析文件。 remove the custom boundary string from the headers (curl will insert its own if you don't overwrite it). 从标题中删除自定义边界字符串(如果不覆盖,curl将插入其自己的字符串)。 your second problem is that you're using $_FILES wrong, you need to extract the upload name if you wish to give it to curl, and you need to convert the filenames to CURLFile objects to have curl upload them for you. 第二个问题是您错误地使用了$ _FILES,如果您希望将其命名为curl,则需要提取上载名称,并且需要将文件名转换为CURLFile对象,以便curl为您上载它们。 another problem is that your script will for no good reason use 100% cpu while executing the multi handle, you should add a curl_multi_select to prevent choking an entire cpu core. 另一个问题是您的脚本在执行多句柄时无缘无故地使用100%cpu,您应该添加curl_multi_select以防止阻塞整个cpu内核。 for how to handle $_FILES, see http://php.net/manual/en/features.file-upload.post-method.php , for how to use CURLFile, see http://php.net/manual/en/curlfile.construct.php and for how to use curl_multi_select, see http://php.net/manual/en/function.curl-multi-select.php 有关如何处理$ _FILES的信息,请参见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/zh/function.curl-multi-select.php

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM