Tag Archives: Binary

Send and receive binary files using PHP and cURL

I was recently working on a project where I had to send and receive binary files to and from a REST API, so I decided to document some of the code I wrote. Keep in mind that I’m extracting all of these code snippets from a custom PHP class I wrote, so if you’re working with an API, I’d encourage you to create a class of your own.

Setup a form to submit a file

Before you can send a binary file to an API, you have to get it from somewhere. In my project that file came from a form. The form could be as simple as this:

<form method="post" action="index.php" enctype="multipart/form-data">
	<input name="file" type="file" />
	<input type="submit" value="Upload" />

Note the enctype attribute is set to multipart/form-data. You must have this set, otherwise the file will not be submitted.

Grab the submitted file

Normally when you process a form, the contents are found inside of the global $_POST variable, however file data is located within the global $_FILES variable.

If you print out the contents of $_FILES on the page the form was submitted to, you’d see something like:

    [file] => Array
            [name] => Array
                    [0] => 400.png
            [type] => Array
                    [0] => image/png
            [tmp_name] => Array
                    [0] => /tmp/php5Wx0aJ
            [error] => Array
                    [0] => 0
            [size] => Array
                    [0] => 15726

What’s unusual about this array is that instead of grouping each file’s data in one array, each piece of information about a file is grouped together. So the values at index 0 in name, type, tmp_name, error and size belong to one file.

The binary file data is located in a temporary storage on your server. In this case, at /tmp/php5Wx0aJ.

Send the binary contents via cURL

The following snippet sends the binary file to a URL:

$url = 'http://some-server.com/api';
$header = array('Content-Type: multipart/form-data');
$fields = array('file' => '@' . $_FILES['file']['tmp_name'][0]);
$token = 'NfxoS9oGjA6MiArPtwg4aR3Cp4ygAbNA2uv6Gg4m';

$resource = curl_init();
curl_setopt($resource, CURLOPT_URL, $url);
curl_setopt($resource, CURLOPT_HTTPHEADER, $header);
curl_setopt($resource, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($resource, CURLOPT_POST, 1);
curl_setopt($resource, CURLOPT_POSTFIELDS, $fields);
curl_setopt($resource, CURLOPT_COOKIE, 'apiToken=' . $token);
$result = json_decode(curl_exec($resource));

Let’s talk about each of these lines, because some of this will depend on the requirements of the API you are using and may not be necessary.

  • $url is where cURL will post your data.
  • $header tells the API that there is a file coming its way. You can supply more headers by adding additional values to the array.
  • $fields contains an associative array. The field name depends on what the API expects it to be. The @ sign in the value tells cURL that we’re dealing with a file.
  • $token is a token that the REST API expects as a cookie. Usually you login to the API once during a transaction, then use a token for all subsequent requests. The cookie is called apiToken, but this may differ depending on the API’s expectations.
  • CURLOPT_RETURNTRANSFER tells cURL we want a response.
  • CURLOPT_POST tells cURL we want our data to be posted.
  • CURLOPT_COOKIE sets the token as a cookie.

Lastly, notice the last line:

$result = json_decode(curl_exec($resource));

In my case I know that the response I’m getting from the API will be in the JSON format, which is why I’m decoding it. You may not need this if you’re getting back a response in XML, for example.

This completes sending a binary file via cURL. Next we’ll look at retrieving that file.

Retrieve the binary contents via cURL

Here’s how to retrieve a binary file:

$resource = curl_init();
curl_setopt($resource, CURLOPT_URL, $url);
curl_setopt($resource, CURLOPT_HEADER, 1);
curl_setopt($resource, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($resource, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($resource, CURLOPT_COOKIE, 'apiToken=' . $token);
$file = curl_exec($resource);

We don’t have to go over anything except for:

  • CURLOPT_HEADER tells cURL that we expect there to be a header. This is important because it tells us what kind of file we’re getting i.e. an image, a Word document, a PDF, etc.
  • CURLOPT_BINARYTRANSFER tells PHP that the result will contain binary data. Lots of people claim you don’t need this line. I say try it with and without, just to be sure.

Now you have the binary file with its headers stored in $file.

Give the file back to the user

Let’s go over on how to give the file back to the user. You could either store the file on the server and give the user a path to the file, or you can just let PHP handle all that on the fly and simply prompt the user to save the file.

Here is how I did that:

$file_array = explode("\n\r", $file, 2);
$header_array = explode("\n", $file_array[0]);
foreach($header_array as $header_value) {
	$header_pieces = explode(':', $header_value);
	if(count($header_pieces) == 2) {
		$headers[$header_pieces[0]] = trim($header_pieces[1]);
header('Content-type: ' . $headers['Content-Type']);
header('Content-Disposition: ' . $headers['Content-Disposition']);
echo substr($file_array[1], 1);
  • On line 1 I separate the header from the rest of the file.
  • On line 2-8 I parse the header contents and put them in an array so I can easily reference the elements I need.
  • On line 9 &10 I tell PHP what the content type is and what the file should be called.
  • On line 11 I output all of the binary contents. Together with the header, it prompts the user to save the file (or displays it in the browser if it’s an image, for example).

I want to touch on the function on line 11: substr($file_array[1], 1);

In my case the binary file had an extra space at the beginning of the file. The substr function removes that. I’m not sure whether that space came from the API or from the explode on line 1, so if this doesn’t work for you, try changing that line to: echo $file_array[1];

Hopefully this info will shed some light on how to post and retrieve files in a binary format. If you have any questions, leave them in the comments below.