Well, I haven’t posted here in quite some time… I’m not dead, and don’t plan on completely ditching this blog, but well…
Anyway, onto the article.
I had a PHP application where I wanted to upload part of a large file to some other server. The naive method may be to simply split the file and upload through cURL, however I wanted to do this without any splitting. So I needed a way to send a POST request, being able to build the request body on the fly (note, you’ll need to know the total size to be able to send the Content-Length header)
The obvious decision would be to use sockets rather than cURL, but I felt like seeing if it was possible with cURL anyway. Although I’ll still probably use sockets (because it’s easier in the end), I thought this might (well, not really) be useful to one of the three readers I get every month.
Anyway, if you look at the curl_setopt documentation, you’ll see a CURLOPT_READFUNCTION constant, however, how to really use it doesn’t seem clear (especially with the boundaries for multipart/form-data encoding type). Also, the documentation is wrong.
Without further ado, here’s some sample code:
<?php
$boundary = '-----------------------------168279961491';
// our request body
$str = "$boundary\r\nContent-Disposition: form-data; name='how_do_i_turn_you'\r\n\r\non\r\n$boundary--\r\n";
// set up cURL
$ch=curl_init('http://example.com/');
curl_setopt_array($ch, array(
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => array( // we need to send these two headers
'Content-Type: multipart/form-data; boundary='.$boundary,
'Content-Length: '.strlen($str)
),
// note, do not set the CURLOPT_POSTFIELDS setting
CURLOPT_READFUNCTION => 'myfunc'
));
// function to stream data
// I'm not sure what the file pointer $fp does in this context
// but $ch is the cURL resource handle, and $len is how many bytes to read
function myfunc($ch, $fp, $len) {
static $pos=0; // keep track of position
global $str;
// set data
$data = substr($str, $pos, $len);
// increment $pos
$pos += strlen($data);
// return the data to send in the request
return $data;
}
// execute request, and show output for lolz
echo curl_exec($ch);
curl_close($ch);
Hopefully the comments give you enough idea how it all works.
