CURLFile replaced the @filename upload in 5.5

For years the way to post a file with cURL was to put @/path/to/file in the fields array. The problem is that cURL applies that rule to every value in the array, so any user-supplied field whose content happens to start with @ is read off the local disk and uploaded to the remote end. PHP 5.5 deprecates the form and gives it a proper object.

// 5.4 and earlier — and a file disclosure if $comment begins with @
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
    'invoice' => '@/var/spool/invoices/8814.pdf',
    'comment' => $comment,
));

// 5.5
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
    'invoice' => new CURLFile('/var/spool/invoices/8814.pdf', 'application/pdf', 'invoice-8814.pdf'),
    'comment' => $comment,
));

CURLOPT_SAFE_UPLOAD is the switch that makes an @ string mean a literal string again, and it is worth setting explicitly rather than relying on the default, because the default changes between versions and the code should behave the same on all of them. CURLFile also takes the MIME type and the filename to present to the server as separate arguments, where the old form guessed both from the path — so the upload that arrived as application/octet-stream and got rejected now arrives correctly labelled. The migration cost is that CURLFile does not exist on 5.4, so a library supporting both needs a version check around the two branches until the last old server is gone.