Using cURL and PHP to upload files through a form post

Lately I have been working on a project that requires me to use PHP to interact with a REST based service. cURL is the logical choice for making HTTP calls to the REST service.

I love cURL, I’ve blogged about it before, but I recently ran into some major issues.

The REST service I was using required me to send two files along with some meta information. easy enough. I used the following code:

$postFields = array();

//files
$postFields['file'] = "@$filePath";
$postFields['thumbnail'] = "@$thumbnailPath";

//metaData
$postFields['title'] = "$title";
$postFields['description'] = "$description";
$postFields['tags'] = "$tags";
$postFields['licenseinfo'] = "$licenseinfo";
$postFields['token'] = "$userToken";

$curl_handle = curl_init();

curl_setopt($curl_handle, CURLOPT_URL, $api_url);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_handle, CURLOPT_POST, true);
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $http_post_fields);

//execute the API Call
$returned_data = curl_exec($curl_handle);

The code worked great, sending an “at” sign (@) before the file path makes sure that cURL sends the file as part of a “multipart/form-data” post. Exactly what we needed.

The form post from cURL worked great, but the REST service was retuning a 400 error and saying “The specified thumbnail file is not supported.”. I was at a loss. The service documentation stated the “jpg, jpeg, gif, and png” files were supported.

I ended up contacting the developers of the service who told me that the content type for the file had to be set to “image/jpg” (for jpg).

After pouring through the cURL documentation and not finding anything about how to set the content type for a single file in a “multipart/form-data” post, I turned to Goolge. My searches with about as helpful as the cURL docs. I sent a few hours hacking my code and trying some things, I ever read some posts from 2008 saying that is was not possible to do. Then, I got a break through, a single ray of light. On a message board was a single sentence replay. “You should try this… $image;type=image/jpg”.

That was the break through I needed. Below is final updated code:

$postFields = array(); 

//files
 $postFields['file'] = "@$filePath";

//get the extension of the image file
$tumbnailExtention = preg_replace('/^.*\.([^.]+)$/D', '$1', $thumbnailPath);
$postFields['thumbnail'] = "@$thumbnailPath;type=image/$tumbnailExtention";

//metaData
$postFields['title'] = "$title";
$postFields['description'] = "$description";
$postFields['tags'] = "$tags";
$postFields['licenseinfo'] = "$licenseinfo";
$postFields['token'] = "$userToken"; 

$curl_handle = curl_init();

curl_setopt($curl_handle, CURLOPT_URL, $api_url);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_handle, CURLOPT_POST, true);
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $http_post_fields); 

//execute the API Call
$returned_data = curl_exec($curl_handle);

In summary, if you need to set the content type of a file being sent an image through cURL, via a POST, use the following format:
$postFields[‘file’] = “@PATHTOFILE;type=CONTENTTYPEHERE”;