1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Sterling Hughes <sterling@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26
27 #if HAVE_CURL
28
29 #include "php_curl.h"
30
31 #include <curl/curl.h>
32 #include <curl/multi.h>
33
34 #ifdef HAVE_SYS_SELECT_H
35 #include <sys/select.h>
36 #endif
37
38 #ifdef HAVE_SYS_TIME_H
39 #include <sys/time.h>
40 #endif
41
42 #ifdef HAVE_SYS_TYPES_H
43 #include <sys/types.h>
44 #endif
45
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49
50 #define SAVE_CURLM_ERROR(__handle, __err) (__handle)->err.no = (int) __err;
51
52 /* {{{ proto resource curl_multi_init(void)
53 Returns a new cURL multi handle */
PHP_FUNCTION(curl_multi_init)54 PHP_FUNCTION(curl_multi_init)
55 {
56 php_curlm *mh;
57
58 if (zend_parse_parameters_none() == FAILURE) {
59 return;
60 }
61
62 mh = ecalloc(1, sizeof(php_curlm));
63 mh->multi = curl_multi_init();
64 mh->handlers = ecalloc(1, sizeof(php_curlm_handlers));
65
66 zend_llist_init(&mh->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0);
67
68 RETURN_RES(zend_register_resource(mh, le_curl_multi_handle));
69 }
70 /* }}} */
71
72 /* {{{ proto int curl_multi_add_handle(resource mh, resource ch)
73 Add a normal cURL handle to a cURL multi handle */
PHP_FUNCTION(curl_multi_add_handle)74 PHP_FUNCTION(curl_multi_add_handle)
75 {
76 zval *z_mh;
77 zval *z_ch;
78 php_curlm *mh;
79 php_curl *ch;
80 CURLMcode error = CURLM_OK;
81
82 ZEND_PARSE_PARAMETERS_START(2,2)
83 Z_PARAM_RESOURCE(z_mh)
84 Z_PARAM_RESOURCE(z_ch)
85 ZEND_PARSE_PARAMETERS_END();
86
87 if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
88 RETURN_FALSE;
89 }
90
91 if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
92 RETURN_FALSE;
93 }
94
95 _php_curl_verify_handlers(ch, 1);
96
97 _php_curl_cleanup_handle(ch);
98
99 GC_ADDREF(Z_RES_P(z_ch));
100 zend_llist_add_element(&mh->easyh, z_ch);
101
102 error = curl_multi_add_handle(mh->multi, ch->cp);
103 SAVE_CURLM_ERROR(mh, error);
104
105 RETURN_LONG((zend_long) error);
106 }
107 /* }}} */
108
_php_curl_multi_cleanup_list(void * data)109 void _php_curl_multi_cleanup_list(void *data) /* {{{ */
110 {
111 zval *z_ch = (zval *)data;
112 php_curl *ch;
113
114 if (!z_ch) {
115 return;
116 }
117 if (!Z_RES_P(z_ch)->ptr) {
118 return;
119 }
120 if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
121 return;
122 }
123
124 zend_list_delete(Z_RES_P(z_ch));
125 }
126 /* }}} */
127
128 /* Used internally as comparison routine passed to zend_list_del_element */
curl_compare_resources(zval * z1,zval * z2)129 static int curl_compare_resources( zval *z1, zval *z2 ) /* {{{ */
130 {
131 return (Z_TYPE_P(z1) == Z_TYPE_P(z2) &&
132 Z_TYPE_P(z1) == IS_RESOURCE &&
133 Z_RES_P(z1) == Z_RES_P(z2));
134 }
135 /* }}} */
136
137 /* Used to find the php_curl resource for a given curl easy handle */
_php_curl_multi_find_easy_handle(php_curlm * mh,CURL * easy)138 static zval *_php_curl_multi_find_easy_handle(php_curlm *mh, CURL *easy) /* {{{ */
139 {
140 php_curl *tmp_ch;
141 zend_llist_position pos;
142 zval *pz_ch_temp;
143
144 for(pz_ch_temp = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch_temp;
145 pz_ch_temp = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
146
147 if ((tmp_ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch_temp), le_curl_name, le_curl)) == NULL) {
148 return NULL;
149 }
150
151 if (tmp_ch->cp == easy) {
152 return pz_ch_temp;
153 }
154 }
155
156 return NULL;
157 }
158 /* }}} */
159
160 /* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
161 Remove a multi handle from a set of cURL handles */
PHP_FUNCTION(curl_multi_remove_handle)162 PHP_FUNCTION(curl_multi_remove_handle)
163 {
164 zval *z_mh;
165 zval *z_ch;
166 php_curlm *mh;
167 php_curl *ch;
168 CURLMcode error = CURLM_OK;
169
170 ZEND_PARSE_PARAMETERS_START(2,2)
171 Z_PARAM_RESOURCE(z_mh)
172 Z_PARAM_RESOURCE(z_ch)
173 ZEND_PARSE_PARAMETERS_END();
174
175 if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
176 RETURN_FALSE;
177 }
178
179 if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
180 RETURN_FALSE;
181 }
182
183 error = curl_multi_remove_handle(mh->multi, ch->cp);
184 SAVE_CURLM_ERROR(mh, error);
185
186 RETVAL_LONG((zend_long) error);
187 zend_llist_del_element(&mh->easyh, z_ch, (int (*)(void *, void *))curl_compare_resources);
188
189 }
190 /* }}} */
191
192 #if LIBCURL_VERSION_NUM < 0x071c00
_make_timeval_struct(struct timeval * to,double timeout)193 static void _make_timeval_struct(struct timeval *to, double timeout) /* {{{ */
194 {
195 unsigned long conv;
196
197 conv = (unsigned long) (timeout * 1000000.0);
198 to->tv_sec = conv / 1000000;
199 to->tv_usec = conv % 1000000;
200 }
201 /* }}} */
202 #endif
203
204 /* {{{ proto int curl_multi_select(resource mh[, double timeout])
205 Get all the sockets associated with the cURL extension, which can then be "selected" */
PHP_FUNCTION(curl_multi_select)206 PHP_FUNCTION(curl_multi_select)
207 {
208 zval *z_mh;
209 php_curlm *mh;
210 double timeout = 1.0;
211 #if LIBCURL_VERSION_NUM >= 0x071c00 /* Available since 7.28.0 */
212 int numfds = 0;
213 #else
214 fd_set readfds;
215 fd_set writefds;
216 fd_set exceptfds;
217 int maxfd;
218 struct timeval to;
219 #endif
220 CURLMcode error = CURLM_OK;
221
222 ZEND_PARSE_PARAMETERS_START(1,2)
223 Z_PARAM_RESOURCE(z_mh)
224 Z_PARAM_OPTIONAL
225 Z_PARAM_DOUBLE(timeout)
226 ZEND_PARSE_PARAMETERS_END();
227
228 if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
229 RETURN_FALSE;
230 }
231
232 #if LIBCURL_VERSION_NUM >= 0x071c00 /* Available since 7.28.0 */
233 error = curl_multi_wait(mh->multi, NULL, 0, (unsigned long) (timeout * 1000.0), &numfds);
234 if (CURLM_OK != error) {
235 SAVE_CURLM_ERROR(mh, error);
236 RETURN_LONG(-1);
237 }
238
239 RETURN_LONG(numfds);
240 #else
241 _make_timeval_struct(&to, timeout);
242
243 FD_ZERO(&readfds);
244 FD_ZERO(&writefds);
245 FD_ZERO(&exceptfds);
246
247 error = curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd);
248 SAVE_CURLM_ERROR(mh, error);
249
250 if (maxfd == -1) {
251 RETURN_LONG(-1);
252 }
253 RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to));
254 #endif
255 }
256 /* }}} */
257
258 /* {{{ proto int curl_multi_exec(resource mh, int &still_running)
259 Run the sub-connections of the current cURL handle */
PHP_FUNCTION(curl_multi_exec)260 PHP_FUNCTION(curl_multi_exec)
261 {
262 zval *z_mh;
263 zval *z_still_running;
264 php_curlm *mh;
265 int still_running;
266 CURLMcode error = CURLM_OK;
267
268 ZEND_PARSE_PARAMETERS_START(2, 2)
269 Z_PARAM_RESOURCE(z_mh)
270 Z_PARAM_ZVAL_DEREF(z_still_running)
271 ZEND_PARSE_PARAMETERS_END();
272
273 if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
274 RETURN_FALSE;
275 }
276
277 {
278 zend_llist_position pos;
279 php_curl *ch;
280 zval *pz_ch;
281
282 for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
283 pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
284
285 if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl)) == NULL) {
286 RETURN_FALSE;
287 }
288
289 _php_curl_verify_handlers(ch, 1);
290 }
291 }
292
293 still_running = zval_get_long(z_still_running);
294 error = curl_multi_perform(mh->multi, &still_running);
295 zval_ptr_dtor(z_still_running);
296 ZVAL_LONG(z_still_running, still_running);
297
298 SAVE_CURLM_ERROR(mh, error);
299 RETURN_LONG((zend_long) error);
300 }
301 /* }}} */
302
303 /* {{{ proto string curl_multi_getcontent(resource ch)
304 Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
PHP_FUNCTION(curl_multi_getcontent)305 PHP_FUNCTION(curl_multi_getcontent)
306 {
307 zval *z_ch;
308 php_curl *ch;
309
310 ZEND_PARSE_PARAMETERS_START(1,1)
311 Z_PARAM_RESOURCE(z_ch)
312 ZEND_PARSE_PARAMETERS_END();
313
314 if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
315 RETURN_FALSE;
316 }
317
318 if (ch->handlers->write->method == PHP_CURL_RETURN) {
319 if (!ch->handlers->write->buf.s) {
320 RETURN_EMPTY_STRING();
321 }
322 smart_str_0(&ch->handlers->write->buf);
323 RETURN_STR_COPY(ch->handlers->write->buf.s);
324 }
325
326 RETURN_NULL();
327 }
328 /* }}} */
329
330 /* {{{ proto array curl_multi_info_read(resource mh [, int &msgs_in_queue])
331 Get information about the current transfers */
PHP_FUNCTION(curl_multi_info_read)332 PHP_FUNCTION(curl_multi_info_read)
333 {
334 zval *z_mh;
335 php_curlm *mh;
336 CURLMsg *tmp_msg;
337 int queued_msgs;
338 zval *zmsgs_in_queue = NULL;
339 php_curl *ch;
340
341 ZEND_PARSE_PARAMETERS_START(1, 2)
342 Z_PARAM_RESOURCE(z_mh)
343 Z_PARAM_OPTIONAL
344 Z_PARAM_ZVAL_DEREF(zmsgs_in_queue)
345 ZEND_PARSE_PARAMETERS_END();
346
347 if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
348 RETURN_FALSE;
349 }
350
351 tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
352 if (tmp_msg == NULL) {
353 RETURN_FALSE;
354 }
355 if (zmsgs_in_queue) {
356 zval_ptr_dtor(zmsgs_in_queue);
357 ZVAL_LONG(zmsgs_in_queue, queued_msgs);
358 }
359
360 array_init(return_value);
361 add_assoc_long(return_value, "msg", tmp_msg->msg);
362 add_assoc_long(return_value, "result", tmp_msg->data.result);
363
364 /* find the original easy curl handle */
365 {
366 zval *pz_ch = _php_curl_multi_find_easy_handle(mh, tmp_msg->easy_handle);
367 if (pz_ch != NULL) {
368 /* we are adding a reference to the underlying php_curl
369 resource, so we need to add one to the resource's refcount
370 in order to ensure it doesn't get destroyed when the
371 underlying curl easy handle goes out of scope.
372 Normally you would call zval_copy_ctor( pz_ch ), or
373 SEPARATE_ZVAL, but those create new zvals, which is already
374 being done in add_assoc_resource */
375 Z_ADDREF_P(pz_ch);
376
377 /* we must save result to be able to read error message */
378 ch = (php_curl*)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl);
379 SAVE_CURL_ERROR(ch, tmp_msg->data.result);
380
381 /* add_assoc_resource automatically creates a new zval to
382 wrap the "resource" represented by the current pz_ch */
383
384 add_assoc_zval(return_value, "handle", pz_ch);
385 }
386 }
387 }
388 /* }}} */
389
390 /* {{{ proto void curl_multi_close(resource mh)
391 Close a set of cURL handles */
PHP_FUNCTION(curl_multi_close)392 PHP_FUNCTION(curl_multi_close)
393 {
394 zval *z_mh;
395 php_curlm *mh;
396
397 ZEND_PARSE_PARAMETERS_START(1,1)
398 Z_PARAM_RESOURCE(z_mh)
399 ZEND_PARSE_PARAMETERS_END();
400
401 if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
402 RETURN_FALSE;
403 }
404
405 zend_list_close(Z_RES_P(z_mh));
406 }
407 /* }}} */
408
_php_curl_multi_close(zend_resource * rsrc)409 void _php_curl_multi_close(zend_resource *rsrc) /* {{{ */
410 {
411 php_curlm *mh = (php_curlm *)rsrc->ptr;
412 if (mh) {
413 zend_llist_position pos;
414 php_curl *ch;
415 zval *pz_ch;
416
417 for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
418 pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
419 /* ptr is NULL means it already be freed */
420 if (Z_RES_P(pz_ch)->ptr) {
421 if ((ch = (php_curl *) zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl))) {
422 _php_curl_verify_handlers(ch, 0);
423 }
424 }
425 }
426
427 curl_multi_cleanup(mh->multi);
428 zend_llist_clean(&mh->easyh);
429 if (mh->handlers->server_push) {
430 zval_ptr_dtor(&mh->handlers->server_push->func_name);
431 efree(mh->handlers->server_push);
432 }
433 if (mh->handlers) {
434 efree(mh->handlers);
435 }
436 efree(mh);
437 rsrc->ptr = NULL;
438 }
439 }
440 /* }}} */
441
442 /* {{{ proto int curl_multi_errno(resource mh)
443 Return an integer containing the last multi curl error number */
PHP_FUNCTION(curl_multi_errno)444 PHP_FUNCTION(curl_multi_errno)
445 {
446 zval *z_mh;
447 php_curlm *mh;
448
449 ZEND_PARSE_PARAMETERS_START(1,1)
450 Z_PARAM_RESOURCE(z_mh)
451 ZEND_PARSE_PARAMETERS_END();
452
453 if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
454 RETURN_FALSE;
455 }
456
457 RETURN_LONG(mh->err.no);
458 }
459 /* }}} */
460
461 /* {{{ proto bool curl_multi_strerror(int code)
462 return string describing error code */
PHP_FUNCTION(curl_multi_strerror)463 PHP_FUNCTION(curl_multi_strerror)
464 {
465 zend_long code;
466 const char *str;
467
468 ZEND_PARSE_PARAMETERS_START(1,1)
469 Z_PARAM_LONG(code)
470 ZEND_PARSE_PARAMETERS_END();
471
472 str = curl_multi_strerror(code);
473 if (str) {
474 RETURN_STRING(str);
475 } else {
476 RETURN_NULL();
477 }
478 }
479 /* }}} */
480
481 #if LIBCURL_VERSION_NUM >= 0x072C00 /* Available since 7.44.0 */
482
_php_server_push_callback(CURL * parent_ch,CURL * easy,size_t num_headers,struct curl_pushheaders * push_headers,void * userp)483 static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_headers, struct curl_pushheaders *push_headers, void *userp) /* {{{ */
484 {
485 php_curl *ch;
486 php_curl *parent;
487 php_curlm *mh = (php_curlm *)userp;
488 size_t rval = CURL_PUSH_DENY;
489 php_curlm_server_push *t = mh->handlers->server_push;
490 zval *pz_parent_ch = NULL;
491 zval pz_ch;
492 zval headers;
493 zval retval;
494 zend_resource *res;
495 char *header;
496 int error;
497 zend_fcall_info fci = empty_fcall_info;
498
499 pz_parent_ch = _php_curl_multi_find_easy_handle(mh, parent_ch);
500 if (pz_parent_ch == NULL) {
501 return rval;
502 }
503
504 parent = (php_curl*)zend_fetch_resource(Z_RES_P(pz_parent_ch), le_curl_name, le_curl);
505
506 ch = alloc_curl_handle();
507 ch->cp = easy;
508 _php_setup_easy_copy_handlers(ch, parent);
509
510 Z_ADDREF_P(pz_parent_ch);
511
512 res = zend_register_resource(ch, le_curl);
513 ch->res = res;
514 ZVAL_RES(&pz_ch, res);
515
516 size_t i;
517 array_init(&headers);
518 for(i=0; i<num_headers; i++) {
519 header = curl_pushheader_bynum(push_headers, i);
520 add_next_index_string(&headers, header);
521 }
522
523 zend_fcall_info_init(&t->func_name, 0, &fci, &t->fci_cache, NULL, NULL);
524
525 zend_fcall_info_argn(
526 &fci, 3,
527 pz_parent_ch,
528 &pz_ch,
529 &headers
530 );
531
532 fci.retval = &retval;
533
534 error = zend_call_function(&fci, &t->fci_cache);
535 zend_fcall_info_args_clear(&fci, 1);
536 zval_ptr_dtor_nogc(&headers);
537
538 if (error == FAILURE) {
539 php_error_docref(NULL, E_WARNING, "Cannot call the CURLMOPT_PUSHFUNCTION");
540 } else if (!Z_ISUNDEF(retval)) {
541 if (CURL_PUSH_DENY != zval_get_long(&retval)) {
542 rval = CURL_PUSH_OK;
543 GC_ADDREF(Z_RES(pz_ch));
544 zend_llist_add_element(&mh->easyh, &pz_ch);
545 } else {
546 /* libcurl will free this easy handle, avoid double free */
547 ch->cp = NULL;
548 }
549 }
550
551 return rval;
552 }
553 /* }}} */
554
555 #endif
556
_php_curl_multi_setopt(php_curlm * mh,zend_long option,zval * zvalue,zval * return_value)557 static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue, zval *return_value) /* {{{ */
558 {
559 CURLMcode error = CURLM_OK;
560
561 switch (option) {
562 #if LIBCURL_VERSION_NUM >= 0x071000 /* 7.16.0 */
563 case CURLMOPT_PIPELINING:
564 #endif
565 #if LIBCURL_VERSION_NUM >= 0x071003 /* 7.16.3 */
566 case CURLMOPT_MAXCONNECTS:
567 #endif
568 #if LIBCURL_VERSION_NUM >= 0x071e00 /* 7.30.0 */
569 case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
570 case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
571 case CURLMOPT_MAX_HOST_CONNECTIONS:
572 case CURLMOPT_MAX_PIPELINE_LENGTH:
573 case CURLMOPT_MAX_TOTAL_CONNECTIONS:
574 #endif
575 error = curl_multi_setopt(mh->multi, option, zval_get_long(zvalue));
576 break;
577 #if LIBCURL_VERSION_NUM > 0x072D00 /* Available since 7.46.0 */
578 case CURLMOPT_PUSHFUNCTION:
579 if (mh->handlers->server_push == NULL) {
580 mh->handlers->server_push = ecalloc(1, sizeof(php_curlm_server_push));
581 } else if (!Z_ISUNDEF(mh->handlers->server_push->func_name)) {
582 zval_ptr_dtor(&mh->handlers->server_push->func_name);
583 mh->handlers->server_push->fci_cache = empty_fcall_info_cache;
584 }
585
586 ZVAL_COPY(&mh->handlers->server_push->func_name, zvalue);
587 mh->handlers->server_push->method = PHP_CURL_USER;
588 error = curl_multi_setopt(mh->multi, option, _php_server_push_callback);
589 if (error != CURLM_OK) {
590 return 0;
591 }
592 error = curl_multi_setopt(mh->multi, CURLMOPT_PUSHDATA, mh);
593 break;
594 #endif
595 default:
596 php_error_docref(NULL, E_WARNING, "Invalid curl multi configuration option");
597 error = CURLM_UNKNOWN_OPTION;
598 break;
599 }
600
601 SAVE_CURLM_ERROR(mh, error);
602 if (error != CURLM_OK) {
603 return 1;
604 } else {
605 return 0;
606 }
607 }
608 /* }}} */
609
610 /* {{{ proto int curl_multi_setopt(resource mh, int option, mixed value)
611 Set an option for the curl multi handle */
PHP_FUNCTION(curl_multi_setopt)612 PHP_FUNCTION(curl_multi_setopt)
613 {
614 zval *z_mh, *zvalue;
615 zend_long options;
616 php_curlm *mh;
617
618 ZEND_PARSE_PARAMETERS_START(3,3)
619 Z_PARAM_RESOURCE(z_mh)
620 Z_PARAM_LONG(options)
621 Z_PARAM_ZVAL(zvalue)
622 ZEND_PARSE_PARAMETERS_END();
623
624 if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
625 RETURN_FALSE;
626 }
627
628 if (!_php_curl_multi_setopt(mh, options, zvalue, return_value)) {
629 RETURN_TRUE;
630 } else {
631 RETURN_FALSE;
632 }
633 }
634 /* }}} */
635
636 #endif
637
638 /*
639 * Local variables:
640 * tab-width: 4
641 * c-basic-offset: 4
642 * End:
643 * vim600: noet sw=4 ts=4 fdm=marker
644 * vim<600: noet sw=4 ts=4
645 */
646