diff --git a/ext/curl/curl.stub.php b/ext/curl/curl.stub.php index 5709a404afe97..bfee14174a498 100644 --- a/ext/curl/curl.stub.php +++ b/ext/curl/curl.stub.php @@ -3553,12 +3553,80 @@ */ const CURLOPT_SAFE_UPLOAD = UNKNOWN; +/** + * @strict-properties + */ +class CurlException extends \Exception {}; + +/** + * @strict-properties + */ +class CurlHandleException extends \CurlException {}; + +/** + * @strict-properties + */ +class CurlMultiException extends \CurlException {}; + +/** + * @strict-properties + */ +class CurlShareException extends \CurlException {}; + /** * @strict-properties * @not-serializable */ final class CurlHandle { + public function __construct(?string $uri = null) {} + + /** @alias curl_errno */ + public function errno(): int {} + + /** @alias curl_error */ + public function error(): string {} + + /** @alias curl_strerror */ + static public function strerror(int $code): string {} + + /** @alias curl_escape */ + public function escape(string $str): string {} + + /** @alias curl_unescape */ + public function unescape(string $str): string {} + + /** + * If CURLOPT_RETURNTRANSFER is True, returns the result on success, + * otherwise returns True, and the result will be output. + * @throws CurlHandleException on failure. + */ + public function exec(): string|true {} + + /** @alias curl_pause */ + public function pause(int $flags): int {} + + /** @alias curl_reset */ + public function reset(): void {} + + /** @alias curl_getinfo */ + public function getInfo(?int $option = null): mixed {} + +#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ + /** @alias curl_upkeep */ + public function upkeep(): bool {} +#endif + + /** + * Varies from curl_setopt() to allow fluent chaining. + * @throws CurlHandleException + */ + public function setOpt(int $option, mixed $value): \CurlHandle {} + /** + * Returns self to match setOpt() behavior. + * @throws CurlHandleException + */ + public function setOptArray(array $option): \CurlHandle {} } /** @@ -3567,6 +3635,53 @@ final class CurlHandle */ final class CurlMultiHandle { + /** + * Returns self for fluent calling. + * @throws CurlException. + */ + public function addHandle(\CurlHandle $handle): \CurlMultiHandle {} + + /** + * Returns self for fluent calling. + * @throws CurlException. + */ + public function removeHandle(\CurlHandle $handle): \CurlMultiHandle {} + + /** + * Returns self for fluent calling. + * @throws CurlException. + */ + public function setOpt(int $option, mixed $value): \CurlMultiHandle {} + + /** @alias curl_multi_errno */ + public function errno(): int {} + + /** @alias curl_multi_error */ + public function error(): ?string {} + + /** @alias curl_multi_strerror */ + public function strerror(int $error_code): ?string {} + + /** + * Returns TRUE if still running, FALSE otherwise. + * @param int $still_running + * @throws CurlException. + */ + public function exec(&$still_running): bool {} + + /** @alias curl_multi_getcontent */ + static public function getContent(\CurlHandle $handle): ?string {} + + /** + * @alias curl_multi_info_read + * @param int $queued_messages + * @return array|false + * @refcount 1 + */ + public function infoRead(&$queued_messages = null): array|false {} + + /** @alias curl_multi_select */ + public function select(float $timeout = 1.0): int {} } /** @@ -3575,6 +3690,17 @@ final class CurlMultiHandle */ final class CurlShareHandle { + + /** @alias curl_share_errno */ + public function errno(): int {} + + /** @alias curl_share_error */ + public function error(): ?string {} + + /** @alias curl_share_strerror */ + static public function strerror(): ?string {} + + public function setOpt(int $option, mixed $value): \CurlShareHandle {} } function curl_close(CurlHandle $handle): void {} @@ -3615,6 +3741,8 @@ function curl_multi_close(CurlMultiHandle $multi_handle): void {} function curl_multi_errno(CurlMultiHandle $multi_handle): int {} +function curl_multi_error(CurlMultiHandle $multi_handle): ?string {} + /** @param int $still_running */ function curl_multi_exec(CurlMultiHandle $multi_handle, &$still_running): int {} @@ -3657,6 +3785,8 @@ function curl_share_setopt(CurlShareHandle $share_handle, int $option, mixed $va /** @refcount 1 */ function curl_share_strerror(int $error_code): ?string {} +function curl_share_error(CurlShareHandle $share_handle): ?string {} + /** @refcount 1 */ function curl_strerror(int $error_code): ?string {} diff --git a/ext/curl/curl_arginfo.h b/ext/curl/curl_arginfo.h index 20c407323adb2..2e71cf8a9b4be 100644 --- a/ext/curl/curl_arginfo.h +++ b/ext/curl/curl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 92f4985790d0dad4216be837571e41c86711b6f8 */ + * Stub hash: e92e5f32d30d2c1df16025b97f2fb6d648bec932 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_close, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, handle, CurlHandle, 0) @@ -68,6 +68,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_multi_errno, 0, 1, IS_LONG, ZEND_ARG_OBJ_INFO(0, multi_handle, CurlMultiHandle, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_multi_error, 0, 1, IS_STRING, 1) + ZEND_ARG_OBJ_INFO(0, multi_handle, CurlMultiHandle, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_multi_exec, 0, 2, IS_LONG, 0) ZEND_ARG_OBJ_INFO(0, multi_handle, CurlMultiHandle, 0) ZEND_ARG_INFO(1, still_running) @@ -133,11 +137,106 @@ ZEND_END_ARG_INFO() #define arginfo_curl_share_strerror arginfo_curl_multi_strerror +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_share_error, 0, 1, IS_STRING, 1) + ZEND_ARG_OBJ_INFO(0, share_handle, CurlShareHandle, 0) +ZEND_END_ARG_INFO() + #define arginfo_curl_strerror arginfo_curl_multi_strerror ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_curl_version, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_CurlHandle___construct, 0, 0, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, uri, IS_STRING, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlHandle_errno, 0, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlHandle_error, 0, 0, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlHandle_strerror, 0, 1, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, code, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlHandle_escape, 0, 1, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_CurlHandle_unescape arginfo_class_CurlHandle_escape + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_CurlHandle_exec, 0, 0, MAY_BE_STRING|MAY_BE_TRUE) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlHandle_pause, 0, 1, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlHandle_reset, 0, 0, IS_VOID, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlHandle_getInfo, 0, 0, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, option, IS_LONG, 1, "null") +ZEND_END_ARG_INFO() + +#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlHandle_upkeep, 0, 0, _IS_BOOL, 0) +ZEND_END_ARG_INFO() +#endif + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_CurlHandle_setOpt, 0, 2, CurlHandle, 0) + ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_CurlHandle_setOptArray, 0, 1, CurlHandle, 0) + ZEND_ARG_TYPE_INFO(0, option, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_CurlMultiHandle_addHandle, 0, 1, CurlMultiHandle, 0) + ZEND_ARG_OBJ_INFO(0, handle, CurlHandle, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_CurlMultiHandle_removeHandle arginfo_class_CurlMultiHandle_addHandle + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_CurlMultiHandle_setOpt, 0, 2, CurlMultiHandle, 0) + ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_CurlMultiHandle_errno arginfo_class_CurlHandle_errno + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlMultiHandle_error, 0, 0, IS_STRING, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_CurlMultiHandle_strerror arginfo_curl_multi_strerror + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlMultiHandle_exec, 0, 1, _IS_BOOL, 0) + ZEND_ARG_INFO(1, still_running) +ZEND_END_ARG_INFO() + +#define arginfo_class_CurlMultiHandle_getContent arginfo_curl_multi_getcontent + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_CurlMultiHandle_infoRead, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE) + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, queued_messages, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_CurlMultiHandle_select, 0, 0, IS_LONG, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timeout, IS_DOUBLE, 0, "1.0") +ZEND_END_ARG_INFO() + +#define arginfo_class_CurlShareHandle_errno arginfo_class_CurlHandle_errno + +#define arginfo_class_CurlShareHandle_error arginfo_class_CurlMultiHandle_error + +#define arginfo_class_CurlShareHandle_strerror arginfo_class_CurlMultiHandle_error + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_CurlShareHandle_setOpt, 0, 2, CurlShareHandle, 0) + ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) +ZEND_END_ARG_INFO() + ZEND_FUNCTION(curl_close); ZEND_FUNCTION(curl_copy_handle); @@ -156,6 +255,7 @@ ZEND_FUNCTION(curl_upkeep); ZEND_FUNCTION(curl_multi_add_handle); ZEND_FUNCTION(curl_multi_close); ZEND_FUNCTION(curl_multi_errno); +ZEND_FUNCTION(curl_multi_error); ZEND_FUNCTION(curl_multi_exec); ZEND_FUNCTION(curl_multi_getcontent); ZEND_FUNCTION(curl_multi_info_read); @@ -172,8 +272,18 @@ ZEND_FUNCTION(curl_share_errno); ZEND_FUNCTION(curl_share_init); ZEND_FUNCTION(curl_share_setopt); ZEND_FUNCTION(curl_share_strerror); +ZEND_FUNCTION(curl_share_error); ZEND_FUNCTION(curl_strerror); ZEND_FUNCTION(curl_version); +ZEND_METHOD(CurlHandle, __construct); +ZEND_METHOD(CurlHandle, exec); +ZEND_METHOD(CurlHandle, setOpt); +ZEND_METHOD(CurlHandle, setOptArray); +ZEND_METHOD(CurlMultiHandle, addHandle); +ZEND_METHOD(CurlMultiHandle, removeHandle); +ZEND_METHOD(CurlMultiHandle, setOpt); +ZEND_METHOD(CurlMultiHandle, exec); +ZEND_METHOD(CurlShareHandle, setOpt); static const zend_function_entry ext_functions[] = { @@ -194,6 +304,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(curl_multi_add_handle, arginfo_curl_multi_add_handle) ZEND_FE(curl_multi_close, arginfo_curl_multi_close) ZEND_FE(curl_multi_errno, arginfo_curl_multi_errno) + ZEND_FE(curl_multi_error, arginfo_curl_multi_error) ZEND_FE(curl_multi_exec, arginfo_curl_multi_exec) ZEND_FE(curl_multi_getcontent, arginfo_curl_multi_getcontent) ZEND_FE(curl_multi_info_read, arginfo_curl_multi_info_read) @@ -210,23 +321,73 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(curl_share_init, arginfo_curl_share_init) ZEND_FE(curl_share_setopt, arginfo_curl_share_setopt) ZEND_FE(curl_share_strerror, arginfo_curl_share_strerror) + ZEND_FE(curl_share_error, arginfo_curl_share_error) ZEND_FE(curl_strerror, arginfo_curl_strerror) ZEND_FE(curl_version, arginfo_curl_version) ZEND_FE_END }; +static const zend_function_entry class_CurlException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_CurlHandleException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_CurlMultiException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_CurlShareException_methods[] = { + ZEND_FE_END +}; + + static const zend_function_entry class_CurlHandle_methods[] = { + ZEND_ME(CurlHandle, __construct, arginfo_class_CurlHandle___construct, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(errno, curl_errno, arginfo_class_CurlHandle_errno, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(error, curl_error, arginfo_class_CurlHandle_error, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(strerror, curl_strerror, arginfo_class_CurlHandle_strerror, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME_MAPPING(escape, curl_escape, arginfo_class_CurlHandle_escape, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(unescape, curl_unescape, arginfo_class_CurlHandle_unescape, ZEND_ACC_PUBLIC) + ZEND_ME(CurlHandle, exec, arginfo_class_CurlHandle_exec, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(pause, curl_pause, arginfo_class_CurlHandle_pause, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(reset, curl_reset, arginfo_class_CurlHandle_reset, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(getInfo, curl_getinfo, arginfo_class_CurlHandle_getInfo, ZEND_ACC_PUBLIC) +#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ + ZEND_ME_MAPPING(upkeep, curl_upkeep, arginfo_class_CurlHandle_upkeep, ZEND_ACC_PUBLIC) +#endif + ZEND_ME(CurlHandle, setOpt, arginfo_class_CurlHandle_setOpt, ZEND_ACC_PUBLIC) + ZEND_ME(CurlHandle, setOptArray, arginfo_class_CurlHandle_setOptArray, ZEND_ACC_PUBLIC) ZEND_FE_END }; static const zend_function_entry class_CurlMultiHandle_methods[] = { + ZEND_ME(CurlMultiHandle, addHandle, arginfo_class_CurlMultiHandle_addHandle, ZEND_ACC_PUBLIC) + ZEND_ME(CurlMultiHandle, removeHandle, arginfo_class_CurlMultiHandle_removeHandle, ZEND_ACC_PUBLIC) + ZEND_ME(CurlMultiHandle, setOpt, arginfo_class_CurlMultiHandle_setOpt, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(errno, curl_multi_errno, arginfo_class_CurlMultiHandle_errno, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(error, curl_multi_error, arginfo_class_CurlMultiHandle_error, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(strerror, curl_multi_strerror, arginfo_class_CurlMultiHandle_strerror, ZEND_ACC_PUBLIC) + ZEND_ME(CurlMultiHandle, exec, arginfo_class_CurlMultiHandle_exec, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(getContent, curl_multi_getcontent, arginfo_class_CurlMultiHandle_getContent, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME_MAPPING(infoRead, curl_multi_info_read, arginfo_class_CurlMultiHandle_infoRead, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(select, curl_multi_select, arginfo_class_CurlMultiHandle_select, ZEND_ACC_PUBLIC) ZEND_FE_END }; static const zend_function_entry class_CurlShareHandle_methods[] = { + ZEND_ME_MAPPING(errno, curl_share_errno, arginfo_class_CurlShareHandle_errno, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(error, curl_share_error, arginfo_class_CurlShareHandle_error, ZEND_ACC_PUBLIC) + ZEND_ME_MAPPING(strerror, curl_share_strerror, arginfo_class_CurlShareHandle_strerror, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(CurlShareHandle, setOpt, arginfo_class_CurlShareHandle_setOpt, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1090,6 +1251,50 @@ static void register_curl_symbols(int module_number) REGISTER_LONG_CONSTANT("CURLOPT_SAFE_UPLOAD", CURLOPT_SAFE_UPLOAD, CONST_PERSISTENT); } +static zend_class_entry *register_class_CurlException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "CurlException", class_CurlException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_CurlHandleException(zend_class_entry *class_entry_CurlException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "CurlHandleException", class_CurlHandleException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_CurlException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_CurlMultiException(zend_class_entry *class_entry_CurlException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "CurlMultiException", class_CurlMultiException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_CurlException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_CurlShareException(zend_class_entry *class_entry_CurlException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "CurlShareException", class_CurlShareException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_CurlException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + static zend_class_entry *register_class_CurlHandle(void) { zend_class_entry ce, *class_entry; diff --git a/ext/curl/curl_private.h b/ext/curl/curl_private.h index aeef5937a0de8..595265bc40d43 100644 --- a/ext/curl/curl_private.h +++ b/ext/curl/curl_private.h @@ -146,7 +146,8 @@ static inline php_curl *curl_from_obj(zend_object *obj) { return (php_curl *)((char *)(obj) - XtOffsetOf(php_curl, std)); } -#define Z_CURL_P(zv) curl_from_obj(Z_OBJ_P(zv)) +#define Z_CURL(zv) curl_from_obj(Z_OBJ(zv)) +#define Z_CURL_P(pzv) curl_from_obj(Z_OBJ_P(pzv)) static inline php_curlsh *curl_share_from_obj(zend_object *obj) { return (php_curlsh *)((char *)(obj) - XtOffsetOf(php_curlsh, std)); diff --git a/ext/curl/interface.c b/ext/curl/interface.c index a4c8b941adc3b..22b6c5e20e861 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -228,15 +228,16 @@ ZEND_GET_MODULE (curl) /* CurlHandle class */ zend_class_entry *curl_ce; +zend_class_entry *curl_exception_ce; +zend_class_entry *curl_handle_exception_ce; zend_class_entry *curl_share_ce; +zend_class_entry *curl_share_exception_ce; static zend_object_handlers curl_object_handlers; static zend_object *curl_create_object(zend_class_entry *class_type); static void curl_free_obj(zend_object *object); static HashTable *curl_get_gc(zend_object *object, zval **table, int *n); -static zend_function *curl_get_constructor(zend_object *object); static zend_object *curl_clone_obj(zend_object *object); -php_curl *init_curl_handle_into_zval(zval *curl); static inline zend_result build_mime_structure_from_hash(php_curl *ch, zval *zpostfields); /* {{{ PHP_INI_BEGIN */ @@ -401,7 +402,6 @@ PHP_MINIT_FUNCTION(curl) curl_object_handlers.offset = XtOffsetOf(php_curl, std); curl_object_handlers.free_obj = curl_free_obj; curl_object_handlers.get_gc = curl_get_gc; - curl_object_handlers.get_constructor = curl_get_constructor; curl_object_handlers.clone_obj = curl_clone_obj; curl_object_handlers.cast_object = curl_cast_object; curl_object_handlers.compare = zend_objects_not_comparable; @@ -413,6 +413,11 @@ PHP_MINIT_FUNCTION(curl) curl_share_register_handlers(); curlfile_register_class(); + curl_exception_ce = register_class_CurlException(zend_ce_exception); + curl_handle_exception_ce = register_class_CurlHandleException(curl_exception_ce); + curl_multi_exception_ce = register_class_CurlMultiException(curl_exception_ce); + curl_share_exception_ce = register_class_CurlShareException(curl_exception_ce); + return SUCCESS; } /* }}} */ @@ -425,12 +430,9 @@ static zend_object *curl_create_object(zend_class_entry *class_type) { zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); - return &intern->std; -} + init_curl_handle(intern); -static zend_function *curl_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct CurlHandle, use curl_init() instead"); - return NULL; + return &intern->std; } static zend_object *curl_clone_obj(zend_object *object) { @@ -442,7 +444,6 @@ static zend_object *curl_clone_obj(zend_object *object) { clone_object = curl_create_object(curl_ce); clone_ch = curl_from_obj(clone_object); - init_curl_handle(clone_ch); ch = curl_from_obj(object); cp = curl_easy_duphandle(ch->cp); @@ -983,6 +984,17 @@ static void curl_free_slist(zval *el) } /* }}} */ +/* {{{ curl_throw_last_error */ +void curl_throw_last_error(php_curl *ch, const char *unknown_error_msg) { + if (ch->err.no) { + ch->err.str[CURL_ERROR_SIZE] = 0; + zend_throw_exception(curl_handle_exception_ce, ch->err.str, ch->err.no); + } else { + zend_throw_exception(curl_handle_exception_ce, unknown_error_msg, 0); + } +} +/* }}} */ + /* {{{ Return cURL version information. */ PHP_FUNCTION(curl_version) { @@ -1036,18 +1048,6 @@ PHP_FUNCTION(curl_version) } /* }}} */ -php_curl *init_curl_handle_into_zval(zval *curl) -{ - php_curl *ch; - - object_init_ex(curl, curl_ce); - ch = Z_CURL_P(curl); - - init_curl_handle(ch); - - return ch; -} - void init_curl_handle(php_curl *ch) { ch->to_free = ecalloc(1, sizeof(struct _php_curl_free)); @@ -1144,40 +1144,61 @@ static void _php_curl_set_default_options(php_curl *ch) /* }}} */ /* {{{ Initialize a cURL session */ -PHP_FUNCTION(curl_init) +void php_curl_init(INTERNAL_FUNCTION_PARAMETERS, zval *dest, const char** err) { - php_curl *ch; - CURL *cp; + php_curl *ch = Z_CURL_P(dest); zend_string *url = NULL; + err = NULL; ZEND_PARSE_PARAMETERS_START(0,1) Z_PARAM_OPTIONAL Z_PARAM_STR_OR_NULL(url) ZEND_PARSE_PARAMETERS_END(); - cp = curl_easy_init(); - if (!cp) { - php_error_docref(NULL, E_WARNING, "Could not initialize a new cURL handle"); - RETURN_FALSE; + ch->cp = curl_easy_init(); + if (!ch->cp) { + *err = "Could not initialize a new cURL handle"; + return; } - ch = init_curl_handle_into_zval(return_value); - - ch->cp = cp; - ch->handlers.write->method = PHP_CURL_STDOUT; ch->handlers.read->method = PHP_CURL_DIRECT; ch->handlers.write_header->method = PHP_CURL_IGNORE; _php_curl_set_default_options(ch); - if (url) { - if (php_curl_option_url(ch, url) == FAILURE) { - zval_ptr_dtor(return_value); - RETURN_FALSE; - } + if (url && (php_curl_option_url(ch, url) == FAILURE)) { + *err = "Could not initialize destination URL for cURL handle"; + return; + } +} + +PHP_FUNCTION(curl_init) +{ + const char *err = NULL; + + object_init_ex(return_value, curl_ce); + php_curl_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &err); + if (err) { + php_error_docref(NULL, E_WARNING, "%s", err); + zval_ptr_dtor(return_value); + RETURN_FALSE; } } + +PHP_METHOD(CurlHandle, __construct) +{ + const char *err = NULL; + php_curl_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, getThis(), &err); + if (err) { + zend_throw_exception(curl_handle_exception_ce, err, 0); + RETURN_THROWS(); + } + + // Unlike the instance produced by curl_init(), + // (new CurlHandle) returns the transfer by default. + Z_CURL_P(getThis())->handlers.write->method = PHP_CURL_RETURN; +} /* }}} */ static void _php_copy_callback(php_curl *ch, php_curl_callback **new_callback, php_curl_callback *source_callback, CURLoption option) @@ -1519,7 +1540,8 @@ PHP_FUNCTION(curl_copy_handle) RETURN_FALSE; } - dupch = init_curl_handle_into_zval(return_value); + object_init_ex(return_value, curl_ce); + dupch = Z_CURL_P(return_value); dupch->cp = cp; _php_setup_easy_copy_handlers(dupch, ch); @@ -2291,6 +2313,27 @@ PHP_FUNCTION(curl_setopt) RETURN_FALSE; } } + +PHP_METHOD(CurlHandle, setOpt) +{ + zval *zvalue; + zend_long options; + php_curl *ch = Z_CURL_P(getThis()); + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_LONG(options) + Z_PARAM_ZVAL(zvalue) + ZEND_PARSE_PARAMETERS_END(); + + if (_php_curl_setopt(ch, options, zvalue, 0) == SUCCESS) { + RETURN_ZVAL(getThis(), 1, 0); + } else { + if (!EG(exception)) { + curl_throw_last_error(ch, "Unknown cURL setopt error"); + } + RETURN_THROWS(); + } +} /* }}} */ /* {{{ Set an array of option for a cURL transfer */ @@ -2322,6 +2365,35 @@ PHP_FUNCTION(curl_setopt_array) RETURN_TRUE; } + +PHP_METHOD(CurlHandle, setOptArray) +{ + zval *arr, *entry; + php_curl *ch = Z_CURL_P(getThis()); + zend_ulong option; + zend_string *string_key; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(arr) + ZEND_PARSE_PARAMETERS_END(); + + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(arr), option, string_key, entry) { + if (string_key) { + zend_argument_value_error(2, "contains an invalid cURL option"); + RETURN_THROWS(); + } + + ZVAL_DEREF(entry); + if (_php_curl_setopt(ch, (zend_long) option, entry, 1) == FAILURE) { + if (!EG(exception)) { + curl_throw_last_error(ch, "Unknown cURL setopt error"); + } + RETURN_THROWS(); + } + } ZEND_HASH_FOREACH_END(); + + RETURN_ZVAL(getThis(), 1, 0); +} /* }}} */ /* {{{ _php_curl_cleanup_handle(ch) @@ -2340,20 +2412,11 @@ void _php_curl_cleanup_handle(php_curl *ch) /* }}} */ /* {{{ Perform a cURL session */ -PHP_FUNCTION(curl_exec) +static zend_result php_curl_exec(zval *return_value, php_curl *ch) { CURLcode error; - zval *zid; - php_curl *ch; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - ZEND_PARSE_PARAMETERS_END(); - - ch = Z_CURL_P(zid); _php_curl_verify_handlers(ch, /* reporterror */ true); - _php_curl_cleanup_handle(ch); error = curl_easy_perform(ch->cp); @@ -2361,7 +2424,7 @@ PHP_FUNCTION(curl_exec) if (error != CURLE_OK) { smart_str_free(&ch->handlers.write->buf); - RETURN_FALSE; + return FAILURE; } if (!Z_ISUNDEF(ch->handlers.std_err)) { @@ -2374,7 +2437,8 @@ PHP_FUNCTION(curl_exec) if (ch->handlers.write->method == PHP_CURL_RETURN && ch->handlers.write->buf.s) { smart_str_0(&ch->handlers.write->buf); - RETURN_STR_COPY(ch->handlers.write->buf.s); + RETVAL_STR_COPY(ch->handlers.write->buf.s); + return SUCCESS; } /* flush the file handle, so any remaining data is synched to disk */ @@ -2386,9 +2450,36 @@ PHP_FUNCTION(curl_exec) } if (ch->handlers.write->method == PHP_CURL_RETURN) { - RETURN_EMPTY_STRING(); + RETVAL_EMPTY_STRING(); } else { - RETURN_TRUE; + RETVAL_TRUE; + } + + return SUCCESS; +} + +PHP_FUNCTION(curl_exec) +{ + zval *zid; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) + ZEND_PARSE_PARAMETERS_END(); + + if (php_curl_exec(return_value, Z_CURL_P(zid)) == FAILURE) { + RETURN_FALSE; + } +} + +PHP_METHOD(CurlHandle, exec) +{ + php_curl *ch = Z_CURL_P(getThis()); + + ZEND_PARSE_PARAMETERS_NONE(); + + if (php_curl_exec(return_value, ch) == FAILURE) { + curl_throw_last_error(ch, "Failed executing cURL request"); + RETURN_THROWS(); } } /* }}} */ @@ -2401,11 +2492,9 @@ PHP_FUNCTION(curl_getinfo) zend_long option; bool option_is_null = 1; - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - Z_PARAM_OPTIONAL - Z_PARAM_LONG_OR_NULL(option, option_is_null) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l!", &zid, curl_ce, &option, &option_is_null) == FAILURE) { + RETURN_THROWS(); + } ch = Z_CURL_P(zid); @@ -2662,9 +2751,9 @@ PHP_FUNCTION(curl_error) zval *zid; php_curl *ch; - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zid, curl_ce) == FAILURE) { + RETURN_THROWS(); + } ch = Z_CURL_P(zid); @@ -2683,9 +2772,9 @@ PHP_FUNCTION(curl_errno) zval *zid; php_curl *ch; - ZEND_PARSE_PARAMETERS_START(1,1) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zid, curl_ce) == FAILURE) { + RETURN_THROWS(); + } ch = Z_CURL_P(zid); @@ -2728,12 +2817,6 @@ static void curl_free_obj(zend_object *object) fprintf(stderr, "DTOR CALLED, ch = %x\n", ch); #endif - if (!ch->cp) { - /* Can happen if constructor throws. */ - zend_object_std_dtor(&ch->std); - return; - } - _php_curl_verify_handlers(ch, /* reporterror */ false); /* @@ -2747,10 +2830,12 @@ static void curl_free_obj(zend_object *object) * * 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); + if (ch->cp) { + curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing); + curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing); - curl_easy_cleanup(ch->cp); + curl_easy_cleanup(ch->cp); + } /* cURL destructors should be invoked only by last curl handle */ if (--(*ch->clone) == 0) { @@ -2882,9 +2967,9 @@ PHP_FUNCTION(curl_reset) zval *zid; php_curl *ch; - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zid, curl_ce) == FAILURE) { + RETURN_THROWS(); + } ch = Z_CURL_P(zid); @@ -2907,10 +2992,9 @@ PHP_FUNCTION(curl_escape) zval *zid; php_curl *ch; - ZEND_PARSE_PARAMETERS_START(2,2) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - Z_PARAM_STR(str) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OS", &zid, curl_ce, &str) == FAILURE) { + RETURN_THROWS(); + } ch = Z_CURL_P(zid); @@ -2936,10 +3020,9 @@ PHP_FUNCTION(curl_unescape) zend_string *str; php_curl *ch; - ZEND_PARSE_PARAMETERS_START(2,2) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - Z_PARAM_STR(str) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OS", &zid, curl_ce, &str) == FAILURE) { + RETURN_THROWS(); + } ch = Z_CURL_P(zid); @@ -2963,10 +3046,9 @@ PHP_FUNCTION(curl_pause) zval *zid; php_curl *ch; - ZEND_PARSE_PARAMETERS_START(2,2) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - Z_PARAM_LONG(bitmask) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &zid, curl_ce, &bitmask) == FAILURE) { + RETURN_THROWS(); + } ch = Z_CURL_P(zid); @@ -2982,9 +3064,9 @@ PHP_FUNCTION(curl_upkeep) zval *zid; php_curl *ch; - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(zid, curl_ce) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zid, curl_ce) == FAILURE) { + RETURN_THROWS(); + } ch = Z_CURL_P(zid); diff --git a/ext/curl/multi.c b/ext/curl/multi.c index a61066b5a6c7c..25b8cad5f3139 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -21,6 +21,7 @@ #endif #include "php.h" +#include "Zend/zend_exceptions.h" #include "Zend/zend_smart_str.h" #include "curl_private.h" @@ -49,6 +50,7 @@ /* CurlMultiHandle class */ zend_class_entry *curl_multi_ce; +zend_class_entry *curl_multi_exception_ce; static inline php_curlm *curl_multi_from_obj(zend_object *obj) { return (php_curlm *)((char *)(obj) - XtOffsetOf(php_curlm, std)); @@ -56,23 +58,25 @@ static inline php_curlm *curl_multi_from_obj(zend_object *obj) { #define Z_CURL_MULTI_P(zv) curl_multi_from_obj(Z_OBJ_P(zv)) +/* {{{ curlm_throw_last_error */ +void curlm_throw_last_error(php_curlm *mh, const char *unknown_error_msg) { + if (mh->err.no) { + const char* str = curl_multi_strerror(mh->err.no); + if (str) { + zend_throw_exception(curl_multi_exception_ce, str, mh->err.no); + return; + } + } + + zend_throw_exception(curl_multi_exception_ce, unknown_error_msg, mh->err.no); +} +/* }}} */ + /* {{{ Returns a new cURL multi handle */ PHP_FUNCTION(curl_multi_init) { - php_curlm *mh; - CURLM *multi; - ZEND_PARSE_PARAMETERS_NONE(); - multi = curl_multi_init(); - if (UNEXPECTED(multi == NULL)) { - zend_throw_error(NULL, "%s(): Could not initialize a new cURL multi handle", get_active_function_name()); - RETURN_THROWS(); - } object_init_ex(return_value, curl_multi_ce); - mh = Z_CURL_MULTI_P(return_value); - mh->multi = multi; - - zend_llist_init(&mh->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0); } /* }}} */ @@ -105,6 +109,36 @@ PHP_FUNCTION(curl_multi_add_handle) RETURN_LONG((zend_long) error); } + +PHP_METHOD(CurlMultiHandle, addHandle) +{ + php_curlm *mh = Z_CURL_MULTI_P(getThis()); + zval *z_ch; + php_curl *ch; + CURLMcode error; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS(z_ch, curl_ce) + ZEND_PARSE_PARAMETERS_END(); + + ch = Z_CURL_P(z_ch); + + _php_curl_verify_handlers(ch, /* reporterror */ true); + + _php_curl_cleanup_handle(ch); + + Z_ADDREF_P(z_ch); + zend_llist_add_element(&mh->easyh, z_ch); + + error = curl_multi_add_handle(mh->multi, ch->cp); + SAVE_CURLM_ERROR(mh, error); + if (error != CURLM_OK) { + curlm_throw_last_error(mh, "Failed adding CurlHandle to CurlMultiHandle"); + RETURN_THROWS(); + } + + RETURN_ZVAL(getThis(), 1, 0); +} /* }}} */ void _php_curl_multi_cleanup_list(void *data) /* {{{ */ @@ -168,6 +202,30 @@ PHP_FUNCTION(curl_multi_remove_handle) zend_llist_del_element(&mh->easyh, z_ch, (int (*)(void *, void *))curl_compare_objects); } + +PHP_METHOD(CurlMultiHandle, removeHandle) +{ + php_curlm *mh = Z_CURL_MULTI_P(getThis()); + zval *z_ch; + php_curl *ch; + CURLMcode error; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS(z_ch, curl_ce) + ZEND_PARSE_PARAMETERS_END(); + + ch = Z_CURL_P(z_ch); + error = curl_multi_remove_handle(mh->multi, ch->cp); + SAVE_CURLM_ERROR(mh, error); + + if (error != CURLM_OK) { + zend_throw_exception(curl_multi_exception_ce, "Failed removing CurlHandle from CurlMultiHandle", error); + RETURN_THROWS(); + } + + zend_llist_del_element(&mh->easyh, z_ch, (int (*)(void *, void *))curl_compare_objects); + RETURN_ZVAL(getThis(), 1, 0); +} /* }}} */ /* {{{ Get all the sockets associated with the cURL extension, which can then be "selected" */ @@ -198,13 +256,40 @@ PHP_FUNCTION(curl_multi_select) /* }}} */ /* {{{ Run the sub-connections of the current cURL handle */ +static zend_result php_curl_multi_exec(php_curlm *mh, zval *z_still_running) +{ + { + zend_llist_position pos; + php_curl *ch; + zval *pz_ch; + + for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch; + pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) { + ch = Z_CURL_P(pz_ch); + + _php_curl_verify_handlers(ch, /* reporterror */ true); + } + } + + { + int still_running = zval_get_long(z_still_running); + CURLMcode error = curl_multi_perform(mh->multi, &still_running); + ZEND_TRY_ASSIGN_REF_LONG(z_still_running, still_running); + SAVE_CURLM_ERROR(mh, error); + + if (error != CURLM_OK) { + return FAILURE; + } + } + + return SUCCESS; +} + PHP_FUNCTION(curl_multi_exec) { zval *z_mh; zval *z_still_running; php_curlm *mh; - int still_running; - CURLMcode error = CURLM_OK; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce) @@ -212,26 +297,29 @@ PHP_FUNCTION(curl_multi_exec) ZEND_PARSE_PARAMETERS_END(); mh = Z_CURL_MULTI_P(z_mh); + php_curl_multi_exec(mh, z_still_running); + RETURN_LONG((zend_long)mh->err.no); +} - { - zend_llist_position pos; - php_curl *ch; - zval *pz_ch; +PHP_METHOD(CurlMultiHandle, exec) +{ + php_curlm *mh = Z_CURL_MULTI_P(getThis()); + zval *z_still_running; - for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch; - pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) { - ch = Z_CURL_P(pz_ch); + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(z_still_running) + ZEND_PARSE_PARAMETERS_END(); - _php_curl_verify_handlers(ch, /* reporterror */ true); - } + if (FAILURE == php_curl_multi_exec(mh, z_still_running)) { + curlm_throw_last_error(mh, "CurlMultiHandle::exec() failure"); + RETURN_THROWS(); } - still_running = zval_get_long(z_still_running); - error = curl_multi_perform(mh->multi, &still_running); - ZEND_TRY_ASSIGN_REF_LONG(z_still_running, still_running); - - SAVE_CURLM_ERROR(mh, error); - RETURN_LONG((zend_long) error); + if (Z_ISREF_P(z_still_running)) { + RETURN_BOOL(Z_LVAL_P(Z_REFVAL_P(z_still_running)) > 0); + } else { + RETURN_BOOL(Z_LVAL_P(z_still_running) > 0); + } } /* }}} */ @@ -336,9 +424,9 @@ PHP_FUNCTION(curl_multi_errno) zval *z_mh; php_curlm *mh; - ZEND_PARSE_PARAMETERS_START(1,1) - Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce) - ZEND_PARSE_PARAMETERS_END(); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &z_mh, curl_multi_ce) == FAILURE) { + RETURN_THROWS(); + } mh = Z_CURL_MULTI_P(z_mh); @@ -346,6 +434,30 @@ PHP_FUNCTION(curl_multi_errno) } /* }}} */ +/* {{{ Return a string containing the last multi curl error message */ +PHP_FUNCTION(curl_multi_error) +{ + zval *z_mh; + php_curlm *mh; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &z_mh, curl_multi_ce) == FAILURE) { + RETURN_THROWS(); + } + + mh = Z_CURL_MULTI_P(z_mh); + if (mh->err.no) { + const char *str = curl_multi_strerror(mh->err.no); + if (str) { + RETURN_STRING(str); + } + } + + RETURN_NULL(); + + RETURN_NULL(); +} +/* }}} */ + /* {{{ return string describing error code */ PHP_FUNCTION(curl_multi_strerror) { @@ -393,7 +505,8 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea parent = Z_CURL_P(pz_parent_ch); - ch = init_curl_handle_into_zval(&pz_ch); + object_init_ex(&pz_ch, curl_ce); + ch = Z_CURL(pz_ch); ch->cp = easy; _php_setup_easy_copy_handlers(ch, parent); @@ -506,6 +619,27 @@ PHP_FUNCTION(curl_multi_setopt) RETURN_FALSE; } } + +PHP_METHOD(CurlMultiHandle, setOpt) +{ + php_curlm *mh = Z_CURL_MULTI_P(getThis()); + zend_long options; + zval *zvalue; + + ZEND_PARSE_PARAMETERS_START(2,2) + Z_PARAM_LONG(options) + Z_PARAM_ZVAL(zvalue) + ZEND_PARSE_PARAMETERS_END(); + + if (!_php_curl_multi_setopt(mh, options, zvalue, NULL)) { + if (!EG(exception)) { + curlm_throw_last_error(mh, "Failed setting option"); + } + RETURN_THROWS(); + } + + RETURN_ZVAL(getThis(), 1, 0); +} /* }}} */ /* CurlMultiHandle class */ @@ -516,12 +650,14 @@ static zend_object *curl_multi_create_object(zend_class_entry *class_type) { zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); - return &intern->std; -} + zend_llist_init(&intern->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0); -static zend_function *curl_multi_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct CurlMultiHandle, use curl_multi_init() instead"); - return NULL; + intern->multi = curl_multi_init(); + if (!intern->multi) { + zend_throw_exception(curl_multi_exception_ce, "Could not initialize a new cURL multi handle", 0); + } + + return &intern->std; } static void curl_multi_free_obj(zend_object *object) @@ -532,10 +668,8 @@ static void curl_multi_free_obj(zend_object *object) php_curl *ch; zval *pz_ch; - if (!mh->multi) { - /* Can happen if constructor throws. */ - zend_object_std_dtor(&mh->std); - return; + if (mh->multi) { + curl_multi_cleanup(mh->multi); } for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch; @@ -546,7 +680,6 @@ static void curl_multi_free_obj(zend_object *object) } } - curl_multi_cleanup(mh->multi); zend_llist_clean(&mh->easyh); if (mh->handlers.server_push) { zval_ptr_dtor(&mh->handlers.server_push->func_name); @@ -587,7 +720,6 @@ void curl_multi_register_handlers(void) { curl_multi_handlers.offset = XtOffsetOf(php_curlm, std); curl_multi_handlers.free_obj = curl_multi_free_obj; curl_multi_handlers.get_gc = curl_multi_get_gc; - curl_multi_handlers.get_constructor = curl_multi_get_constructor; curl_multi_handlers.clone_obj = NULL; curl_multi_handlers.cast_object = curl_cast_object; curl_multi_handlers.compare = zend_objects_not_comparable; diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h index bc92c51121ec8..4634c4d02f666 100644 --- a/ext/curl/php_curl.h +++ b/ext/curl/php_curl.h @@ -41,4 +41,9 @@ PHP_CURL_API extern zend_class_entry *curl_multi_ce; PHP_CURL_API extern zend_class_entry *curl_CURLFile_class; PHP_CURL_API extern zend_class_entry *curl_CURLStringFile_class; +PHP_CURL_API extern zend_class_entry *curl_exception_ce; +PHP_CURL_API extern zend_class_entry *curl_handle_exception_ce; +PHP_CURL_API extern zend_class_entry *curl_multi_exception_ce; +PHP_CURL_API extern zend_class_entry *curl_share_exception_ce; + #endif /* _PHP_CURL_H */ diff --git a/ext/curl/share.c b/ext/curl/share.c index f30790250e0ca..958de98039978 100644 --- a/ext/curl/share.c +++ b/ext/curl/share.c @@ -21,6 +21,7 @@ #endif #include "php.h" +#include "zend_exceptions.h" #include "curl_private.h" @@ -28,17 +29,25 @@ #define SAVE_CURLSH_ERROR(__handle, __err) (__handle)->err.no = (int) __err; +/* {{{ curlm_throw_last_error */ +void curlsh_throw_last_error(php_curlsh *sh, const char *unknown_error_msg) { + if (sh->err.no) { + const char* str = curl_share_strerror(sh->err.no); + if (str) { + zend_throw_exception(curl_share_exception_ce, str, sh->err.no); + return; + } + } + + zend_throw_exception(curl_share_exception_ce, unknown_error_msg, sh->err.no); +} +/* }}} */ + /* {{{ Initialize a share curl handle */ PHP_FUNCTION(curl_share_init) { - php_curlsh *sh; - ZEND_PARSE_PARAMETERS_NONE(); - object_init_ex(return_value, curl_share_ce); - sh = Z_CURL_SHARE_P(return_value); - - sh->share = curl_share_init(); } /* }}} */ @@ -53,7 +62,7 @@ PHP_FUNCTION(curl_share_close) } /* }}} */ -static bool _php_curl_share_setopt(php_curlsh *sh, zend_long option, zval *zvalue, zval *return_value) /* {{{ */ +static bool _php_curl_share_setopt(php_curlsh *sh, int argnum, zend_long option, zval *zvalue, zval *return_value) /* {{{ */ { CURLSHcode error = CURLSHE_OK; @@ -64,7 +73,7 @@ static bool _php_curl_share_setopt(php_curlsh *sh, zend_long option, zval *zvalu break; default: - zend_argument_value_error(2, "is not a valid cURL share option"); + zend_argument_value_error(argnum, "is not a valid cURL share option"); error = CURLSHE_BAD_OPTION; break; } @@ -90,30 +99,66 @@ PHP_FUNCTION(curl_share_setopt) sh = Z_CURL_SHARE_P(z_sh); - if (_php_curl_share_setopt(sh, options, zvalue, return_value)) { + if (_php_curl_share_setopt(sh, 2, options, zvalue, return_value)) { RETURN_TRUE; } else { RETURN_FALSE; } } + +PHP_METHOD(CurlShareHandle, setOpt) +{ + php_curlsh *sh = Z_CURL_SHARE_P(getThis()); + zval *zvalue; + zend_long options; + + ZEND_PARSE_PARAMETERS_START(2,2) + Z_PARAM_LONG(options) + Z_PARAM_ZVAL(zvalue) + ZEND_PARSE_PARAMETERS_END(); + + if (!_php_curl_share_setopt(sh, 1, options, zvalue, return_value)) { + if (!EG(exception)) { + curlsh_throw_last_error(sh, "Failed setting cURL share option"); + } + RETURN_THROWS(); + } + + RETURN_ZVAL(getThis(), 1, 0); +} /* }}} */ /* {{{ Return an integer containing the last share curl error number */ PHP_FUNCTION(curl_share_errno) { zval *z_sh; - php_curlsh *sh; - - ZEND_PARSE_PARAMETERS_START(1,1) - Z_PARAM_OBJECT_OF_CLASS(z_sh, curl_share_ce) - ZEND_PARSE_PARAMETERS_END(); - sh = Z_CURL_SHARE_P(z_sh); + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &z_sh, curl_share_ce) == FAILURE) { + RETURN_THROWS(); + } - RETURN_LONG(sh->err.no); + RETURN_LONG(Z_CURL_SHARE_P(z_sh)->err.no); } /* }}} */ +/* {{{ Return a string containing the last share curl error message */ +PHP_FUNCTION(curl_share_error) +{ + zval *z_sh; + const char *str; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &z_sh, curl_share_ce) == FAILURE) { + RETURN_THROWS(); + } + + str = curl_share_strerror(Z_CURL_SHARE_P(z_sh)->err.no); + if (str) { + RETURN_STRING(str); + } else { + RETURN_NULL(); + } +} +/* }}} */ /* {{{ return string describing error code */ PHP_FUNCTION(curl_share_strerror) @@ -142,12 +187,9 @@ static zend_object *curl_share_create_object(zend_class_entry *class_type) { zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); - return &intern->std; -} + intern->share = curl_share_init(); -static zend_function *curl_share_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct CurlShareHandle, use curl_share_init() instead"); - return NULL; + return &intern->std; } void curl_share_free_obj(zend_object *object) @@ -167,7 +209,6 @@ void curl_share_register_handlers(void) { memcpy(&curl_share_handlers, &std_object_handlers, sizeof(zend_object_handlers)); curl_share_handlers.offset = XtOffsetOf(php_curlsh, std); curl_share_handlers.free_obj = curl_share_free_obj; - curl_share_handlers.get_constructor = curl_share_get_constructor; curl_share_handlers.clone_obj = NULL; curl_share_handlers.compare = zend_objects_not_comparable; } diff --git a/ext/curl/tests/bug80121.phpt b/ext/curl/tests/bug80121.phpt deleted file mode 100644 index a7bf6385367d6..0000000000000 --- a/ext/curl/tests/bug80121.phpt +++ /dev/null @@ -1,28 +0,0 @@ ---TEST-- -Bug #80121: Null pointer deref if CurlHandle directly instantiated ---EXTENSIONS-- -curl ---FILE-- -getMessage(), "\n"; -} -try { - new CurlMultiHandle; -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} -try { - new CurlShareHandle; -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} - -?> ---EXPECT-- -Cannot directly construct CurlHandle, use curl_init() instead -Cannot directly construct CurlMultiHandle, use curl_multi_init() instead -Cannot directly construct CurlShareHandle, use curl_share_init() instead diff --git a/ext/curl/tests/curl_multi_getcontent_oop3.phpt b/ext/curl/tests/curl_multi_getcontent_oop3.phpt new file mode 100644 index 0000000000000..6f243f2fba64c --- /dev/null +++ b/ext/curl/tests/curl_multi_getcontent_oop3.phpt @@ -0,0 +1,58 @@ +--TEST-- +CurlMultiHandle::getContent() basic test with different sources (local file/http) +--CREDITS-- +Based on curl_multi_getcontent_basic3.phpt by: +Rein Velt (rein@velt.org) +#TestFest Utrecht 20090509 +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_URL, "{$host}/get.inc?test=getpost&get_param=Hello%20World") + ->setOpt(CURLOPT_RETURNTRANSFER, true); + + $ch2 = (new CurlHandle) + ->setOpt(CURLOPT_URL, "file://" . __DIR__ . DIRECTORY_SEPARATOR . "curl_testdata2.txt") + ->setOpt(CURLOPT_RETURNTRANSFER, true); + + //CREATE MULTIPLE CURL HANDLE + $mh = (new CurlMultiHandle) + ->addHandle($ch1) + ->addHandle($ch2); + + //EXECUTE + $running=0; + while ($mh->exec($running)); + + $results1 = CurlMultiHandle::getContent($ch1); + $results2 = CurlMultiHandle::getContent($ch2); + + //CLOSE + $mh->removeHandle($ch1)->removeHandle($ch2); + + echo $results1; + echo $results2; +} catch (\Throwable $e) { + var_dump($e); +} +?> +--EXPECT-- +array(2) { + ["test"]=> + string(7) "getpost" + ["get_param"]=> + string(11) "Hello World" +} +array(0) { +} +CURL2 diff --git a/ext/curl/tests/curl_multi_init_oop.phpt b/ext/curl/tests/curl_multi_init_oop.phpt new file mode 100644 index 0000000000000..f370b7682a03d --- /dev/null +++ b/ext/curl/tests/curl_multi_init_oop.phpt @@ -0,0 +1,21 @@ +--TEST-- +Test CurlMultiHandle +--CREDITS-- +Based on curl_multi_init_basic.phpt by: +Mark van der Velden +#testfest Utrecht 2009 +--EXTENSIONS-- +curl +--FILE-- + +TestFest 2009 - AFUP - Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_URL, $url)->exec(); + unset($ch); + $echoed_content = ob_get_contents(); + ob_end_clean(); + + var_dump($echoed_content); + var_dump($returned_content); +?> +--EXPECT-- +*** Testing CurlHandle::exec() : basic functionality *** +string(0) "" +string(25) "Hello World! +Hello World!" diff --git a/ext/curl/tests/curl_oop_002.phpt b/ext/curl/tests/curl_oop_002.phpt new file mode 100644 index 0000000000000..f3ba81b5a5153 --- /dev/null +++ b/ext/curl/tests/curl_oop_002.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test CurlHandle::setOpt() function with CURLOPT_RETURNTRANSFER parameter set to 0 +--CREDITS-- +Based on curl_basic_002.phpt by: +Sebastian Deutsch +TestFest 2009 - AFUP - Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_RETURNTRANSFER, 0) + ->setOpt(CURLOPT_URL, $url) + ->exec(); + $echoed_contents = ob_get_contents(); + ob_end_clean(); + + var_dump($ok); + var_dump($echoed_contents); +--EXPECT-- +*** Testing CurlHandle::setOpt(CURLOPT_RETURNTRANSFER, 0); *** +bool(true) +string(25) "Hello World! +Hello World!" diff --git a/ext/curl/tests/curl_oop_003.phpt b/ext/curl/tests/curl_oop_003.phpt new file mode 100644 index 0000000000000..a9545cb14a5a5 --- /dev/null +++ b/ext/curl/tests/curl_oop_003.phpt @@ -0,0 +1,41 @@ +--TEST-- +Test CurlHandle::setOpt() method with POST parameters +--CREDITS-- +Based on curl_basic_003.phpt by: +Sebastian Deutsch +TestFest 2009 - AFUP - Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_POST, 1) + ->setOpt(CURLOPT_POSTFIELDS, "Hello=World&Foo=Bar&Person=John%20Doe") + ->exec(); + + var_dump( $curl_content ); +?> +--EXPECT-- +*** Testing curl sending through GET an POST *** +string(208) "array(2) { + ["test"]=> + string(7) "getpost" + ["get_param"]=> + string(11) "Hello World" +} +array(3) { + ["Hello"]=> + string(5) "World" + ["Foo"]=> + string(3) "Bar" + ["Person"]=> + string(8) "John Doe" +} +" diff --git a/ext/curl/tests/curl_oop_004.phpt b/ext/curl/tests/curl_oop_004.phpt new file mode 100644 index 0000000000000..43ca4b35f2467 --- /dev/null +++ b/ext/curl/tests/curl_oop_004.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test CurlHandle::setOpt() function with setting referer +--CREDITS-- +Based on curl_basic_004.phpt by: +Sebastian Deutsch +TestFest 2009 - AFUP - Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_REFERER, 'http://www.refer.er') + ->exec(); + + var_dump( $curl_content ); +?> +--EXPECT-- +*** Testing curl setting referer *** +string(19) "http://www.refer.er" diff --git a/ext/curl/tests/curl_oop_005.phpt b/ext/curl/tests/curl_oop_005.phpt new file mode 100644 index 0000000000000..195cd304eda3f --- /dev/null +++ b/ext/curl/tests/curl_oop_005.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test CurlHandle::setOpt() function with user agent +--CREDITS-- +Based on curl_basic_005.phpt by: +Sebastian Deutsch +TestFest 2009 - AFUP - Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_USERAGENT, 'cURL phpt') + ->exec(); + + var_dump( $curl_content ); +?> +--EXPECT-- +*** Testing curl with user agent *** +string(9) "cURL phpt" diff --git a/ext/curl/tests/curl_oop_006.phpt b/ext/curl/tests/curl_oop_006.phpt new file mode 100644 index 0000000000000..8b4870e7e3517 --- /dev/null +++ b/ext/curl/tests/curl_oop_006.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test CurlHandle::setOpt() function with CURLOPT_WRITEFUNCTION parameter set to a closure +--CREDITS-- +Based on curl_basic_006.phpt by: +TestFest 2009 - AFUP - Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_WRITEFUNCTION, ); ***' . "\n"; + + $alldata = ''; + $url = "{$host}/get.inc?test=get"; + ob_start(); // start output buffering + (new CurlHandle($url))->setOpt(CURLOPT_WRITEFUNCTION, function ($ch, $data) { + $GLOBALS['alldata'] .= $data; + return strlen ($data); + })->exec(); + ob_end_flush(); + echo "Data: $alldata"; +?> +===DONE=== +--EXPECT-- +*** Testing $ch->setOpt(CURLOPT_WRITEFUNCTION, ); *** +Data: Hello World! +Hello World!===DONE=== diff --git a/ext/curl/tests/curl_oop_007.phpt b/ext/curl/tests/curl_oop_007.phpt new file mode 100644 index 0000000000000..0a355eeb266a2 --- /dev/null +++ b/ext/curl/tests/curl_oop_007.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test CurlHandle::error() & CurlHandle::errno() function without url +--CREDITS-- +Based on curl_basic_007.phpt by: +TestFest 2009 - AFUP - Perrick Penet +--EXTENSIONS-- +curl +--FILE-- +exec(); +} catch (\CurlHandleException $ex) { + echo 'Caught: '; + var_dump($ex->getMessage()); +} + +echo 'Error: '; +var_dump($ch->error()); +var_dump($ch->errno()); + +?> +--EXPECTF-- +Caught: string(%d) "No URL set%A" +Error: string(%d) "No URL set%A" +int(3) diff --git a/ext/curl/tests/curl_oop_008.phpt b/ext/curl/tests/curl_oop_008.phpt new file mode 100644 index 0000000000000..0bb27beb0a9cf --- /dev/null +++ b/ext/curl/tests/curl_oop_008.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test CurlHandle::error() & CurlHandle::errno() function with problematic host +--CREDITS-- +Based on curl_basic_008.phpt by: +TestFest 2009 - AFUP - Perrick Penet +--EXTENSIONS-- +curl +--SKIPIF-- + +--FILE-- +exec(); +} catch (\CurlHandleException $ex) { + echo 'Caught: '; + var_dump($ex->getMessage()); +} + +echo 'Error: '; +var_dump($ch->error()); +var_dump($ch->errno()); + +?> +--EXPECTF-- +Caught: %s resolve%s +Error: %s resolve%s +int(6) diff --git a/ext/curl/tests/curl_oop_009.phpt b/ext/curl/tests/curl_oop_009.phpt new file mode 100644 index 0000000000000..6c2ed02067711 --- /dev/null +++ b/ext/curl/tests/curl_oop_009.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test CurlHandle::error() & CurlHandle::errno() function with problematic protocol +--CREDITS-- +Based on curl_basic_009.phpt by: +TestFest 2009 - AFUP - Perrick Penet +--EXTENSIONS-- +curl +--FILE-- +exec(); +} catch (\CurlHandleException $ex) { + echo 'Caught: '; + var_dump($ex->getMessage()); +} + +echo 'Error: '; +var_dump($ch->error()); +var_dump($ch->errno()); + +?> +--EXPECTF-- +Caught: string(%d) "%Srotocol%s" +Error: string(%d) "%Srotocol%s" +int(1) diff --git a/ext/curl/tests/curl_oop_010.phpt b/ext/curl/tests/curl_oop_010.phpt new file mode 100644 index 0000000000000..9f70fd1c2eb7c --- /dev/null +++ b/ext/curl/tests/curl_oop_010.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test CurlHandle::error() & CurlHandle::errno() function with problematic proxy +--CREDITS-- +Based on curl_basic_010.phpt by: +TestFest 2009 - AFUP - Perrick Penet +--EXTENSIONS-- +curl +--SKIPIF-- + +--FILE-- +setOpt(CURLOPT_PROXY, uniqid().":".uniqid()); + +try { + $ch->exec(); +} catch (\CurlHandleException $ex) { + echo 'Caught: '; + var_dump($ex->getMessage()); +} + +echo 'Error: '; +var_dump($ch->error()); +var_dump($ch->errno()); + +--EXPECTF-- +Caught: string(%d) "%r(Couldn't resolve proxy|Could not resolve proxy:|Could not resolve host:|Could not resolve:|Unsupported proxy syntax in)%r %s" +Error: string(%d) "%r(Couldn't resolve proxy|Could not resolve proxy:|Could not resolve host:|Could not resolve:|Unsupported proxy syntax in)%r %s" +int(5) diff --git a/ext/curl/tests/curl_oop_011.phpt b/ext/curl/tests/curl_oop_011.phpt new file mode 100644 index 0000000000000..edec1e4d76bdb --- /dev/null +++ b/ext/curl/tests/curl_oop_011.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test CurlHandle::setOpt() function with COOKIE +--CREDITS-- +Based on curl_basic_011.phpt by: +TestFest 2009 - AFUP - Xavier Gorse +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_COOKIE, 'foo=bar') + ->exec(); + + var_dump( $curl_content ); +?> +--EXPECT-- +*** Testing curl with cookie *** +string(3) "bar" diff --git a/ext/curl/tests/curl_oop_012.phpt b/ext/curl/tests/curl_oop_012.phpt new file mode 100644 index 0000000000000..e40ad081158c4 --- /dev/null +++ b/ext/curl/tests/curl_oop_012.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test CurlHandle::setOpt() function with CURLOPT_HTTP_VERSION/CURL_HTTP_VERSION_1_0 +--CREDITS-- +Based on curl_basic_012.phpt by: +TestFest 2009 - AFUP - Xavier Gorse +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0) + ->exec(); + + var_dump( $curl_content ); +?> +--EXPECT-- +*** Testing curl with HTTP/1.0 *** +string(8) "HTTP/1.0" + diff --git a/ext/curl/tests/curl_oop_013.phpt b/ext/curl/tests/curl_oop_013.phpt new file mode 100644 index 0000000000000..673b33319d426 --- /dev/null +++ b/ext/curl/tests/curl_oop_013.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test CurlHandle::setOpt() function with CURLOPT_HTTP_VERSION/CURL_HTTP_VERSION_1_1 +--CREDITS-- +Based on curl_basic_013.phpt by: +TestFest 2009 - AFUP - Xavier Gorse +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1) + ->exec(); + + var_dump( $curl_content ); +?> +--EXPECT-- +*** Testing curl with HTTP/1.1 *** +string(8) "HTTP/1.1" + diff --git a/ext/curl/tests/curl_oop_014.phpt b/ext/curl/tests/curl_oop_014.phpt new file mode 100644 index 0000000000000..e762ef99dbf19 --- /dev/null +++ b/ext/curl/tests/curl_oop_014.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test CurlHandle object with basic functionality +--CREDITS-- +Based on curl_basic_014.phpt +Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +object(CurlHandle)#1 (0) { +} diff --git a/ext/curl/tests/curl_oop_015.phpt b/ext/curl/tests/curl_oop_015.phpt new file mode 100644 index 0000000000000..cdcae0eef55c1 --- /dev/null +++ b/ext/curl/tests/curl_oop_015.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test CurlHandle constructor with $url parameter defined +--CREDITS-- +Based on curl_basic_015.phpt by: +Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +getInfo(CURLINFO_EFFECTIVE_URL)); +?> +--EXPECT-- +string(23) "http://www.example.com/" diff --git a/ext/curl/tests/curl_oop_018.phpt b/ext/curl/tests/curl_oop_018.phpt new file mode 100644 index 0000000000000..ca8ff120cdb82 --- /dev/null +++ b/ext/curl/tests/curl_oop_018.phpt @@ -0,0 +1,44 @@ +--TEST-- +Test CurlHandle::setOpt() with CurlMultiHandle class with basic functionality +--CREDITS-- +Based on curl_basic_018.phpt by: +TestFest 2009 - AFUP - Thomas Rabaix +--EXTENSIONS-- +curl +--FILE-- +addHandle($chs[$i]); + } + + //execute the handles + $running=null; + while ($mh->exec($running)); + + $curl_content = ''; + for ($i = 0; $i < 3; ++$i) { + $curl_content .= CurlMultiHandle::getContent($chs[$i]); + $mh->removeHandle($chs[$i]); + } + curl_multi_close($mh); + + var_dump( $curl_content ); + +?> +--EXPECT-- +*** Testing CurlMultiHandle::exec() : basic functionality *** +string(75) "Hello World! +Hello World!Hello World! +Hello World!Hello World! +Hello World!" diff --git a/ext/curl/tests/curl_oop_019.phpt b/ext/curl/tests/curl_oop_019.phpt new file mode 100644 index 0000000000000..2a0c701fbf973 --- /dev/null +++ b/ext/curl/tests/curl_oop_019.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test CurlHandle::getInfo() function with CURLINFO_EFFECTIVE_URL parameter +--CREDITS-- +Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_RETURNTRANSFER, 0); + $ch->exec(); + + $info = $ch->getInfo(CURLINFO_EFFECTIVE_URL); + echo PHP_EOL; + var_dump($url == $info); +--EXPECT-- +Hello World! +Hello World! +bool(true) diff --git a/ext/curl/tests/curl_oop_020.phpt b/ext/curl/tests/curl_oop_020.phpt new file mode 100644 index 0000000000000..f8bf489a06c2c --- /dev/null +++ b/ext/curl/tests/curl_oop_020.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test CurlHandle::getInfo() function with CURLINFO_HTTP_CODE parameter +--CREDITS-- +Based on curl_basic_020.phpt by: +Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_RETURNTRANSFER, 0); + $ok = $ch->exec(); + echo PHP_EOL; + var_dump($ok); + var_dump($ch->getInfo(CURLINFO_HTTP_CODE)); +?> +--EXPECT-- +Hello World! +Hello World! +bool(true) +int(200) diff --git a/ext/curl/tests/curl_oop_021.phpt b/ext/curl/tests/curl_oop_021.phpt new file mode 100644 index 0000000000000..e25421e20ad37 --- /dev/null +++ b/ext/curl/tests/curl_oop_021.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test CurlHandle:getInfo() function with CURLINFO_CONTENT_TYPE parameter +--CREDITS-- +Based on curl_basic_021.phpt by: +Jean-Marc Fontaine +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_RETURNTRANSFER, 0); + $ok = $ch->exec(); + var_dump($ok); + var_dump(curl_getinfo($ch, CURLINFO_CONTENT_TYPE)); + curl_close($ch); +?> +--EXPECT-- +bool(true) +string(24) "text/plain;charset=utf-8" diff --git a/ext/curl/tests/curl_oop_022.phpt b/ext/curl/tests/curl_oop_022.phpt new file mode 100644 index 0000000000000..5d20e84b9496b --- /dev/null +++ b/ext/curl/tests/curl_oop_022.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test CurlHandle::getInfo() function with CURLINFO_COOKIELIST parameter +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLOPT_COOKIELIST, 'Set-Cookie: C1=v1; expires=Thu, 31-Dec-2037 23:59:59 GMT; path=/; domain=.php.net') + ->setOpt(CURLOPT_COOKIELIST, 'Set-Cookie: C2=v2; expires=Thu, 31-Dec-2037 23:59:59 GMT; path=/; domain=.php.net'); + +var_dump($ch->getInfo(CURLINFO_COOKIELIST)); + +--EXPECT-- +array(2) { + [0]=> + string(38) ".php.net TRUE / FALSE 2145916799 C1 v1" + [1]=> + string(38) ".php.net TRUE / FALSE 2145916799 C2 v2" +} diff --git a/ext/curl/tests/curl_oop_023.phpt b/ext/curl/tests/curl_oop_023.phpt new file mode 100644 index 0000000000000..b296e76eac84f --- /dev/null +++ b/ext/curl/tests/curl_oop_023.phpt @@ -0,0 +1,21 @@ +--TEST-- +Test CurlHandle::getInfo() function with CURLINFO_HTTP_VERSION parameter +--EXTENSIONS-- +curl +--FILE-- +getInfo(CURLINFO_HTTP_VERSION)); + +$host = curl_cli_server_start(); + +$url = "{$host}/get.inc?test="; +$ch->setOpt(CURLOPT_URL, $url)->exec(); +var_dump(CURL_HTTP_VERSION_1_1 === curl_getinfo($ch, CURLINFO_HTTP_VERSION)); +curl_close($ch); +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/curl/tests/curl_oop_024.phpt b/ext/curl/tests/curl_oop_024.phpt new file mode 100644 index 0000000000000..7066876f45804 --- /dev/null +++ b/ext/curl/tests/curl_oop_024.phpt @@ -0,0 +1,21 @@ +--TEST-- +Test CurlHandle::getInfo() function with CURLINFO_* from curl >= 7.52.0 +--EXTENSIONS-- +curl +--FILE-- +exec(); +var_dump(CURLPROTO_HTTP === $ch->getInfo(CURLINFO_PROTOCOL)); +var_dump(0 === $ch->getInfo(CURLINFO_PROXY_SSL_VERIFYRESULT)); +var_dump($ch->getInfo(CURLINFO_SCHEME)); +--EXPECT-- +bool(true) +bool(true) +string(4) "HTTP" diff --git a/ext/curl/tests/curl_oop_025.phpt b/ext/curl/tests/curl_oop_025.phpt new file mode 100644 index 0000000000000..ab41c83a69141 --- /dev/null +++ b/ext/curl/tests/curl_oop_025.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test CurlHandle::getInfo() function with CURLINFO_* from curl >= 7.72.0 +--EXTENSIONS-- +curl +--SKIPIF-- += 7.72.0"); +} +?> +--FILE-- +setOpt(CURLOPT_POSTFIELDS, "data"); +$ch->exec(); +var_dump($ch->getInfo(CURLINFO_EFFECTIVE_METHOD)); +--EXPECT-- +string(4) "POST" diff --git a/ext/curl/tests/curl_oop_026.phpt b/ext/curl/tests/curl_oop_026.phpt new file mode 100644 index 0000000000000..6ac6963ab0e5a --- /dev/null +++ b/ext/curl/tests/curl_oop_026.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test curl_getinfo() function with CURLOPT_* from curl >= 7.81.0 +--EXTENSIONS-- +curl +--SKIPIF-- += 7.81.0"); +} +?> +--FILE-- +setOpt(CURLOPT_MIME_OPTIONS, CURLMIMEOPT_FORMESCAPE) + ->exec(); +var_dump("Done"); +--EXPECT-- +string(4) "Done" diff --git a/ext/curl/tests/curl_oop_027.phpt b/ext/curl/tests/curl_oop_027.phpt new file mode 100644 index 0000000000000..925d358266848 --- /dev/null +++ b/ext/curl/tests/curl_oop_027.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test CurlHandle::getInfo() function with CURLINFO_* and CURLOPT_* from curl >= 7.84.0 +--EXTENSIONS-- +curl +--SKIPIF-- += 7.84.0"); +} +?> +--FILE-- +getInfo())); +var_dump(array_key_exists('cainfo', $ch->getInfo())); + +$host = curl_cli_server_start(); + +$url = "{$host}/get.inc?test="; +$ch->setOpt(CURLOPT_URL, $url) + ->setOpt(CURLOPT_SSH_HOSTKEYFUNCTION, function ($ch, $keytype, $key, $keylen) { + // Can't really trigger this in a test + var_dump($keytype); + var_dump($key); + var_dump($keylen); + return CURLKHMATCH_OK; +})->exec(); + +var_dump('Done'); +--EXPECT-- +bool(true) +bool(true) +string(4) "Done" diff --git a/ext/curl/tests/curl_oop_028.phpt b/ext/curl/tests/curl_oop_028.phpt new file mode 100644 index 0000000000000..f9b1fe90ed837 --- /dev/null +++ b/ext/curl/tests/curl_oop_028.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test CurlHandle::getInfo() function with CURLOPT_* from curl >= 7.85.0 +--INI-- +open_basedir=. +--EXTENSIONS-- +curl +--SKIPIF-- += 7.85.0"); +} +?> +--FILE-- +setOpt(CURLOPT_PROTOCOLS_STR, "FilE,DICT"); +} catch (\CurlHandleException $ex) { + echo 'Caught: ', $ex->getMessage(), PHP_EOL; +} + +$ch->setOpt(CURLOPT_PROTOCOLS_STR, "DICT")) + ->setOpt(CURLOPT_REDIR_PROTOCOLS_STR, "HTTP") + ->exec(); +var_dump('Done'); +--EXPECTF-- +Caught: The FILE protocol cannot be activated when an open_basedir is set in %s on line %d +string(4) "Done" diff --git a/ext/curl/tests/curl_oop_029.phpt b/ext/curl/tests/curl_oop_029.phpt new file mode 100644 index 0000000000000..ed2ea0c5876c3 --- /dev/null +++ b/ext/curl/tests/curl_oop_029.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test CurlHandle::setOpt() function with CURLOPT_* from curl >= 7.86.0 +--EXTENSIONS-- +curl +--SKIPIF-- += 7.86.0"); +} +?> +--FILE-- +setOpt(CURLOPT_WS_OPTIONS, $val); + var_dump(true); + } catch (\CurlHandleException $ex) { + var_dump(false); + } +}; + +$try(0); +$try(CURLWS_RAW_MODE); + +$ch->exec(); +--EXPECTF-- +bool(%s) +bool(%s) diff --git a/ext/curl/tests/curl_oop_030.phpt b/ext/curl/tests/curl_oop_030.phpt new file mode 100644 index 0000000000000..0beace9a7eac3 --- /dev/null +++ b/ext/curl/tests/curl_oop_030.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test curl_getinfo() function with CURLOPT_* from curl >= 7.87.0 +--EXTENSIONS-- +curl +--SKIPIF-- += 7.87.0"); +} +?> +--FILE-- + +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/curl/tests/curl_share_setopt_oop001.phpt b/ext/curl/tests/curl_share_setopt_oop001.phpt new file mode 100644 index 0000000000000..52172014bd5af --- /dev/null +++ b/ext/curl/tests/curl_share_setopt_oop001.phpt @@ -0,0 +1,22 @@ +--TEST-- +CurlShareHandle::setOpt() basic test +--EXTENSIONS-- +curl +--FILE-- +setOpt(CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE) + ->setOpt(CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE); + +try { + echo "Setting invalid option\n"; + $sh->setOpt(-1, 0); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Setting invalid option +CurlShareHandle::setOpt(): Argument #1 ($option) is not a valid cURL share option