Merge branch 'PHP-7.4'

* PHP-7.4:
  Extend CURLFile to support streams
This commit is contained in:
Christoph M. Becker 2019-04-29 10:21:44 +02:00
commit d09d3e28df
5 changed files with 146 additions and 1 deletions

View file

@ -1803,6 +1803,14 @@ static void curl_free_post(void **post)
} }
/* }}} */ /* }}} */
/* {{{ curl_free_stream
*/
static void curl_free_stream(void **post)
{
php_stream_close((php_stream *)*post);
}
/* }}} */
/* {{{ curl_free_slist /* {{{ curl_free_slist
*/ */
static void curl_free_slist(zval *el) static void curl_free_slist(zval *el)
@ -1894,6 +1902,7 @@ php_curl *alloc_curl_handle()
zend_llist_init(&ch->to_free->str, sizeof(char *), (llist_dtor_func_t)curl_free_string, 0); zend_llist_init(&ch->to_free->str, sizeof(char *), (llist_dtor_func_t)curl_free_string, 0);
zend_llist_init(&ch->to_free->post, sizeof(struct HttpPost *), (llist_dtor_func_t)curl_free_post, 0); zend_llist_init(&ch->to_free->post, sizeof(struct HttpPost *), (llist_dtor_func_t)curl_free_post, 0);
zend_llist_init(&ch->to_free->stream, sizeof(php_stream *), (llist_dtor_func_t)curl_free_stream, 0);
ch->to_free->slist = emalloc(sizeof(HashTable)); ch->to_free->slist = emalloc(sizeof(HashTable));
zend_hash_init(ch->to_free->slist, 4, NULL, curl_free_slist, 0); zend_hash_init(ch->to_free->slist, 4, NULL, curl_free_slist, 0);
@ -2121,6 +2130,32 @@ PHP_FUNCTION(curl_copy_handle)
} }
/* }}} */ /* }}} */
#if LIBCURL_VERSION_NUM >= 0x073800
static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */
{
php_stream *stream = (php_stream *) arg;
size_t numread = php_stream_read(stream, buffer, nitems * size);
if (numread == (size_t)-1) {
return CURL_READFUNC_ABORT;
}
return numread;
}
/* }}} */
static int seek_cb(void *arg, curl_off_t offset, int origin) /* {{{ */
{
php_stream *stream = (php_stream *) arg;
int res = php_stream_seek(stream, offset, origin);
if (res) {
return CURL_SEEKFUNC_CANTSEEK;
}
return CURL_SEEKFUNC_OK;
}
/* }}} */
#endif
static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ */ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ */
{ {
CURLcode error = CURLE_OK; CURLcode error = CURLE_OK;
@ -2756,6 +2791,9 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
/* new-style file upload */ /* new-style file upload */
zval *prop, rv; zval *prop, rv;
char *type = NULL, *filename = NULL; char *type = NULL, *filename = NULL;
#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
php_stream *stream;
#endif
prop = zend_read_property(curl_CURLFile_class, current, "name", sizeof("name")-1, 0, &rv); prop = zend_read_property(curl_CURLFile_class, current, "name", sizeof("name")-1, 0, &rv);
if (Z_TYPE_P(prop) != IS_STRING) { if (Z_TYPE_P(prop) != IS_STRING) {
@ -2777,17 +2815,24 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
} }
#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
if (!(stream = php_stream_open_wrapper(ZSTR_VAL(postval), "rb", IGNORE_PATH, NULL))) {
zend_string_release_ex(string_key, 0);
return FAILURE;
}
part = curl_mime_addpart(mime); part = curl_mime_addpart(mime);
if (part == NULL) { if (part == NULL) {
php_stream_close(stream);
zend_string_release_ex(string_key, 0); zend_string_release_ex(string_key, 0);
return FAILURE; return FAILURE;
} }
if ((form_error = curl_mime_name(part, ZSTR_VAL(string_key))) != CURLE_OK if ((form_error = curl_mime_name(part, ZSTR_VAL(string_key))) != CURLE_OK
|| (form_error = curl_mime_filedata(part, ZSTR_VAL(postval))) != CURLE_OK || (form_error = curl_mime_data_cb(part, -1, read_cb, seek_cb, NULL, stream)) != CURLE_OK
|| (form_error = curl_mime_filename(part, filename ? filename : ZSTR_VAL(postval))) != CURLE_OK || (form_error = curl_mime_filename(part, filename ? filename : ZSTR_VAL(postval))) != CURLE_OK
|| (form_error = curl_mime_type(part, type ? type : "application/octet-stream")) != CURLE_OK) { || (form_error = curl_mime_type(part, type ? type : "application/octet-stream")) != CURLE_OK) {
php_stream_close(stream);
error = form_error; error = form_error;
} }
zend_llist_add_element(&ch->to_free->stream, &stream);
#else #else
form_error = curl_formadd(&first, &last, form_error = curl_formadd(&first, &last,
CURLFORM_COPYNAME, ZSTR_VAL(string_key), CURLFORM_COPYNAME, ZSTR_VAL(string_key),
@ -3517,6 +3562,7 @@ static void _php_curl_close_ex(php_curl *ch)
if (--(*ch->clone) == 0) { if (--(*ch->clone) == 0) {
zend_llist_clean(&ch->to_free->str); zend_llist_clean(&ch->to_free->str);
zend_llist_clean(&ch->to_free->post); zend_llist_clean(&ch->to_free->post);
zend_llist_clean(&ch->to_free->stream);
zend_hash_destroy(ch->to_free->slist); zend_hash_destroy(ch->to_free->slist);
efree(ch->to_free->slist); efree(ch->to_free->slist);
efree(ch->to_free); efree(ch->to_free);

View file

@ -167,6 +167,7 @@ struct _php_curl_send_headers {
struct _php_curl_free { struct _php_curl_free {
zend_llist str; zend_llist str;
zend_llist post; zend_llist post;
zend_llist stream;
HashTable *slist; HashTable *slist;
}; };

View file

@ -0,0 +1,32 @@
--TEST--
FR #77711 (CURLFile should support UNICODE filenames)
--SKIPIF--
<?php include 'skipif.inc'; ?>
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();
$ch = curl_init();
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, 1);
curl_setopt($ch, CURLOPT_URL, "{$host}/get.php?test=file");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$filename = __DIR__ . '/АБВ.txt';
file_put_contents($filename, "Test.");
$file = curl_file_create($filename);
$params = array('file' => $file);
var_dump(curl_setopt($ch, CURLOPT_POSTFIELDS, $params));
var_dump(curl_exec($ch));
curl_close($ch);
?>
===DONE===
--EXPECTF--
bool(true)
string(%d) "АБВ.txt|application/octet-stream"
===DONE===
--CLEAN--
<?php
@unlink(__DIR__ . '/АБВ.txt');
?>

View file

@ -0,0 +1,38 @@
--TEST--
curl_copy_handle() allows to post CURLFile multiple times
--SKIPIF--
<?php include 'skipif.inc'; ?>
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();
$ch1 = curl_init();
curl_setopt($ch1, CURLOPT_SAFE_UPLOAD, 1);
curl_setopt($ch1, CURLOPT_URL, "{$host}/get.php?test=file");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1);
$filename = __DIR__ . '/АБВ.txt';
file_put_contents($filename, "Test.");
$file = curl_file_create($filename);
$params = array('file' => $file);
var_dump(curl_setopt($ch1, CURLOPT_POSTFIELDS, $params));
$ch2 = curl_copy_handle($ch1);
var_dump(curl_exec($ch1));
curl_close($ch1);
var_dump(curl_exec($ch2));
curl_close($ch2);
?>
===DONE===
--EXPECTF--
bool(true)
string(%d) "АБВ.txt|application/octet-stream"
string(%d) "АБВ.txt|application/octet-stream"
===DONE===
--CLEAN--
<?php
@unlink(__DIR__ . '/АБВ.txt');
?>

View file

@ -0,0 +1,28 @@
--TEST--
CURL file uploading from stream
--SKIPIF--
<?php include 'skipif.inc'; ?>
<?php
if (curl_version()['version_number'] < 0x73800) die('skip requires curl >= 7.56.0');
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();
$ch = curl_init();
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, 1);
curl_setopt($ch, CURLOPT_URL, "{$host}/get.inc?test=file");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$file = curl_file_create('data://text/plain;base64,SSBsb3ZlIFBIUAo=', 'text/plain', 'i-love-php');
$params = array('file' => $file);
var_dump(curl_setopt($ch, CURLOPT_POSTFIELDS, $params));
var_dump(curl_exec($ch));
curl_close($ch);
?>
===DONE===
--EXPECT--
bool(true)
string(21) "i-love-php|text/plain"
===DONE===