Commit:    a9d013bb020591cb6306afa2748da80f68b81f56
Author:    Stanislav Malyshev <s...@php.net>         Mon, 28 Jan 2013 22:22:59 
-0800
Parents:   420bcc1a8e4d4dd38f6b1f019d31ec87fe582867
Branches:  PHP-5.5 master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=a9d013bb020591cb6306afa2748da80f68b81f56

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

Bugs:
https://bugs.php.net/46439

Changed paths:
  M  NEWS
  M  UPGRADING
  M  ext/curl/config.m4
  M  ext/curl/config.w32
  M  ext/curl/interface.c
  M  ext/curl/php_curl.h
  M  ext/curl/tests/bug27023.phpt
  A  ext/curl/tests/curl_file_serialize.phpt
  A  ext/curl/tests/curl_file_upload.phpt
  M  ext/curl/tests/curl_setopt_error.phpt

diff --git a/NEWS b/NEWS
index 6cd007c..3775558 100644
--- a/NEWS
+++ b/NEWS
@@ -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:
diff --git a/UPGRADING b/UPGRADING
index 7bf0e85..8c9b3de 100755
--- a/UPGRADING
+++ b/UPGRADING
@@ -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
 ========================================
diff --git a/ext/curl/config.m4 b/ext/curl/config.m4
index 92559be..e549330 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/config.w32 b/ext/curl/config.w32
index a056845..5acda7e 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/interface.c b/ext/curl/interface.c
index 2e05581..0714148 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 */
@@ -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
diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h
index a8c26c0..c4222c0 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 <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
diff --git a/ext/curl/tests/bug27023.phpt b/ext/curl/tests/bug27023.phpt
index b738c95..62effec 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--
 <?php 
 if (!extension_loaded("curl")) {
diff --git a/ext/curl/tests/curl_file_serialize.phpt 
b/ext/curl/tests/curl_file_serialize.phpt
new file mode 100644
index 0000000..43b272a
--- /dev/null
+++ b/ext/curl/tests/curl_file_serialize.phpt
@@ -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
+
diff --git a/ext/curl/tests/curl_file_upload.phpt 
b/ext/curl/tests/curl_file_upload.phpt
new file mode 100644
index 0000000..d3168e5
--- /dev/null
+++ b/ext/curl/tests/curl_file_upload.phpt
@@ -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"
+}
+"
diff --git a/ext/curl/tests/curl_setopt_error.phpt 
b/ext/curl/tests/curl_setopt_error.phpt
index ad73318..01593af 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
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to