Асинхронная загрузка с использованием Curl в PHP - curl_multi_exec () - PullRequest
0 голосов
/ 28 апреля 2018

В течение нескольких дней я пытаюсь выяснить, можно ли вообще загружать несколько файлов с помощью 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-адресом конечной точки в методе register) $ _FILES всегда является пустым массивом:

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

Это, к сожалению, не сработало.

Что я делаю не так?

как я могу получить файловый ресурс, сохраненный в $ _FILES global в опубликованном скрипте (upload.php)?

Дополнительная информация для отладки:

на 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) на upload.php возвращает следующий ответ:

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] => 
)
"
}

Я ценю любой ответ.

Спасибо

Eden

1 Ответ

0 голосов
/ 28 апреля 2018

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% ЦП при выполнении дескриптора multi, вам следует добавить curl_multi_select, чтобы предотвратить засорение всего ядра ЦП. о том, как обрабатывать $ _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/en/function.curl-multi-select.php

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...