2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
15 #include <ext/spl/spl_observer.h>
16 #include <ext/standard/php_array.h>
18 PHP_HTTP_API php_http_client_t
*php_http_client_init(php_http_client_t
*h
, php_http_client_ops_t
*ops
, php_http_resource_factory_t
*rf
, void *init_arg TSRMLS_DC
)
20 php_http_client_t
*free_h
= NULL
;
23 free_h
= h
= emalloc(sizeof(*h
));
25 memset(h
, 0, sizeof(*h
));
30 } else if (ops
->rsrc
) {
31 h
->rf
= php_http_resource_factory_init(NULL
, h
->ops
->rsrc
, h
, NULL
);
33 h
->request
.buffer
= php_http_buffer_init(NULL
);
34 h
->request
.parser
= php_http_message_parser_init(NULL TSRMLS_CC
);
35 h
->request
.message
= php_http_message_init(NULL
, 0 TSRMLS_CC
);
37 h
->response
.buffer
= php_http_buffer_init(NULL
);
38 h
->response
.parser
= php_http_message_parser_init(NULL TSRMLS_CC
);
39 h
->response
.message
= php_http_message_init(NULL
, 0 TSRMLS_CC
);
41 TSRMLS_SET_CTX(h
->ts
);
44 if (!(h
= h
->ops
->init(h
, init_arg
))) {
45 php_http_error(HE_WARNING
, PHP_HTTP_E_CLIENT
, "Could not initialize request");
48 php_http_client_free(&free_h
);
56 PHP_HTTP_API
void php_http_client_dtor(php_http_client_t
*h
)
62 php_http_resource_factory_free(&h
->rf
);
64 php_http_message_parser_free(&h
->request
.parser
);
65 php_http_message_free(&h
->request
.message
);
66 php_http_buffer_free(&h
->request
.buffer
);
68 php_http_message_parser_free(&h
->response
.parser
);
69 php_http_message_free(&h
->response
.message
);
70 php_http_buffer_free(&h
->response
.buffer
);
73 PHP_HTTP_API
void php_http_client_free(php_http_client_t
**h
)
76 php_http_client_dtor(*h
);
82 PHP_HTTP_API php_http_client_t
*php_http_client_copy(php_http_client_t
*from
, php_http_client_t
*to
)
84 if (!from
->ops
->copy
) {
87 TSRMLS_FETCH_FROM_CTX(from
->ts
);
90 to
= ecalloc(1, sizeof(*to
));
95 php_http_resource_factory_addref(from
->rf
);
97 } else if (to
->ops
->rsrc
){
98 to
->rf
= php_http_resource_factory_init(NULL
, to
->ops
->rsrc
, to
, NULL
);
101 to
->request
.buffer
= php_http_buffer_init(NULL
);
102 to
->request
.parser
= php_http_message_parser_init(NULL TSRMLS_CC
);
103 to
->request
.message
= php_http_message_init(NULL
, 0 TSRMLS_CC
);
105 to
->response
.buffer
= php_http_buffer_init(NULL
);
106 to
->response
.parser
= php_http_message_parser_init(NULL TSRMLS_CC
);
107 to
->response
.message
= php_http_message_init(NULL
, 0 TSRMLS_CC
);
109 TSRMLS_SET_CTX(to
->ts
);
111 return to
->ops
->copy(from
, to
);
115 PHP_HTTP_API STATUS
php_http_client_exec(php_http_client_t
*h
, php_http_message_t
*msg
)
118 return h
->ops
->exec(h
, msg
);
123 PHP_HTTP_API STATUS
php_http_client_reset(php_http_client_t
*h
)
126 return h
->ops
->reset(h
);
131 PHP_HTTP_API STATUS
php_http_client_setopt(php_http_client_t
*h
, php_http_client_setopt_opt_t opt
, void *arg
)
133 if (h
->ops
->setopt
) {
134 return h
->ops
->setopt(h
, opt
, arg
);
139 PHP_HTTP_API STATUS
php_http_client_getopt(php_http_client_t
*h
, php_http_client_getopt_opt_t opt
, void *arg
)
141 if (h
->ops
->getopt
) {
142 return h
->ops
->getopt(h
, opt
, arg
);
147 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClient, method, 0, req_args)
148 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClient, method, 0)
149 #define PHP_HTTP_CLIENT_ME(method, visibility) PHP_ME(HttpClient, method, PHP_HTTP_ARGS(HttpClient, method), visibility)
150 #define PHP_HTTP_CLIENT_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpClient, method))
151 #define PHP_HTTP_CLIENT_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpClient_##al), PHP_HTTP_ARGS(HttpClient, al), vis)
153 PHP_HTTP_BEGIN_ARGS(__construct
, 0)
154 PHP_HTTP_ARG_ARR(options
, 1, 0)
157 PHP_HTTP_EMPTY_ARGS(getOptions
);
158 PHP_HTTP_BEGIN_ARGS(setOptions
, 0)
159 PHP_HTTP_ARG_ARR(options
, 1, 0)
162 PHP_HTTP_EMPTY_ARGS(getSslOptions
);
163 PHP_HTTP_BEGIN_ARGS(setSslOptions
, 0)
164 PHP_HTTP_ARG_ARR(ssl_options
, 1, 0)
167 PHP_HTTP_BEGIN_ARGS(addSslOptions
, 0)
168 PHP_HTTP_ARG_ARR(ssl_options
, 1, 0)
171 PHP_HTTP_EMPTY_ARGS(getCookies
);
172 PHP_HTTP_BEGIN_ARGS(setCookies
, 0)
173 PHP_HTTP_ARG_VAL(cookies
, 0)
176 PHP_HTTP_BEGIN_ARGS(addCookies
, 1)
177 PHP_HTTP_ARG_VAL(cookies
, 0)
180 PHP_HTTP_EMPTY_ARGS(enableCookies
);
181 PHP_HTTP_BEGIN_ARGS(resetCookies
, 0)
182 PHP_HTTP_ARG_VAL(session_only
, 0)
184 PHP_HTTP_EMPTY_ARGS(flushCookies
);
186 PHP_HTTP_EMPTY_ARGS(getResponseMessageClass
);
187 PHP_HTTP_BEGIN_ARGS(setResponseMessageClass
, 1)
188 PHP_HTTP_ARG_VAL(message_class_name
, 0)
191 PHP_HTTP_EMPTY_ARGS(getResponseMessage
);
192 PHP_HTTP_EMPTY_ARGS(getRequestMessage
);
193 PHP_HTTP_EMPTY_ARGS(getHistory
);
194 PHP_HTTP_EMPTY_ARGS(clearHistory
);
196 PHP_HTTP_BEGIN_ARGS(setRequest
, 1)
197 PHP_HTTP_ARG_OBJ(http
\\Client
\\Request
, request
, 1)
199 PHP_HTTP_EMPTY_ARGS(getRequest
);
201 PHP_HTTP_EMPTY_ARGS(getObservers
);
202 PHP_HTTP_BEGIN_ARGS(attach
, 1)
203 PHP_HTTP_ARG_OBJ(SplObserver
, observer
, 0)
205 PHP_HTTP_BEGIN_ARGS(detach
, 1)
206 PHP_HTTP_ARG_OBJ(SplObserver
, observer
, 0)
208 PHP_HTTP_EMPTY_ARGS(notify
);
209 PHP_HTTP_EMPTY_ARGS(getProgress
);
210 PHP_HTTP_BEGIN_ARGS(getTransferInfo
, 0)
211 PHP_HTTP_ARG_VAL(name
, 0)
214 PHP_HTTP_BEGIN_ARGS(request
, 2)
215 PHP_HTTP_ARG_VAL(method
, 0)
216 PHP_HTTP_ARG_VAL(url
, 0)
217 PHP_HTTP_ARG_ARR(headers
, 1, 0)
218 PHP_HTTP_ARG_VAL(body
, 0)
219 PHP_HTTP_ARG_ARR(options
, 1, 0)
222 static zend_class_entry
*php_http_client_class_entry
;
224 zend_class_entry
*php_http_client_get_class_entry(void)
226 return php_http_client_class_entry
;
229 static zend_function_entry php_http_client_method_entry
[] = {
230 PHP_HTTP_CLIENT_ME(__construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
231 PHP_HTTP_CLIENT_ME(getObservers
, ZEND_ACC_PUBLIC
)
232 PHP_HTTP_CLIENT_ME(notify
, ZEND_ACC_PUBLIC
)
233 PHP_HTTP_CLIENT_ME(attach
, ZEND_ACC_PUBLIC
)
234 PHP_HTTP_CLIENT_ME(detach
, ZEND_ACC_PUBLIC
)
235 PHP_HTTP_CLIENT_ME(getProgress
, ZEND_ACC_PUBLIC
)
236 PHP_HTTP_CLIENT_ME(getTransferInfo
, ZEND_ACC_PUBLIC
)
238 PHP_HTTP_CLIENT_ME(setOptions
, ZEND_ACC_PUBLIC
)
239 PHP_HTTP_CLIENT_ME(getOptions
, ZEND_ACC_PUBLIC
)
240 PHP_HTTP_CLIENT_ME(setSslOptions
, ZEND_ACC_PUBLIC
)
241 PHP_HTTP_CLIENT_ME(getSslOptions
, ZEND_ACC_PUBLIC
)
242 PHP_HTTP_CLIENT_ME(addSslOptions
, ZEND_ACC_PUBLIC
)
244 PHP_HTTP_CLIENT_ME(addCookies
, ZEND_ACC_PUBLIC
)
245 PHP_HTTP_CLIENT_ME(getCookies
, ZEND_ACC_PUBLIC
)
246 PHP_HTTP_CLIENT_ME(setCookies
, ZEND_ACC_PUBLIC
)
248 PHP_HTTP_CLIENT_ME(enableCookies
, ZEND_ACC_PUBLIC
)
249 PHP_HTTP_CLIENT_ME(resetCookies
, ZEND_ACC_PUBLIC
)
250 PHP_HTTP_CLIENT_ME(flushCookies
, ZEND_ACC_PUBLIC
)
252 PHP_HTTP_CLIENT_ME(setRequest
, ZEND_ACC_PUBLIC
)
253 PHP_HTTP_CLIENT_ME(getRequest
, ZEND_ACC_PUBLIC
)
255 PHP_HTTP_CLIENT_ME(getResponseMessage
, ZEND_ACC_PUBLIC
)
256 PHP_HTTP_CLIENT_ME(getRequestMessage
, ZEND_ACC_PUBLIC
)
257 PHP_HTTP_CLIENT_ME(getHistory
, ZEND_ACC_PUBLIC
)
258 PHP_HTTP_CLIENT_ME(clearHistory
, ZEND_ACC_PUBLIC
)
260 PHP_HTTP_CLIENT_ME(getResponseMessageClass
, ZEND_ACC_PUBLIC
)
261 PHP_HTTP_CLIENT_ME(setResponseMessageClass
, ZEND_ACC_PUBLIC
)
263 PHP_HTTP_CLIENT_ME(request
, ZEND_ACC_PUBLIC
)
268 static zend_object_handlers php_http_client_object_handlers
;
270 zend_object_handlers
*php_http_client_get_object_handlers(void)
272 return &php_http_client_object_handlers
;
275 static php_http_client_ops_t php_http_client_user_ops
= {
284 (php_http_new_t
) php_http_client_object_new_ex
,
285 php_http_client_get_class_entry
288 zend_object_value
php_http_client_object_new(zend_class_entry
*ce TSRMLS_DC
)
290 return php_http_client_object_new_ex(ce
, NULL
, NULL TSRMLS_CC
);
293 zend_object_value
php_http_client_object_new_ex(zend_class_entry
*ce
, php_http_client_t
*r
, php_http_client_object_t
**ptr TSRMLS_DC
)
295 zend_object_value ov
;
296 php_http_client_object_t
*o
;
298 o
= ecalloc(1, sizeof(*o
));
299 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
300 object_properties_init((zend_object
*) o
, ce
);
302 ov
.handle
= zend_objects_store_put(o
, NULL
, php_http_client_object_free
, NULL TSRMLS_CC
);
303 ov
.handlers
= &php_http_client_object_handlers
;
305 if (!(o
->client
= r
)) {
306 o
->client
= php_http_client_init(NULL
, &php_http_client_user_ops
, NULL
, &ov TSRMLS_CC
);
316 zend_object_value
php_http_client_object_clone(zval
*this_ptr TSRMLS_DC
)
318 zend_object_value new_ov
;
319 php_http_client_object_t
*new_obj
, *old_obj
= zend_object_store_get_object(this_ptr TSRMLS_CC
);
321 new_ov
= php_http_client_object_new_ex(old_obj
->zo
.ce
, php_http_client_copy(old_obj
->client
, NULL
), &new_obj TSRMLS_CC
);
322 zend_objects_clone_members(&new_obj
->zo
, new_ov
, &old_obj
->zo
, Z_OBJ_HANDLE_P(this_ptr
) TSRMLS_CC
);
327 void php_http_client_object_free(void *object TSRMLS_DC
)
329 php_http_client_object_t
*o
= (php_http_client_object_t
*) object
;
331 php_http_client_free(&o
->client
);
332 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
336 static inline zend_object_value
php_http_client_object_message(zval
*this_ptr
, php_http_message_t
*msg TSRMLS_DC
)
338 zend_object_value ov
;
339 zval
*zcn
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("responseMessageClass"), 0 TSRMLS_CC
);
340 zend_class_entry
*class_entry
;
343 && (class_entry
= zend_fetch_class(Z_STRVAL_P(zcn
), Z_STRLEN_P(zcn
), 0 TSRMLS_CC
))
344 && (SUCCESS
== php_http_new(&ov
, class_entry
, (php_http_new_t
) php_http_message_object_new_ex
, php_http_client_response_get_class_entry(), msg
, NULL TSRMLS_CC
))) {
347 return php_http_message_object_new_ex(php_http_client_response_get_class_entry(), msg
, NULL TSRMLS_CC
);
351 STATUS
php_http_client_object_handle_request(zval
*zclient
, zval
**zreq TSRMLS_DC
)
353 php_http_client_object_t
*obj
= zend_object_store_get_object(zclient TSRMLS_CC
);
354 php_http_client_progress_t
*progress
;
358 /* do we have a valid request? */
360 /* remember the request */
361 zend_update_property(php_http_client_class_entry
, zclient
, ZEND_STRL("request"), *zreq TSRMLS_CC
);
363 /* maybe a request is already set */
364 *zreq
= zend_read_property(php_http_client_class_entry
, zclient
, ZEND_STRL("request"), 0 TSRMLS_CC
);
366 if (Z_TYPE_PP(zreq
) != IS_OBJECT
|| !instanceof_function(Z_OBJCE_PP(zreq
), php_http_client_request_get_class_entry() TSRMLS_CC
)) {
367 php_http_error(HE_WARNING
, PHP_HTTP_E_CLIENT
, "The client does not have a valid request set");
372 /* reset request handle */
373 php_http_client_reset(obj
->client
);
375 /* reset transfer info */
376 zend_update_property_null(php_http_client_class_entry
, zclient
, ZEND_STRL("transferInfo") TSRMLS_CC
);
379 /* set client options */
380 zend_hash_init(&options
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
381 zoptions
= zend_read_property(php_http_client_class_entry
, zclient
, ZEND_STRL("options"), 0 TSRMLS_CC
);
382 if (Z_TYPE_P(zoptions
) == IS_ARRAY
&& zend_hash_num_elements(Z_ARRVAL_P(zoptions
))) {
383 php_array_merge(&options
, Z_ARRVAL_P(zoptions
), 1 TSRMLS_CC
);
385 zoptions
= zend_read_property(php_http_client_request_get_class_entry(), *zreq
, ZEND_STRL("options"), 0 TSRMLS_CC
);
386 if (Z_TYPE_P(zoptions
) == IS_ARRAY
&& zend_hash_num_elements(Z_ARRVAL_P(zoptions
))) {
387 php_array_merge(&options
, Z_ARRVAL_P(zoptions
), 1 TSRMLS_CC
);
389 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_SETTINGS
, &options
);
390 zend_hash_destroy(&options
);
392 /* set progress callback */
393 if (SUCCESS
== php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO
, &progress
)) {
394 if (!progress
->callback
) {
395 php_http_client_progress_callback_t
*callback
= emalloc(sizeof(*callback
));
397 callback
->type
= PHP_HTTP_CLIENT_PROGRESS_CALLBACK_USER
;
398 callback
->pass_state
= 0;
399 MAKE_STD_ZVAL(callback
->func
.user
);
400 array_init(callback
->func
.user
);
402 add_next_index_zval(callback
->func
.user
, zclient
);
403 add_next_index_stringl(callback
->func
.user
, ZEND_STRL("notify"), 1);
405 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK
, callback
);
407 progress
->state
.info
= "start";
408 php_http_client_progress_notify(progress TSRMLS_CC
);
409 progress
->state
.started
= 1;
416 STATUS
php_http_client_object_handle_response(zval
*zclient TSRMLS_DC
)
418 php_http_client_object_t
*obj
= zend_object_store_get_object(zclient TSRMLS_CC
);
419 php_http_client_progress_t
*progress
;
420 php_http_message_t
*msg
;
423 /* always fetch info */
426 php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO
, Z_ARRVAL_P(info
));
427 zend_update_property(php_http_client_class_entry
, zclient
, ZEND_STRL("transferInfo"), info TSRMLS_CC
);
428 zval_ptr_dtor(&info
);
430 if ((msg
= obj
->client
->response
.message
)) {
431 if (i_zend_is_true(zend_read_property(php_http_client_class_entry
, zclient
, ZEND_STRL("recordHistory"), 0 TSRMLS_CC
))) {
432 zval
*new_hist
, *old_hist
= zend_read_property(php_http_client_class_entry
, zclient
, ZEND_STRL("history"), 0 TSRMLS_CC
);
433 php_http_message_t
*zipped
= php_http_message_zip(obj
->client
->response
.message
, obj
->client
->request
.message
);
434 zend_object_value ov
= php_http_client_object_message(zclient
, zipped TSRMLS_CC
);
436 MAKE_STD_ZVAL(new_hist
);
437 ZVAL_OBJVAL(new_hist
, ov
, 0);
439 if (Z_TYPE_P(old_hist
) == IS_OBJECT
) {
440 php_http_message_object_prepend(new_hist
, old_hist
, 1 TSRMLS_CC
);
443 zend_update_property(php_http_client_class_entry
, zclient
, ZEND_STRL("history"), new_hist TSRMLS_CC
);
444 zval_ptr_dtor(&new_hist
);
447 /* update response info */
448 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE
, msg
)) {
451 MAKE_STD_ZVAL(message
);
452 ZVAL_OBJVAL(message
, php_http_client_object_message(zclient
, msg TSRMLS_CC
), 0);
453 zend_update_property(php_http_client_class_entry
, zclient
, ZEND_STRL("responseMessage"), message TSRMLS_CC
);
454 zval_ptr_dtor(&message
);
456 obj
->client
->response
.message
= php_http_message_init(NULL
, 0 TSRMLS_CC
);
458 zend_update_property_null(php_http_client_class_entry
, zclient
, ZEND_STRL("responseMessage") TSRMLS_CC
);
461 zend_update_property_null(php_http_client_class_entry
, zclient
, ZEND_STRL("responseMessage") TSRMLS_CC
);
464 if ((msg
= obj
->client
->request
.message
)) {
465 if (PHP_HTTP_MESSAGE_TYPE(REQUEST
, msg
)) {
468 /* update the actual request message */
469 MAKE_STD_ZVAL(message
);
470 ZVAL_OBJVAL(message
, php_http_message_object_new_ex(php_http_message_get_class_entry(), msg
, NULL TSRMLS_CC
), 0);
471 zend_update_property(php_http_client_class_entry
, zclient
, ZEND_STRL("requestMessage"), message TSRMLS_CC
);
472 zval_ptr_dtor(&message
);
473 obj
->client
->request
.message
= php_http_message_init(NULL
, 0 TSRMLS_CC
);
477 if (SUCCESS
== php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO
, &progress
)) {
478 progress
->state
.info
= "finished";
479 progress
->state
.finished
= 1;
480 php_http_client_progress_notify(progress TSRMLS_CC
);
482 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK
, NULL
);
487 void php_http_client_options_set(zval
*this_ptr
, zval
*opts TSRMLS_DC
)
489 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
492 zend_class_entry
*this_ce
= Z_OBJCE_P(getThis());
493 zend_bool is_client
= instanceof_function(this_ce
, php_http_client_class_entry TSRMLS_CC
);
495 MAKE_STD_ZVAL(new_opts
);
496 array_init(new_opts
);
498 if (!opts
|| !zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
499 zend_update_property(this_ce
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
500 zval_ptr_dtor(&new_opts
);
502 zval
*old_opts
, *add_opts
, **opt
;
504 MAKE_STD_ZVAL(add_opts
);
505 array_init(add_opts
);
506 /* some options need extra attention -- thus cannot use array_merge() directly */
507 FOREACH_KEYVAL(pos
, opts
, key
, opt
) {
508 if (key
.type
== HASH_KEY_IS_STRING
) {
509 #define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s))
510 if (Z_TYPE_PP(opt
) == IS_ARRAY
&& (KEYMATCH(key
, "ssl") || KEYMATCH(key
, "cookies"))) {
511 php_http_client_options_set_subr(getThis(), key
.str
, key
.len
, *opt
, 0 TSRMLS_CC
);
512 } else if (is_client
&& (KEYMATCH(key
, "recordHistory") || KEYMATCH(key
, "responseMessageClass"))) {
513 zend_update_property(this_ce
, getThis(), key
.str
, key
.len
-1, *opt TSRMLS_CC
);
514 } else if (Z_TYPE_PP(opt
) == IS_NULL
) {
515 old_opts
= zend_read_property(this_ce
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
516 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
517 zend_symtable_del(Z_ARRVAL_P(old_opts
), key
.str
, key
.len
);
521 add_assoc_zval_ex(add_opts
, key
.str
, key
.len
, *opt
);
526 old_opts
= zend_read_property(this_ce
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
527 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
528 array_copy(Z_ARRVAL_P(old_opts
), Z_ARRVAL_P(new_opts
));
530 array_join(Z_ARRVAL_P(add_opts
), Z_ARRVAL_P(new_opts
), 0, 0);
531 zend_update_property(this_ce
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
532 zval_ptr_dtor(&new_opts
);
533 zval_ptr_dtor(&add_opts
);
537 void php_http_client_options_set_subr(zval
*this_ptr
, char *key
, size_t len
, zval
*opts
, int overwrite TSRMLS_DC
)
539 if (overwrite
|| (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
)))) {
540 zend_class_entry
*this_ce
= Z_OBJCE_P(getThis());
541 zval
*old_opts
, *new_opts
, **entry
= NULL
;
543 MAKE_STD_ZVAL(new_opts
);
544 array_init(new_opts
);
545 old_opts
= zend_read_property(this_ce
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
546 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
547 array_copy(Z_ARRVAL_P(old_opts
), Z_ARRVAL_P(new_opts
));
551 if (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
553 zend_symtable_update(Z_ARRVAL_P(new_opts
), key
, len
, (void *) &opts
, sizeof(zval
*), NULL
);
555 zend_symtable_del(Z_ARRVAL_P(new_opts
), key
, len
);
557 } else if (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
558 if (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(new_opts
), key
, len
, (void *) &entry
)) {
559 array_join(Z_ARRVAL_P(opts
), Z_ARRVAL_PP(entry
), 0, 0);
562 zend_symtable_update(Z_ARRVAL_P(new_opts
), key
, len
, (void *) &opts
, sizeof(zval
*), NULL
);
566 zend_update_property(this_ce
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
567 zval_ptr_dtor(&new_opts
);
571 void php_http_client_options_get_subr(zval
*this_ptr
, char *key
, size_t len
, zval
*return_value TSRMLS_DC
)
573 zend_class_entry
*this_ce
= Z_OBJCE_P(getThis());
574 zval
**options
, *opts
= zend_read_property(this_ce
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
576 if ((Z_TYPE_P(opts
) == IS_ARRAY
) && (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(opts
), key
, len
, (void *) &options
))) {
577 RETVAL_ZVAL(*options
, 1, 0);
581 PHP_METHOD(HttpClient
, __construct
)
583 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
584 zval
*os
, *opts
= NULL
;
587 object_init_ex(os
, spl_ce_SplObjectStorage
);
588 zend_update_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), os TSRMLS_CC
);
591 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
592 php_http_client_options_set(getThis(), opts TSRMLS_CC
);
595 } end_error_handling();
598 PHP_METHOD(HttpClient
, getObservers
)
600 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
601 if (SUCCESS
== zend_parse_parameters_none()) {
602 RETVAL_PROP(php_http_client_class_entry
, "observers");
604 } end_error_handling();
607 static int notify(zend_object_iterator
*iter
, void *puser TSRMLS_DC
)
609 zval
**observer
= NULL
;
611 iter
->funcs
->get_current_data(iter
, &observer TSRMLS_CC
);
615 zend_call_method_with_1_params(observer
, NULL
, NULL
, "update", &retval
, puser
);
616 zval_ptr_dtor(&retval
);
622 PHP_METHOD(HttpClient
, notify
)
624 if (SUCCESS
== zend_parse_parameters_none()) {
625 zval
*observers
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC
);
627 if (Z_TYPE_P(observers
) == IS_OBJECT
) {
628 Z_ADDREF_P(getThis());
629 spl_iterator_apply(observers
, notify
, getThis() TSRMLS_CC
);
630 zval_ptr_dtor(&getThis());
634 RETVAL_ZVAL(getThis(), 1, 0);
637 PHP_METHOD(HttpClient
, attach
)
641 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &observer
, spl_ce_SplObserver
)) {
642 zval
*retval
, *observers
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC
);
643 zend_call_method_with_1_params(&observers
, NULL
, NULL
, "attach", &retval
, observer
);
644 zval_ptr_dtor(&retval
);
647 RETVAL_ZVAL(getThis(), 1, 0);
650 PHP_METHOD(HttpClient
, detach
)
654 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &observer
, spl_ce_SplObserver
)) {
655 zval
*retval
, *observers
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC
);
656 zend_call_method_with_1_params(&observers
, NULL
, NULL
, "detach", &retval
, observer
);
657 zval_ptr_dtor(&retval
);
660 RETVAL_ZVAL(getThis(), 1, 0);
663 PHP_METHOD(HttpClient
, getProgress
)
665 if (SUCCESS
== zend_parse_parameters_none()) {
666 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
667 php_http_client_progress_t
*progress
= NULL
;
669 if (SUCCESS
== php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO
, &progress
)) {
670 object_init(return_value
);
671 add_property_bool(return_value
, "started", progress
->state
.started
);
672 add_property_bool(return_value
, "finished", progress
->state
.finished
);
673 add_property_string(return_value
, "info", STR_PTR(progress
->state
.info
), 1);
674 add_property_double(return_value
, "dltotal", progress
->state
.dl
.total
);
675 add_property_double(return_value
, "dlnow", progress
->state
.dl
.now
);
676 add_property_double(return_value
, "ultotal", progress
->state
.ul
.total
);
677 add_property_double(return_value
, "ulnow", progress
->state
.ul
.now
);
682 PHP_METHOD(HttpClient
, getTransferInfo
)
684 char *info_name
= NULL
;
687 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &info_name
, &info_len
)) {
688 zval
**infop
, *temp
= NULL
, *info
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("transferInfo"), 0 TSRMLS_CC
);
690 /* request completed? */
691 if (Z_TYPE_P(info
) != IS_ARRAY
) {
692 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
696 php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO
, Z_ARRVAL_P(temp
));
700 if (info_len
&& info_name
) {
701 if (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(info
), php_http_pretty_key(info_name
, info_len
, 0, 0), info_len
+ 1, (void *) &infop
)) {
702 RETVAL_ZVAL(*infop
, 1, 0);
704 php_http_error(HE_NOTICE
, PHP_HTTP_E_INVALID_PARAM
, "Could not find transfer info named %s", info_name
);
708 RETVAL_ZVAL(info
, 1, 0);
712 zval_ptr_dtor(&temp
);
719 PHP_METHOD(HttpClient
, setOptions
)
723 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
724 php_http_client_options_set(getThis(), opts TSRMLS_CC
);
726 RETVAL_ZVAL(getThis(), 1, 0);
730 PHP_METHOD(HttpClient
, getOptions
)
732 if (SUCCESS
== zend_parse_parameters_none()) {
733 RETURN_PROP(php_http_client_class_entry
, "options");
738 PHP_METHOD(HttpClient
, setSslOptions
)
742 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
743 php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts
, 1 TSRMLS_CC
);
745 RETVAL_ZVAL(getThis(), 1, 0);
749 PHP_METHOD(HttpClient
, addSslOptions
)
753 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
754 php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts
, 0 TSRMLS_CC
);
756 RETVAL_ZVAL(getThis(), 1, 0);
760 PHP_METHOD(HttpClient
, getSslOptions
)
762 if (SUCCESS
== zend_parse_parameters_none()) {
763 php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC
);
767 PHP_METHOD(HttpClient
, setCookies
)
771 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
772 php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts
, 1 TSRMLS_CC
);
774 RETVAL_ZVAL(getThis(), 1, 0);
778 PHP_METHOD(HttpClient
, addCookies
)
782 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
783 php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts
, 0 TSRMLS_CC
);
785 RETVAL_ZVAL(getThis(), 1, 0);
789 PHP_METHOD(HttpClient
, getCookies
)
791 if (SUCCESS
== zend_parse_parameters_none()) {
792 php_http_client_options_get_subr(getThis(), ZEND_STRS("cookies"), return_value TSRMLS_CC
);
796 PHP_METHOD(HttpClient
, enableCookies
)
798 if (SUCCESS
== zend_parse_parameters_none()){
799 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
801 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_COOKIES_ENABLE
, NULL
);
803 RETVAL_ZVAL(getThis(), 1, 0);
806 PHP_METHOD(HttpClient
, resetCookies
)
808 zend_bool session_only
= 0;
810 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|b", &session_only
)) {
811 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
813 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_COOKIES_RESET_SESSION
, NULL
);
815 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_COOKIES_RESET
, NULL
);
818 RETVAL_ZVAL(getThis(), 1, 0);
821 PHP_METHOD(HttpClient
, flushCookies
)
823 if (SUCCESS
== zend_parse_parameters_none()) {
824 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
826 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_COOKIES_FLUSH
, NULL
);
828 RETVAL_ZVAL(getThis(), 1, 0);
831 PHP_METHOD(HttpClient
, getResponseMessage
)
833 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
834 if (SUCCESS
== zend_parse_parameters_none()) {
835 zval
*message
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC
);
837 if (Z_TYPE_P(message
) == IS_OBJECT
) {
838 RETVAL_OBJECT(message
, 1);
840 php_http_error(HE_WARNING
, PHP_HTTP_E_RUNTIME
, "HttpClient does not contain a response message");
843 } end_error_handling();
846 PHP_METHOD(HttpClient
, getRequestMessage
)
848 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
849 if (SUCCESS
== zend_parse_parameters_none()) {
850 zval
*message
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("requestMessage"), 0 TSRMLS_CC
);
852 if (Z_TYPE_P(message
) == IS_OBJECT
) {
853 RETVAL_OBJECT(message
, 1);
855 php_http_error(HE_WARNING
, PHP_HTTP_E_RUNTIME
, "HttpClient does not contain a request message");
858 } end_error_handling();
861 PHP_METHOD(HttpClient
, getHistory
)
863 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
864 if (SUCCESS
== zend_parse_parameters_none()) {
865 zval
*hist
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC
);
867 if (Z_TYPE_P(hist
) == IS_OBJECT
) {
868 RETVAL_OBJECT(hist
, 1);
870 php_http_error(HE_WARNING
, PHP_HTTP_E_RUNTIME
, "The history is empty");
873 } end_error_handling();
876 PHP_METHOD(HttpClient
, clearHistory
)
878 if (SUCCESS
== zend_parse_parameters_none()) {
879 zend_update_property_null(php_http_client_class_entry
, getThis(), ZEND_STRL("history") TSRMLS_CC
);
881 RETVAL_ZVAL(getThis(), 1, 0);
884 PHP_METHOD(HttpClient
, getResponseMessageClass
)
886 if (SUCCESS
== zend_parse_parameters_none()) {
887 RETURN_PROP(php_http_client_class_entry
, "responseMessageClass");
892 PHP_METHOD(HttpClient
, setResponseMessageClass
)
897 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &cn
, &cl
)) {
898 zend_update_property_stringl(php_http_client_class_entry
, getThis(), ZEND_STRL("responseMessageClass"), cn
, cl TSRMLS_CC
);
900 RETVAL_ZVAL(getThis(), 1, 0);
903 PHP_METHOD(HttpClient
, setRequest
)
907 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &zreq
, php_http_client_request_get_class_entry())) {
908 zend_update_property(php_http_client_class_entry
, getThis(), ZEND_STRL("request"), zreq TSRMLS_CC
);
910 RETURN_ZVAL(getThis(), 1, 0);
913 PHP_METHOD(HttpClient
, getRequest
)
915 if (SUCCESS
== zend_parse_parameters_none()) {
916 RETURN_PROP(php_http_client_class_entry
, "request");
920 PHP_METHOD(HttpClient
, request
)
922 char *meth_str
, *url_str
;
923 int meth_len
, url_len
;
924 zval
*zheader
, *zbody
, *zoptions
;
926 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
927 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|a!z!a!/", &meth_str
, &meth_len
, &url_str
, &url_len
, &zheader
, &zbody
, &zoptions
)) {
928 php_http_message_object_t
*msg_obj
;
929 zend_object_value ov
;
930 zval
*req
, *res
= NULL
;
932 php_http_new(&ov
, php_http_client_request_get_class_entry(), (php_http_new_t
) php_http_message_object_new_ex
, NULL
, NULL
, (void *) &msg_obj TSRMLS_CC
);
934 ZVAL_OBJVAL(req
, ov
, 0);
936 msg_obj
->message
= php_http_message_init(NULL
, PHP_HTTP_REQUEST TSRMLS_CC
);
937 PHP_HTTP_INFO(msg_obj
->message
).request
.url
= estrndup(url_str
, url_len
);
938 PHP_HTTP_INFO(msg_obj
->message
).request
.method
= estrndup(meth_str
, meth_len
);
941 array_copy(Z_ARRVAL_P(zheader
), &msg_obj
->message
->hdrs
);
945 php_http_message_object_set_body(msg_obj
, zbody TSRMLS_CC
);
949 php_http_client_options_set(req
, zoptions TSRMLS_CC
);
952 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "send", &res
, req
);
953 RETVAL_ZVAL(res
, 0, 1);
956 } end_error_handling();
959 PHP_METHOD(HttpClient
, send
)
965 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
966 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|O!", &zreq
, php_http_client_request_get_class_entry())) {
967 if (SUCCESS
== php_http_client_object_handle_request(getThis(), &zreq TSRMLS_CC
)) {
968 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
969 php_http_message_object_t
*req
= zend_object_store_get_object(zreq TSRMLS_CC
);
971 php_http_client_exec(obj
->client
, req
->message
);
973 if (SUCCESS
== php_http_client_object_handle_response(getThis() TSRMLS_CC
)) {
974 RETVAL_PROP(php_http_client_class_entry
, "responseMessage");
976 php_http_error(HE_WARNING
, PHP_HTTP_E_CLIENT
, "Failed to handle response");
979 php_http_error(HE_WARNING
, PHP_HTTP_E_CLIENT
, "Failed to handle request");
982 } end_error_handling();
985 PHP_MINIT_FUNCTION(http_client
)
987 PHP_HTTP_REGISTER_CLASS(http
\\Client
, AbstractClient
, http_client
, php_http_object_get_class_entry(), ZEND_ACC_ABSTRACT
);
988 php_http_client_class_entry
->create_object
= php_http_client_object_new
;
989 memcpy(&php_http_client_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
990 php_http_client_object_handlers
.clone_obj
= php_http_client_object_clone
;
992 zend_class_implements(php_http_client_class_entry TSRMLS_CC
, 2, spl_ce_SplSubject
, php_http_client_interface_get_class_entry());
994 zend_declare_property_string(php_http_client_class_entry
, ZEND_STRL("responseMessageClass"), "", ZEND_ACC_PRIVATE TSRMLS_CC
);
995 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("observers"), ZEND_ACC_PRIVATE TSRMLS_CC
);
996 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("transferInfo"), ZEND_ACC_PRIVATE TSRMLS_CC
);
997 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("responseMessage"), ZEND_ACC_PRIVATE TSRMLS_CC
);
998 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("requestMessage"), ZEND_ACC_PRIVATE TSRMLS_CC
);
999 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("history"), ZEND_ACC_PRIVATE TSRMLS_CC
);
1001 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("options"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1002 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("request"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1004 zend_declare_property_bool(php_http_client_class_entry
, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
1014 * vim600: noet sw=4 ts=4 fdm=marker
1015 * vim<600: noet sw=4 ts=4