Implement fix for bug #46439 - add CURLFile class for safer uploads

This commit is contained in:
Stanislav Malyshev 2013-01-28 22:22:59 -08:00
parent 420bcc1a8e
commit a9d013bb02
10 changed files with 243 additions and 49 deletions

4
NEWS
View file

@ -5,6 +5,10 @@ PHP NEWS
. Fixed bug # 60833 (self, parent, static behave inconsistently
case-sensitive). (Stas, mario at include-once dot org)
- cURL:
. Implemented FR #46439 - added CURLFile for safer file uploads.
(Stas)
24 Jan 2013, PHP 5.5.0 Alpha 4
- Core:

View file

@ -155,6 +155,8 @@ PHP 5.5 UPGRADE NOTES
bool(true) was returned.
- setcookie(), setrawcookie() and ext/session now send Max-Age headers alongside
Expires headers. (see https://wiki.php.net/rfc/cookie_max-age)
- curl_setopt now accepts new option CURLOPT_SAFE_UPLOAD and CURLFile object for
safer file uploads (see https://wiki.php.net/rfc/curl-file-upload)
========================================
5. New Functions
@ -167,6 +169,9 @@ PHP 5.5 UPGRADE NOTES
- password_needs_rehash()
- password_verify()
- cURL:
- curl_file_create
- Hash:
- hash_pbkdf2()
@ -267,6 +272,9 @@ PHP 5.5 UPGRADE NOTES
- IntlRuleBasedBreakIterator
- IntlCodePointBreakIterator
- cURL:
- CURLFile
========================================
7. Removed Extensions
========================================
@ -286,6 +294,9 @@ PHP 5.5 UPGRADE NOTES
- mysqli:
- Added MYSQLI_SERVER_PUBLIC_KEY constant to be used with mysqli_options()
- cURL:
- Added CURLOPT_SAFE_UPLOAD to be used with curl_setopt().
========================================
10. Changes to INI File Handling
========================================

View file

@ -149,6 +149,6 @@ int main(int argc, char *argv[])
AC_DEFINE(PHP_CURL_URL_WRAPPERS,1,[ ])
fi
PHP_NEW_EXTENSION(curl, interface.c multi.c share.c streams.c, $ext_shared)
PHP_NEW_EXTENSION(curl, interface.c multi.c share.c streams.c curl_file.c, $ext_shared)
PHP_SUBST(CURL_SHARED_LIBADD)
fi

View file

@ -13,7 +13,7 @@ if (PHP_CURL != "no") {
&& (((PHP_ZLIB=="no") && (CHECK_LIB("zlib_a.lib;zlib.lib", "curl", PHP_CURL))) ||
(PHP_ZLIB_SHARED && CHECK_LIB("zlib.lib", "curl", PHP_CURL)) || (PHP_ZLIB == "yes" && (!PHP_ZLIB_SHARED)))
) {
EXTENSION("curl", "interface.c multi.c share.c streams.c", true);
EXTENSION("curl", "interface.c multi.c share.c streams.c curl_file.c", true);
AC_DEFINE('HAVE_CURL', 1, 'Have cURL library');
AC_DEFINE('HAVE_CURL_SSL', 1, 'Have SSL suppurt in cURL');
AC_DEFINE('HAVE_CURL_EASY_STRERROR', 1, 'Have curl_easy_strerror in cURL');

View file

@ -317,7 +317,7 @@ ZEND_END_ARG_INFO()
#if LIBCURL_VERSION_NUM >= 0x070c01 /* 7.12.1 */
ZEND_BEGIN_ARG_INFO(arginfo_curl_reset, 0)
ZEND_ARG_INFO(0, ch)
ZEND_END_ARG_INFO()
ZEND_END_ARG_INFO()
#endif
#if LIBCURL_VERSION_NUM > 0x070f03 /* 7.15.4 */
@ -403,6 +403,12 @@ ZEND_BEGIN_ARG_INFO(arginfo_curl_pause, 0)
ZEND_ARG_INFO(0, bitmask)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_curlfile_create, 0, 0, 1)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, mimetype)
ZEND_ARG_INFO(0, postname)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ curl_functions[]
@ -446,6 +452,7 @@ const zend_function_entry curl_functions[] = {
PHP_FE(curl_share_init, arginfo_curl_share_init)
PHP_FE(curl_share_close, arginfo_curl_share_close)
PHP_FE(curl_share_setopt, arginfo_curl_share_setopt)
PHP_FE(curl_file_create, arginfo_curlfile_create)
PHP_FE_END
};
/* }}} */
@ -526,7 +533,7 @@ PHP_MINFO_FUNCTION(curl)
#endif
#if LIBCURL_VERSION_NUM >= 0x071600 /* 7.22.0 */
{"NTLMWB", CURL_VERSION_NTLM_WB},
#endif
#endif
#if LIBCURL_VERSION_NUM >= 0x070a08 /* 7.10.8 */
{"SPNEGO", CURL_VERSION_SPNEGO},
#endif
@ -804,7 +811,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLINFO_STARTTRANSFER_TIME);
REGISTER_CURL_CONSTANT(CURLINFO_TOTAL_TIME);
/* Other */
/* Other */
REGISTER_CURL_CONSTANT(CURLMSG_DONE);
REGISTER_CURL_CONSTANT(CURLVERSION_NOW);
@ -846,7 +853,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURL_SSLVERSION_SSLv2);
REGISTER_CURL_CONSTANT(CURL_SSLVERSION_SSLv3);
REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1);
/* Curl TIMECOND constants (CURLOPT_TIMECONDITION) */
REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFMODSINCE);
REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFUNMODSINCE);
@ -910,7 +917,7 @@ PHP_MINIT_FUNCTION(curl)
#if LIBCURL_VERSION_NUM >= 0x070d00 /* Available since 7.13.0 */
REGISTER_CURL_CONSTANT(CURLOPT_FTP_ACCOUNT);
#endif
#endif
#if LIBCURL_VERSION_NUM >= 0x070b02 /* Available since 7.11.2 */
REGISTER_CURL_CONSTANT(CURLOPT_TCP_NODELAY);
@ -918,7 +925,7 @@ PHP_MINIT_FUNCTION(curl)
#if LIBCURL_VERSION_NUM >= 0x070c02 /* Available since 7.12.2 */
REGISTER_CURL_CONSTANT(CURLINFO_OS_ERRNO);
#endif
#endif
#if LIBCURL_VERSION_NUM >= 0x070c03 /* Available since 7.12.3 */
REGISTER_CURL_CONSTANT(CURLINFO_NUM_CONNECTS);
@ -959,7 +966,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLOPT_FTP_ALTERNATIVE_TO_USER);
REGISTER_CURL_CONSTANT(CURLOPT_MAX_RECV_SPEED_LARGE);
REGISTER_CURL_CONSTANT(CURLOPT_MAX_SEND_SPEED_LARGE);
#endif
#endif
#if LIBCURL_VERSION_NUM >= 0x071000 /* Available since 7.16.0 */
REGISTER_CURL_CONSTANT(CURLOPT_SSL_SESSIONID_CACHE);
@ -1003,7 +1010,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLUSESSL_CONTROL);
REGISTER_CURL_CONSTANT(CURLUSESSL_NONE);
REGISTER_CURL_CONSTANT(CURLUSESSL_TRY);
#endif
#endif
#if LIBCURL_VERSION_NUM >= 0x071101 /* Available since 7.17.1 */
REGISTER_CURL_CONSTANT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5);
@ -1053,7 +1060,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLOPT_USERNAME);
#endif
#if LIBCURL_VERSION_NUM >= 0x071303 /* Available since 7.19.3 */
#if LIBCURL_VERSION_NUM >= 0x071303 /* Available since 7.19.3 */
REGISTER_CURL_CONSTANT(CURLAUTH_DIGEST_IE);
#endif
@ -1135,7 +1142,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_FAIL);
REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_MATCH);
REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_NOMATCH);
#endif
#endif
#if LIBCURL_VERSION_NUM >= 0x071502 /* Available since 7.21.2 */
REGISTER_CURL_CONSTANT(CURLPROTO_GOPHER);
@ -1187,6 +1194,7 @@ PHP_MINIT_FUNCTION(curl)
#if CURLOPT_PASSWDFUNCTION != 0
REGISTER_CURL_CONSTANT(CURLOPT_PASSWDFUNCTION);
#endif
REGISTER_CURL_CONSTANT(CURLOPT_SAFE_UPLOAD);
#ifdef PHP_CURL_NEED_OPENSSL_TSL
if (!CRYPTO_get_id_callback()) {
@ -1229,6 +1237,8 @@ PHP_MINIT_FUNCTION(curl)
}
#endif
curlfile_register_class(TSRMLS_C);
return SUCCESS;
}
/* }}} */
@ -1275,7 +1285,7 @@ PHP_MSHUTDOWN_FUNCTION(curl)
/* {{{ curl_write_nothing
* Used as a work around. See _php_curl_close_ex
*/
static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx)
static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx)
{
return size * nmemb;
}
@ -1812,6 +1822,7 @@ static void alloc_curl_handle(php_curl **ch)
zend_llist_init(&(*ch)->to_free->str, sizeof(char *), (llist_dtor_func_t) curl_free_string, 0);
zend_llist_init(&(*ch)->to_free->slist, sizeof(struct curl_slist), (llist_dtor_func_t) curl_free_slist, 0);
zend_llist_init(&(*ch)->to_free->post, sizeof(struct HttpPost), (llist_dtor_func_t) curl_free_post, 0);
(*ch)->safe_upload = 0; /* for now, for BC reason we allow unsafe API */
}
/* }}} */
@ -1833,7 +1844,7 @@ static void split_certinfo(char *string, zval *hash)
split = strstr(s, "; ");
if(split)
*split = '\0';
key = s;
tmp = memchr(key, '=', 64);
if(tmp) {
@ -1853,13 +1864,13 @@ static void split_certinfo(char *string, zval *hash)
static void create_certinfo(struct curl_certinfo *ci, zval *listcode TSRMLS_DC)
{
int i;
if(ci) {
zval *certhash = NULL;
for(i=0; i<ci->num_of_certs; i++) {
struct curl_slist *slist;
MAKE_STD_ZVAL(certhash);
array_init(certhash);
for(slist = ci->certinfo[i]; slist; slist = slist->next) {
@ -1876,14 +1887,14 @@ static void create_certinfo(struct curl_certinfo *ci, zval *listcode TSRMLS_DC)
MAKE_STD_ZVAL(hash);
array_init(hash);
split_certinfo(&slist->data[len+1], hash);
add_assoc_zval(certhash, s, hash);
} else {
add_assoc_string(certhash, s, &slist->data[len+1], 1);
}
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not extract hash key from certificate info");
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not extract hash key from certificate info");
}
}
add_next_index_zval(listcode, certhash);
@ -2056,7 +2067,7 @@ PHP_FUNCTION(curl_copy_handle)
if (ch->handlers->fnmatch->func_name) {
zval_add_ref(&ch->handlers->fnmatch->func_name);
dupch->handlers->fnmatch->func_name = ch->handlers->fnmatch->func_name;
}
}
dupch->handlers->fnmatch->method = ch->handlers->fnmatch->method;
curl_easy_setopt(dupch->cp, CURLOPT_FNMATCH_DATA, (void *) dupch);
}
@ -2135,7 +2146,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
#if LIBCURL_VERSION_NUM >= 0x070a06 /* Available since 7.10.6 */
case CURLOPT_HTTPAUTH:
#endif
#if LIBCURL_VERSION_NUM >= 0x070a07 /* Available since 7.10.7 */
#if LIBCURL_VERSION_NUM >= 0x070a07 /* Available since 7.10.7 */
case CURLOPT_FTP_CREATE_MISSING_DIRS:
case CURLOPT_PROXYAUTH:
#endif
@ -2185,11 +2196,11 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
case CURLOPT_USE_SSL:
#elif LIBCURL_VERSION_NUM >= 0x070b00 /* Available since 7.11.0 */
case CURLOPT_FTP_SSL:
#endif
#endif
#if LIBCURL_VERSION_NUM >= 0x071100 /* Available since 7.17.0 */
case CURLOPT_APPEND:
case CURLOPT_DIRLISTONLY:
#else
#else
case CURLOPT_FTPAPPEND:
case CURLOPT_FTPLISTONLY:
#endif
@ -2247,6 +2258,10 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
#endif
error = curl_easy_setopt(ch->cp, option, Z_LVAL_PP(zvalue));
break;
case CURLOPT_SAFE_UPLOAD:
convert_to_long_ex(zvalue);
ch->safe_upload = (Z_LVAL_PP(zvalue) != 0);
break;
/* String options */
case CURLOPT_CAINFO:
@ -2282,7 +2297,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
#endif
#if LIBCURL_VERSION_NUM >= 0x071004 /* Available since 7.16.4 */
case CURLOPT_KRBLEVEL:
#else
#else
case CURLOPT_KRB4LEVEL:
#endif
#if LIBCURL_VERSION_NUM >= 0x071101 /* Available since 7.17.1 */
@ -2307,7 +2322,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
case CURLOPT_TLSAUTH_PASSWORD:
case CURLOPT_TLSAUTH_USERNAME:
#endif
#if LIBCURL_VERSION_NUM >= 0x071506 /* Available since 7.21.6 */
#if LIBCURL_VERSION_NUM >= 0x071506 /* Available since 7.21.6 */
case CURLOPT_ACCEPT_ENCODING:
case CURLOPT_TRANSFER_ENCODING:
#else
@ -2315,7 +2330,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
#endif
#if LIBCURL_VERSION_NUM >= 0x071800 /* Available since 7.24.0 */
case CURLOPT_DNS_SERVERS:
#endif
#endif
#if LIBCURL_VERSION_NUM >= 0x071900 /* Available since 7.25.0 */
case CURLOPT_MAIL_AUTH:
#endif
@ -2339,8 +2354,8 @@ string_copy:
#if LIBCURL_VERSION_NUM >= 0x071100
/* Strings passed to libcurl as char * arguments, are copied by the library... NOTE: before 7.17.0 strings were not copied. */
error = curl_easy_setopt(ch->cp, option, Z_STRVAL_PP(zvalue));
#else
goto string_copy;
#else
goto string_copy;
#endif
}
}
@ -2350,7 +2365,7 @@ string_copy:
/* Curl file handle options */
case CURLOPT_FILE:
case CURLOPT_INFILE:
case CURLOPT_STDERR:
case CURLOPT_STDERR:
case CURLOPT_WRITEHEADER: {
FILE *fp = NULL;
int type;
@ -2560,9 +2575,6 @@ string_copy:
ulong num_key;
int numeric_key;
SEPARATE_ZVAL(current);
convert_to_string_ex(current);
zend_hash_get_current_key_ex(postfields, &string_key, &string_key_len, &num_key, 0, NULL);
/* Pretend we have a string_key here */
@ -2574,15 +2586,59 @@ string_copy:
numeric_key = 0;
}
if(Z_TYPE_PP(current) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(current), curl_CURLFile_class TSRMLS_CC)) {
/* new-style file upload */
zval *prop;
char *type = NULL, *filename = NULL;
prop = zend_read_property(curl_CURLFile_class, *current, "name", sizeof("name")-1, 0 TSRMLS_CC);
if(Z_TYPE_P(prop) != IS_STRING) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid filename for key %s", string_key);
} else {
postval = Z_STRVAL_P(prop);
if (php_check_open_basedir(postval TSRMLS_CC)) {
RETVAL_FALSE;
return 1;
}
prop = zend_read_property(curl_CURLFile_class, *current, "mime", sizeof("mime")-1, 0 TSRMLS_CC);
if(Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
type = Z_STRVAL_P(prop);
}
prop = zend_read_property(curl_CURLFile_class, *current, "postname", sizeof("postname")-1, 0 TSRMLS_CC);
if(Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
filename = Z_STRVAL_P(prop);
}
error = curl_formadd(&first, &last,
CURLFORM_COPYNAME, string_key,
CURLFORM_NAMELENGTH, (long)string_key_len - 1,
CURLFORM_FILENAME, filename ? filename : postval,
CURLFORM_CONTENTTYPE, type ? type : "application/octet-stream",
CURLFORM_FILE, postval,
CURLFORM_END);
}
if (numeric_key) {
efree(string_key);
}
continue;
}
SEPARATE_ZVAL(current);
convert_to_string_ex(current);
postval = Z_STRVAL_PP(current);
/* The arguments after _NAMELENGTH and _CONTENTSLENGTH
* must be explicitly cast to long in curl_formadd
* use since curl needs a long not an int. */
if (*postval == '@') {
if (!ch->safe_upload && *postval == '@') {
char *type, *filename;
++postval;
php_error_docref("curl.curlfile" TSRMLS_CC, E_DEPRECATED, "The usage of the @filename API for file uploading is deprecated. Please use the CURLFile class instead");
if ((type = php_memnstr(postval, ";type=", sizeof(";type=") - 1, postval + Z_STRLEN_PP(current)))) {
*type = '\0';
}
@ -2725,7 +2781,7 @@ string_copy:
/* the following options deal with files, therefore the open_basedir check
* is required.
*/
case CURLOPT_COOKIEFILE:
case CURLOPT_COOKIEFILE:
case CURLOPT_COOKIEJAR:
case CURLOPT_RANDOM_FILE:
case CURLOPT_SSLCERT:
@ -2829,7 +2885,7 @@ PHP_FUNCTION(curl_setopt)
ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
if (options <= 0) {
if (options <= 0 && options != CURLOPT_SAFE_UPLOAD) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid curl configuration option");
RETURN_FALSE;
}
@ -3045,7 +3101,7 @@ PHP_FUNCTION(curl_getinfo)
CAAS("redirect_url", s_code);
}
#endif
#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 */
#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 */
if (curl_easy_getinfo(ch->cp, CURLINFO_PRIMARY_IP, &s_code) == CURLE_OK) {
CAAS("primary_ip", s_code);
}
@ -3085,7 +3141,7 @@ PHP_FUNCTION(curl_getinfo)
struct curl_certinfo *ci = NULL;
array_init(return_value);
if (curl_easy_getinfo(ch->cp, CURLINFO_CERTINFO, &ci) == CURLE_OK) {
create_certinfo(ci, return_value TSRMLS_CC);
} else {
@ -3100,7 +3156,7 @@ PHP_FUNCTION(curl_getinfo)
case CURLINFO_STRING:
{
char *s_code = NULL;
if (curl_easy_getinfo(ch->cp, option, &s_code) == CURLE_OK && s_code) {
RETURN_STRING(s_code, 1);
} else {
@ -3111,7 +3167,7 @@ PHP_FUNCTION(curl_getinfo)
case CURLINFO_LONG:
{
long code = 0;
if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
RETURN_LONG(code);
} else {
@ -3221,16 +3277,16 @@ static void _php_curl_close_ex(php_curl *ch TSRMLS_DC)
_php_curl_verify_handlers(ch, 0 TSRMLS_CC);
/*
/*
* Libcurl is doing connection caching. When easy handle is cleaned up,
* if the handle was previously used by the curl_multi_api, the connection
* if the handle was previously used by the curl_multi_api, the connection
* remains open un the curl multi handle is cleaned up. Some protocols are
* sending content like the FTP one, and libcurl try to use the
* sending content like the FTP one, and libcurl try to use the
* WRITEFUNCTION or the HEADERFUNCTION. Since structures used in those
* callback are freed, we need to use an other callback to which avoid
* segfaults.
*
* Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2
* Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2
*/
curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing);
curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing);
@ -3349,7 +3405,7 @@ static void _php_curl_reset_handlers(php_curl *ch)
}
ch->handlers->write->fp = NULL;
ch->handlers->write->method = PHP_CURL_STDOUT;
if (ch->handlers->write_header->stream) {
Z_DELREF_P(ch->handlers->write_header->stream);
ch->handlers->write_header->stream = NULL;
@ -3443,7 +3499,7 @@ PHP_FUNCTION(curl_escape)
/* {{{ proto void curl_unescape(resource ch, string str)
URL decodes the given string */
PHP_FUNCTION(curl_unescape)
PHP_FUNCTION(curl_unescape)
{
char *str = NULL, *out = NULL;
int str_len = 0, out_len;
@ -3481,7 +3537,7 @@ PHP_FUNCTION(curl_pause)
ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
RETURN_LONG(curl_easy_pause(ch->cp, bitmask));
RETURN_LONG(curl_easy_pause(ch->cp, bitmask));
}
/* }}} */
#endif

View file

@ -34,6 +34,14 @@
#define PHP_CURL_DEBUG 0
#ifdef PHP_WIN32
# define PHP_CURL_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# define PHP_CURL_API __attribute__ ((visibility("default")))
#else
# define PHP_CURL_API
#endif
#include <curl/curl.h>
#include <curl/multi.h>
@ -103,6 +111,8 @@ PHP_FUNCTION(curl_multi_setopt);
#if LIBCURL_VERSION_NUM >= 0x071200 /* 7.18.0 */
PHP_FUNCTION(curl_pause);
#endif
PHP_FUNCTION(curl_file_create);
void _php_curl_multi_close(zend_rsrc_list_entry * TSRMLS_DC);
void _php_curl_share_close(zend_rsrc_list_entry * TSRMLS_DC);
@ -171,8 +181,11 @@ typedef struct {
long id;
zend_bool in_callback;
zval *clone;
zend_bool safe_upload;
} php_curl;
#define CURLOPT_SAFE_UPLOAD -1
typedef struct {
int still_running;
CURLM *multi;
@ -211,7 +224,7 @@ typedef struct {
fd_set readfds, writefds, excfds;
int maxfd;
char errstr[CURL_ERROR_SIZE + 1];
CURLMcode mcode;
int pending;
@ -219,6 +232,8 @@ typedef struct {
struct curl_slist *headers_slist; /* holds custom headers sent out in the request */
} php_curl_stream;
void curlfile_register_class(TSRMLS_D);
PHP_CURL_API extern zend_class_entry *curl_CURLFile_class;
#else
#define curl_module_ptr NULL

View file

@ -1,5 +1,7 @@
--TEST--
Bug #27023 (CURLOPT_POSTFIELDS does not parse content types for files)
--INI--
error_reporting = E_ALL & ~E_DEPRECATED
--SKIPIF--
<?php
if (!extension_loaded("curl")) {

View file

@ -0,0 +1,21 @@
--TEST--
CURL file uploading
--SKIPIF--
<?php
if (!extension_loaded("curl")) {
exit("skip curl extension not loaded");
}
?>
--FILE--
<?php
$data = 'a:2:{s:4:"file";O:8:"CURLFile":3:{s:4:"name";s:13:"testdata1.txt";s:4:"mime";s:0:"";s:8:"postname";s:0:"";}s:4:"data";s:3:"foo";}';
var_dump(unserialize($data));
?>
--EXPECTF--
Fatal error: Uncaught exception 'Exception' with message 'Unserialization of CURLFile instances is not allowed' in %s
Stack trace:
#0 [internal function]: CURLFile->__wakeup()
#1 %s
#2 {main}
thrown in %s on line %d

View file

@ -0,0 +1,85 @@
--TEST--
CURL file uploading
--SKIPIF--
<?php
if (!extension_loaded("curl")) {
exit("skip curl extension not loaded");
}
if (false === getenv('PHP_CURL_HTTP_REMOTE_SERVER')) {
exit("skip PHP_CURL_HTTP_REMOTE_SERVER env variable is not defined");
}
?>
--FILE--
<?php
function testcurl($ch, $name, $mime = '', $postname = '')
{
if(!empty($postname)) {
$file = new CurlFile($name, $mime, $postname);
} else if(!empty($mime)) {
$file = new CurlFile($name, $mime);
} else {
$file = new CurlFile($name);
}
curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => $file));
var_dump(curl_exec($ch));
}
$host = getenv('PHP_CURL_HTTP_REMOTE_SERVER');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "{$host}/get.php?test=file");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
testcurl($ch, __DIR__ . '/curl_testdata1.txt');
testcurl($ch, __DIR__ . '/curl_testdata1.txt', 'text/plain');
testcurl($ch, __DIR__ . '/curl_testdata1.txt', '', 'foo.txt');
testcurl($ch, __DIR__ . '/curl_testdata1.txt', 'text/plain', 'foo.txt');
$file = new CurlFile(__DIR__ . '/curl_testdata1.txt');
$file->setMimeType('text/plain');
var_dump($file->getMimeType());
var_dump($file->getFilename());
curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => $file));
var_dump(curl_exec($ch));
$file = curl_file_create(__DIR__ . '/curl_testdata1.txt');
$file->setPostFilename('foo.txt');
var_dump($file->getPostFilename());
curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => $file));
var_dump(curl_exec($ch));
$params = array('file' => '@' . __DIR__ . '/curl_testdata1.txt');
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
var_dump(curl_exec($ch));
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
$params = array('file' => '@' . __DIR__ . '/curl_testdata1.txt');
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
var_dump(curl_exec($ch));
curl_setopt($ch, CURLOPT_URL, "{$host}/get.php?test=post");
$params = array('file' => '@' . __DIR__ . '/curl_testdata1.txt');
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
var_dump(curl_exec($ch));
curl_close($ch);
?>
--EXPECTF--
string(%d) "curl_testdata1.txt|application/octet-stream"
string(%d) "curl_testdata1.txt|text/plain"
string(%d) "foo.txt|application/octet-stream"
string(%d) "foo.txt|text/plain"
string(%d) "text/plain"
string(%d) "%s/curl_testdata1.txt"
string(%d) "curl_testdata1.txt|text/plain"
string(%d) "foo.txt"
string(%d) "foo.txt|application/octet-stream"
Deprecated: curl_setopt(): The usage of the @filename API for file uploading is deprecated. Please use the CURLFile class instead in %s on line %d
string(%d) "curl_testdata1.txt|application/octet-stream"
string(0) ""
string(%d) "array(1) {
["file"]=>
string(%d) "@%s/curl_testdata1.txt"
}
"

View file

@ -14,14 +14,14 @@ curl_setopt(false);
curl_setopt($ch);
curl_setopt($ch, false);
curl_setopt($ch, -1);
curl_setopt($ch, -10);
curl_setopt($ch, '');
curl_setopt($ch, 1, false);
curl_setopt(false, false, false);
curl_setopt($ch, '', false);
curl_setopt($ch, 1, '');
curl_setopt($ch, -1, 0);
curl_setopt($ch, -10, 0);
?>
--EXPECTF--
*** curl_setopt() call with incorrect parameters