From 7efa63e1ff43229b6ca20957bed91f2b113663a6 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sun, 6 Jan 2013 22:27:37 -0800 Subject: [PATCH 1/5] bug #46439 - better handling of CURL file uploads --- ext/curl/config.m4 | 2 +- ext/curl/curl_file.c | 151 +++++++++++++++++++++++++++ ext/curl/interface.c | 75 ++++++++++--- ext/curl/php_curl.h | 4 +- ext/curl/tests/bug27023.phpt | 2 + ext/curl/tests/curl_file_upload.phpt | 69 ++++++++++++ 6 files changed, 285 insertions(+), 18 deletions(-) create mode 100644 ext/curl/curl_file.c create mode 100644 ext/curl/tests/curl_file_upload.phpt diff --git a/ext/curl/config.m4 b/ext/curl/config.m4 index 92559be7c42a0..e549330c50c1b 100644 --- a/ext/curl/config.m4 +++ b/ext/curl/config.m4 @@ -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 diff --git a/ext/curl/curl_file.c b/ext/curl/curl_file.c new file mode 100644 index 0000000000000..f2d36fbf4555d --- /dev/null +++ b/ext/curl/curl_file.c @@ -0,0 +1,151 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Stanislav Malyshev | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#if HAVE_CURL + +PHPAPI zend_class_entry *curl_CURLFile_class; + +/* {{{ proto string CURLFile::__construct(string $name, [string $mimetype [, string $postfilename]]) + Create the CURLFile object */ +ZEND_METHOD(CURLFile, __construct) +{ + char *fname = NULL, *mime = NULL, *postname = NULL; + int fname_len, mime_len, postname_len; + zval *cf = getThis(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss", &fname, &fname_len, &mime, &mime_len, &postname, &postname_len) == FAILURE) { + return; + } + + if (fname) { + zend_update_property_string(curl_CURLFile_class, cf, "name", sizeof("name")-1, fname TSRMLS_CC); + } + + if (mime) { + zend_update_property_string(curl_CURLFile_class, cf, "mime", sizeof("mime")-1, mime TSRMLS_CC); + } + + if (postname) { + zend_update_property_string(curl_CURLFile_class, cf, "postname", sizeof("postname")-1, postname TSRMLS_CC); + } +} + +/* }}} */ + +static void curlfile_get_property(char *name, INTERNAL_FUNCTION_PARAMETERS) +{ + zval *res; + if (zend_parse_parameters_none() == FAILURE) { + return; + } + res = zend_read_property(curl_CURLFile_class, getThis(), name, strlen(name), 1 TSRMLS_CC); + *return_value = *res; + zval_copy_ctor(return_value); + INIT_PZVAL(return_value); +} + +static void curlfile_set_property(char *name, INTERNAL_FUNCTION_PARAMETERS) +{ + char *arg = NULL; + int arg_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { + return; + } + zend_update_property_string(curl_CURLFile_class, getThis(), name, strlen(name), arg); +} + +/* {{{ proto string CURLFile::getFilename() + Get file name */ +ZEND_METHOD(CURLFile, getFilename) +{ + curlfile_get_property("name", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto string CURLFile::getMimeType() + Get MIME type */ +ZEND_METHOD(CURLFile, getMimeType) +{ + curlfile_get_property("mime", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto string CURLFile::getPostFilename() + Get file name for POST */ +ZEND_METHOD(CURLFile, getPostFilename) +{ + curlfile_get_property("postname", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto string CURLFile::setMimeType(string $mime) + Set MIME type */ +ZEND_METHOD(CURLFile, setMimeType) +{ + curlfile_set_property("mime", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto string CURLFile::setPostFilename(string $name) + Set file name for POST */ +ZEND_METHOD(CURLFile, setPostFilename) +{ + curlfile_set_property("postname", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +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() + +ZEND_BEGIN_ARG_INFO(arginfo_curlfile_name, 0) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO() + + +static const zend_function_entry curlfile_funcs[] = { + PHP_ME(CURLFile, __construct, arginfo_curlfile_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME(CURLFile, getFilename, NULL, ZEND_ACC_PUBLIC) + PHP_ME(CURLFile, getMimeType, NULL, ZEND_ACC_PUBLIC) + PHP_ME(CURLFile, setMimeType, arginfo_curlfile_name, ZEND_ACC_PUBLIC) + PHP_ME(CURLFile, getPostFilename, NULL, ZEND_ACC_PUBLIC) + PHP_ME(CURLFile, setPostFilename, arginfo_curlfile_name, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +void curlfile_register_class(TSRMLS_D) +{ + zend_class_entry ce; + INIT_CLASS_ENTRY( ce, "CURLFile", curlfile_funcs ); + curl_CURLFile_class = zend_register_internal_class(&ce TSRMLS_CC); + zend_declare_property_string(curl_CURLFile_class, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_string(curl_CURLFile_class, "mime", sizeof("mime")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_string(curl_CURLFile_class, "postname", sizeof("postname")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC); +} + +#endif diff --git a/ext/curl/interface.c b/ext/curl/interface.c index e0c95efed52ad..5e9c6aa855b37 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1229,6 +1229,8 @@ PHP_MINIT_FUNCTION(curl) } #endif + curlfile_register_class(TSRMLS_C); + return SUCCESS; } /* }}} */ @@ -1275,7 +1277,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; } @@ -1853,13 +1855,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; inum_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 +1878,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); @@ -2342,8 +2344,8 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu #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 } } @@ -2563,9 +2565,6 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu 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 */ @@ -2577,6 +2576,48 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu 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 @@ -2586,6 +2627,8 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu char *type, *filename; ++postval; + php_error_docref("curl.curlfile" TSRMLS_CC, E_DEPRECATED, "Usage of @filename API for file uploading is deprecated. Please use CURLFile parameter instead"); + if ((type = php_memnstr(postval, ";type=", sizeof(";type=") - 1, postval + Z_STRLEN_PP(current)))) { *type = '\0'; } @@ -3088,7 +3131,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 { @@ -3228,16 +3271,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); diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h index 5c24fc1302710..f149d15b88547 100644 --- a/ext/curl/php_curl.h +++ b/ext/curl/php_curl.h @@ -212,7 +212,7 @@ typedef struct { fd_set readfds, writefds, excfds; int maxfd; - + char errstr[CURL_ERROR_SIZE + 1]; CURLMcode mcode; int pending; @@ -220,6 +220,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); +extern zend_class_entry *curl_CURLFile_class; #else #define curl_module_ptr NULL diff --git a/ext/curl/tests/bug27023.phpt b/ext/curl/tests/bug27023.phpt index b738c956e9280..62effec990be4 100644 --- a/ext/curl/tests/bug27023.phpt +++ b/ext/curl/tests/bug27023.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #27023 (CURLOPT_POSTFIELDS does not parse content types for files) +--INI-- +error_reporting = E_ALL & ~E_DEPRECATED --SKIPIF-- +--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 = new CurlFile(__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_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(): Usage of @filename API for file uploading is deprecated. Please use CURLFile parameter instead in %s on line %d +string(%d) "curl_testdata1.txt|application/octet-stream" From 9681fa9a83c3e59d24df98899e8eca725b6a0939 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Tue, 8 Jan 2013 01:06:48 -0800 Subject: [PATCH 2/5] fixes from Anatoliy Belsky --- ext/curl/config.w32 | 2 +- ext/curl/curl_file.c | 5 +++-- ext/curl/php_curl.h | 10 +++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ext/curl/config.w32 b/ext/curl/config.w32 index a056845575899..5acda7ec9e957 100644 --- a/ext/curl/config.w32 +++ b/ext/curl/config.w32 @@ -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'); diff --git a/ext/curl/curl_file.c b/ext/curl/curl_file.c index f2d36fbf4555d..f3ef70a2e2171 100644 --- a/ext/curl/curl_file.c +++ b/ext/curl/curl_file.c @@ -23,9 +23,10 @@ #endif #include "php.h" +#include "php_curl.h" #if HAVE_CURL -PHPAPI zend_class_entry *curl_CURLFile_class; +PHP_CURL_API zend_class_entry *curl_CURLFile_class; /* {{{ proto string CURLFile::__construct(string $name, [string $mimetype [, string $postfilename]]) Create the CURLFile object */ @@ -74,7 +75,7 @@ static void curlfile_set_property(char *name, INTERNAL_FUNCTION_PARAMETERS) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { return; } - zend_update_property_string(curl_CURLFile_class, getThis(), name, strlen(name), arg); + zend_update_property_string(curl_CURLFile_class, getThis(), name, strlen(name), arg TSRMLS_CC); } /* {{{ proto string CURLFile::getFilename() diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h index f149d15b88547..7101398c0fbfb 100644 --- a/ext/curl/php_curl.h +++ b/ext/curl/php_curl.h @@ -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 #include @@ -221,7 +229,7 @@ typedef struct { } php_curl_stream; void curlfile_register_class(TSRMLS_D); -extern zend_class_entry *curl_CURLFile_class; +PHP_CURL_API extern zend_class_entry *curl_CURLFile_class; #else #define curl_module_ptr NULL From ffa22fdd4908f31fe6f2f2aa8eff955455f29ceb Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Tue, 8 Jan 2013 02:09:53 -0800 Subject: [PATCH 3/5] add CURLOPT_SAFE_UPLOAD option --- ext/curl/interface.c | 62 +++++++++++++++------------- ext/curl/php_curl.h | 3 ++ ext/curl/tests/curl_file_upload.phpt | 22 ++++++++-- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 5e9c6aa855b37..6ef6912525be4 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -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 */ @@ -526,7 +526,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 +804,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 +846,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 +910,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 +918,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 +959,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 +1003,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 +1053,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 +1135,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 +1187,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()) { @@ -1814,6 +1815,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 */ } /* }}} */ @@ -1835,7 +1837,7 @@ static void split_certinfo(char *string, zval *hash) split = strstr(s, "; "); if(split) *split = '\0'; - + key = s; tmp = memchr(key, '=', 64); if(tmp) { @@ -2061,7 +2063,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); } @@ -2140,7 +2142,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 @@ -2190,11 +2192,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 @@ -2252,6 +2254,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: @@ -2287,7 +2293,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 */ @@ -2312,7 +2318,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 @@ -2320,7 +2326,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 @@ -2355,7 +2361,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu /* Curl file handle options */ case CURLOPT_FILE: case CURLOPT_INFILE: - case CURLOPT_STDERR: + case CURLOPT_STDERR: case CURLOPT_WRITEHEADER: { FILE *fp = NULL; int type; @@ -2623,7 +2629,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu /* 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; @@ -2771,7 +2777,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu /* 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: @@ -2875,7 +2881,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; } @@ -3091,7 +3097,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); } @@ -3146,7 +3152,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 { @@ -3157,7 +3163,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 { @@ -3399,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; @@ -3493,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; @@ -3531,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 diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h index 7101398c0fbfb..0e2df225c774f 100644 --- a/ext/curl/php_curl.h +++ b/ext/curl/php_curl.h @@ -180,8 +180,11 @@ typedef struct { unsigned int uses; zend_bool in_callback; zval *clone; + zend_bool safe_upload; } php_curl; +#define CURLOPT_SAFE_UPLOAD -1 + typedef struct { int still_running; CURLM *multi; diff --git a/ext/curl/tests/curl_file_upload.phpt b/ext/curl/tests/curl_file_upload.phpt index 2f4621ec8879c..6b329a55a05fa 100644 --- a/ext/curl/tests/curl_file_upload.phpt +++ b/ext/curl/tests/curl_file_upload.phpt @@ -1,7 +1,7 @@ --TEST-- CURL file uploading --SKIPIF-- - '@' . __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-- @@ -67,3 +77,9 @@ string(%d) "foo.txt|application/octet-stream" Deprecated: curl_setopt(): Usage of @filename API for file uploading is deprecated. Please use CURLFile parameter 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" +} +" \ No newline at end of file From 1ba339021ae289b2c83098e881858efc99fedde7 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Tue, 8 Jan 2013 16:58:46 -0800 Subject: [PATCH 4/5] improve message --- ext/curl/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 6ef6912525be4..fa43eb90d7bad 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -2633,7 +2633,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu char *type, *filename; ++postval; - php_error_docref("curl.curlfile" TSRMLS_CC, E_DEPRECATED, "Usage of @filename API for file uploading is deprecated. Please use CURLFile parameter instead"); + 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'; From 80136dc49d79155c34f7a0f5bdc963648c82dbbe Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sat, 12 Jan 2013 16:17:40 -0800 Subject: [PATCH 5/5] For those who dislikes classes, add curl_file_create --- ext/curl/curl_file.c | 22 ++++++++++++++++++---- ext/curl/interface.c | 7 +++++++ ext/curl/php_curl.h | 2 ++ ext/curl/tests/curl_file_upload.phpt | 6 +++--- ext/curl/tests/curl_setopt_error.phpt | 4 ++-- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/ext/curl/curl_file.c b/ext/curl/curl_file.c index f3ef70a2e2171..a8a09d3f06ac3 100644 --- a/ext/curl/curl_file.c +++ b/ext/curl/curl_file.c @@ -28,13 +28,11 @@ PHP_CURL_API zend_class_entry *curl_CURLFile_class; -/* {{{ proto string CURLFile::__construct(string $name, [string $mimetype [, string $postfilename]]) - Create the CURLFile object */ -ZEND_METHOD(CURLFile, __construct) +static void curlfile_ctor(INTERNAL_FUNCTION_PARAMETERS) { char *fname = NULL, *mime = NULL, *postname = NULL; int fname_len, mime_len, postname_len; - zval *cf = getThis(); + zval *cf = return_value; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss", &fname, &fname_len, &mime, &mime_len, &postname, &postname_len) == FAILURE) { return; @@ -53,6 +51,22 @@ ZEND_METHOD(CURLFile, __construct) } } +/* {{{ proto string CURLFile::__construct(string $name, [string $mimetype [, string $postfilename]]) + Create the CURLFile object */ +ZEND_METHOD(CURLFile, __construct) +{ + return_value = getThis(); + curlfile_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto string curl_file_create(string $name, [string $mimetype [, string $postfilename]]) + Create the CURLFile object */ +PHP_FUNCTION(curl_file_create) +{ + object_init_ex( return_value, curl_CURLFile_class ); + curlfile_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} /* }}} */ static void curlfile_get_property(char *name, INTERNAL_FUNCTION_PARAMETERS) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index fa43eb90d7bad..73b3bb85999c4 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -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 }; /* }}} */ diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h index 0e2df225c774f..d4f83ac4385d8 100644 --- a/ext/curl/php_curl.h +++ b/ext/curl/php_curl.h @@ -111,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); diff --git a/ext/curl/tests/curl_file_upload.phpt b/ext/curl/tests/curl_file_upload.phpt index 6b329a55a05fa..d3168e578ac98 100644 --- a/ext/curl/tests/curl_file_upload.phpt +++ b/ext/curl/tests/curl_file_upload.phpt @@ -42,7 +42,7 @@ var_dump($file->getFilename()); curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => $file)); var_dump(curl_exec($ch)); -$file = new CurlFile(__DIR__ . '/curl_testdata1.txt'); +$file = curl_file_create(__DIR__ . '/curl_testdata1.txt'); $file->setPostFilename('foo.txt'); var_dump($file->getPostFilename()); curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => $file)); @@ -75,11 +75,11 @@ string(%d) "curl_testdata1.txt|text/plain" string(%d) "foo.txt" string(%d) "foo.txt|application/octet-stream" -Deprecated: curl_setopt(): Usage of @filename API for file uploading is deprecated. Please use CURLFile parameter instead in %s on line %d +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" } -" \ No newline at end of file +" diff --git a/ext/curl/tests/curl_setopt_error.phpt b/ext/curl/tests/curl_setopt_error.phpt index ad73318f1cc3f..01593aff22c90 100644 --- a/ext/curl/tests/curl_setopt_error.phpt +++ b/ext/curl/tests/curl_setopt_error.phpt @@ -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