====== Request for Comments: Fix CURL file uploads ====== * Version: 1.0 * Date: 2013-01-06 * Author: Stas Malyshev * Status: Implemented in PHP 5.5 * First Published at: http://wiki.php.net/rfc/curl-file-upload * See also: https://bugs.php.net/bug.php?id=46439 * Implementation: https://github.com/php/php-src/pull/255 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 inconvenient 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() {} } Also, the functional API to creating CURLFile is provided by request: /** * Create CURLFile object * @param string $name File name * @param string $mimetype Mime type, optional * @param string $postfilename Post filename, defaults to actual filename */ function curl_file_create($name, $mimetype = '', $postfilename = '') {} This will create a new ```CURLFile``` object just as ```new CURLFile()``` would. ===== 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. * 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 ===== * CURL form API: http://curl.haxx.se/libcurl/c/curl_formadd.html * curl_setopt: http://php.net/manual/en/function.curl-setopt.php * Pull request: https://github.com/php/php-src/pull/255 ===== Vote ===== Voting ended on Monday, January 28th 2013. In order to pass, the requirement is 50%+1 vote, since PHP core language is not changed. The result is: **ACCEPTED**. * Yes * No ===== Changelog ===== * 2013-01-05 First draft * 2013-01-06 Added pull req * 2013-01-07 Added CURLOPT_SAFE_UPLOAD description * 2013-01-12 Added curl_file_create()