Skip to content

CURL extension update proposal. #7823

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions ext/curl/curl_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ typedef struct {
php_curl_read *read;
zval std_err;
php_curl_callback *progress;
#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
php_curl_callback *fnmatch;
#if LIBCURL_VERSION_NUM >= 0x072000
php_curl_callback *xferinfo;
#endif
php_curl_callback *fnmatch;
} php_curl_handlers;

struct _php_curl_error {
Expand Down
104 changes: 101 additions & 3 deletions ext/curl/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,9 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLOPT_VERBOSE);
REGISTER_CURL_CONSTANT(CURLOPT_WRITEFUNCTION);
REGISTER_CURL_CONSTANT(CURLOPT_WRITEHEADER);
#if LIBCURL_VERSION_NUM >= 0x072000
REGISTER_CURL_CONSTANT(CURLOPT_XFERINFOFUNCTION);
#endif

/* */
REGISTER_CURL_CONSTANT(CURLE_ABORTED_BY_CALLBACK);
Expand Down Expand Up @@ -1287,11 +1290,15 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n)
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.progress->func_name);
}

#if LIBCURL_VERSION_NUM >= 0x071500
#if LIBCURL_VERSION_NUM >= 0x072000
if (curl->handlers.xferinfo) {
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.xferinfo->func_name);
}
#endif

if (curl->handlers.fnmatch) {
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.fnmatch->func_name);
}
#endif

zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.std_err);
zend_get_gc_buffer_add_zval(gc_buffer, &curl->private_data);
Expand Down Expand Up @@ -1496,6 +1503,56 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double
}
/* }}} */

#if LIBCURL_VERSION_NUM >= 0x072000
/* {{{ curl_xferinfo */
static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
php_curl *ch = (php_curl *)clientp;
php_curl_callback *t = ch->handlers.xferinfo;
size_t rval = 0;

#if PHP_CURL_DEBUG
fprintf(stderr, "curl_xferinfo() called\n");
fprintf(stderr, "clientp = %x, dltotal = %ld, dlnow = %ld, ultotal = %ld, ulnow = %ld\n", clientp, dltotal, dlnow, ultotal, ulnow);
#endif

zval argv[5];
zval retval;
zend_result error;
zend_fcall_info fci;

GC_ADDREF(&ch->std);
ZVAL_OBJ(&argv[0], &ch->std);
ZVAL_LONG(&argv[1], dltotal);
ZVAL_LONG(&argv[2], dlnow);
ZVAL_LONG(&argv[3], ultotal);
ZVAL_LONG(&argv[4], ulnow);

fci.size = sizeof(fci);
ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
fci.object = NULL;
fci.retval = &retval;
fci.param_count = 5;
fci.params = argv;
fci.named_params = NULL;

ch->in_callback = 1;
error = zend_call_function(&fci, &t->fci_cache);
ch->in_callback = 0;
if (error == FAILURE) {
php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_XFERINFOFUNCTION");
} else if (!Z_ISUNDEF(retval)) {
_php_curl_verify_handlers(ch, /* reporterror */ true);
if (0 != zval_get_long(&retval)) {
rval = 1;
}
}
zval_ptr_dtor(&argv[0]);
return rval;
}
/* }}} */
#endif

/* {{{ curl_read */
static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
{
Expand Down Expand Up @@ -1753,6 +1810,9 @@ void init_curl_handle(php_curl *ch)
ch->handlers.write_header = ecalloc(1, sizeof(php_curl_write));
ch->handlers.read = ecalloc(1, sizeof(php_curl_read));
ch->handlers.progress = NULL;
#if LIBCURL_VERSION_NUM >= 0x072000
ch->handlers.xferinfo = NULL;
#endif
ch->handlers.fnmatch = NULL;
ch->clone = emalloc(sizeof(uint32_t));
*ch->clone = 1;
Expand Down Expand Up @@ -1925,6 +1985,16 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
curl_easy_setopt(ch->cp, CURLOPT_PROGRESSDATA, (void *) ch);
}

#if LIBCURL_VERSION_NUM >= 0x072000
if (source->handlers.xferinfo) {
ch->handlers.xferinfo = ecalloc(1, sizeof(php_curl_callback));
if (!Z_ISUNDEF(source->handlers.xferinfo->func_name)) {
ZVAL_COPY(&ch->handlers.xferinfo->func_name, &source->handlers.xferinfo->func_name);
}
curl_easy_setopt(ch->cp, CURLOPT_XFERINFODATA, (void *) ch);
}
#endif

if (source->handlers.fnmatch) {
ch->handlers.fnmatch = ecalloc(1, sizeof(php_curl_callback));
if (!Z_ISUNDEF(source->handlers.fnmatch->func_name)) {
Expand Down Expand Up @@ -2884,6 +2954,20 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
ch->handlers.write->method = PHP_CURL_USER;
break;

#if LIBCURL_VERSION_NUM >= 0x072000
case CURLOPT_XFERINFOFUNCTION:
curl_easy_setopt(ch->cp, CURLOPT_XFERINFOFUNCTION, curl_xferinfo);
curl_easy_setopt(ch->cp, CURLOPT_XFERINFODATA, ch);
if (ch->handlers.xferinfo == NULL) {
ch->handlers.xferinfo = ecalloc(1, sizeof(php_curl_callback));
} else if (!Z_ISUNDEF(ch->handlers.xferinfo->func_name)) {
zval_ptr_dtor(&ch->handlers.xferinfo->func_name);
ch->handlers.xferinfo->fci_cache = empty_fcall_info_cache;
}
ZVAL_COPY(&ch->handlers.xferinfo->func_name, zvalue);
break;
#endif

/* Curl off_t options */
case CURLOPT_MAX_RECV_SPEED_LARGE:
case CURLOPT_MAX_SEND_SPEED_LARGE:
Expand Down Expand Up @@ -3521,6 +3605,13 @@ static void curl_free_obj(zend_object *object)
efree(ch->handlers.progress);
}

#if LIBCURL_VERSION_NUM >= 0x072000
if (ch->handlers.xferinfo) {
zval_ptr_dtor(&ch->handlers.xferinfo->func_name);
efree(ch->handlers.xferinfo);
}
#endif

if (ch->handlers.fnmatch) {
zval_ptr_dtor(&ch->handlers.fnmatch->func_name);
efree(ch->handlers.fnmatch);
Expand Down Expand Up @@ -3593,12 +3684,19 @@ static void _php_curl_reset_handlers(php_curl *ch)
ch->handlers.progress = NULL;
}

#if LIBCURL_VERSION_NUM >= 0x072000
if (ch->handlers.xferinfo) {
zval_ptr_dtor(&ch->handlers.xferinfo->func_name);
efree(ch->handlers.xferinfo);
ch->handlers.xferinfo = NULL;
}
#endif

if (ch->handlers.fnmatch) {
zval_ptr_dtor(&ch->handlers.fnmatch->func_name);
efree(ch->handlers.fnmatch);
ch->handlers.fnmatch = NULL;
}

}
/* }}} */

Expand Down
3 changes: 2 additions & 1 deletion ext/curl/sync-constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
const MIN_SUPPORTED_CURL_VERSION = '7.29.0';

const IGNORED_CONSTANTS = [
'CURLOPT_PROGRESSDATA'
'CURLOPT_PROGRESSDATA',
'CURLOPT_XFERINFODATA'
];

const CONSTANTS_REGEX_PATTERN = '~^CURL(?:OPT|_VERSION)_[A-Z0-9_]+$~';
Expand Down
27 changes: 27 additions & 0 deletions ext/curl/tests/curl_copy_handle_xferinfo.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
Test curl_copy_handle() with CURLOPT_XFERINFOFUNCTION
--EXTENSIONS--
curl
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();

$url = "{$host}/get.inc";
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_XFERINFOFUNCTION, function() { static $done = false; if (!$done) { echo "Download progress!\n"; $done = true; } });
$ch2 = curl_copy_handle($ch);
echo curl_exec($ch), PHP_EOL;
unset($ch);
echo curl_exec($ch2);

?>
--EXPECT--
Download progress!
Hello World!
Hello World!
Hello World!
Hello World!