3

I need to HTTP PUT a csv file and some POST fields using multipart POST with PHP and Curl to a REST API endpoint.

The contents of the file upload is stored in a variable $list. The other end point is $url.

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PUT, true);
$post = array(
    //Other Post fields array
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

$fh = fopen('php://memory', 'rw');
fwrite($fh, $list);
rewind($fh);
curl_setopt($ch, CURLOPT_INFILE, $fh);  
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($list));  
$response = curl_exec($ch);

The above code seems to work the only problem is that the other end point requires a specific fieldname for the file upload. How do i set a filename ?

Am i doing something wrong ?

This is the PUT format they have mentioned on API

Content-Disposition: form-data; name="list[csv]"; filename="RackMultipart20110923-63966-hfpyg"
Content-Length: 33
Content-Type: text/csv
Content-Transfer-Encoding: binary

xxxx
yyyy
zzzz
-------------MultipartPost
Content-Disposition: form-data; name="list[list_type]"

Blacklist
-------------MultipartPost--
5
  • 1
    You are aware that PUT is the wrong method for multipart data? PUT requests are supposed to pertain directly to the contents a file on the server and it doesn't really make much sense to PUT multipart requests - are you sure you shouldn't be POSTing it instead? It seems like POSTing multipart/form-data would make much more sense here... The file would be specified with a Content-Disposition: attachment; name="field-name"; filename="file-name" header Commented May 7, 2012 at 14:18
  • 1. The REST endpoint requires a PUT. 2. File upload using POST will require me to specify a filename in the POST array and i need to upload it from a variable. Probably an intermediate solution could be to create a temp file from the variable and upload it but i don't want to do this. Commented May 7, 2012 at 14:26
  • What is the MIME type of the content you are sending? Can you show us any API docs for the endpoint? I don't understand how one would specify a file name without using some form of multipart/* type, in which case it is the Content-Disposition header you need - you might need to construct the message body yourself though. Commented May 7, 2012 at 15:15
  • Is $post a multi-dimensional array? Is the name of the form control for the file required to be list[csv]? Commented May 7, 2012 at 15:35
  • yes multidimensional array. yes the form control name is list[csv] Commented May 7, 2012 at 15:41

1 Answer 1

5

FYI that is multipart/form-data. You will need to build the body yourself I think, I don't think cURL could be made to build that sort of request with a PUT request. However, this is not a serious problem:

<?php

  function recursive_array_mpfd ($array, $separator, &$output, $prefix = '') {
    // Recurses through a multidimensional array and populates $output with a 
    // multipart/form-data string representing the data
    foreach ($array as $key => $val) {
      $name = ($prefix) ? $prefix."[".$key."]" : $key;
      if (is_array($val)) {
        recursive_array_mpfd($val, $separator, $output, $name);
      } else {
        $output .= "--$separator\r\n"
                 . "Content-Disposition: form-data; name=\"$name\"\r\n"
                 . "\r\n"
                 . "$val\r\n";
      }
    }
  }

  // This will hold the request body string
  $requestBody = '';

  // We'll need a separator
  $separator = '-----'.md5(microtime()).'-----';

  // First add the postfields
  $post = array(
    //Other Post fields array
  );
  recursive_array_mpfd($post, $separator, $requestBody);

  // Now add the file
  $list = "this,is,some,csv,data"; // The content of the file
  $filename = "data.csv"; // The name of the file
  $requestBody .= "--$separator\r\n"
                . "Content-Disposition: form-data; name=\"list[list_type]\"; filename=\"$filename\"\r\n"
                . "Content-Length: ".strlen($list)."\r\n"
                . "Content-Type: text/csv\r\n"
                . "Content-Transfer-Encoding: binary\r\n"
                . "\r\n"
                . "$list\r\n";

  // Terminate the body
  $requestBody .= "--$separator--";

  // Let's go cURLing...
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_PUT, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
  curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: multipart/form-data; boundary="'.$separator.'"'
  ));
  $response = curl_exec($ch);

If you have any problems with this, try echo $requestBody; before the cURL request and make sure it looks like you expect it to.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.