Php Curl отправляет данные файлов И массивов


Я хочу отправлять сложные почтовые данные с помощью Curl.

Данные, которые я пытаюсь отправить:

Array
(
    [test] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )

    [file] => CURLFile Object
        (
            [name] => H:\wwwroot\curl/upload.txt
            [mime] => 
            [postname] => 
        )

)

Мне нужно использовать переменные в пост-стороне как $_POST["тест"] и $_FILES["файл"] Но я не могу этого осознать. Для (иногда многомерных) массивов данных мне нужен http_build_query, но это нарушает файл. Если я не использую http_build_query, мой массив выдает ошибку "преобразование массива в строку".

Как я могу передать это работать? Код:

Index.php

$curl = curl_init();

$postValues = Array("test" => Array(1,2,3));
$postValues["file"] = new CurlFile(dirname(__FILE__). "/upload.txt");

curl_setopt($curl, CURLOPT_URL, "localhost/curl/post.php");
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postValues);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);

$curlResult = curl_exec($curl);
$curlStatus = curl_getinfo($curl);

echo $curlResult;

Post.php

print_r($_REQUEST);
print_r($_FILES);
Author: Wim te Groen, 2016-03-01

2 answers

После очень долгих исследований по решению одной и той же проблемы я думаю, что более простым решением могло бы быть:

$postValues = Array("test[0]" => 1, "test[1]" => 2, "test[2]" => 3);

Это правильный способ эмулировать то, что происходит в браузерах

<input type="hidden" name="test[0]" value="1">
<input type="hidden" name="test[1]" value="2">
...

Результат таков:

Array
(
    [test] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )

)
Array
(
    [file] => Array
        (
            [name] => upload.txt
            [type] => application/octet-stream
            [tmp_name] => /tmp/phprRGsPU
            [error] => 0
            [size] => 30
        )

)
 3
Author: Andrej Pandovich, 2017-05-10 10:10:21

После долгих исследований и тестирования у меня есть (не очень приятное, но рабочее) решение:

function createHttpHeader($postValues, $overrideKey = null) {
    global $delimiter;
    // invalid characters for "name" and "filename"
    $disallow = array("\0", "\"", "\r", "\n");

    $data = Array();

    if (!is_array($postValues)) {
        $postValues = Array($postValues);
    }

    foreach($postValues as $key => $value) {
        $useKey = $overrideKey === null ? $key : $overrideKey. "[$key]";
        $useKey = str_replace($disallow, "_", $useKey);

        if (is_array($value)) {
            $data = array_merge($data, addPostData($value, $useKey));
        } else {
            $data[] = "--". $delimiter. "\r\n";
            $data[] = "Content-Disposition: form-data; name=\"". $useKey. "\"";

            if (is_a($value, "\CurlFile")) {
                $data[] = "; filename=\"". basename($value->name). "\"\r\n";
                $data[] = "Content-Type: application/octet-stream\r\n\r\n";
                $data[] = file_get_contents($value->name). "\r\n";
            } else {
                $data[] = "\r\n\r\n". $value. "\r\n";
            }
        }
    }

    return $data;
}

Тест с помощью:

$postValues = Array(
    "blaat" => 1,
    "test" => Array(1,2,3),
    "grid" => Array(0 => array(1,2), 1 => array(4,5)),
    "gridComplex" => Array("rows" => array(1,2), "columns" => array(0 => array(1,2,3,4), 1 => array(4,5,4,5)))
 );

$postValues["file[0]"] = new CurlFile($file, "text/plain");
$postValues["file[1]"] = new CurlFile($file, "text/plain");
// print_r(new CurlFile($file));exit;

$delimiter = "-------------" . uniqid();
$data = createHttpHeader($postValues);

$data[] = "--" . $delimiter . "--\r\n";
$data = implode("", $data);

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "localhost/curl/post.php");
curl_setopt($curl, CURLOPT_HTTPHEADER , array('Content-Type: multipart/form-data; boundary=' . $delimiter, 'Content-Length: ' . strlen($data)));
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);

$curlResult = curl_exec($curl);
echo $curlResult;

Изменить: добавить функцию addPostData:

    function addPostData($postValues, $delimiter, $overrideKey = null) {
        // invalid characters for "name" and "filename"
        $disallow = array("\0", "\"", "\r", "\n");

        $data = Array();

        if (!is_array($postValues)) {
            $postValues = Array($postValues);
        }

        foreach($postValues as $key => $value) {
            $useKey = $overrideKey === null ? $key : $overrideKey. "[$key]";
            $useKey = str_replace($disallow, "_", $useKey);

            if (is_array($value)) {
                $data = array_merge($data, $this->addPostData($value, $delimiter, $useKey));
            } else {
                $data[] = "--". $delimiter. "\r\n";
                $data[] = "Content-Disposition: form-data; name=\"". $useKey. "\"";

                if (is_a($value, "\CurlFile")) {
                    $data[] = "; filename=\"". basename($value->postname). "\"\r\n";
                    $data[] = "Content-Type: ". $value->mime. "\r\n\r\n";
                    $data[] = file_get_contents($value->name). "\r\n";
                } else {
                    $data[] = "\r\n\r\n". $value. "\r\n";
                }
            }
        }

        return $data;
    }
 2
Author: Wim te Groen, 2017-05-11 10:52:58