Aditya Singh
Aditya Singh

Reputation: 852

Multipart PUT upload using Curl and PHP to a REST endpoint

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--

Upvotes: 3

Views: 5084

Answers (1)

DaveRandom
DaveRandom

Reputation: 88647

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.

Upvotes: 5

Related Questions