diff --git a/ext/curl/interface.c b/ext/curl/interface.c index d122051ade070..748de7f7e40d7 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -609,6 +609,9 @@ PHP_MINIT_FUNCTION(curl) REGISTER_CURL_CONSTANT(CURLOPT_FILETIME); REGISTER_CURL_CONSTANT(CURLOPT_WRITEFUNCTION); REGISTER_CURL_CONSTANT(CURLOPT_READFUNCTION); +#if LIBCURL_VERSION_NUM > 0x071200 + REGISTER_CURL_CONSTANT(CURLOPT_SEEKFUNCTION); +#endif #if CURLOPT_PASSWDFUNCTION != 0 REGISTER_CURL_CONSTANT(CURLOPT_PASSWDFUNCTION); #endif @@ -1212,6 +1215,89 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) } /* }}} */ +#if LIBCURL_VERSION_NUM > 0x071200 +/* {{{ curl_seek + */ +static int curl_seek(void *ctx, curl_off_t offset, int origin) +{ + php_curl *ch = (php_curl *) ctx; + php_curl_seek *t = ch->handlers->seek; + int status = CURL_SEEKFUNC_CANTSEEK; + + switch (t->method) { + case PHP_CURL_DIRECT: + if (t->fp) { + if (fseek(t->fp, offset, origin) == 0) + { + return CURL_SEEKFUNC_OK; + } + } + break; + case PHP_CURL_USER: { + zval **argv[4]; + zval *handle = NULL; + zval *zfd = NULL; + zval *zoffset = NULL; + zval *zorigin = NULL; + zval *retval_ptr; + int error; + zend_fcall_info fci; + TSRMLS_FETCH_FROM_CTX(ch->thread_ctx); + + MAKE_STD_ZVAL(handle); + MAKE_STD_ZVAL(zfd); + MAKE_STD_ZVAL(zoffset); + MAKE_STD_ZVAL(zorigin); + + ZVAL_RESOURCE(handle, ch->id); + zend_list_addref(ch->id); + ZVAL_RESOURCE(zfd, t->fd); + zend_list_addref(t->fd); + ZVAL_LONG(zoffset, (int) offset); + ZVAL_LONG(zorigin, (int) origin); + + argv[0] = &handle; + argv[1] = &zfd; + argv[2] = &zoffset; + argv[3] = &zorigin; + + fci.size = sizeof(fci); + fci.function_table = EG(function_table); + fci.function_name = t->func_name; + fci.object_ptr = NULL; + fci.retval_ptr_ptr = &retval_ptr; + fci.param_count = 4; + fci.params = argv; + fci.no_separation = 0; + fci.symbol_table = NULL; + + ch->in_callback = 1; + error = zend_call_function(&fci, &t->fci_cache TSRMLS_CC); + ch->in_callback = 0; + if (error == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot call the CURLOPT_SEEKFUNCTION"); + } else if (retval_ptr) { + if (Z_TYPE_P(retval_ptr) != IS_BOOL) { + convert_to_boolean_ex(&retval_ptr); + } + if (Z_LVAL_P(retval_ptr) == 1) + { + status = CURL_SEEKFUNC_OK; + } + zval_ptr_dtor(&retval_ptr); + } + zval_ptr_dtor(argv[0]); + zval_ptr_dtor(argv[1]); + zval_ptr_dtor(argv[2]); + zval_ptr_dtor(argv[3]); + } + break; + } + return status; +} +/* }}} */ +#endif + /* {{{ curl_write_header */ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx) @@ -1430,6 +1516,9 @@ static void alloc_curl_handle(php_curl **ch) (*ch)->handlers->write = ecalloc(1, sizeof(php_curl_write)); (*ch)->handlers->write_header = ecalloc(1, sizeof(php_curl_write)); (*ch)->handlers->read = ecalloc(1, sizeof(php_curl_read)); +#if LIBCURL_VERSION_NUM > 0x071200 + (*ch)->handlers->seek = ecalloc(1, sizeof(php_curl_seek)); +#endif (*ch)->handlers->progress = ecalloc(1, sizeof(php_curl_progress)); (*ch)->in_callback = 0; @@ -1568,6 +1657,10 @@ PHP_FUNCTION(curl_init) curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write); curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch); curl_easy_setopt(ch->cp, CURLOPT_READFUNCTION, curl_read); +#if LIBCURL_VERSION_NUM > 0x071200 + curl_easy_setopt(ch->cp, CURLOPT_SEEKFUNCTION, curl_seek); + curl_easy_setopt(ch->cp, CURLOPT_SEEKDATA, ch); +#endif curl_easy_setopt(ch->cp, CURLOPT_INFILE, (void *) ch); curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_header); curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch); @@ -2010,6 +2103,17 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu ch->handlers->read->func_name = *zvalue; ch->handlers->read->method = PHP_CURL_USER; break; +#if LIBCURL_VERSION_NUM > 0x071200 + case CURLOPT_SEEKFUNCTION: + if (ch->handlers->seek->func_name) { + zval_ptr_dtor(&ch->handlers->seek->func_name); + ch->handlers->seek->fci_cache = empty_fcall_info_cache; + } + zval_add_ref(zvalue); + ch->handlers->seek->func_name = *zvalue; + ch->handlers->seek->method = PHP_CURL_USER; + break; +#endif case CURLOPT_PROGRESSFUNCTION: curl_easy_setopt(ch->cp, CURLOPT_PROGRESSFUNCTION, curl_progress); curl_easy_setopt(ch->cp, CURLOPT_PROGRESSDATA, ch); diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h index 911d87a6b4c26..1fcad36fe2960 100644 --- a/ext/curl/php_curl.h +++ b/ext/curl/php_curl.h @@ -98,6 +98,17 @@ typedef struct { zval *stream; } php_curl_read; +#if LIBCURL_VERSION_NUM > 0x071200 +typedef struct { + zval *func_name; + zend_fcall_info_cache fci_cache; + FILE *fp; + long fd; + int method; + zval *stream; +} php_curl_seek; +#endif + typedef struct { zval *func_name; zend_fcall_info_cache fci_cache; @@ -108,6 +119,9 @@ typedef struct { php_curl_write *write; php_curl_write *write_header; php_curl_read *read; +#if LIBCURL_VERSION_NUM > 0x071200 + php_curl_seek *seek; +#endif zval *passwd; zval *std_err; php_curl_progress *progress;