rfc:curl-file-upload

This is an old revision of the document!


Request for Comments: Fix CURL file uploads

This RFC discusses improvement for CURL file uploading option.

Introduction

Currently, cURL file uploading is done as:

curl_setopt($curl_handle, CURLOPT_POST, 1);
$args['file'] = '@/path/to/file';
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $args);

This API is both invonvenient and insecure, it is impossible to send data starting with '@' to the POST, and any user data that is being re-sent via cURL need to be sanitized so that the data value does not start with @. In general, in-bound signalling usually vulnerable to all sorts of injections and better not done in this way.

CurlFile proposal

Instead of using the above method, the following should be used to upload files with CURLOPT_POSTFIELDS:

curl_setopt($curl_handle, CURLOPT_POST, 1);
$args['file'] = new CurlFile('filename.png', 'image/png');
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $args);

The curl API will be modified to look for objects of type CurlFile and treat them as entries with @ were previously treated.

The file given to CurlFile will not be opened/read until curl_setopt() call.

CurlFile API

class CurlFile
{
    /**
     * Create CurlFile object
     * @param string $name File name
     * @param string $mimetype Mime type, optional
     * @param string $postfilename Post filename, defaults to actual filename
     */
    public function __construct($name, $mimetype = '', $postfilename = '')
    {}
 
    /**
     * Set mime type
     * @param string $mimetype
     * @return CurlFile
     */
    public function setMimeType($mimetype)
    {}
 
    /**
     * Set mime type
     * @param string $mimetype
     * @return string
     */
    public function getMimeType($mimetype)
    {}
 
    /**
     * Get file name from which the data will be read
     * @return string
     */
    public function getFilename()
    {}
 
    /**
     * Get file name which will be sent in the post
     * @param string $name File name
     * @return string
     */
    public function setPostFilename($name)
    {}
 
    /**
     * Set file name which will be sent in the post
     * @return string
     * @return CurlFile
     */
    public function getPostFilename()
    {}
}

Backward compatibility

A new option is introduced: CURLOPT_SAFE_UPLOAD. By default, in order to assure orderly transition to the use of the new API, the proposal is in 5.5 to leave the @ option working, but make it produce E_DEPRECATED error referring the user to the use of the new API. In order to disable it, CURLOPT_SAFE_UPLOAD can be used:

curl_setopt($curl_handle, CURLOPT_SAFE_UPLOAD, true);

In 5.6, @ option will be switched off by default, but can still be enabled by explicit curl_setopt setting, such as:

curl_setopt($curl_handle, CURLOPT_SAFE_UPLOAD, false);

In future versions, this capability may be removed completely.

Optional

  • If upstream cURL API permits, we could add in the future uploading files from string buffers, stream names, stream resources and such, which is now impossible with existing @-based API. The CurlFile API above will then be extended with required functions to support these, such as “setUploadData()”, “setUploadStream()” etc.
  • For people that are not comfortable with “new” operator, we could also add duplicate function-only API like:
$data['file'] = curl_file_upload($filename, $mime);
  • It is possible to include validation of the file resource given in the constructor, so that appropriate error message can be produced if this file can not be read.

References

Changelog

  • 2013-01-05 First draft
  • 2013-01-06 Added pull req
  • 2013-01-07 Added CURLOPT_SAFE_UPLOAD description
rfc/curl-file-upload.1357693174.txt.gz · Last modified: 2013/01/09 01:59 by stas