Sending multiple files from php curl

Viewed 91

I'm using curl to send data and files to a web service.

From the shell I execute something like this:

curl -X POST -i -F "file[]=@fil1.png" -F "file[]=@file2.pdf" -F "g=GROUP" -F "o=Object" -F "m=Body." http://localhost/api/email.php

and the web service receives an array named "file":

Array
(
    [file] => Array
        (
            [name] => Array
                (
                    [0] => file1.png
                    [1] => file2.pdf
                )
            [type] => Array
                (
                    [0] => image/png
                    [1] => application/pdf
                )
            [tmp_name] => Array
                (
                    [0] => /tmp/php1SFdK3
                    [1] => /tmp/phpPmwL8p
                )
            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                )
            [size] => Array
                (
                    [0] => 74040
                    [1] => 169090
                )
        )
)

If I call it from php with this code:

    $data = [
      "g" => "GROUP",
      "o" => "object",
      "m" => "body.",
      "file[]" => $curlfile1,
      "file[]" => $curlfile2,
    ];
    
    $options = array(
      CURLOPT_URL => 'http://localhost/api/email.php',
      CURLOPT_POST => true,
      CURLOPT_POSTFIELDS => $data,
      CURLOPT_HEADERFUNCTION => "readHeader",
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_SSL_VERIFYPEER => false
    );
    $ch = curl_init();
    curl_setopt_array($ch, $options);
    $response = curl_exec($ch);
    curl_close($ch);

the web service receives only the second file:

Array
(
    [file] => Array
        (
            [name] => Array
                (
                    [0] => file2.pdf
                )
            [type] => Array
                (
                    [0] => application/pdf
                )
            [tmp_name] => Array
                (
                    [0] => /tmp/phpPmwL8p
                )
            [error] => Array
                (
                    [0] => 0
                )
            [size] => Array
                (
                    [0] => 169090
                )
        )
)

It works fine if I put the keys in the file array:

    $data = [
      "g" => "GROUP",
      "o" => "object",
      "m" => "body.",
      "file[0]" => $curlfile1,
      "file[1]" => $curlfile2,
    ];

Is there a syntax so that I can avoid to put the keys of the file array, like in the shell command?

1 Answers

it should have worked, but doesn't, someone should complain on the php bugtracker... seems the answer is no, there's no pretty way to do it.

with that said, you could make a preprosessor function to prettify it for you... eg

<?php

function postArrayFixer(&$data):void{
    $original_keys = array_keys($data);
    foreach($original_keys as $key){
        $val = $data[$key];
        if(is_iterable($val)){
            foreach($val as $inner_key=>$inner_val){
                $data[$key.'['.$inner_key.']']=$inner_val;
            }
            unset($data[$key]);
        }
    }
}

$curlfile1=new CURLFile();
$curlfile2=new CURLFile();
$data = [
  "g" => "GROUP",
  "o" => "object", 
  "m" => "body.",
  "files" => array($curlfile1, $curlfile2)
];

$data["files"][]=new CURLFile();
postArrayFixer($data);
var_export($data);

makes

array (
  'g' => 'GROUP',
  'o' => 'object',
  'm' => 'body.',
  'files[0]' =>
  CURLFile::__set_state(array(
     'name' => '',
     'mime' => '',
     'postname' => '',
  )),
  'files[1]' =>
  CURLFile::__set_state(array(
     'name' => '',
     'mime' => '',
     'postname' => '',
  )),
  'files[2]' =>
  CURLFile::__set_state(array(
     'name' => '',
     'mime' => '',
     'postname' => '',
  )),
)

but this should have been unnecessary, sigh

Related