PHP file transfer: Forget the @ - use `curl_file_create`
I just struggled uploading a file with PHP cURL. Basically, sending HTTP POST data is pretty easy. And to send a file you just needed to prefix it with an at sign (@). Adapted from the most cited example:
You see, if you add an ‘@’ sign as the first character of a post field the content will be interpreted as a file name and will be replaced by the file’s content.
At least, that is how it used to be… And how most of the examples out there show you.
However, they changed the behaviour. They recognised that this is obviously inconvenient, insecure and error prone. You cannot send POST data that starts with an @ and you always need to sanitise user-data before sending it, as it otherwise may send the contents of files on your server. And, thus, they changed that behaviour in version 5.6, see the RFC.
That means by default the
@/some/filename.ext won’t be recognized as a file – PHP cURL will literally send the @ and the filename (
@/some/filename.ext) instead of the content of that file. Took ma a while and some tcpdumping to figure that out..
Instead, they introduced a new function called
curl_file_create that will create a proper
CURLFile object for you. Thus, you should update the above snippet with the following:
Note that the contents of the
file_contents field of the
$post data differs.
The php.net manual for the file_contents function is unfortunatelly not very verbose, but the RFC on wiki.php.net tells you a bit more about the new function:
So you can also define a mime type and some file name that will be sent.
That of course makes it a bit tricky to develop for different platforms, as you want your code to be valid on both PHP 5.4 and PHP 5.6 etc. Therefore you could introduce the following as a fallback:
as suggested by mipa on php.net. This creates a dummy function that is compliant with the old behaviour if there is no
Leave a comment
There are multiple options to leave a comment:
- send me an email
- submit a comment through the feedback page (anonymously via TOR)
- Fork this repo at GitHub, add your comment to the _data/comments directory and send me a pull request
- Fill the following form and Staticman will automagically create a pull request for you:
Hallo, here Frank from Belgium.
I found your script who works fine. However i have multiple images tos end. Do you have an example how to work with curl_create_file in a loop or array?
Thank you in advance.
$postvariable is only an associative array. Thus, you should be able to simply add whatever you want to send. Let’s assume you have an array called
$image_pathsthat contains the paths to images, then you may do something like
for ($i = 0; $i < count($image_paths); ++$i) $post["upload-$i"] = curl_file_create ($image_paths[$i]);and afterwards send the the
$postcontents as usual. Does that help?
Btw, the function is called
Just wanted to say thank you for your post about cURL and the deprecation of ‘@’… I must have lost 2 years of my life today trying to figure out why my cURL requests weren’t sending files anymore.