@@ -1797,8 +1797,14 @@ static void curl_free_post(void **post)
1797
1797
/* }}} */
1798
1798
1799
1799
struct mime_file {
1800
- zend_string * name ;
1801
- php_stream * stream ;
1800
+ php_curl * ch ;
1801
+ union {
1802
+ zval postfields ;
1803
+ struct {
1804
+ zend_string * name ;
1805
+ php_stream * stream ;
1806
+ };
1807
+ };
1802
1808
};
1803
1809
1804
1810
/* {{{ curl_free_stream
@@ -1807,8 +1813,12 @@ static void curl_free_stream(void **post)
1807
1813
{
1808
1814
struct mime_file * mime_file = (struct mime_file * ) * post ;
1809
1815
1810
- ZEND_ASSERT (mime_file -> stream == NULL );
1811
- zend_string_release (mime_file -> name );
1816
+ if (mime_file -> ch ) {
1817
+ Z_DELREF (mime_file -> postfields );
1818
+ } else {
1819
+ ZEND_ASSERT (mime_file -> stream == NULL );
1820
+ zend_string_release (mime_file -> name );
1821
+ }
1812
1822
efree (mime_file );
1813
1823
}
1814
1824
/* }}} */
@@ -2104,13 +2114,148 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
2104
2114
(* source -> clone )++ ;
2105
2115
}
2106
2116
2117
+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2118
+ static size_t read_cb (char * buffer , size_t size , size_t nitems , void * arg );
2119
+ static int seek_cb (void * arg , curl_off_t offset , int origin );
2120
+ static void free_cb (void * arg );
2121
+
2122
+ static int rebuild_mime_structure (php_curl * ch , zval * zpostfields )
2123
+ {
2124
+ CURLcode error = CURLE_OK ;
2125
+ zval * current ;
2126
+ zend_string * string_key ;
2127
+ zend_ulong num_key ;
2128
+ curl_mime * mime = NULL ;
2129
+ curl_mimepart * part ;
2130
+ CURLcode form_error ;
2131
+ HashTable * postfields = Z_ARRVAL_P (zpostfields );
2132
+
2133
+ if (zend_hash_num_elements (postfields ) > 0 ) {
2134
+ mime = curl_mime_init (ch -> cp );
2135
+ if (mime == NULL ) {
2136
+ return FAILURE ;
2137
+ }
2138
+ }
2139
+
2140
+ ZEND_HASH_FOREACH_KEY_VAL (postfields , num_key , string_key , current ) {
2141
+ zend_string * postval , * tmp_postval ;
2142
+ /* Pretend we have a string_key here */
2143
+ if (!string_key ) {
2144
+ string_key = zend_long_to_str (num_key );
2145
+ } else {
2146
+ zend_string_addref (string_key );
2147
+ }
2148
+
2149
+ ZVAL_DEREF (current );
2150
+ if (Z_TYPE_P (current ) == IS_OBJECT &&
2151
+ instanceof_function (Z_OBJCE_P (current ), curl_CURLFile_class )) {
2152
+ /* new-style file upload */
2153
+ zval * prop , rv ;
2154
+ char * type = NULL , * filename = NULL ;
2155
+
2156
+ struct mime_file * mime_file ;
2157
+
2158
+
2159
+ prop = zend_read_property (curl_CURLFile_class , current , "name" , sizeof ("name" )- 1 , 0 , & rv );
2160
+ if (Z_TYPE_P (prop ) != IS_STRING ) {
2161
+ php_error_docref (NULL , E_WARNING , "Invalid filename for key %s" , ZSTR_VAL (string_key ));
2162
+ } else {
2163
+ postval = Z_STR_P (prop );
2164
+
2165
+ if (php_check_open_basedir (ZSTR_VAL (postval ))) {
2166
+ return 1 ;
2167
+ }
2168
+
2169
+ prop = zend_read_property (curl_CURLFile_class , current , "mime" , sizeof ("mime" )- 1 , 0 , & rv );
2170
+ if (Z_TYPE_P (prop ) == IS_STRING && Z_STRLEN_P (prop ) > 0 ) {
2171
+ type = Z_STRVAL_P (prop );
2172
+ }
2173
+ prop = zend_read_property (curl_CURLFile_class , current , "postname" , sizeof ("postname" )- 1 , 0 , & rv );
2174
+ if (Z_TYPE_P (prop ) == IS_STRING && Z_STRLEN_P (prop ) > 0 ) {
2175
+ filename = Z_STRVAL_P (prop );
2176
+ }
2177
+
2178
+ mime_file = emalloc (sizeof * mime_file );
2179
+ mime_file -> ch = ch ;
2180
+ ZVAL_COPY (& mime_file -> postfields , zpostfields );
2181
+ zend_llist_add_element (& ch -> to_free -> stream , & mime_file );
2182
+
2183
+ mime_file = emalloc (sizeof * mime_file );
2184
+ mime_file -> ch = NULL ;
2185
+ mime_file -> name = zend_string_copy (postval );
2186
+ mime_file -> stream = NULL ;
2187
+ part = curl_mime_addpart (mime );
2188
+ if (part == NULL ) {
2189
+ zend_string_release_ex (string_key , 0 );
2190
+ return FAILURE ;
2191
+ }
2192
+ if ((form_error = curl_mime_name (part , ZSTR_VAL (string_key ))) != CURLE_OK
2193
+ || (form_error = curl_mime_data_cb (part , -1 , read_cb , seek_cb , free_cb , mime_file )) != CURLE_OK
2194
+ || (form_error = curl_mime_filename (part , filename ? filename : ZSTR_VAL (postval ))) != CURLE_OK
2195
+ || (form_error = curl_mime_type (part , type ? type : "application/octet-stream" )) != CURLE_OK ) {
2196
+ error = form_error ;
2197
+ }
2198
+ zend_llist_add_element (& ch -> to_free -> stream , & mime_file );
2199
+ }
2200
+
2201
+ zend_string_release_ex (string_key , 0 );
2202
+ continue ;
2203
+ }
2204
+
2205
+ postval = zval_get_tmp_string (current , & tmp_postval );
2206
+
2207
+ part = curl_mime_addpart (mime );
2208
+ if (part == NULL ) {
2209
+ zend_tmp_string_release (tmp_postval );
2210
+ zend_string_release_ex (string_key , 0 );
2211
+ return FAILURE ;
2212
+ }
2213
+ if ((form_error = curl_mime_name (part , ZSTR_VAL (string_key ))) != CURLE_OK
2214
+ || (form_error = curl_mime_data (part , ZSTR_VAL (postval ), ZSTR_LEN (postval ))) != CURLE_OK ) {
2215
+ error = form_error ;
2216
+ }
2217
+ zend_tmp_string_release (tmp_postval );
2218
+ zend_string_release_ex (string_key , 0 );
2219
+ } ZEND_HASH_FOREACH_END ();
2220
+
2221
+ SAVE_CURL_ERROR (ch , error );
2222
+ if (error != CURLE_OK ) {
2223
+ return FAILURE ;
2224
+ }
2225
+
2226
+ if ((* ch -> clone ) == 1 ) {
2227
+ zend_llist_clean (& ch -> to_free -> post );
2228
+ }
2229
+ zend_llist_add_element (& ch -> to_free -> post , & mime );
2230
+ error = curl_easy_setopt (ch -> cp , CURLOPT_MIMEPOST , mime );
2231
+
2232
+ return SUCCESS ;
2233
+ }
2234
+
2235
+ static HashTable * get_postfields_of_handle (php_curl * ch )
2236
+ {
2237
+ struct mime_file * mime_file , * * mfp ;
2238
+
2239
+ mfp = zend_llist_get_last (& ch -> to_free -> stream );
2240
+ while (mfp ) {
2241
+ mime_file = * mfp ;
2242
+ if (mime_file -> ch == ch ) {
2243
+ return & mime_file -> postfields ;
2244
+ }
2245
+ mfp = zend_llist_get_prev (& ch -> to_free -> stream );
2246
+ }
2247
+ return NULL ;
2248
+ }
2249
+ #endif
2250
+
2107
2251
/* {{{ proto resource curl_copy_handle(resource ch)
2108
2252
Copy a cURL handle along with all of it's preferences */
2109
2253
PHP_FUNCTION (curl_copy_handle )
2110
2254
{
2111
2255
CURL * cp ;
2112
2256
zval * zid ;
2113
2257
php_curl * ch , * dupch ;
2258
+ zval * postfields ;
2114
2259
2115
2260
ZEND_PARSE_PARAMETERS_START (1 ,1 )
2116
2261
Z_PARAM_RESOURCE (zid )
@@ -2131,6 +2276,17 @@ PHP_FUNCTION(curl_copy_handle)
2131
2276
2132
2277
_php_setup_easy_copy_handlers (dupch , ch );
2133
2278
2279
+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2280
+ postfields = get_postfields_of_handle (ch );
2281
+ if (postfields ) {
2282
+ if (rebuild_mime_structure (dupch , postfields ) != SUCCESS ) {
2283
+ _php_curl_close_ex (dupch );
2284
+ php_error_docref (NULL , E_WARNING , "Cannot rebuild mime structure" );
2285
+ RETURN_FALSE ;
2286
+ }
2287
+ }
2288
+ #endif
2289
+
2134
2290
Z_ADDREF_P (zid );
2135
2291
2136
2292
ZVAL_RES (return_value , zend_register_resource (dupch , le_curl ));
@@ -2144,13 +2300,15 @@ static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{
2144
2300
struct mime_file * mime_file = (struct mime_file * ) arg ;
2145
2301
ssize_t numread ;
2146
2302
2303
+ ZEND_ASSERT (!mime_file -> ch );
2304
+
2147
2305
if (mime_file -> stream == NULL ) {
2148
2306
if (!(mime_file -> stream = php_stream_open_wrapper (ZSTR_VAL (mime_file -> name ), "rb" , IGNORE_PATH , NULL ))) {
2149
2307
return CURL_READFUNC_ABORT ;
2150
2308
}
2151
2309
}
2152
2310
numread = php_stream_read (mime_file -> stream , buffer , nitems * size );
2153
- if (numread <= 0 ) {
2311
+ if (numread < 0 ) {
2154
2312
php_stream_close (mime_file -> stream );
2155
2313
mime_file -> stream = NULL ;
2156
2314
}
@@ -2163,17 +2321,28 @@ static int seek_cb(void *arg, curl_off_t offset, int origin) /* {{{ */
2163
2321
struct mime_file * mime_file = (struct mime_file * ) arg ;
2164
2322
int res ;
2165
2323
2324
+ ZEND_ASSERT (!mime_file -> ch );
2325
+
2166
2326
if (mime_file -> stream == NULL ) {
2167
2327
if (!(mime_file -> stream = php_stream_open_wrapper (ZSTR_VAL (mime_file -> name ), "rb" , IGNORE_PATH , NULL ))) {
2168
2328
return CURL_SEEKFUNC_CANTSEEK ;
2169
2329
}
2170
2330
}
2171
2331
res = php_stream_seek (mime_file -> stream , offset , origin );
2172
- if (res ) {
2332
+ return !res ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK ;
2333
+ }
2334
+ /* }}} */
2335
+
2336
+ static void free_cb (void * arg ) /* {{{ */
2337
+ {
2338
+ struct mime_file * mime_file = (struct mime_file * ) arg ;
2339
+
2340
+ ZEND_ASSERT (!mime_file -> ch );
2341
+
2342
+ if (mime_file -> stream != NULL ) {
2173
2343
php_stream_close (mime_file -> stream );
2174
2344
mime_file -> stream = NULL ;
2175
2345
}
2176
- return !res ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK ;
2177
2346
}
2178
2347
/* }}} */
2179
2348
#endif
@@ -2840,15 +3009,22 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
2840
3009
2841
3010
#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2842
3011
mime_file = emalloc (sizeof * mime_file );
3012
+ mime_file -> ch = ch ;
3013
+ ZVAL_COPY (& mime_file -> postfields , zvalue );
3014
+ zend_llist_add_element (& ch -> to_free -> stream , & mime_file );
3015
+
3016
+ mime_file = emalloc (sizeof * mime_file );
3017
+ mime_file -> ch = NULL ;
2843
3018
mime_file -> name = zend_string_copy (postval );
2844
3019
mime_file -> stream = NULL ;
3020
+
2845
3021
part = curl_mime_addpart (mime );
2846
3022
if (part == NULL ) {
2847
3023
zend_string_release_ex (string_key , 0 );
2848
3024
return FAILURE ;
2849
3025
}
2850
3026
if ((form_error = curl_mime_name (part , ZSTR_VAL (string_key ))) != CURLE_OK
2851
- || (form_error = curl_mime_data_cb (part , -1 , read_cb , seek_cb , NULL , mime_file )) != CURLE_OK
3027
+ || (form_error = curl_mime_data_cb (part , -1 , read_cb , seek_cb , free_cb , mime_file )) != CURLE_OK
2852
3028
|| (form_error = curl_mime_filename (part , filename ? filename : ZSTR_VAL (postval ))) != CURLE_OK
2853
3029
|| (form_error = curl_mime_type (part , type ? type : "application/octet-stream" )) != CURLE_OK ) {
2854
3030
error = form_error ;
0 commit comments