php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
interface.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Sterling Hughes <sterling@php.net> |
14 +----------------------------------------------------------------------+
15*/
16
17#define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include "php.h"
25
26#include <stdio.h>
27#include <string.h>
28
29#ifdef PHP_WIN32
30#include <winsock2.h>
31#include <sys/types.h>
32#endif
33
34#include <curl/curl.h>
35#include <curl/easy.h>
36
37/* As of curl 7.11.1 this is no longer defined inside curl.h */
38#ifndef HttpPost
39#define HttpPost curl_httppost
40#endif
41
42/* {{{ cruft for thread safe SSL crypto locks */
43#if defined(ZTS) && defined(HAVE_CURL_OLD_OPENSSL)
44# if defined(HAVE_OPENSSL_CRYPTO_H)
45# define PHP_CURL_NEED_OPENSSL_TSL
46# include <openssl/crypto.h>
47# else
48# warning \
49 "libcurl was compiled with OpenSSL support, but configure could not find " \
50 "openssl/crypto.h; thus no SSL crypto locking callbacks will be set, which may " \
51 "cause random crashes on SSL requests"
52# endif
53#endif /* ZTS && HAVE_CURL_OLD_OPENSSL */
54/* }}} */
55
56#include "zend_smart_str.h"
57#include "ext/standard/info.h"
58#include "ext/standard/file.h"
59#include "ext/standard/url.h"
60#include "curl_private.h"
61
62#ifdef __GNUC__
63/* don't complain about deprecated CURLOPT_* we're exposing to PHP; we
64 need to keep using those to avoid breaking PHP API compatibiltiy */
65# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
66#endif
67
68#include "curl_arginfo.h"
69
70#ifdef PHP_CURL_NEED_OPENSSL_TSL /* {{{ */
71static MUTEX_T *php_curl_openssl_tsl = NULL;
72
73/* Locking callbacks are no longer used since OpenSSL 1.1. Mark the functions as unused to
74 * avoid warnings due to this. */
75static ZEND_ATTRIBUTE_UNUSED void php_curl_ssl_lock(int mode, int n, const char * file, int line)
76{
77 if (mode & CRYPTO_LOCK) {
78 tsrm_mutex_lock(php_curl_openssl_tsl[n]);
79 } else {
80 tsrm_mutex_unlock(php_curl_openssl_tsl[n]);
81 }
82}
83
84static ZEND_ATTRIBUTE_UNUSED unsigned long php_curl_ssl_id(void)
85{
86 return (unsigned long) tsrm_thread_id();
87}
88#endif
89/* }}} */
90
91#define CAAL(s, v) add_assoc_long_ex(return_value, s, sizeof(s) - 1, (zend_long) v);
92#define CAAD(s, v) add_assoc_double_ex(return_value, s, sizeof(s) - 1, (double) v);
93#define CAAS(s, v) add_assoc_string_ex(return_value, s, sizeof(s) - 1, (char *) (v ? v : ""));
94#define CAASTR(s, v) add_assoc_str_ex(return_value, s, sizeof(s) - 1, \
95 v ? zend_string_copy(v) : ZSTR_EMPTY_ALLOC());
96#define CAAZ(s, v) add_assoc_zval_ex(return_value, s, sizeof(s) -1 , (zval *) v);
97
98#if defined(PHP_WIN32) || defined(__GNUC__)
99# define php_curl_ret(__ret) RETVAL_FALSE; return __ret;
100#else
101# define php_curl_ret(__ret) RETVAL_FALSE; return;
102#endif
103
104static zend_result php_curl_option_str(php_curl *ch, zend_long option, const char *str, const size_t len)
105{
106 if (zend_char_has_nul_byte(str, len)) {
107 zend_value_error("%s(): cURL option must not contain any null bytes", get_active_function_name());
108 return FAILURE;
109 }
110
111 CURLcode error = curl_easy_setopt(ch->cp, option, str);
113
114 return error == CURLE_OK ? SUCCESS : FAILURE;
115}
116
117static zend_result php_curl_option_url(php_curl *ch, const zend_string *url) /* {{{ */
118{
119 /* Disable file:// if open_basedir are used */
120 if (PG(open_basedir) && *PG(open_basedir)) {
121 curl_easy_setopt(ch->cp, CURLOPT_PROTOCOLS, CURLPROTO_ALL & ~CURLPROTO_FILE);
122 }
123
124#ifdef PHP_WIN32
125 if (
127 && '/' != ZSTR_VAL(url)[sizeof("file://") - 1]
128 && ZSTR_LEN(url) < MAXPATHLEN - 2
129 ) {
130 char _tmp[MAXPATHLEN] = {0};
131
132 memmove(_tmp, "file:///", sizeof("file:///") - 1);
133 memmove(_tmp + sizeof("file:///") - 1, ZSTR_VAL(url) + sizeof("file://") - 1, ZSTR_LEN(url) - sizeof("file://") + 1);
134
135 return php_curl_option_str(ch, CURLOPT_URL, _tmp, ZSTR_LEN(url) + 1);
136 }
137#endif
138
139 return php_curl_option_str(ch, CURLOPT_URL, ZSTR_VAL(url), ZSTR_LEN(url));
140}
141/* }}} */
142
143void _php_curl_verify_handlers(php_curl *ch, bool reporterror) /* {{{ */
144{
145 php_stream *stream;
146
148
149 if (!Z_ISUNDEF(ch->handlers.std_err)) {
151 if (stream == NULL) {
152 if (reporterror) {
153 php_error_docref(NULL, E_WARNING, "CURLOPT_STDERR resource has gone away, resetting to stderr");
154 }
155 zval_ptr_dtor(&ch->handlers.std_err);
156 ZVAL_UNDEF(&ch->handlers.std_err);
157
158 curl_easy_setopt(ch->cp, CURLOPT_STDERR, stderr);
159 }
160 }
161 if (ch->handlers.read && !Z_ISUNDEF(ch->handlers.read->stream)) {
162 stream = (php_stream *)zend_fetch_resource2_ex(&ch->handlers.read->stream, NULL, php_file_le_stream(), php_file_le_pstream());
163 if (stream == NULL) {
164 if (reporterror) {
165 php_error_docref(NULL, E_WARNING, "CURLOPT_INFILE resource has gone away, resetting to default");
166 }
167 zval_ptr_dtor(&ch->handlers.read->stream);
168 ZVAL_UNDEF(&ch->handlers.read->stream);
169 ch->handlers.read->res = NULL;
170 ch->handlers.read->fp = 0;
171
172 curl_easy_setopt(ch->cp, CURLOPT_INFILE, (void *) ch);
173 }
174 }
175 if (ch->handlers.write_header && !Z_ISUNDEF(ch->handlers.write_header->stream)) {
176 stream = (php_stream *)zend_fetch_resource2_ex(&ch->handlers.write_header->stream, NULL, php_file_le_stream(), php_file_le_pstream());
177 if (stream == NULL) {
178 if (reporterror) {
179 php_error_docref(NULL, E_WARNING, "CURLOPT_WRITEHEADER resource has gone away, resetting to default");
180 }
181 zval_ptr_dtor(&ch->handlers.write_header->stream);
182 ZVAL_UNDEF(&ch->handlers.write_header->stream);
183 ch->handlers.write_header->fp = 0;
184
185 ch->handlers.write_header->method = PHP_CURL_IGNORE;
186 curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch);
187 }
188 }
189 if (ch->handlers.write && !Z_ISUNDEF(ch->handlers.write->stream)) {
190 stream = (php_stream *)zend_fetch_resource2_ex(&ch->handlers.write->stream, NULL, php_file_le_stream(), php_file_le_pstream());
191 if (stream == NULL) {
192 if (reporterror) {
193 php_error_docref(NULL, E_WARNING, "CURLOPT_FILE resource has gone away, resetting to default");
194 }
195 zval_ptr_dtor(&ch->handlers.write->stream);
196 ZVAL_UNDEF(&ch->handlers.write->stream);
197 ch->handlers.write->fp = 0;
198
199 ch->handlers.write->method = PHP_CURL_STDOUT;
200 curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch);
201 }
202 }
203 return;
204}
205/* }}} */
206
207/* {{{ curl_module_entry */
210 "curl",
211 ext_functions,
212 PHP_MINIT(curl),
213 PHP_MSHUTDOWN(curl),
214 NULL,
215 NULL,
216 PHP_MINFO(curl),
219};
220/* }}} */
221
222#ifdef COMPILE_DL_CURL
223ZEND_GET_MODULE (curl)
224#endif
225
226/* CurlHandle class */
227
230static zend_object_handlers curl_object_handlers;
231
232static zend_object *curl_create_object(zend_class_entry *class_type);
233static void curl_free_obj(zend_object *object);
234static HashTable *curl_get_gc(zend_object *object, zval **table, int *n);
235static zend_function *curl_get_constructor(zend_object *object);
236static zend_object *curl_clone_obj(zend_object *object);
238static inline zend_result build_mime_structure_from_hash(php_curl *ch, zval *zpostfields);
239
240/* {{{ PHP_INI_BEGIN */
242 PHP_INI_ENTRY("curl.cainfo", "", PHP_INI_SYSTEM, NULL)
244/* }}} */
245
246/* {{{ PHP_MINFO_FUNCTION */
248{
249 curl_version_info_data *d;
250 char **p;
251 char str[1024];
252 size_t n = 0;
253
254 d = curl_version_info(CURLVERSION_NOW);
256 php_info_print_table_row(2, "cURL support", "enabled");
257 php_info_print_table_row(2, "cURL Information", d->version);
258 snprintf(str, sizeof(str), "%d", d->age);
259 php_info_print_table_row(2, "Age", str);
260
261 /* To update on each new cURL release using src/main.c in cURL sources */
262 /* make sure to sync this list with curl_version as well */
263 if (d->features) {
264 struct feat {
265 const char *name;
266 int bitmask;
267 };
268
269 unsigned int i;
270
271 static const struct feat feats[] = {
272 {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
273 {"CharConv", CURL_VERSION_CONV},
274 {"Debug", CURL_VERSION_DEBUG},
275 {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
276 {"IDN", CURL_VERSION_IDN},
277 {"IPv6", CURL_VERSION_IPV6},
278 {"krb4", CURL_VERSION_KERBEROS4},
279 {"Largefile", CURL_VERSION_LARGEFILE},
280 {"libz", CURL_VERSION_LIBZ},
281 {"NTLM", CURL_VERSION_NTLM},
282 {"NTLMWB", CURL_VERSION_NTLM_WB},
283 {"SPNEGO", CURL_VERSION_SPNEGO},
284 {"SSL", CURL_VERSION_SSL},
285 {"SSPI", CURL_VERSION_SSPI},
286 {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP},
287 {"HTTP2", CURL_VERSION_HTTP2},
288 {"GSSAPI", CURL_VERSION_GSSAPI},
289 {"KERBEROS5", CURL_VERSION_KERBEROS5},
290 {"UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS},
291 {"PSL", CURL_VERSION_PSL},
292 {"HTTPS_PROXY", CURL_VERSION_HTTPS_PROXY},
293 {"MULTI_SSL", CURL_VERSION_MULTI_SSL},
294 {"BROTLI", CURL_VERSION_BROTLI},
295#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */
296 {"ALTSVC", CURL_VERSION_ALTSVC},
297#endif
298#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */
299 {"HTTP3", CURL_VERSION_HTTP3},
300#endif
301#if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */
302 {"UNICODE", CURL_VERSION_UNICODE},
303 {"ZSTD", CURL_VERSION_ZSTD},
304#endif
305#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */
306 {"HSTS", CURL_VERSION_HSTS},
307#endif
308#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */
309 {"GSASL", CURL_VERSION_GSASL},
310#endif
311 {NULL, 0}
312 };
313
314 php_info_print_table_row(1, "Features");
315 for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
316 if (feats[i].name) {
317 php_info_print_table_row(2, feats[i].name, d->features & feats[i].bitmask ? "Yes" : "No");
318 }
319 }
320 }
321
322 n = 0;
323 p = (char **) d->protocols;
324 while (*p != NULL) {
325 n += snprintf(str + n, sizeof(str) - n, "%s%s", *p, *(p + 1) != NULL ? ", " : "");
326 p++;
327 }
328 php_info_print_table_row(2, "Protocols", str);
329
330 php_info_print_table_row(2, "Host", d->host);
331
332 if (d->ssl_version) {
333 php_info_print_table_row(2, "SSL Version", d->ssl_version);
334 }
335
336 if (d->libz_version) {
337 php_info_print_table_row(2, "ZLib Version", d->libz_version);
338 }
339
340#if defined(CURLVERSION_SECOND) && CURLVERSION_NOW >= CURLVERSION_SECOND
341 if (d->ares) {
342 php_info_print_table_row(2, "ZLib Version", d->ares);
343 }
344#endif
345
346#if defined(CURLVERSION_THIRD) && CURLVERSION_NOW >= CURLVERSION_THIRD
347 if (d->libidn) {
348 php_info_print_table_row(2, "libIDN Version", d->libidn);
349 }
350#endif
351
352 if (d->iconv_ver_num) {
353 php_info_print_table_row(2, "IconV Version", d->iconv_ver_num);
354 }
355
356 if (d->libssh_version) {
357 php_info_print_table_row(2, "libSSH Version", d->libssh_version);
358 }
359
361
363}
364/* }}} */
365
366/* {{{ PHP_MINIT_FUNCTION */
368{
370
371 register_curl_symbols(module_number);
372
373#ifdef PHP_CURL_NEED_OPENSSL_TSL
374 if (!CRYPTO_get_id_callback()) {
375 int i, c = CRYPTO_num_locks();
376
377 php_curl_openssl_tsl = malloc(c * sizeof(MUTEX_T));
378 if (!php_curl_openssl_tsl) {
379 return FAILURE;
380 }
381
382 for (i = 0; i < c; ++i) {
383 php_curl_openssl_tsl[i] = tsrm_mutex_alloc();
384 }
385
386 CRYPTO_set_id_callback(php_curl_ssl_id);
387 CRYPTO_set_locking_callback(php_curl_ssl_lock);
388 }
389#endif
390
391 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
392 return FAILURE;
393 }
394
395 curl_ce = register_class_CurlHandle();
396 curl_ce->create_object = curl_create_object;
397 curl_ce->default_object_handlers = &curl_object_handlers;
398
399 memcpy(&curl_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
400 curl_object_handlers.offset = XtOffsetOf(php_curl, std);
401 curl_object_handlers.free_obj = curl_free_obj;
402 curl_object_handlers.get_gc = curl_get_gc;
403 curl_object_handlers.get_constructor = curl_get_constructor;
404 curl_object_handlers.clone_obj = curl_clone_obj;
405 curl_object_handlers.cast_object = curl_cast_object;
406 curl_object_handlers.compare = zend_objects_not_comparable;
407
408 curl_multi_ce = register_class_CurlMultiHandle();
410
411 curl_share_ce = register_class_CurlShareHandle();
414
415 return SUCCESS;
416}
417/* }}} */
418
419/* CurlHandle class */
420
421static zend_object *curl_create_object(zend_class_entry *class_type) {
422 php_curl *intern = zend_object_alloc(sizeof(php_curl), class_type);
423
424 zend_object_std_init(&intern->std, class_type);
425 object_properties_init(&intern->std, class_type);
426
427 return &intern->std;
428}
429
430static zend_function *curl_get_constructor(zend_object *object) {
431 zend_throw_error(NULL, "Cannot directly construct CurlHandle, use curl_init() instead");
432 return NULL;
433}
434
435static zend_object *curl_clone_obj(zend_object *object) {
436 php_curl *ch;
437 CURL *cp;
438 zval *postfields;
439 zend_object *clone_object;
440 php_curl *clone_ch;
441
442 clone_object = curl_create_object(curl_ce);
443 clone_ch = curl_from_obj(clone_object);
444 init_curl_handle(clone_ch);
445
446 ch = curl_from_obj(object);
447 cp = curl_easy_duphandle(ch->cp);
448 if (!cp) {
449 zend_throw_exception(NULL, "Failed to clone CurlHandle", 0);
450 return &clone_ch->std;
451 }
452
453 clone_ch->cp = cp;
455
456 postfields = &clone_ch->postfields;
457 if (Z_TYPE_P(postfields) != IS_UNDEF) {
458 if (build_mime_structure_from_hash(clone_ch, postfields) == FAILURE) {
459 zend_throw_exception(NULL, "Failed to clone CurlHandle", 0);
460 return &clone_ch->std;
461 }
462 }
463
464 return &clone_ch->std;
465}
466
467static HashTable *curl_get_gc(zend_object *object, zval **table, int *n)
468{
469 php_curl *curl = curl_from_obj(object);
470
472
473 zend_get_gc_buffer_add_zval(gc_buffer, &curl->postfields);
474 if (curl->handlers.read) {
476 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.read->fcc);
477 }
478 zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.read->stream);
479 }
480
481 if (curl->handlers.write) {
483 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.write->fcc);
484 }
485 zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write->stream);
486 }
487
488 if (curl->handlers.write_header) {
490 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.write_header->fcc);
491 }
492 zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write_header->stream);
493 }
494
496 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.progress);
497 }
498
500 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.xferinfo);
501 }
502
504 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.fnmatch);
505 }
506
508 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.debug);
509 }
510
511#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
512 if (ZEND_FCC_INITIALIZED(curl->handlers.prereq)) {
513 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.prereq);
514 }
515#endif
516#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
517 if (ZEND_FCC_INITIALIZED(curl->handlers.sshhostkey)) {
518 zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.sshhostkey);
519 }
520#endif
521
522 zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.std_err);
523 zend_get_gc_buffer_add_zval(gc_buffer, &curl->private_data);
524
525 zend_get_gc_buffer_use(gc_buffer, table, n);
526
527 return zend_std_get_properties(object);
528}
529
531{
532 if (type == IS_LONG) {
533 /* For better backward compatibility, make (int) $curl_handle return the object ID,
534 * similar to how it previously returned the resource ID. */
535 ZVAL_LONG(result, obj->handle);
536 return SUCCESS;
537 }
538
540}
541
542/* {{{ PHP_MSHUTDOWN_FUNCTION */
544{
545 curl_global_cleanup();
546#ifdef PHP_CURL_NEED_OPENSSL_TSL
547 if (php_curl_openssl_tsl) {
548 int i, c = CRYPTO_num_locks();
549
550 CRYPTO_set_id_callback(NULL);
551 CRYPTO_set_locking_callback(NULL);
552
553 for (i = 0; i < c; ++i) {
554 tsrm_mutex_free(php_curl_openssl_tsl[i]);
555 }
556
557 free(php_curl_openssl_tsl);
558 php_curl_openssl_tsl = NULL;
559 }
560#endif
562 return SUCCESS;
563}
564/* }}} */
565
566/* {{{ curl_write */
567static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
568{
569 php_curl *ch = (php_curl *) ctx;
570 php_curl_write *write_handler = ch->handlers.write;
571 size_t length = size * nmemb;
572
573#if PHP_CURL_DEBUG
574 fprintf(stderr, "curl_write() called\n");
575 fprintf(stderr, "data = %s, size = %d, nmemb = %d, ctx = %x\n", data, size, nmemb, ctx);
576#endif
577
578 switch (write_handler->method) {
579 case PHP_CURL_STDOUT:
580 PHPWRITE(data, length);
581 break;
582 case PHP_CURL_FILE:
583 return fwrite(data, size, nmemb, write_handler->fp);
584 case PHP_CURL_RETURN:
585 if (length > 0) {
586 smart_str_appendl(&write_handler->buf, data, (int) length);
587 }
588 break;
589 case PHP_CURL_USER: {
590 zval argv[2];
591 zval retval;
592
593 GC_ADDREF(&ch->std);
594 ZVAL_OBJ(&argv[0], &ch->std);
595 ZVAL_STRINGL(&argv[1], data, length);
596
597 ch->in_callback = true;
598 zend_call_known_fcc(&write_handler->fcc, &retval, /* param_count */ 2, argv, /* named_params */ NULL);
599 ch->in_callback = false;
600 if (!Z_ISUNDEF(retval)) {
601 _php_curl_verify_handlers(ch, /* reporterror */ true);
602 /* TODO Check callback returns an int or something castable to int */
603 length = zval_get_long(&retval);
604 }
605
606 zval_ptr_dtor(&argv[0]);
607 zval_ptr_dtor(&argv[1]);
608 break;
609 }
610 }
611
612 return length;
613}
614/* }}} */
615
616/* {{{ curl_fnmatch */
617static int curl_fnmatch(void *ctx, const char *pattern, const char *string)
618{
619 php_curl *ch = (php_curl *) ctx;
620 int rval = CURL_FNMATCHFUNC_FAIL;
621 zval argv[3];
622 zval retval;
623
624 GC_ADDREF(&ch->std);
625 ZVAL_OBJ(&argv[0], &ch->std);
626 ZVAL_STRING(&argv[1], pattern);
627 ZVAL_STRING(&argv[2], string);
628
629 ch->in_callback = true;
630 zend_call_known_fcc(&ch->handlers.fnmatch, &retval, /* param_count */ 3, argv, /* named_params */ NULL);
631 ch->in_callback = false;
632
633 if (!Z_ISUNDEF(retval)) {
634 _php_curl_verify_handlers(ch, /* reporterror */ true);
635 /* TODO Check callback returns an int or something castable to int */
636 rval = zval_get_long(&retval);
637 }
638 zval_ptr_dtor(&argv[0]);
639 zval_ptr_dtor(&argv[1]);
640 zval_ptr_dtor(&argv[2]);
641 return rval;
642}
643/* }}} */
644
645/* {{{ curl_progress */
646static size_t curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
647{
648 php_curl *ch = (php_curl *)clientp;
649 size_t rval = 0;
650
651#if PHP_CURL_DEBUG
652 fprintf(stderr, "curl_progress() called\n");
653 fprintf(stderr, "clientp = %x, dltotal = %f, dlnow = %f, ultotal = %f, ulnow = %f\n", clientp, dltotal, dlnow, ultotal, ulnow);
654#endif
655
656 zval args[5];
657 zval retval;
658
659 GC_ADDREF(&ch->std);
660 ZVAL_OBJ(&args[0], &ch->std);
661 ZVAL_LONG(&args[1], (zend_long)dltotal);
662 ZVAL_LONG(&args[2], (zend_long)dlnow);
663 ZVAL_LONG(&args[3], (zend_long)ultotal);
664 ZVAL_LONG(&args[4], (zend_long)ulnow);
665
666 ch->in_callback = true;
667 zend_call_known_fcc(&ch->handlers.progress, &retval, /* param_count */ 5, args, /* named_params */ NULL);
668 ch->in_callback = false;
669
670 if (!Z_ISUNDEF(retval)) {
671 _php_curl_verify_handlers(ch, /* reporterror */ true);
672 /* TODO Check callback returns an int or something castable to int */
673 if (0 != zval_get_long(&retval)) {
674 rval = 1;
675 }
676 }
677
678 zval_ptr_dtor(&args[0]);
679 return rval;
680}
681/* }}} */
682
683/* {{{ curl_xferinfo */
684static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
685{
686 php_curl *ch = (php_curl *)clientp;
687 size_t rval = 0;
688
689#if PHP_CURL_DEBUG
690 fprintf(stderr, "curl_xferinfo() called\n");
691 fprintf(stderr, "clientp = %x, dltotal = %ld, dlnow = %ld, ultotal = %ld, ulnow = %ld\n", clientp, dltotal, dlnow, ultotal, ulnow);
692#endif
693
694 zval argv[5];
695 zval retval;
696
697 GC_ADDREF(&ch->std);
698 ZVAL_OBJ(&argv[0], &ch->std);
699 ZVAL_LONG(&argv[1], dltotal);
700 ZVAL_LONG(&argv[2], dlnow);
701 ZVAL_LONG(&argv[3], ultotal);
702 ZVAL_LONG(&argv[4], ulnow);
703
704 ch->in_callback = true;
705 zend_call_known_fcc(&ch->handlers.xferinfo, &retval, /* param_count */ 5, argv, /* named_params */ NULL);
706 ch->in_callback = false;
707
708 if (!Z_ISUNDEF(retval)) {
709 _php_curl_verify_handlers(ch, /* reporterror */ true);
710 /* TODO Check callback returns an int or something castable to int */
711 if (0 != zval_get_long(&retval)) {
712 rval = 1;
713 }
714 }
715
716 zval_ptr_dtor(&argv[0]);
717 return rval;
718}
719/* }}} */
720
721#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
722static int curl_prereqfunction(void *clientp, char *conn_primary_ip, char *conn_local_ip, int conn_primary_port, int conn_local_port)
723{
724 php_curl *ch = (php_curl *)clientp;
725 int rval = CURL_PREREQFUNC_OK;
726
727 // when CURLOPT_PREREQFUNCTION is set to null, curl_prereqfunction still
728 // gets called. Return CURL_PREREQFUNC_OK immediately in this case to avoid
729 // zend_call_known_fcc() with an uninitialized FCC.
730 if (!ZEND_FCC_INITIALIZED(ch->handlers.prereq)) {
731 return rval;
732 }
733
734#if PHP_CURL_DEBUG
735 fprintf(stderr, "curl_prereqfunction() called\n");
736 fprintf(stderr, "conn_primary_ip = %s, conn_local_ip = %s, conn_primary_port = %d, conn_local_port = %d\n", conn_primary_ip, conn_local_ip, conn_primary_port, conn_local_port);
737#endif
738
739 zval args[5];
740 zval retval;
741
742 GC_ADDREF(&ch->std);
743 ZVAL_OBJ(&args[0], &ch->std);
744 ZVAL_STRING(&args[1], conn_primary_ip);
745 ZVAL_STRING(&args[2], conn_local_ip);
746 ZVAL_LONG(&args[3], conn_primary_port);
747 ZVAL_LONG(&args[4], conn_local_port);
748
749 ch->in_callback = true;
750 zend_call_known_fcc(&ch->handlers.prereq, &retval, /* param_count */ 5, args, /* named_params */ NULL);
751 ch->in_callback = false;
752
753 if (!Z_ISUNDEF(retval)) {
754 _php_curl_verify_handlers(ch, /* reporterror */ true);
755 if (Z_TYPE(retval) == IS_LONG) {
756 zend_long retval_long = Z_LVAL(retval);
757 if (retval_long == CURL_PREREQFUNC_OK || retval_long == CURL_PREREQFUNC_ABORT) {
758 rval = retval_long;
759 } else {
760 zend_value_error("The CURLOPT_PREREQFUNCTION callback must return either CURL_PREREQFUNC_OK or CURL_PREREQFUNC_ABORT");
761 }
762 } else {
763 zend_type_error("The CURLOPT_PREREQFUNCTION callback must return either CURL_PREREQFUNC_OK or CURL_PREREQFUNC_ABORT");
764 }
765 }
766
767 zval_ptr_dtor(&args[0]);
768 zval_ptr_dtor(&args[1]);
769 zval_ptr_dtor(&args[2]);
770
771 return rval;
772}
773#endif
774
775#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
776static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key, size_t keylen)
777{
778 php_curl *ch = (php_curl *)clientp;
779 int rval = CURLKHMATCH_MISMATCH; /* cancel connection in case of an exception */
780
781#if PHP_CURL_DEBUG
782 fprintf(stderr, "curl_ssh_hostkeyfunction() called\n");
783 fprintf(stderr, "clientp = %x, keytype = %d, key = %s, keylen = %zu\n", clientp, keytype, key, keylen);
784#endif
785
786 zval args[4];
787 zval retval;
788
789 GC_ADDREF(&ch->std);
790 ZVAL_OBJ(&args[0], &ch->std);
791 ZVAL_LONG(&args[1], keytype);
792 ZVAL_STRINGL(&args[2], key, keylen);
793 ZVAL_LONG(&args[3], keylen);
794
795 ch->in_callback = true;
796 zend_call_known_fcc(&ch->handlers.sshhostkey, &retval, /* param_count */ 4, args, /* named_params */ NULL);
797 ch->in_callback = false;
798
799 if (!Z_ISUNDEF(retval)) {
800 _php_curl_verify_handlers(ch, /* reporterror */ true);
801 if (Z_TYPE(retval) == IS_LONG) {
802 zend_long retval_long = Z_LVAL(retval);
803 if (retval_long == CURLKHMATCH_OK || retval_long == CURLKHMATCH_MISMATCH) {
804 rval = retval_long;
805 } else {
806 zend_throw_error(NULL, "The CURLOPT_SSH_HOSTKEYFUNCTION callback must return either CURLKHMATCH_OK or CURLKHMATCH_MISMATCH");
807 }
808 } else {
809 zend_throw_error(NULL, "The CURLOPT_SSH_HOSTKEYFUNCTION callback must return either CURLKHMATCH_OK or CURLKHMATCH_MISMATCH");
810 }
811 }
812
813 zval_ptr_dtor(&args[0]);
814 zval_ptr_dtor(&args[2]);
815 return rval;
816}
817#endif
818
819/* {{{ curl_read */
820static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
821{
822 php_curl *ch = (php_curl *)ctx;
823 php_curl_read *read_handler = ch->handlers.read;
824 int length = 0;
825
826 switch (read_handler->method) {
827 case PHP_CURL_DIRECT:
828 if (read_handler->fp) {
829 length = fread(data, size, nmemb, read_handler->fp);
830 }
831 break;
832 case PHP_CURL_USER: {
833 zval argv[3];
834 zval retval;
835
836 GC_ADDREF(&ch->std);
837 ZVAL_OBJ(&argv[0], &ch->std);
838 if (read_handler->res) {
839 GC_ADDREF(read_handler->res);
840 ZVAL_RES(&argv[1], read_handler->res);
841 } else {
842 ZVAL_NULL(&argv[1]);
843 }
844 ZVAL_LONG(&argv[2], (int)size * nmemb);
845
846 ch->in_callback = true;
847 zend_call_known_fcc(&read_handler->fcc, &retval, /* param_count */ 3, argv, /* named_params */ NULL);
848 ch->in_callback = false;
849 if (!Z_ISUNDEF(retval)) {
850 _php_curl_verify_handlers(ch, /* reporterror */ true);
851 if (Z_TYPE(retval) == IS_STRING) {
852 length = MIN((size * nmemb), Z_STRLEN(retval));
853 memcpy(data, Z_STRVAL(retval), length);
854 } else if (Z_TYPE(retval) == IS_LONG) {
855 length = Z_LVAL_P(&retval);
856 }
857 // TODO Do type error if invalid type?
859 }
860
861 zval_ptr_dtor(&argv[0]);
862 zval_ptr_dtor(&argv[1]);
863 break;
864 }
865 }
866
867 return length;
868}
869/* }}} */
870
871/* {{{ curl_write_header */
872static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx)
873{
874 php_curl *ch = (php_curl *) ctx;
875 php_curl_write *write_handler = ch->handlers.write_header;
876 size_t length = size * nmemb;
877
878 switch (write_handler->method) {
879 case PHP_CURL_STDOUT:
880 /* Handle special case write when we're returning the entire transfer
881 */
882 if (ch->handlers.write->method == PHP_CURL_RETURN && length > 0) {
883 smart_str_appendl(&ch->handlers.write->buf, data, (int) length);
884 } else {
885 PHPWRITE(data, length);
886 }
887 break;
888 case PHP_CURL_FILE:
889 return fwrite(data, size, nmemb, write_handler->fp);
890 case PHP_CURL_USER: {
891 zval argv[2];
892 zval retval;
893
894 GC_ADDREF(&ch->std);
895 ZVAL_OBJ(&argv[0], &ch->std);
896 ZVAL_STRINGL(&argv[1], data, length);
897
898 ch->in_callback = true;
899 zend_call_known_fcc(&write_handler->fcc, &retval, /* param_count */ 2, argv, /* named_params */ NULL);
900 ch->in_callback = false;
901 if (!Z_ISUNDEF(retval)) {
902 // TODO: Check for valid int type for return value
903 _php_curl_verify_handlers(ch, /* reporterror */ true);
904 length = zval_get_long(&retval);
905 }
906 zval_ptr_dtor(&argv[0]);
907 zval_ptr_dtor(&argv[1]);
908 break;
909 }
910
911 case PHP_CURL_IGNORE:
912 return length;
913
914 default:
915 return -1;
916 }
917
918 return length;
919}
920/* }}} */
921
922static int curl_debug(CURL *handle, curl_infotype type, char *data, size_t size, void *clientp) /* {{{ */
923{
924 php_curl *ch = (php_curl *)clientp;
925
926 #if PHP_CURL_DEBUG
927 fprintf(stderr, "curl_debug() called\n");
928 fprintf(stderr, "type = %d, data = %s\n", type, data);
929 #endif
930
931 // Implicitly store the headers for compatibility with CURLINFO_HEADER_OUT
932 // used as a Curl option. Previously, setting CURLINFO_HEADER_OUT set curl_debug
933 // as the CURLOPT_DEBUGFUNCTION and stored the debug data when type is set to
934 // CURLINFO_HEADER_OUT. For backward compatibility, we now store the headers
935 // but also call the user-callback function if available.
936 if (type == CURLINFO_HEADER_OUT) {
937 if (ch->header.str) {
938 zend_string_release_ex(ch->header.str, 0);
939 }
940 ch->header.str = zend_string_init(data, size, 0);
941 }
942
943 if (!ZEND_FCC_INITIALIZED(ch->handlers.debug)) {
944 return 0;
945 }
946
947 zval args[3];
948
949 GC_ADDREF(&ch->std);
950 ZVAL_OBJ(&args[0], &ch->std);
951 ZVAL_LONG(&args[1], type);
952 ZVAL_STRINGL(&args[2], data, size);
953
954 ch->in_callback = true;
955 zend_call_known_fcc(&ch->handlers.debug, NULL, /* param_count */ 3, args, /* named_params */ NULL);
956 ch->in_callback = false;
957
958 zval_ptr_dtor(&args[0]);
959 zval_ptr_dtor(&args[2]);
960
961 return 0;
962}
963/* }}} */
964
965/* {{{ curl_free_post */
966static void curl_free_post(void **post)
967{
968 curl_mime_free((curl_mime *)*post);
969}
970/* }}} */
971
976
977/* {{{ curl_free_cb_arg */
978static void curl_free_cb_arg(void **cb_arg_p)
979{
980 struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) *cb_arg_p;
981
982 ZEND_ASSERT(cb_arg->stream == NULL);
983 zend_string_release(cb_arg->filename);
984 efree(cb_arg);
985}
986/* }}} */
987
988/* {{{ curl_free_slist */
989static void curl_free_slist(zval *el)
990{
991 curl_slist_free_all(((struct curl_slist *)Z_PTR_P(el)));
992}
993/* }}} */
994
995/* {{{ Return cURL version information. */
997{
998 curl_version_info_data *d;
999
1001
1002 d = curl_version_info(CURLVERSION_NOW);
1003 if (d == NULL) {
1005 }
1006
1008
1009 CAAL("version_number", d->version_num);
1010 CAAL("age", d->age);
1011 CAAL("features", d->features);
1012 /* Add an array of features */
1013 {
1014 struct feat {
1015 const char *name;
1016 int bitmask;
1017 };
1018
1019 unsigned int i;
1020 zval feature_list;
1021 array_init(&feature_list);
1022
1023 /* Sync this list with PHP_MINFO_FUNCTION(curl) as well */
1024 static const struct feat feats[] = {
1025 {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
1026 {"CharConv", CURL_VERSION_CONV},
1027 {"Debug", CURL_VERSION_DEBUG},
1028 {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
1029 {"IDN", CURL_VERSION_IDN},
1030 {"IPv6", CURL_VERSION_IPV6},
1031 {"krb4", CURL_VERSION_KERBEROS4},
1032 {"Largefile", CURL_VERSION_LARGEFILE},
1033 {"libz", CURL_VERSION_LIBZ},
1034 {"NTLM", CURL_VERSION_NTLM},
1035 {"NTLMWB", CURL_VERSION_NTLM_WB},
1036 {"SPNEGO", CURL_VERSION_SPNEGO},
1037 {"SSL", CURL_VERSION_SSL},
1038 {"SSPI", CURL_VERSION_SSPI},
1039 {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP},
1040 {"HTTP2", CURL_VERSION_HTTP2},
1041 {"GSSAPI", CURL_VERSION_GSSAPI},
1042 {"KERBEROS5", CURL_VERSION_KERBEROS5},
1043 {"UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS},
1044 {"PSL", CURL_VERSION_PSL},
1045 {"HTTPS_PROXY", CURL_VERSION_HTTPS_PROXY},
1046 {"MULTI_SSL", CURL_VERSION_MULTI_SSL},
1047 {"BROTLI", CURL_VERSION_BROTLI},
1048#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */
1049 {"ALTSVC", CURL_VERSION_ALTSVC},
1050#endif
1051#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */
1052 {"HTTP3", CURL_VERSION_HTTP3},
1053#endif
1054#if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */
1055 {"UNICODE", CURL_VERSION_UNICODE},
1056 {"ZSTD", CURL_VERSION_ZSTD},
1057#endif
1058#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */
1059 {"HSTS", CURL_VERSION_HSTS},
1060#endif
1061#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */
1062 {"GSASL", CURL_VERSION_GSASL},
1063#endif
1064 };
1065
1066 for(i = 0; i < sizeof(feats) / sizeof(feats[0]); i++) {
1067 if (feats[i].name) {
1068 add_assoc_bool(&feature_list, feats[i].name, d->features & feats[i].bitmask ? true : false);
1069 }
1070 }
1071
1072 CAAZ("feature_list", &feature_list);
1073 }
1074 CAAL("ssl_version_number", d->ssl_version_num);
1075 CAAS("version", d->version);
1076 CAAS("host", d->host);
1077 CAAS("ssl_version", d->ssl_version);
1078 CAAS("libz_version", d->libz_version);
1079 /* Add an array of protocols */
1080 {
1081 char **p = (char **) d->protocols;
1082 zval protocol_list;
1083
1084 array_init(&protocol_list);
1085
1086 while (*p != NULL) {
1087 add_next_index_string(&protocol_list, *p);
1088 p++;
1089 }
1090 CAAZ("protocols", &protocol_list);
1091 }
1092 if (d->age >= 1) {
1093 CAAS("ares", d->ares);
1094 CAAL("ares_num", d->ares_num);
1095 }
1096 if (d->age >= 2) {
1097 CAAS("libidn", d->libidn);
1098 }
1099 if (d->age >= 3) {
1100 CAAL("iconv_ver_num", d->iconv_ver_num);
1101 CAAS("libssh_version", d->libssh_version);
1102 }
1103 if (d->age >= 4) {
1104 CAAL("brotli_ver_num", d->brotli_ver_num);
1105 CAAS("brotli_version", d->brotli_version);
1106 }
1107}
1108/* }}} */
1109
1111{
1112 php_curl *ch;
1113
1114 object_init_ex(curl, curl_ce);
1115 ch = Z_CURL_P(curl);
1116
1118
1119 return ch;
1120}
1121
1123{
1124 ch->to_free = ecalloc(1, sizeof(struct _php_curl_free));
1125 ch->handlers.write = ecalloc(1, sizeof(php_curl_write));
1126 ch->handlers.write_header = ecalloc(1, sizeof(php_curl_write));
1127 ch->handlers.read = ecalloc(1, sizeof(php_curl_read));
1128 ch->handlers.progress = empty_fcall_info_cache;
1129 ch->handlers.xferinfo = empty_fcall_info_cache;
1130 ch->handlers.fnmatch = empty_fcall_info_cache;
1131 ch->handlers.debug = empty_fcall_info_cache;
1132#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
1133 ch->handlers.prereq = empty_fcall_info_cache;
1134#endif
1135#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
1136 ch->handlers.sshhostkey = empty_fcall_info_cache;
1137#endif
1138 ch->clone = emalloc(sizeof(uint32_t));
1139 *ch->clone = 1;
1140
1141 memset(&ch->err, 0, sizeof(struct _php_curl_error));
1142
1143 zend_llist_init(&ch->to_free->post, sizeof(struct HttpPost *), (llist_dtor_func_t)curl_free_post, 0);
1144 zend_llist_init(&ch->to_free->stream, sizeof(struct mime_data_cb_arg *), (llist_dtor_func_t)curl_free_cb_arg, 0);
1145
1146 ch->to_free->slist = emalloc(sizeof(HashTable));
1147 zend_hash_init(ch->to_free->slist, 4, NULL, curl_free_slist, 0);
1148 ZVAL_UNDEF(&ch->postfields);
1149}
1150
1151/* }}} */
1152
1153/* {{{ create_certinfo */
1154static void create_certinfo(struct curl_certinfo *ci, zval *listcode)
1155{
1156 int i;
1157
1158 if (ci) {
1159 zval certhash;
1160
1161 for (i=0; i<ci->num_of_certs; i++) {
1162 struct curl_slist *slist;
1163
1164 array_init(&certhash);
1165 for (slist = ci->certinfo[i]; slist; slist = slist->next) {
1166 int len;
1167 char s[64];
1168 char *tmp;
1169 strncpy(s, slist->data, sizeof(s));
1170 s[sizeof(s)-1] = '\0';
1171 tmp = memchr(s, ':', sizeof(s));
1172 if(tmp) {
1173 *tmp = '\0';
1174 len = strlen(s);
1175 add_assoc_string(&certhash, s, &slist->data[len+1]);
1176 } else {
1177 php_error_docref(NULL, E_WARNING, "Could not extract hash key from certificate info");
1178 }
1179 }
1180 add_next_index_zval(listcode, &certhash);
1181 }
1182 }
1183}
1184/* }}} */
1185
1186/* {{{ _php_curl_set_default_options()
1187 Set default options for a handle */
1188static void _php_curl_set_default_options(php_curl *ch)
1189{
1190 char *cainfo;
1191
1192 curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS, 1);
1193 curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0);
1194 curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str);
1195 curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write);
1196 curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch);
1197 curl_easy_setopt(ch->cp, CURLOPT_READFUNCTION, curl_read);
1198 curl_easy_setopt(ch->cp, CURLOPT_INFILE, (void *) ch);
1199 curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_header);
1200 curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch);
1201 curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120);
1202 curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20); /* prevent infinite redirects */
1203
1204 cainfo = INI_STR("openssl.cafile");
1205 if (!(cainfo && cainfo[0] != '\0')) {
1206 cainfo = INI_STR("curl.cainfo");
1207 }
1208 if (cainfo && cainfo[0] != '\0') {
1209 curl_easy_setopt(ch->cp, CURLOPT_CAINFO, cainfo);
1210 }
1211
1212#ifdef ZTS
1213 curl_easy_setopt(ch->cp, CURLOPT_NOSIGNAL, 1);
1214#endif
1215}
1216/* }}} */
1217
1218/* {{{ Initialize a cURL session */
1220{
1221 php_curl *ch;
1222 CURL *cp;
1223 zend_string *url = NULL;
1224
1229
1230 cp = curl_easy_init();
1231 if (!cp) {
1232 php_error_docref(NULL, E_WARNING, "Could not initialize a new cURL handle");
1234 }
1235
1237
1238 ch->cp = cp;
1239
1240 ch->handlers.write->method = PHP_CURL_STDOUT;
1241 ch->handlers.read->method = PHP_CURL_DIRECT;
1242 ch->handlers.write_header->method = PHP_CURL_IGNORE;
1243
1244 _php_curl_set_default_options(ch);
1245
1246 if (url) {
1247 if (php_curl_option_url(ch, url) == FAILURE) {
1250 }
1251 }
1252}
1253/* }}} */
1254
1255static void php_curl_copy_fcc_with_option(php_curl *ch, CURLoption option, zend_fcall_info_cache *target_fcc, zend_fcall_info_cache *source_fcc)
1256{
1257 if (ZEND_FCC_INITIALIZED(*source_fcc)) {
1258 zend_fcc_dup(target_fcc, source_fcc);
1259 curl_easy_setopt(ch->cp, option, (void *) ch);
1260 }
1261}
1262
1264{
1265 if (!Z_ISUNDEF(source->handlers.write->stream)) {
1266 Z_ADDREF(source->handlers.write->stream);
1267 }
1268 ch->handlers.write->stream = source->handlers.write->stream;
1269 ch->handlers.write->method = source->handlers.write->method;
1270 if (!Z_ISUNDEF(source->handlers.read->stream)) {
1271 Z_ADDREF(source->handlers.read->stream);
1272 }
1273 ch->handlers.read->stream = source->handlers.read->stream;
1274 ch->handlers.read->method = source->handlers.read->method;
1275 ch->handlers.write_header->method = source->handlers.write_header->method;
1276 if (!Z_ISUNDEF(source->handlers.write_header->stream)) {
1278 }
1279 ch->handlers.write_header->stream = source->handlers.write_header->stream;
1280
1281 ch->handlers.write->fp = source->handlers.write->fp;
1282 ch->handlers.write_header->fp = source->handlers.write_header->fp;
1283 ch->handlers.read->fp = source->handlers.read->fp;
1284 ch->handlers.read->res = source->handlers.read->res;
1285
1286 if (ZEND_FCC_INITIALIZED(source->handlers.read->fcc)) {
1287 zend_fcc_dup(&ch->handlers.read->fcc, &source->handlers.read->fcc);
1288 }
1289 if (ZEND_FCC_INITIALIZED(source->handlers.write->fcc)) {
1290 zend_fcc_dup(&ch->handlers.write->fcc, &source->handlers.write->fcc);
1291 }
1293 zend_fcc_dup(&ch->handlers.write_header->fcc, &source->handlers.write_header->fcc);
1294 }
1295
1296 curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str);
1297 curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch);
1298 curl_easy_setopt(ch->cp, CURLOPT_INFILE, (void *) ch);
1299 curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch);
1300 curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *) ch);
1301
1302 php_curl_copy_fcc_with_option(ch, CURLOPT_PROGRESSDATA, &ch->handlers.progress, &source->handlers.progress);
1303 php_curl_copy_fcc_with_option(ch, CURLOPT_XFERINFODATA, &ch->handlers.xferinfo, &source->handlers.xferinfo);
1304 php_curl_copy_fcc_with_option(ch, CURLOPT_FNMATCH_DATA, &ch->handlers.fnmatch, &source->handlers.fnmatch);
1305 php_curl_copy_fcc_with_option(ch, CURLOPT_DEBUGDATA, &ch->handlers.debug, &source->handlers.debug);
1306#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
1307 php_curl_copy_fcc_with_option(ch, CURLOPT_PREREQDATA, &ch->handlers.prereq, &source->handlers.prereq);
1308#endif
1309#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
1310 php_curl_copy_fcc_with_option(ch, CURLOPT_SSH_HOSTKEYDATA, &ch->handlers.sshhostkey, &source->handlers.sshhostkey);
1311#endif
1312
1313 ZVAL_COPY(&ch->private_data, &source->private_data);
1314
1315 efree(ch->to_free->slist);
1316 efree(ch->to_free);
1317 ch->to_free = source->to_free;
1318 efree(ch->clone);
1319 ch->clone = source->clone;
1320
1321 /* Keep track of cloned copies to avoid invoking curl destructors for every clone */
1322 (*source->clone)++;
1323}
1324
1325static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */
1326{
1327 struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg;
1328 ssize_t numread;
1329
1330 if (cb_arg->stream == NULL) {
1331 if (!(cb_arg->stream = php_stream_open_wrapper(ZSTR_VAL(cb_arg->filename), "rb", IGNORE_PATH, NULL))) {
1332 return CURL_READFUNC_ABORT;
1333 }
1334 }
1335 numread = php_stream_read(cb_arg->stream, buffer, nitems * size);
1336 if (numread < 0) {
1337 php_stream_close(cb_arg->stream);
1338 cb_arg->stream = NULL;
1339 return CURL_READFUNC_ABORT;
1340 }
1341 return numread;
1342}
1343/* }}} */
1344
1345static int seek_cb(void *arg, curl_off_t offset, int origin) /* {{{ */
1346{
1347 struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg;
1348 int res;
1349
1350 if (cb_arg->stream == NULL) {
1351 return CURL_SEEKFUNC_CANTSEEK;
1352 }
1353 res = php_stream_seek(cb_arg->stream, offset, origin);
1354 return res == SUCCESS ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK;
1355}
1356/* }}} */
1357
1358static void free_cb(void *arg) /* {{{ */
1359{
1360 struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg;
1361
1362 if (cb_arg->stream != NULL) {
1363 php_stream_close(cb_arg->stream);
1364 cb_arg->stream = NULL;
1365 }
1366}
1367/* }}} */
1368
1369static inline CURLcode add_simple_field(curl_mime *mime, zend_string *string_key, zval *current)
1370{
1371 CURLcode error = CURLE_OK;
1372 curl_mimepart *part;
1373 CURLcode form_error;
1374 zend_string *postval, *tmp_postval;
1375
1376 postval = zval_get_tmp_string(current, &tmp_postval);
1377
1378 part = curl_mime_addpart(mime);
1379 if (part == NULL) {
1380 zend_tmp_string_release(tmp_postval);
1381 zend_string_release_ex(string_key, 0);
1382 return CURLE_OUT_OF_MEMORY;
1383 }
1384 if ((form_error = curl_mime_name(part, ZSTR_VAL(string_key))) != CURLE_OK
1385 || (form_error = curl_mime_data(part, ZSTR_VAL(postval), ZSTR_LEN(postval))) != CURLE_OK) {
1386 error = form_error;
1387 }
1388
1389 zend_tmp_string_release(tmp_postval);
1390
1391 return error;
1392}
1393
1394static inline zend_result build_mime_structure_from_hash(php_curl *ch, zval *zpostfields) /* {{{ */
1395{
1396 HashTable *postfields = Z_ARRVAL_P(zpostfields);
1397 CURLcode error = CURLE_OK;
1398 zval *current;
1399 zend_string *string_key;
1400 zend_ulong num_key;
1401 curl_mime *mime = NULL;
1402 curl_mimepart *part;
1403 CURLcode form_error;
1404
1405 if (zend_hash_num_elements(postfields) > 0) {
1406 mime = curl_mime_init(ch->cp);
1407 if (mime == NULL) {
1408 return FAILURE;
1409 }
1410 }
1411
1412 ZEND_HASH_FOREACH_KEY_VAL(postfields, num_key, string_key, current) {
1413 zend_string *postval;
1414 /* Pretend we have a string_key here */
1415 if (!string_key) {
1416 string_key = zend_long_to_str(num_key);
1417 } else {
1418 zend_string_addref(string_key);
1419 }
1420
1422 if (Z_TYPE_P(current) == IS_OBJECT &&
1423 instanceof_function(Z_OBJCE_P(current), curl_CURLFile_class)) {
1424 /* new-style file upload */
1425 zval *prop, rv;
1426 char *type = NULL, *filename = NULL;
1427 struct mime_data_cb_arg *cb_arg;
1430 size_t filesize = -1;
1431 curl_seek_callback seekfunc = seek_cb;
1432
1433 prop = zend_read_property_ex(curl_CURLFile_class, Z_OBJ_P(current), ZSTR_KNOWN(ZEND_STR_NAME), /* silent */ false, &rv);
1434 ZVAL_DEREF(prop);
1435 if (Z_TYPE_P(prop) != IS_STRING) {
1436 php_error_docref(NULL, E_WARNING, "Invalid filename for key %s", ZSTR_VAL(string_key));
1437 } else {
1438 postval = Z_STR_P(prop);
1439
1440 if (php_check_open_basedir(ZSTR_VAL(postval))) {
1441 goto out_string;
1442 }
1443
1444 prop = zend_read_property(curl_CURLFile_class, Z_OBJ_P(current), "mime", sizeof("mime")-1, 0, &rv);
1445 ZVAL_DEREF(prop);
1446 if (Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
1447 type = Z_STRVAL_P(prop);
1448 }
1449 prop = zend_read_property(curl_CURLFile_class, Z_OBJ_P(current), "postname", sizeof("postname")-1, 0, &rv);
1450 ZVAL_DEREF(prop);
1451 if (Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
1452 filename = Z_STRVAL_P(prop);
1453 }
1454
1455 zval_ptr_dtor(&ch->postfields);
1456 ZVAL_COPY(&ch->postfields, zpostfields);
1457
1458 if ((stream = php_stream_open_wrapper(ZSTR_VAL(postval), "rb", STREAM_MUST_SEEK, NULL))) {
1459 if (!stream->readfilters.head && !php_stream_stat(stream, &ssb)) {
1460 filesize = ssb.sb.st_size;
1461 }
1462 } else {
1463 seekfunc = NULL;
1464 }
1465
1466 part = curl_mime_addpart(mime);
1467 if (part == NULL) {
1468 if (stream) {
1470 }
1471 goto out_string;
1472 }
1473
1474 cb_arg = emalloc(sizeof *cb_arg);
1475 cb_arg->filename = zend_string_copy(postval);
1476 cb_arg->stream = stream;
1477
1478 if ((form_error = curl_mime_name(part, ZSTR_VAL(string_key))) != CURLE_OK
1479 || (form_error = curl_mime_data_cb(part, filesize, read_cb, seekfunc, free_cb, cb_arg)) != CURLE_OK
1480 || (form_error = curl_mime_filename(part, filename ? filename : ZSTR_VAL(postval))) != CURLE_OK
1481 || (form_error = curl_mime_type(part, type ? type : "application/octet-stream")) != CURLE_OK) {
1482 error = form_error;
1483 }
1484 zend_llist_add_element(&ch->to_free->stream, &cb_arg);
1485 }
1486
1487 zend_string_release_ex(string_key, 0);
1488 continue;
1489 }
1490
1491 if (Z_TYPE_P(current) == IS_OBJECT && instanceof_function(Z_OBJCE_P(current), curl_CURLStringFile_class)) {
1492 /* new-style file upload from string */
1493 zval *prop, rv;
1494 char *type = NULL, *filename = NULL;
1495
1496 prop = zend_read_property(curl_CURLStringFile_class, Z_OBJ_P(current), "postname", sizeof("postname")-1, 0, &rv);
1497 if (EG(exception)) {
1498 goto out_string;
1499 }
1500 ZVAL_DEREF(prop);
1501 ZEND_ASSERT(Z_TYPE_P(prop) == IS_STRING);
1502
1503 filename = Z_STRVAL_P(prop);
1504
1505 prop = zend_read_property(curl_CURLStringFile_class, Z_OBJ_P(current), "mime", sizeof("mime")-1, 0, &rv);
1506 if (EG(exception)) {
1507 goto out_string;
1508 }
1509 ZVAL_DEREF(prop);
1510 ZEND_ASSERT(Z_TYPE_P(prop) == IS_STRING);
1511
1512 type = Z_STRVAL_P(prop);
1513
1514 prop = zend_read_property(curl_CURLStringFile_class, Z_OBJ_P(current), "data", sizeof("data")-1, 0, &rv);
1515 if (EG(exception)) {
1516 goto out_string;
1517 }
1518 ZVAL_DEREF(prop);
1519 ZEND_ASSERT(Z_TYPE_P(prop) == IS_STRING);
1520
1521 postval = Z_STR_P(prop);
1522
1523 zval_ptr_dtor(&ch->postfields);
1524 ZVAL_COPY(&ch->postfields, zpostfields);
1525
1526 part = curl_mime_addpart(mime);
1527 if (part == NULL) {
1528 goto out_string;
1529 }
1530 if ((form_error = curl_mime_name(part, ZSTR_VAL(string_key))) != CURLE_OK
1531 || (form_error = curl_mime_data(part, ZSTR_VAL(postval), ZSTR_LEN(postval))) != CURLE_OK
1532 || (form_error = curl_mime_filename(part, filename)) != CURLE_OK
1533 || (form_error = curl_mime_type(part, type)) != CURLE_OK) {
1534 error = form_error;
1535 }
1536
1537 zend_string_release_ex(string_key, 0);
1538 continue;
1539 }
1540
1541 if (Z_TYPE_P(current) == IS_ARRAY) {
1542 zval *current_element;
1543
1544 ZEND_HASH_FOREACH_VAL(HASH_OF(current), current_element) {
1545 add_simple_field(mime, string_key, current_element);
1547
1548 zend_string_release_ex(string_key, 0);
1549 continue;
1550 }
1551
1552 add_simple_field(mime, string_key, current);
1553
1554 zend_string_release_ex(string_key, 0);
1556
1558 if (error != CURLE_OK) {
1559 goto out_mime;
1560 }
1561
1562 if ((*ch->clone) == 1) {
1563 zend_llist_clean(&ch->to_free->post);
1564 }
1565 zend_llist_add_element(&ch->to_free->post, &mime);
1566 error = curl_easy_setopt(ch->cp, CURLOPT_MIMEPOST, mime);
1567
1569 return error == CURLE_OK ? SUCCESS : FAILURE;
1570
1571out_string:
1572 zend_string_release_ex(string_key, false);
1573out_mime:
1574 curl_mime_free(mime);
1575 return FAILURE;
1576}
1577/* }}} */
1578
1579/* {{{ Copy a cURL handle along with all of it's preferences */
1581{
1582 php_curl *ch;
1583 CURL *cp;
1584 zval *zid;
1585 php_curl *dupch;
1586 zval *postfields;
1587
1591
1592 ch = Z_CURL_P(zid);
1593
1594 cp = curl_easy_duphandle(ch->cp);
1595 if (!cp) {
1596 php_error_docref(NULL, E_WARNING, "Cannot duplicate cURL handle");
1598 }
1599
1601 dupch->cp = cp;
1602
1604
1605 postfields = &ch->postfields;
1606 if (Z_TYPE_P(postfields) != IS_UNDEF) {
1607 if (build_mime_structure_from_hash(dupch, postfields) == FAILURE) {
1609 php_error_docref(NULL, E_WARNING, "Cannot rebuild mime structure");
1611 }
1612 }
1613}
1614/* }}} */
1615
1616static bool php_curl_set_callable_handler(zend_fcall_info_cache *const handler_fcc, zval *callable, bool is_array_config, const char *option_name)
1617{
1618 if (ZEND_FCC_INITIALIZED(*handler_fcc)) {
1619 zend_fcc_dtor(handler_fcc);
1620 }
1621
1622 if (Z_TYPE_P(callable) == IS_NULL) {
1623 return true;
1624 }
1625
1626 char *error = NULL;
1627 if (UNEXPECTED(!zend_is_callable_ex(callable, /* object */ NULL, /* check_flags */ 0, /* callable_name */ NULL, handler_fcc, /* error */ &error))) {
1628 if (!EG(exception)) {
1629 zend_argument_type_error(2 + !is_array_config, "must be a valid callback for option %s, %s", option_name, error);
1630 }
1631 efree(error);
1632 return false;
1633 }
1634 zend_fcc_addref(handler_fcc);
1635 return true;
1636}
1637
1638
1639#define HANDLE_CURL_OPTION_CALLABLE_PHP_CURL_USER(curl_ptr, constant_no_function, handler_type, default_method) \
1640 case constant_no_function##FUNCTION: { \
1641 bool result = php_curl_set_callable_handler(&curl_ptr->handlers.handler_type->fcc, zvalue, is_array_config, #constant_no_function "FUNCTION"); \
1642 if (!result) { \
1643 curl_ptr->handlers.handler_type->method = default_method; \
1644 return FAILURE; \
1645 } \
1646 if (!ZEND_FCC_INITIALIZED(curl_ptr->handlers.handler_type->fcc)) { \
1647 curl_ptr->handlers.handler_type->method = default_method; \
1648 return SUCCESS; \
1649 } \
1650 curl_ptr->handlers.handler_type->method = PHP_CURL_USER; \
1651 break; \
1652 }
1653
1654#define HANDLE_CURL_OPTION_CALLABLE(curl_ptr, constant_no_function, handler_fcc, c_callback) \
1655 case constant_no_function##FUNCTION: { \
1656 bool result = php_curl_set_callable_handler(&curl_ptr->handler_fcc, zvalue, is_array_config, #constant_no_function "FUNCTION"); \
1657 if (!result) { \
1658 return FAILURE; \
1659 } \
1660 curl_easy_setopt(curl_ptr->cp, constant_no_function##FUNCTION, (c_callback)); \
1661 curl_easy_setopt(curl_ptr->cp, constant_no_function##DATA, curl_ptr); \
1662 break; \
1663 }
1664
1665static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool is_array_config) /* {{{ */
1666{
1667 CURLcode error = CURLE_OK;
1668 zend_long lval;
1669
1670 switch (option) {
1671 /* Callable options */
1675
1676 HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_PROGRESS, handlers.progress, curl_progress);
1677 HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_XFERINFO, handlers.xferinfo, curl_xferinfo);
1678 HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_FNMATCH_, handlers.fnmatch, curl_fnmatch);
1679 HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_DEBUG, handlers.debug, curl_debug);
1680
1681#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
1682 HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_PREREQ, handlers.prereq, curl_prereqfunction);
1683#endif
1684#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
1685 HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_SSH_HOSTKEY, handlers.sshhostkey, curl_ssh_hostkeyfunction);
1686#endif
1687
1688 /* Long options */
1690 lval = zval_get_long(zvalue);
1691 if (lval == 1) {
1692 php_error_docref(NULL, E_NOTICE, "CURLOPT_SSL_VERIFYHOST no longer accepts the value 1, value 2 will be used instead");
1693 error = curl_easy_setopt(ch->cp, option, 2);
1694 break;
1695 }
1698 case CURLOPT_BUFFERSIZE:
1701 case CURLOPT_CRLF:
1704 case CURLOPT_FILETIME:
1709 case CURLOPT_HEADER:
1710 case CURLOPT_HTTPGET:
1713 case CURLOPT_INFILESIZE:
1717 case CURLOPT_MAXREDIRS:
1718 case CURLOPT_NETRC:
1719 case CURLOPT_NOBODY:
1720 case CURLOPT_NOPROGRESS:
1721 case CURLOPT_NOSIGNAL:
1722 case CURLOPT_PORT:
1723 case CURLOPT_POST:
1724 case CURLOPT_PROXYPORT:
1725 case CURLOPT_PROXYTYPE:
1726 case CURLOPT_PUT:
1728 case CURLOPT_SSLVERSION:
1731 case CURLOPT_TIMEOUT:
1732 case CURLOPT_TIMEVALUE:
1735 case CURLOPT_UPLOAD:
1736 case CURLOPT_VERBOSE:
1737 case CURLOPT_HTTPAUTH:
1739 case CURLOPT_PROXYAUTH:
1741 case CURLOPT_IPRESOLVE:
1744 case CURLOPT_FTPSSLAUTH:
1749 case CURLOPT_LOCALPORT:
1757 case CURLOPT_TIMEOUT_MS:
1760 case CURLOPT_USE_SSL:
1761 case CURLOPT_APPEND:
1765 case CURLOPT_CERTINFO:
1766 case CURLOPT_PROTOCOLS:
1781 case CURLOPT_SASL_IR:
1785 case CURLOPT_HEADEROPT:
1787 case CURLOPT_PATH_AS_IS:
1789 case CURLOPT_PIPEWAIT:
1805#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */
1808#endif
1809#if LIBCURL_VERSION_NUM >= 0x074000 /* Available since 7.64.0 */
1811#endif
1812#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */
1814#endif
1815#if LIBCURL_VERSION_NUM >= 0x074100 /* Available since 7.65.0 */
1817#endif
1818#if LIBCURL_VERSION_NUM >= 0x074500 /* Available since 7.69.0 */
1820#endif
1821#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */
1822 case CURLOPT_HSTS_CTRL:
1823#endif
1824#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */
1828#endif
1829#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
1831#endif
1832#if LIBCURL_VERSION_NUM >= 0x075100 /* Available since 7.81.0 */
1834#endif
1835#if LIBCURL_VERSION_NUM >= 0x075600 /* Available since 7.86.0 */
1836 case CURLOPT_WS_OPTIONS:
1837#endif
1838#if LIBCURL_VERSION_NUM >= 0x075700 /* Available since 7.87.0 */
1840 case CURLOPT_QUICK_EXIT:
1841#endif
1842#if LIBCURL_VERSION_NUM >= 0x080900 /* Available since 8.9.0 */
1844#endif
1845 lval = zval_get_long(zvalue);
1846 if ((option == CURLOPT_PROTOCOLS || option == CURLOPT_REDIR_PROTOCOLS) &&
1847 (PG(open_basedir) && *PG(open_basedir)) && (lval & CURLPROTO_FILE)) {
1848 php_error_docref(NULL, E_WARNING, "CURLPROTO_FILE cannot be activated when an open_basedir is set");
1849 return FAILURE;
1850 }
1851 error = curl_easy_setopt(ch->cp, option, lval);
1852 break;
1854 if (!zend_is_true(zvalue)) {
1855 zend_value_error("%s(): Disabling safe uploads is no longer supported", get_active_function_name());
1856 return FAILURE;
1857 }
1858 break;
1859
1860 /* String options */
1861 case CURLOPT_CAINFO:
1862 case CURLOPT_CAPATH:
1863 case CURLOPT_COOKIE:
1864 case CURLOPT_EGDSOCKET:
1865 case CURLOPT_INTERFACE:
1866 case CURLOPT_PROXY:
1868 case CURLOPT_REFERER:
1870 case CURLOPT_SSLENGINE:
1872 case CURLOPT_SSLKEY:
1874 case CURLOPT_SSLKEYTYPE:
1876 case CURLOPT_USERAGENT:
1877 case CURLOPT_COOKIELIST:
1882 case CURLOPT_NOPROXY:
1884 case CURLOPT_MAIL_FROM:
1892 case CURLOPT_MAIL_AUTH:
1898 case CURLOPT_PRE_PROXY:
1916#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */
1917 case CURLOPT_ALTSVC:
1918#endif
1919#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */
1921#endif
1922#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */
1924#endif
1925#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */
1927#endif
1928#if LIBCURL_VERSION_NUM >= 0x074b00 /* Available since 7.75.0 */
1929 case CURLOPT_AWS_SIGV4:
1930#endif
1931#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
1933#endif
1934#if LIBCURL_VERSION_NUM >= 0x075500 /* Available since 7.85.0 */
1937#endif
1938 {
1939 zend_string *tmp_str;
1940 zend_string *str = zval_get_tmp_string(zvalue, &tmp_str);
1941#if LIBCURL_VERSION_NUM >= 0x075500 /* Available since 7.85.0 */
1942 if ((option == CURLOPT_PROTOCOLS_STR || option == CURLOPT_REDIR_PROTOCOLS_STR) &&
1943 (PG(open_basedir) && *PG(open_basedir))
1944 && (php_memnistr(ZSTR_VAL(str), "file", sizeof("file") - 1, ZSTR_VAL(str) + ZSTR_LEN(str)) != NULL
1945 || php_memnistr(ZSTR_VAL(str), "all", sizeof("all") - 1, ZSTR_VAL(str) + ZSTR_LEN(str)) != NULL)) {
1946 zend_tmp_string_release(tmp_str);
1947 php_error_docref(NULL, E_WARNING, "The FILE protocol cannot be activated when an open_basedir is set");
1948 return FAILURE;
1949 }
1950#endif
1951 zend_result ret = php_curl_option_str(ch, option, ZSTR_VAL(str), ZSTR_LEN(str));
1952 zend_tmp_string_release(tmp_str);
1953 return ret;
1954 }
1955
1956 /* Curl nullable string options */
1958 case CURLOPT_FTPPORT:
1959 case CURLOPT_RANGE:
1968#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */
1969 case CURLOPT_DOH_URL:
1970#endif
1971#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */
1972 case CURLOPT_HSTS:
1973#endif
1974 case CURLOPT_KRBLEVEL:
1975 // Authorization header would be implictly set
1976 // with an empty string thus we explictly set the option
1977 // to null to avoid this unwarranted side effect
1978 case CURLOPT_USERPWD:
1979 case CURLOPT_USERNAME:
1980 case CURLOPT_PASSWORD:
1981 {
1982 if (Z_ISNULL_P(zvalue)) {
1983 error = curl_easy_setopt(ch->cp, option, NULL);
1984 } else {
1985 zend_string *tmp_str;
1986 zend_string *str = zval_get_tmp_string(zvalue, &tmp_str);
1987 zend_result ret = php_curl_option_str(ch, option, ZSTR_VAL(str), ZSTR_LEN(str));
1988 zend_tmp_string_release(tmp_str);
1989 return ret;
1990 }
1991 break;
1992 }
1993
1994 /* Curl private option */
1995 case CURLOPT_PRIVATE:
1996 {
1997 zval_ptr_dtor(&ch->private_data);
1998 ZVAL_COPY(&ch->private_data, zvalue);
1999 return SUCCESS;
2000 }
2001
2002 /* Curl url option */
2003 case CURLOPT_URL:
2004 {
2005 zend_string *tmp_str;
2006 zend_string *str = zval_get_tmp_string(zvalue, &tmp_str);
2007 zend_result ret = php_curl_option_url(ch, str);
2008 zend_tmp_string_release(tmp_str);
2009 return ret;
2010 }
2011
2012 /* Curl file handle options */
2013 case CURLOPT_FILE:
2014 case CURLOPT_INFILE:
2015 case CURLOPT_STDERR:
2016 case CURLOPT_WRITEHEADER: {
2017 FILE *fp = NULL;
2018 php_stream *what = NULL;
2019
2020 if (Z_TYPE_P(zvalue) != IS_NULL) {
2021 what = (php_stream *)zend_fetch_resource2_ex(zvalue, "File-Handle", php_file_le_stream(), php_file_le_pstream());
2022 if (!what) {
2023 return FAILURE;
2024 }
2025
2026 if (FAILURE == php_stream_cast(what, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
2027 return FAILURE;
2028 }
2029
2030 if (!fp) {
2031 return FAILURE;
2032 }
2033 }
2034
2035 error = CURLE_OK;
2036 switch (option) {
2037 case CURLOPT_FILE:
2038 if (!what) {
2039 if (!Z_ISUNDEF(ch->handlers.write->stream)) {
2040 zval_ptr_dtor(&ch->handlers.write->stream);
2041 ZVAL_UNDEF(&ch->handlers.write->stream);
2042 }
2043 ch->handlers.write->fp = NULL;
2044 ch->handlers.write->method = PHP_CURL_STDOUT;
2045 } else if (what->mode[0] != 'r' || what->mode[1] == '+') {
2046 zval_ptr_dtor(&ch->handlers.write->stream);
2047 ch->handlers.write->fp = fp;
2048 ch->handlers.write->method = PHP_CURL_FILE;
2049 ZVAL_COPY(&ch->handlers.write->stream, zvalue);
2050 } else {
2051 zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
2052 return FAILURE;
2053 }
2054 break;
2056 if (!what) {
2057 if (!Z_ISUNDEF(ch->handlers.write_header->stream)) {
2058 zval_ptr_dtor(&ch->handlers.write_header->stream);
2059 ZVAL_UNDEF(&ch->handlers.write_header->stream);
2060 }
2061 ch->handlers.write_header->fp = NULL;
2062 ch->handlers.write_header->method = PHP_CURL_IGNORE;
2063 } else if (what->mode[0] != 'r' || what->mode[1] == '+') {
2064 zval_ptr_dtor(&ch->handlers.write_header->stream);
2065 ch->handlers.write_header->fp = fp;
2066 ch->handlers.write_header->method = PHP_CURL_FILE;
2067 ZVAL_COPY(&ch->handlers.write_header->stream, zvalue);
2068 } else {
2069 zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
2070 return FAILURE;
2071 }
2072 break;
2073 case CURLOPT_INFILE:
2074 if (!what) {
2075 if (!Z_ISUNDEF(ch->handlers.read->stream)) {
2076 zval_ptr_dtor(&ch->handlers.read->stream);
2077 ZVAL_UNDEF(&ch->handlers.read->stream);
2078 }
2079 ch->handlers.read->fp = NULL;
2080 ch->handlers.read->res = NULL;
2081 } else {
2082 zval_ptr_dtor(&ch->handlers.read->stream);
2083 ch->handlers.read->fp = fp;
2084 ch->handlers.read->res = Z_RES_P(zvalue);
2085 ZVAL_COPY(&ch->handlers.read->stream, zvalue);
2086 }
2087 break;
2088 case CURLOPT_STDERR:
2089 if (!what) {
2090 if (!Z_ISUNDEF(ch->handlers.std_err)) {
2091 zval_ptr_dtor(&ch->handlers.std_err);
2092 ZVAL_UNDEF(&ch->handlers.std_err);
2093 }
2094 } else if (what->mode[0] != 'r' || what->mode[1] == '+') {
2095 zval_ptr_dtor(&ch->handlers.std_err);
2096 ZVAL_COPY(&ch->handlers.std_err, zvalue);
2097 } else {
2098 zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
2099 return FAILURE;
2100 }
2102 default:
2103 error = curl_easy_setopt(ch->cp, option, fp);
2104 break;
2105 }
2106 break;
2107 }
2108
2109 /* Curl linked list options */
2111 case CURLOPT_HTTPHEADER:
2112 case CURLOPT_POSTQUOTE:
2113 case CURLOPT_PREQUOTE:
2114 case CURLOPT_QUOTE:
2116 case CURLOPT_MAIL_RCPT:
2117 case CURLOPT_RESOLVE:
2119 case CURLOPT_CONNECT_TO:
2120 {
2121 zval *current;
2122 HashTable *ph;
2123 zend_string *val, *tmp_val;
2124 struct curl_slist *slist = NULL;
2125
2126 if (Z_TYPE_P(zvalue) != IS_ARRAY) {
2127 const char *name = NULL;
2128 switch (option) {
2129 case CURLOPT_HTTPHEADER:
2130 name = "CURLOPT_HTTPHEADER";
2131 break;
2132 case CURLOPT_QUOTE:
2133 name = "CURLOPT_QUOTE";
2134 break;
2136 name = "CURLOPT_HTTP200ALIASES";
2137 break;
2138 case CURLOPT_POSTQUOTE:
2139 name = "CURLOPT_POSTQUOTE";
2140 break;
2141 case CURLOPT_PREQUOTE:
2142 name = "CURLOPT_PREQUOTE";
2143 break;
2145 name = "CURLOPT_TELNETOPTIONS";
2146 break;
2147 case CURLOPT_MAIL_RCPT:
2148 name = "CURLOPT_MAIL_RCPT";
2149 break;
2150 case CURLOPT_RESOLVE:
2151 name = "CURLOPT_RESOLVE";
2152 break;
2154 name = "CURLOPT_PROXYHEADER";
2155 break;
2156 case CURLOPT_CONNECT_TO:
2157 name = "CURLOPT_CONNECT_TO";
2158 break;
2159 }
2160
2161 zend_type_error("%s(): The %s option must have an array value", get_active_function_name(), name);
2162 return FAILURE;
2163 }
2164
2165 ph = Z_ARRVAL_P(zvalue);
2168 val = zval_get_tmp_string(current, &tmp_val);
2169 slist = curl_slist_append(slist, ZSTR_VAL(val));
2170 zend_tmp_string_release(tmp_val);
2171 if (!slist) {
2172 php_error_docref(NULL, E_WARNING, "Could not build curl_slist");
2173 return FAILURE;
2174 }
2176
2177 if (slist) {
2178 if ((*ch->clone) == 1) {
2179 zend_hash_index_update_ptr(ch->to_free->slist, option, slist);
2180 } else {
2181 zend_hash_next_index_insert_ptr(ch->to_free->slist, slist);
2182 }
2183 }
2184
2185 error = curl_easy_setopt(ch->cp, option, slist);
2186
2187 break;
2188 }
2189
2192 /* Do nothing, just backward compatibility */
2193 break;
2194
2196 lval = zend_is_true(zvalue);
2197 error = curl_easy_setopt(ch->cp, option, lval);
2198 break;
2199
2200 case CURLOPT_POSTFIELDS:
2201 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
2202 if (zend_hash_num_elements(HASH_OF(zvalue)) == 0) {
2203 /* no need to build the mime structure for empty hashtables;
2204 also works around https://github.com/curl/curl/issues/6455 */
2205 curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, "");
2206 error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, 0);
2207 } else {
2208 return build_mime_structure_from_hash(ch, zvalue);
2209 }
2210 } else {
2211 zend_string *tmp_str;
2212 zend_string *str = zval_get_tmp_string(zvalue, &tmp_str);
2213 /* with curl 7.17.0 and later, we can use COPYPOSTFIELDS, but we have to provide size before */
2214 error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, ZSTR_LEN(str));
2215 error = curl_easy_setopt(ch->cp, CURLOPT_COPYPOSTFIELDS, ZSTR_VAL(str));
2216 zend_tmp_string_release(tmp_str);
2217 }
2218 break;
2219
2221 if (zend_is_true(zvalue)) {
2222 ch->handlers.write->method = PHP_CURL_RETURN;
2223 } else {
2224 ch->handlers.write->method = PHP_CURL_STDOUT;
2225 }
2226 break;
2227
2228 /* Curl off_t options */
2233 lval = zval_get_long(zvalue);
2234 error = curl_easy_setopt(ch->cp, option, (curl_off_t)lval);
2235 break;
2236
2237 case CURLOPT_POSTREDIR:
2238 lval = zval_get_long(zvalue);
2239 error = curl_easy_setopt(ch->cp, CURLOPT_POSTREDIR, lval & CURL_REDIR_POST_ALL);
2240 break;
2241
2242 /* the following options deal with files, therefore the open_basedir check
2243 * is required.
2244 */
2245 case CURLOPT_COOKIEFILE:
2246 case CURLOPT_COOKIEJAR:
2248 case CURLOPT_SSLCERT:
2249 case CURLOPT_NETRC_FILE:
2252 case CURLOPT_CRLFILE:
2253 case CURLOPT_ISSUERCERT:
2255 {
2256 zend_string *tmp_str;
2257 zend_string *str = zval_get_tmp_string(zvalue, &tmp_str);
2259
2260 if (ZSTR_LEN(str) && php_check_open_basedir(ZSTR_VAL(str))) {
2261 zend_tmp_string_release(tmp_str);
2262 return FAILURE;
2263 }
2264
2265 ret = php_curl_option_str(ch, option, ZSTR_VAL(str), ZSTR_LEN(str));
2266 zend_tmp_string_release(tmp_str);
2267 return ret;
2268 }
2269
2271 if (ZEND_FCC_INITIALIZED(ch->handlers.debug)) {
2272 zend_value_error("CURLINFO_HEADER_OUT option must not be set when the CURLOPT_DEBUGFUNCTION option is set");
2273 return FAILURE;
2274 }
2275
2276 if (zend_is_true(zvalue)) {
2277 curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, curl_debug);
2278 curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *)ch);
2279 curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1);
2280 } else {
2281 curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, NULL);
2282 curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, NULL);
2283 curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0);
2284 }
2285 break;
2286
2287 case CURLOPT_SHARE:
2288 {
2289 if (Z_TYPE_P(zvalue) == IS_OBJECT && Z_OBJCE_P(zvalue) == curl_share_ce) {
2290 php_curlsh *sh = Z_CURL_SHARE_P(zvalue);
2291 curl_easy_setopt(ch->cp, CURLOPT_SHARE, sh->share);
2292
2293 if (ch->share) {
2294 OBJ_RELEASE(&ch->share->std);
2295 }
2296 GC_ADDREF(&sh->std);
2297 ch->share = sh;
2298 }
2299 }
2300 break;
2301
2302 /* Curl blob options */
2303#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */
2310#if LIBCURL_VERSION_NUM >= 0x074d00 /* Available since 7.77.0 */
2313#endif
2314 {
2315 zend_string *tmp_str;
2316 zend_string *str = zval_get_tmp_string(zvalue, &tmp_str);
2317
2318 struct curl_blob stblob;
2319 stblob.data = ZSTR_VAL(str);
2320 stblob.len = ZSTR_LEN(str);
2321 stblob.flags = CURL_BLOB_COPY;
2322 error = curl_easy_setopt(ch->cp, option, &stblob);
2323
2324 zend_tmp_string_release(tmp_str);
2325 }
2326 break;
2327#endif
2328
2329 default:
2330 if (is_array_config) {
2331 zend_argument_value_error(2, "must contain only valid cURL options");
2332 } else {
2333 zend_argument_value_error(2, "is not a valid cURL option");
2334 }
2335 error = CURLE_UNKNOWN_OPTION;
2336 break;
2337 }
2338
2340 if (error != CURLE_OK) {
2341 return FAILURE;
2342 } else {
2343 return SUCCESS;
2344 }
2345}
2346/* }}} */
2347
2348/* {{{ Set an option for a cURL transfer */
2350{
2351 zval *zid, *zvalue;
2353 php_curl *ch;
2354
2358 Z_PARAM_ZVAL(zvalue)
2360
2361 ch = Z_CURL_P(zid);
2362
2363 if (_php_curl_setopt(ch, options, zvalue, 0) == SUCCESS) {
2365 } else {
2367 }
2368}
2369/* }}} */
2370
2371/* {{{ Set an array of option for a cURL transfer */
2373{
2374 zval *zid, *arr, *entry;
2375 php_curl *ch;
2376 zend_ulong option;
2377 zend_string *string_key;
2378
2381 Z_PARAM_ARRAY(arr)
2383
2384 ch = Z_CURL_P(zid);
2385
2386 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(arr), option, string_key, entry) {
2387 if (string_key) {
2388 zend_argument_value_error(2, "contains an invalid cURL option");
2389 RETURN_THROWS();
2390 }
2391
2392 ZVAL_DEREF(entry);
2393 if (_php_curl_setopt(ch, (zend_long) option, entry, 1) == FAILURE) {
2395 }
2397
2399}
2400/* }}} */
2401
2402/* {{{ _php_curl_cleanup_handle(ch)
2403 Cleanup an execution phase */
2405{
2406 smart_str_free(&ch->handlers.write->buf);
2407 if (ch->header.str) {
2408 zend_string_release_ex(ch->header.str, 0);
2409 ch->header.str = NULL;
2410 }
2411
2412 memset(ch->err.str, 0, CURL_ERROR_SIZE + 1);
2413 ch->err.no = 0;
2414}
2415/* }}} */
2416
2417/* {{{ Perform a cURL session */
2419{
2420 CURLcode error;
2421 zval *zid;
2422 php_curl *ch;
2423
2427
2428 ch = Z_CURL_P(zid);
2429
2430 _php_curl_verify_handlers(ch, /* reporterror */ true);
2431
2433
2434 error = curl_easy_perform(ch->cp);
2436
2437 if (error != CURLE_OK) {
2438 smart_str_free(&ch->handlers.write->buf);
2440 }
2441
2442 if (!Z_ISUNDEF(ch->handlers.std_err)) {
2443 php_stream *stream;
2445 if (stream) {
2446 php_stream_flush(stream);
2447 }
2448 }
2449
2450 if (ch->handlers.write->method == PHP_CURL_RETURN && ch->handlers.write->buf.s) {
2451 smart_str_0(&ch->handlers.write->buf);
2452 RETURN_STR_COPY(ch->handlers.write->buf.s);
2453 }
2454
2455 /* flush the file handle, so any remaining data is synched to disk */
2456 if (ch->handlers.write->method == PHP_CURL_FILE && ch->handlers.write->fp) {
2457 fflush(ch->handlers.write->fp);
2458 }
2459 if (ch->handlers.write_header->method == PHP_CURL_FILE && ch->handlers.write_header->fp) {
2460 fflush(ch->handlers.write_header->fp);
2461 }
2462
2463 if (ch->handlers.write->method == PHP_CURL_RETURN) {
2465 } else {
2467 }
2468}
2469/* }}} */
2470
2471/* {{{ Get information regarding a specific transfer */
2473{
2474 zval *zid;
2475 php_curl *ch;
2476 zend_long option;
2477 bool option_is_null = 1;
2478
2482 Z_PARAM_LONG_OR_NULL(option, option_is_null)
2484
2485 ch = Z_CURL_P(zid);
2486
2487 if (option_is_null) {
2488 char *s_code;
2489 /* libcurl expects long datatype. So far no cases are known where
2490 it would be an issue. Using zend_long would truncate a 64-bit
2491 var on Win64, so the exact long datatype fits everywhere, as
2492 long as there's no 32-bit int overflow. */
2493 long l_code;
2494 double d_code;
2495 struct curl_certinfo *ci = NULL;
2496 zval listcode;
2497 curl_off_t co;
2498
2500
2501 if (curl_easy_getinfo(ch->cp, CURLINFO_EFFECTIVE_URL, &s_code) == CURLE_OK) {
2502 CAAS("url", s_code);
2503 }
2504 if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_TYPE, &s_code) == CURLE_OK) {
2505 if (s_code != NULL) {
2506 CAAS("content_type", s_code);
2507 } else {
2508 zval retnull;
2509 ZVAL_NULL(&retnull);
2510 CAAZ("content_type", &retnull);
2511 }
2512 }
2513 if (curl_easy_getinfo(ch->cp, CURLINFO_HTTP_CODE, &l_code) == CURLE_OK) {
2514 CAAL("http_code", l_code);
2515 }
2516 if (curl_easy_getinfo(ch->cp, CURLINFO_HEADER_SIZE, &l_code) == CURLE_OK) {
2517 CAAL("header_size", l_code);
2518 }
2519 if (curl_easy_getinfo(ch->cp, CURLINFO_REQUEST_SIZE, &l_code) == CURLE_OK) {
2520 CAAL("request_size", l_code);
2521 }
2522 if (curl_easy_getinfo(ch->cp, CURLINFO_FILETIME, &l_code) == CURLE_OK) {
2523 CAAL("filetime", l_code);
2524 }
2525 if (curl_easy_getinfo(ch->cp, CURLINFO_SSL_VERIFYRESULT, &l_code) == CURLE_OK) {
2526 CAAL("ssl_verify_result", l_code);
2527 }
2528 if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_COUNT, &l_code) == CURLE_OK) {
2529 CAAL("redirect_count", l_code);
2530 }
2531 if (curl_easy_getinfo(ch->cp, CURLINFO_TOTAL_TIME, &d_code) == CURLE_OK) {
2532 CAAD("total_time", d_code);
2533 }
2534 if (curl_easy_getinfo(ch->cp, CURLINFO_NAMELOOKUP_TIME, &d_code) == CURLE_OK) {
2535 CAAD("namelookup_time", d_code);
2536 }
2537 if (curl_easy_getinfo(ch->cp, CURLINFO_CONNECT_TIME, &d_code) == CURLE_OK) {
2538 CAAD("connect_time", d_code);
2539 }
2540 if (curl_easy_getinfo(ch->cp, CURLINFO_PRETRANSFER_TIME, &d_code) == CURLE_OK) {
2541 CAAD("pretransfer_time", d_code);
2542 }
2543 if (curl_easy_getinfo(ch->cp, CURLINFO_SIZE_UPLOAD, &d_code) == CURLE_OK) {
2544 CAAD("size_upload", d_code);
2545 }
2546 if (curl_easy_getinfo(ch->cp, CURLINFO_SIZE_DOWNLOAD, &d_code) == CURLE_OK) {
2547 CAAD("size_download", d_code);
2548 }
2549 if (curl_easy_getinfo(ch->cp, CURLINFO_SPEED_DOWNLOAD, &d_code) == CURLE_OK) {
2550 CAAD("speed_download", d_code);
2551 }
2552 if (curl_easy_getinfo(ch->cp, CURLINFO_SPEED_UPLOAD, &d_code) == CURLE_OK) {
2553 CAAD("speed_upload", d_code);
2554 }
2555 if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d_code) == CURLE_OK) {
2556 CAAD("download_content_length", d_code);
2557 }
2558 if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_LENGTH_UPLOAD, &d_code) == CURLE_OK) {
2559 CAAD("upload_content_length", d_code);
2560 }
2561 if (curl_easy_getinfo(ch->cp, CURLINFO_STARTTRANSFER_TIME, &d_code) == CURLE_OK) {
2562 CAAD("starttransfer_time", d_code);
2563 }
2564 if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_TIME, &d_code) == CURLE_OK) {
2565 CAAD("redirect_time", d_code);
2566 }
2567 if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_URL, &s_code) == CURLE_OK) {
2568 CAAS("redirect_url", s_code);
2569 }
2570 if (curl_easy_getinfo(ch->cp, CURLINFO_PRIMARY_IP, &s_code) == CURLE_OK) {
2571 CAAS("primary_ip", s_code);
2572 }
2573 if (curl_easy_getinfo(ch->cp, CURLINFO_CERTINFO, &ci) == CURLE_OK) {
2574 array_init(&listcode);
2575 create_certinfo(ci, &listcode);
2576 CAAZ("certinfo", &listcode);
2577 }
2578 if (curl_easy_getinfo(ch->cp, CURLINFO_PRIMARY_PORT, &l_code) == CURLE_OK) {
2579 CAAL("primary_port", l_code);
2580 }
2581 if (curl_easy_getinfo(ch->cp, CURLINFO_LOCAL_IP, &s_code) == CURLE_OK) {
2582 CAAS("local_ip", s_code);
2583 }
2584 if (curl_easy_getinfo(ch->cp, CURLINFO_LOCAL_PORT, &l_code) == CURLE_OK) {
2585 CAAL("local_port", l_code);
2586 }
2587 if (curl_easy_getinfo(ch->cp, CURLINFO_HTTP_VERSION, &l_code) == CURLE_OK) {
2588 CAAL("http_version", l_code);
2589 }
2590 if (curl_easy_getinfo(ch->cp, CURLINFO_PROTOCOL, &l_code) == CURLE_OK) {
2591 CAAL("protocol", l_code);
2592 }
2593 if (curl_easy_getinfo(ch->cp, CURLINFO_PROXY_SSL_VERIFYRESULT, &l_code) == CURLE_OK) {
2594 CAAL("ssl_verifyresult", l_code);
2595 }
2596 if (curl_easy_getinfo(ch->cp, CURLINFO_SCHEME, &s_code) == CURLE_OK) {
2597 CAAS("scheme", s_code);
2598 }
2599 if (curl_easy_getinfo(ch->cp, CURLINFO_APPCONNECT_TIME_T, &co) == CURLE_OK) {
2600 CAAL("appconnect_time_us", co);
2601 }
2602 if (curl_easy_getinfo(ch->cp, CURLINFO_CONNECT_TIME_T, &co) == CURLE_OK) {
2603 CAAL("connect_time_us", co);
2604 }
2605 if (curl_easy_getinfo(ch->cp, CURLINFO_NAMELOOKUP_TIME_T, &co) == CURLE_OK) {
2606 CAAL("namelookup_time_us", co);
2607 }
2608 if (curl_easy_getinfo(ch->cp, CURLINFO_PRETRANSFER_TIME_T, &co) == CURLE_OK) {
2609 CAAL("pretransfer_time_us", co);
2610 }
2611 if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_TIME_T, &co) == CURLE_OK) {
2612 CAAL("redirect_time_us", co);
2613 }
2614 if (curl_easy_getinfo(ch->cp, CURLINFO_STARTTRANSFER_TIME_T, &co) == CURLE_OK) {
2615 CAAL("starttransfer_time_us", co);
2616 }
2617#if LIBCURL_VERSION_NUM >= 0x080a00 /* Available since 8.10.0 */
2618 if (curl_easy_getinfo(ch->cp, CURLINFO_POSTTRANSFER_TIME_T, &co) == CURLE_OK) {
2619 CAAL("posttransfer_time_us", co);
2620 }
2621#endif
2622 if (curl_easy_getinfo(ch->cp, CURLINFO_TOTAL_TIME_T, &co) == CURLE_OK) {
2623 CAAL("total_time_us", co);
2624 }
2625 if (ch->header.str) {
2626 CAASTR("request_header", ch->header.str);
2627 }
2628#if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */
2629 if (curl_easy_getinfo(ch->cp, CURLINFO_EFFECTIVE_METHOD, &s_code) == CURLE_OK) {
2630 CAAS("effective_method", s_code);
2631 }
2632#endif
2633#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
2634 if (curl_easy_getinfo(ch->cp, CURLINFO_CAPATH, &s_code) == CURLE_OK) {
2635 CAAS("capath", s_code);
2636 }
2637 if (curl_easy_getinfo(ch->cp, CURLINFO_CAINFO, &s_code) == CURLE_OK) {
2638 CAAS("cainfo", s_code);
2639 }
2640#endif
2641 } else {
2642 switch (option) {
2644 if (ch->header.str) {
2645 RETURN_STR_COPY(ch->header.str);
2646 } else {
2648 }
2649 case CURLINFO_CERTINFO: {
2650 struct curl_certinfo *ci = NULL;
2651
2653
2654 if (curl_easy_getinfo(ch->cp, CURLINFO_CERTINFO, &ci) == CURLE_OK) {
2655 create_certinfo(ci, return_value);
2656 } else {
2658 }
2659 break;
2660 }
2661 case CURLINFO_PRIVATE:
2662 if (!Z_ISUNDEF(ch->private_data)) {
2663 RETURN_COPY(&ch->private_data);
2664 } else {
2666 }
2667 break;
2668 default: {
2669 int type = CURLINFO_TYPEMASK & option;
2670 switch (type) {
2671 case CURLINFO_STRING:
2672 {
2673 char *s_code = NULL;
2674
2675 if (curl_easy_getinfo(ch->cp, option, &s_code) == CURLE_OK && s_code) {
2676 RETURN_STRING(s_code);
2677 } else {
2679 }
2680 break;
2681 }
2682 case CURLINFO_LONG:
2683 {
2684 zend_long code = 0;
2685
2686 if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
2687 RETURN_LONG(code);
2688 } else {
2690 }
2691 break;
2692 }
2693 case CURLINFO_DOUBLE:
2694 {
2695 double code = 0.0;
2696
2697 if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
2698 RETURN_DOUBLE(code);
2699 } else {
2701 }
2702 break;
2703 }
2704 case CURLINFO_SLIST:
2705 {
2706 struct curl_slist *slist;
2707 if (curl_easy_getinfo(ch->cp, option, &slist) == CURLE_OK) {
2708 struct curl_slist *current = slist;
2710 while (current) {
2712 current = current->next;
2713 }
2714 curl_slist_free_all(slist);
2715 } else {
2717 }
2718 break;
2719 }
2720 case CURLINFO_OFF_T:
2721 {
2722 curl_off_t c_off;
2723 if (curl_easy_getinfo(ch->cp, option, &c_off) == CURLE_OK) {
2724 RETURN_LONG((long) c_off);
2725 } else {
2727 }
2728 break;
2729 }
2730 default:
2732 }
2733 }
2734 }
2735 }
2736}
2737/* }}} */
2738
2739/* {{{ Return a string contain the last error for the current session */
2741{
2742 zval *zid;
2743 php_curl *ch;
2744
2748
2749 ch = Z_CURL_P(zid);
2750
2751 if (ch->err.no) {
2752 ch->err.str[CURL_ERROR_SIZE] = 0;
2753 if (strlen(ch->err.str) > 0) {
2754 RETURN_STRING(ch->err.str);
2755 } else {
2756 RETURN_STRING(curl_easy_strerror(ch->err.no));
2757 }
2758 } else {
2760 }
2761}
2762/* }}} */
2763
2764/* {{{ Return an integer containing the last error number */
2766{
2767 zval *zid;
2768 php_curl *ch;
2769
2773
2774 ch = Z_CURL_P(zid);
2775
2776 RETURN_LONG(ch->err.no);
2777}
2778/* }}} */
2779
2780/* {{{ Close a cURL session */
2782{
2783 zval *zid;
2784 php_curl *ch;
2785
2789
2790 ch = Z_CURL_P(zid);
2791
2792 if (ch->in_callback) {
2793 zend_throw_error(NULL, "%s(): Attempt to close cURL handle from a callback", get_active_function_name());
2794 RETURN_THROWS();
2795 }
2796}
2797/* }}} */
2798
2799static void curl_free_obj(zend_object *object)
2800{
2801 php_curl *ch = curl_from_obj(object);
2802
2803#if PHP_CURL_DEBUG
2804 fprintf(stderr, "DTOR CALLED, ch = %x\n", ch);
2805#endif
2806
2807 if (!ch->cp) {
2808 /* Can happen if constructor throws. */
2809 zend_object_std_dtor(&ch->std);
2810 return;
2811 }
2812
2813 _php_curl_verify_handlers(ch, /* reporterror */ false);
2814
2815 curl_easy_cleanup(ch->cp);
2816
2817 /* cURL destructors should be invoked only by last curl handle */
2818 if (--(*ch->clone) == 0) {
2819 zend_llist_clean(&ch->to_free->post);
2820 zend_llist_clean(&ch->to_free->stream);
2821
2822 zend_hash_destroy(ch->to_free->slist);
2823 efree(ch->to_free->slist);
2824 efree(ch->to_free);
2825 efree(ch->clone);
2826 }
2827
2828 smart_str_free(&ch->handlers.write->buf);
2829 if (ZEND_FCC_INITIALIZED(ch->handlers.write->fcc)) {
2830 zend_fcc_dtor(&ch->handlers.write->fcc);
2831 }
2832 if (ZEND_FCC_INITIALIZED(ch->handlers.write_header->fcc)) {
2833 zend_fcc_dtor(&ch->handlers.write_header->fcc);
2834 }
2835 if (ZEND_FCC_INITIALIZED(ch->handlers.read->fcc)) {
2836 zend_fcc_dtor(&ch->handlers.read->fcc);
2837 }
2838 zval_ptr_dtor(&ch->handlers.std_err);
2839 if (ch->header.str) {
2840 zend_string_release_ex(ch->header.str, 0);
2841 }
2842
2843 zval_ptr_dtor(&ch->handlers.write_header->stream);
2844 zval_ptr_dtor(&ch->handlers.write->stream);
2845 zval_ptr_dtor(&ch->handlers.read->stream);
2846
2847 efree(ch->handlers.write);
2848 efree(ch->handlers.write_header);
2849 efree(ch->handlers.read);
2850
2851 if (ZEND_FCC_INITIALIZED(ch->handlers.progress)) {
2852 zend_fcc_dtor(&ch->handlers.progress);
2853 }
2854 if (ZEND_FCC_INITIALIZED(ch->handlers.xferinfo)) {
2855 zend_fcc_dtor(&ch->handlers.xferinfo);
2856 }
2857 if (ZEND_FCC_INITIALIZED(ch->handlers.fnmatch)) {
2858 zend_fcc_dtor(&ch->handlers.fnmatch);
2859 }
2860 if (ZEND_FCC_INITIALIZED(ch->handlers.debug)) {
2861 zend_fcc_dtor(&ch->handlers.debug);
2862 }
2863#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
2864 if (ZEND_FCC_INITIALIZED(ch->handlers.prereq)) {
2865 zend_fcc_dtor(&ch->handlers.prereq);
2866 }
2867#endif
2868#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
2869 if (ZEND_FCC_INITIALIZED(ch->handlers.sshhostkey)) {
2870 zend_fcc_dtor(&ch->handlers.sshhostkey);
2871 }
2872#endif
2873
2874 zval_ptr_dtor(&ch->postfields);
2875 zval_ptr_dtor(&ch->private_data);
2876
2877 if (ch->share) {
2878 OBJ_RELEASE(&ch->share->std);
2879 }
2880
2881 zend_object_std_dtor(&ch->std);
2882}
2883/* }}} */
2884
2885/* {{{ return string describing error code */
2887{
2888 zend_long code;
2889 const char *str;
2890
2892 Z_PARAM_LONG(code)
2894
2895 str = curl_easy_strerror(code);
2896 if (str) {
2897 RETURN_STRING(str);
2898 } else {
2899 RETURN_NULL();
2900 }
2901}
2902/* }}} */
2903
2904/* {{{ _php_curl_reset_handlers()
2905 Reset all handlers of a given php_curl */
2906static void _php_curl_reset_handlers(php_curl *ch)
2907{
2908 if (!Z_ISUNDEF(ch->handlers.write->stream)) {
2909 zval_ptr_dtor(&ch->handlers.write->stream);
2910 ZVAL_UNDEF(&ch->handlers.write->stream);
2911 }
2912 ch->handlers.write->fp = NULL;
2913 ch->handlers.write->method = PHP_CURL_STDOUT;
2914
2915 if (!Z_ISUNDEF(ch->handlers.write_header->stream)) {
2916 zval_ptr_dtor(&ch->handlers.write_header->stream);
2917 ZVAL_UNDEF(&ch->handlers.write_header->stream);
2918 }
2919 ch->handlers.write_header->fp = NULL;
2920 ch->handlers.write_header->method = PHP_CURL_IGNORE;
2921
2922 if (!Z_ISUNDEF(ch->handlers.read->stream)) {
2923 zval_ptr_dtor(&ch->handlers.read->stream);
2924 ZVAL_UNDEF(&ch->handlers.read->stream);
2925 }
2926 ch->handlers.read->fp = NULL;
2927 ch->handlers.read->res = NULL;
2928 ch->handlers.read->method = PHP_CURL_DIRECT;
2929
2930 if (!Z_ISUNDEF(ch->handlers.std_err)) {
2931 zval_ptr_dtor(&ch->handlers.std_err);
2932 ZVAL_UNDEF(&ch->handlers.std_err);
2933 }
2934
2935 if (ZEND_FCC_INITIALIZED(ch->handlers.progress)) {
2936 zend_fcc_dtor(&ch->handlers.progress);
2937 }
2938
2939 if (ZEND_FCC_INITIALIZED(ch->handlers.xferinfo)) {
2940 zend_fcc_dtor(&ch->handlers.xferinfo);
2941 }
2942
2943 if (ZEND_FCC_INITIALIZED(ch->handlers.fnmatch)) {
2944 zend_fcc_dtor(&ch->handlers.fnmatch);
2945 }
2946
2947 if (ZEND_FCC_INITIALIZED(ch->handlers.debug)) {
2948 zend_fcc_dtor(&ch->handlers.debug);
2949 }
2950#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
2951 if (ZEND_FCC_INITIALIZED(ch->handlers.prereq)) {
2952 zend_fcc_dtor(&ch->handlers.prereq);
2953 }
2954#endif
2955#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
2956 if (ZEND_FCC_INITIALIZED(ch->handlers.sshhostkey)) {
2957 zend_fcc_dtor(&ch->handlers.sshhostkey);
2958 }
2959#endif
2960}
2961/* }}} */
2962
2963/* {{{ Reset all options of a libcurl session handle */
2965{
2966 zval *zid;
2967 php_curl *ch;
2968
2972
2973 ch = Z_CURL_P(zid);
2974
2975 if (ch->in_callback) {
2976 zend_throw_error(NULL, "%s(): Attempt to reset cURL handle from a callback", get_active_function_name());
2977 RETURN_THROWS();
2978 }
2979
2980 curl_easy_reset(ch->cp);
2981 _php_curl_reset_handlers(ch);
2982 _php_curl_set_default_options(ch);
2983}
2984/* }}} */
2985
2986/* {{{ URL encodes the given string */
2988{
2989 zend_string *str;
2990 char *res;
2991 zval *zid;
2992 php_curl *ch;
2993
2996 Z_PARAM_STR(str)
2998
2999 ch = Z_CURL_P(zid);
3000
3001 if (ZEND_SIZE_T_INT_OVFL(ZSTR_LEN(str))) {
3003 }
3004
3005 if ((res = curl_easy_escape(ch->cp, ZSTR_VAL(str), ZSTR_LEN(str)))) {
3007 curl_free(res);
3008 } else {
3010 }
3011}
3012/* }}} */
3013
3014/* {{{ URL decodes the given string */
3016{
3017 char *out = NULL;
3018 int out_len;
3019 zval *zid;
3020 zend_string *str;
3021 php_curl *ch;
3022
3025 Z_PARAM_STR(str)
3027
3028 ch = Z_CURL_P(zid);
3029
3030 if (ZEND_SIZE_T_INT_OVFL(ZSTR_LEN(str))) {
3032 }
3033
3034 if ((out = curl_easy_unescape(ch->cp, ZSTR_VAL(str), ZSTR_LEN(str), &out_len))) {
3035 RETVAL_STRINGL(out, out_len);
3036 curl_free(out);
3037 } else {
3039 }
3040}
3041/* }}} */
3042
3043/* {{{ pause and unpause a connection */
3045{
3047 zval *zid;
3048 php_curl *ch;
3049
3054
3055 ch = Z_CURL_P(zid);
3056
3057 RETURN_LONG(curl_easy_pause(ch->cp, bitmask));
3058}
3059/* }}} */
3060
3061#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */
3062/* {{{ perform connection upkeep checks */
3064{
3065 CURLcode error;
3066 zval *zid;
3067 php_curl *ch;
3068
3072
3073 ch = Z_CURL_P(zid);
3074
3075 error = curl_easy_upkeep(ch->cp);
3077
3079}
3080/*}}} */
3081#endif
size_t len
Definition apprentice.c:174
bool exception
Definition assert.c:30
fprintf($stream, string $format, mixed ... $values)
file(string $filename, int $flags=0, $context=null)
fwrite($stream, string $data, ?int $length=null)
fread($stream, int $length)
fflush($stream)
filesize(string $filename)
char s[4]
Definition cdf.c:77
void _php_curl_cleanup_handle(php_curl *ch)
Definition interface.c:2404
void init_curl_handle(php_curl *ch)
Definition interface.c:1122
#define CAAL(s, v)
Definition interface.c:91
#define CAAD(s, v)
Definition interface.c:92
#define HANDLE_CURL_OPTION_CALLABLE(curl_ptr, constant_no_function, handler_fcc, c_callback)
Definition interface.c:1654
zend_class_entry * curl_ce
Definition interface.c:228
#define CAAS(s, v)
Definition interface.c:93
php_curl * init_curl_handle_into_zval(zval *curl)
Definition interface.c:1110
zend_result curl_cast_object(zend_object *obj, zval *result, int type)
Definition interface.c:530
zend_class_entry * curl_share_ce
Definition interface.c:229
void _php_curl_verify_handlers(php_curl *ch, bool reporterror)
Definition interface.c:143
#define HANDLE_CURL_OPTION_CALLABLE_PHP_CURL_USER(curl_ptr, constant_no_function, handler_type, default_method)
Definition interface.c:1639
#define CAAZ(s, v)
Definition interface.c:96
zend_module_entry curl_module_entry
Definition interface.c:208
void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
Definition interface.c:1263
#define HttpPost
Definition interface.c:39
#define CAASTR(s, v)
Definition interface.c:94
const CURLOPT_RESUME_FROM
const CURLINFO_STARTTRANSFER_TIME_T
const CURLOPT_EXPECT_100_TIMEOUT_MS
const CURLOPT_SSL_VERIFYPEER
const CURLOPT_SSLCERTTYPE
curl_strerror(int $error_code)
const CURLOPT_MAIL_RCPT
const CURLOPT_REDIR_PROTOCOLS
const CURLOPT_PROXY_SERVICE_NAME
curl_setopt_array(CurlHandle $handle, array $options)
const CURLOPT_SSL_ENABLE_NPN
const CURLINFO_SSL_VERIFYRESULT
const CURLOPT_SSL_ENABLE_ALPN
const CURLOPT_ISSUERCERT_BLOB
const CURLOPT_CAPATH
Definition curl.stub.php:34
const CURLOPT_COOKIE
Definition curl.stub.php:44
const CURLOPT_LOW_SPEED_TIME
const CURLINFO_TOTAL_TIME
const CURLOPT_TFTP_NO_OPTIONS
const CURLOPT_DNS_INTERFACE
const CURLOPT_PORT
const CURLOPT_HTTPPROXYTUNNEL
const CURLOPT_TLSAUTH_PASSWORD
const CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
const CURLINFO_CONNECT_TIME
const CURLOPT_MAXREDIRS
const CURLINFO_HEADER_OUT
const CURLINFO_FILETIME
const CURLOPT_PROXYUSERNAME
const CURLOPT_PROTOCOLS_STR
const CURLINFO_PROXY_SSL_VERIFYRESULT
const CURL_VERSION_LIBZ
const CURLOPT_PROXY_CAPATH
const CURLOPT_PROXY_ISSUERCERT
const CURLOPT_REFERER
const CURLINFO_HTTP_CODE
const CURLINFO_LOCAL_IP
curl_errno(CurlHandle $handle)
const CURLOPT_DNS_LOCAL_IP6
const CURLINFO_CONTENT_LENGTH_UPLOAD
const CURLOPT_PROXY_SSLCERT
curl_upkeep(CurlHandle $handle)
const CURL_VERSION_GSSAPI
const CURLOPT_UPKEEP_INTERVAL_MS
const CURLOPT_TRANSFER_ENCODING
const CURLOPT_SSH_PUBLIC_KEYFILE
const CURL_PREREQFUNC_OK
const CURLOPT_PROXY_SSLCERTTYPE
const CURLOPT_SUPPRESS_CONNECT_HEADERS
const CURLOPT_DNS_SERVERS
curl_unescape(CurlHandle $handle, string $string)
const CURLINFO_POSTTRANSFER_TIME_T
const CURLINFO_PRIMARY_PORT
const CURLOPT_BUFFERSIZE
Definition curl.stub.php:24
const CURLOPT_PROXY_TLSAUTH_TYPE
const CURLOPT_KEEP_SENDING_ON_ERROR
const CURLOPT_MAX_RECV_SPEED_LARGE
const CURLOPT_UPLOAD
const CURLOPT_CAINFO
Definition curl.stub.php:29
const CURLINFO_EFFECTIVE_METHOD
const CURLOPT_PROXYUSERPWD
const CURLOPT_CONNECTTIMEOUT_MS
const CURLOPT_PIPEWAIT
const CURLOPT_FILE
const CURLOPT_FTPPORT
const CURLOPT_IPRESOLVE
const CURLINFO_PRIMARY_IP
const CURLOPT_SSLVERSION
const CURLKHMATCH_OK
const CURL_VERSION_ALTSVC
curl_copy_handle(CurlHandle $handle)
const CURLOPT_TLSAUTH_USERNAME
const CURLOPT_DNS_USE_GLOBAL_CACHE
Definition curl.stub.php:79
const CURLOPT_PROXY_SSL_CIPHER_LIST
const CURLOPT_CRLFILE
const CURLOPT_ACCEPTTIMEOUT_MS
const CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256
const CURLOPT_SOCKS5_GSSAPI_SERVICE
const CURLINFO_PRIVATE
const CURLOPT_POSTREDIR
const CURLOPT_MAXFILESIZE
const CURLINFO_HTTP_VERSION
const CURLINFO_CAINFO
const CURLOPT_TELNETOPTIONS
const CURLOPT_PROXY_TRANSFER_MODE
const CURLOPT_FTP_USE_EPSV
const CURLINFO_CERTINFO
const CURLOPT_TIMEVALUE_LARGE
const CURL_VERSION_NTLM
curl_reset(CurlHandle $handle)
const CURLOPT_KRBLEVEL
const CURLOPT_SERVER_RESPONSE_TIMEOUT
const CURL_VERSION_TLSAUTH_SRP
const CURLOPT_SSL_SESSIONID_CACHE
const CURL_VERSION_UNICODE
const CURLOPT_IGNORE_CONTENT_LENGTH
const CURLOPT_PROXY_CAINFO
const CURLOPT_DIRLISTONLY
const CURLOPT_HAPROXYPROTOCOL
const CURLINFO_SIZE_UPLOAD
const CURLOPT_LOGIN_OPTIONS
const CURLE_OUT_OF_MEMORY
const CURL_VERSION_IPV6
const CURLOPT_FILETIME
const CURL_FNMATCHFUNC_FAIL
const CURLINFO_SIZE_DOWNLOAD
const CURLOPT_HTTPAUTH
const CURL_VERSION_LARGEFILE
const CURLOPT_TCP_FASTOPEN
const CURLINFO_PRETRANSFER_TIME
const CURLPROTO_FILE
const CURLOPT_QUOTE
const CURLOPT_RESOLVE
const CURL_VERSION_BROTLI
const CURLKHMATCH_MISMATCH
const CURLINFO_STARTTRANSFER_TIME
const CURLOPT_NOBODY
curl_getinfo(CurlHandle $handle, ?int $option=null)
const CURL_VERSION_UNIX_SOCKETS
const CURLOPT_USERNAME
const CURLOPT_CUSTOMREQUEST
Definition curl.stub.php:69
const CURL_VERSION_HSTS
curl_setopt(CurlHandle $handle, int $option, mixed $value)
const CURLOPT_PROXY_TLS13_CIPHERS
const CURLOPT_READFUNCTION
const CURLOPT_SSH_AUTH_TYPES
const CURLOPT_VERBOSE
const CURL_VERSION_PSL
const CURLINFO_REDIRECT_URL
const CURLOPT_PREQUOTE
const CURLOPT_MAXCONNECTS
const CURLOPT_DEBUGFUNCTION
curl_error(CurlHandle $handle)
const CURLOPT_PROXY_PINNEDPUBLICKEY
const CURL_VERSION_SSL
const CURLOPT_COOKIESESSION
Definition curl.stub.php:59
const CURLOPT_DNS_SHUFFLE_ADDRESSES
const CURLOPT_LOW_SPEED_LIMIT
const CURLOPT_TIMEOUT
const CURLOPT_SOCKS5_AUTH
const CURLOPT_SSL_OPTIONS
const CURLOPT_PROXY_SSLKEY
const CURLOPT_NOPROXY
const CURLOPT_HTTPHEADER
curl_init(?string $url=null)
const CURLOPT_PROXY
const CURLOPT_DOH_SSL_VERIFYHOST
const CURLOPT_SSLKEY_BLOB
const CURL_REDIR_POST_ALL
const CURLOPT_PRE_PROXY
curl_close(CurlHandle $handle)
const CURLOPT_SASL_AUTHZID
const CURLOPT_WRITEHEADER
const CURLOPT_TRANSFERTEXT
const CURLOPT_HTTP_CONTENT_DECODING
const CURLOPT_PROXY_SSL_OPTIONS
const CURLOPT_CAINFO_BLOB
const CURLOPT_TCP_KEEPINTVL
const CURL_VERSION_KERBEROS5
const CURLINFO_APPCONNECT_TIME_T
const CURLOPT_GSSAPI_DELEGATION
const CURLOPT_SSLKEY
const CURLOPT_ALTSVC
const CURLOPT_MAXFILESIZE_LARGE
const CURLOPT_FTP_USE_EPRT
const CURLOPT_CA_CACHE_TIMEOUT
const CURLOPT_CERTINFO
const CURLOPT_PROXY_SSLKEY_BLOB
const CURLOPT_DOH_SSL_VERIFYPEER
const CURLOPT_ALTSVC_CTRL
const CURLOPT_POST
const CURLOPT_LOCALPORTRANGE
const CURL_VERSION_NTLM_WB
const CURLOPT_USERAGENT
const CURLOPT_HTTP200ALIASES
const CURLOPT_INFILE
const CURLOPT_PROXY_TLSAUTH_USERNAME
const CURLOPT_UNIX_SOCKET_PATH
const CURLOPT_COOKIELIST
const CURLOPT_APPEND
const CURLOPT_MAIL_FROM
const CURLOPT_NOSIGNAL
const CURLOPT_FTP_CREATE_MISSING_DIRS
const CURLINFO_EFFECTIVE_URL
const CURLOPT_TCP_KEEPIDLE
const CURLOPT_COOKIEJAR
Definition curl.stub.php:54
const CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS
const CURLOPT_TLSAUTH_TYPE
const CURLINFO_NAMELOOKUP_TIME_T
const CURLOPT_SSL_FALSESTART
const CURLOPT_DNS_CACHE_TIMEOUT
Definition curl.stub.php:74
const CURLOPT_SSLKEYPASSWD
const CURLOPT_MAXLIFETIME_CONN
const CURL_VERSION_MULTI_SSL
const CURLOPT_PROXY_SSLVERSION
const CURLOPT_HSTS
const CURLOPT_RTSP_STREAM_URI
const CURLOPT_RTSP_CLIENT_CSEQ
const CURLOPT_HEADER
const CURLOPT_HTTP_TRANSFER_DECODING
const CURLINFO_SCHEME
const CURLOPT_HEADERFUNCTION
const CURL_VERSION_SPNEGO
const CURLINFO_SPEED_DOWNLOAD
const CURLOPT_FTP_SSL_CCC
const CURLOPT_REDIR_PROTOCOLS_STR
const CURLOPT_TIMECONDITION
const CURLOPT_SSH_PRIVATE_KEYFILE
const CURLOPT_PROXYTYPE
const CURLOPT_SSLENGINE_DEFAULT
const CURL_VERSION_SSPI
const CURLOPT_FTP_FILEMETHOD
const CURLOPT_SSL_CIPHER_LIST
const CURL_VERSION_ZSTD
const CURLOPT_QUICK_EXIT
const CURLOPT_USERPWD
const CURLOPT_AWS_SIGV4
const CURLOPT_AUTOREFERER
Definition curl.stub.php:13
const CURL_VERSION_IDN
const CURLOPT_WRITEFUNCTION
const CURLOPT_CRLF
Definition curl.stub.php:64
const CURLOPT_RTSP_REQUEST
const CURLOPT_ADDRESS_SCOPE
const CURLOPT_ACCEPT_ENCODING
const CURL_VERSION_HTTP2
const CURLOPT_FORBID_REUSE
const CURLOPT_EGDSOCKET
Definition curl.stub.php:84
const CURLINFO_REQUEST_SIZE
const CURLOPT_TIMEOUT_MS
const CURLOPT_SSH_KNOWNHOSTS
const CURL_VERSION_ASYNCHDNS
const CURLINFO_REDIRECT_TIME
const CURLOPT_PINNEDPUBLICKEY
const CURLOPT_NOPROGRESS
const CURLOPT_FTP_ALTERNATIVE_TO_USER
const CURLOPT_WILDCARDMATCH
const CURLOPT_MIME_OPTIONS
const CURL_VERSION_HTTP3
const CURLOPT_TFTP_BLKSIZE
const CURLOPT_TIMEVALUE
const CURLOPT_DOH_SSL_VERIFYSTATUS
const CURLOPT_PROXY_SSL_VERIFYPEER
const CURL_PREREQFUNC_ABORT
const CURLOPT_CONNECTTIMEOUT
Definition curl.stub.php:39
const CURLOPT_PROTOCOLS
const CURLOPT_ISSUERCERT
const CURL_VERSION_DEBUG
const CURLOPT_PATH_AS_IS
const CURLOPT_STREAM_WEIGHT
const CURLOPT_PROXY_TLSAUTH_PASSWORD
const CURLOPT_UPLOAD_BUFFERSIZE
const CURLOPT_RTSP_SERVER_CSEQ
const CURLOPT_DNS_LOCAL_IP4
const CURLOPT_MAIL_AUTH
const CURLOPT_TLS13_CIPHERS
const CURLOPT_DOH_URL
const CURLOPT_TCP_KEEPALIVE
const CURLOPT_SSLCERT_BLOB
const CURLOPT_RANGE
const CURL_VERSION_HTTPS_PROXY
const CURLOPT_WS_OPTIONS
const CURLOPT_PROXYHEADER
const CURLOPT_PROXY_CRLFILE
const CURLOPT_SSLCERT
const CURLOPT_FTPSSLAUTH
const CURLOPT_RANDOM_FILE
const CURLOPT_POSTQUOTE
const CURLINFO_TOTAL_TIME_T
const CURLE_OK
const CURLPROTO_ALL
const CURLOPT_PROXY_SSLCERT_BLOB
const CURLOPT_ABSTRACT_UNIX_SOCKET
const CURLOPT_PASSWORD
const CURLINFO_LOCAL_PORT
const CURLOPT_UNRESTRICTED_AUTH
const CURLOPT_MAXAGE_CONN
const CURLOPT_SSH_COMPRESSION
const CURLOPT_MAIL_RCPT_ALLLOWFAILS
curl_exec(CurlHandle $handle)
const CURLOPT_FAILONERROR
Definition curl.stub.php:95
const CURLOPT_TCP_NODELAY
const CURLOPT_HSTS_CTRL
const CURLOPT_SSL_EC_CURVES
const CURLOPT_SSLENGINE
const CURLOPT_RTSP_TRANSPORT
const CURLOPT_PROXY_SSLKEYTYPE
const CURLOPT_FRESH_CONNECT
const CURLOPT_PUT
const CURLOPT_FTP_SKIP_PASV_IP
curl_escape(CurlHandle $handle, string $string)
const CURLOPT_SHARE
const CURLINFO_CONNECT_TIME_T
const CURLOPT_PROXY_KEYPASSWD
const CURLOPT_PRIVATE
const CURLINFO_CAPATH
const CURLINFO_PRETRANSFER_TIME_T
const CURLOPT_SERVICE_NAME
const CURLOPT_FOLLOWLOCATION
const CURLINFO_REDIRECT_COUNT
const CURLOPT_USE_SSL
const CURLOPT_INTERFACE
const CURLOPT_SSLKEYTYPE
const CURLOPT_REQUEST_TARGET
const CURLOPT_HTTP_VERSION
const CURLOPT_STDERR
const CURLOPT_PROXY_SSL_VERIFYHOST
const CURLOPT_SSL_VERIFYSTATUS
const CURLINFO_CONTENT_TYPE
const CURLOPT_PROXY_ISSUERCERT_BLOB
const CURLOPT_NETRC_FILE
const CURLINFO_CONTENT_LENGTH_DOWNLOAD
const CURL_VERSION_GSASL
const CURLOPT_DISALLOW_USERNAME_IN_URL
const CURLOPT_SASL_IR
const CURLOPT_HEADEROPT
const CURLOPT_CONNECT_ONLY
const CURLOPT_HTTPGET
const CURLOPT_PROXYPORT
const CURLOPT_INFILESIZE
const CURLOPT_URL
const CURLINFO_REDIRECT_TIME_T
const CURLOPT_PROXY_CAINFO_BLOB
const CURLINFO_PROTOCOL
const CURLOPT_SOCKS5_GSSAPI_NEC
const CURLINFO_NAMELOOKUP_TIME
const CURLINFO_SPEED_UPLOAD
const CURLOPT_TCP_KEEPCNT
const CURLOPT_NEW_DIRECTORY_PERMS
const CURL_VERSION_GSSNEGOTIATE
const CURLOPT_CONNECT_TO
const CURLOPT_NETRC
const CURLOPT_RTSP_SESSION_ID
const CURLOPT_PROXYPASSWORD
const CURL_VERSION_KERBEROS4
const CURLOPT_NEW_FILE_PERMS
curl_version()
const CURLOPT_HTTP09_ALLOWED
const CURLOPT_XOAUTH2_BEARER
const CURLOPT_LOCALPORT
const CURL_VERSION_CONV
const CURLOPT_POSTFIELDS
const CURLOPT_MAX_SEND_SPEED_LARGE
const CURLOPT_SSL_VERIFYHOST
const CURLINFO_HEADER_SIZE
const CURLOPT_COOKIEFILE
Definition curl.stub.php:49
const CURLOPT_FTP_USE_PRET
const CURLOPT_DEFAULT_PROTOCOL
const CURLOPT_FTP_ACCOUNT
curl_pause(CurlHandle $handle, int $flags)
const CURLVERSION_NOW
const CURLOPT_PROXYAUTH
PHP_CURL_API zend_class_entry * curl_CURLFile_class
Definition curl_file.c:26
void curlfile_register_class(void)
Definition curl_file.c:146
PHP_CURL_API zend_class_entry * curl_CURLStringFile_class
Definition curl_file.c:27
void curl_share_register_handlers(void)
Definition share.c:163
#define PHP_CURL_IGNORE
#define Z_CURL_P(zv)
#define PHP_CURL_DIRECT
void curl_multi_register_handlers(void)
Definition multi.c:583
#define SAVE_CURL_ERROR(__handle, __err)
#define CURLOPT_SAFE_UPLOAD
struct _php_curlsh php_curlsh
#define Z_CURL_SHARE_P(zv)
#define CURLOPT_BINARYTRANSFER
#define CURLOPT_RETURNTRANSFER
#define PHP_CURL_FILE
#define PHP_CURL_RETURN
zend_result curl_cast_object(zend_object *obj, zval *result, int type)
Definition interface.c:530
#define PHP_CURL_USER
#define PHP_CURL_VERSION
#define PHP_CURL_STDOUT
error($message)
Definition ext_skel.php:22
zend_ffi_type * type
Definition ffi.c:3812
DL_HANDLE handle
Definition ffi.c:3028
zend_long ch
Definition ffi.c:4580
zend_long n
Definition ffi.c:4979
new_type size
Definition ffi.c:4365
zend_string * res
Definition ffi.c:4692
memcpy(ptr1, ptr2, size)
zval * arg
Definition ffi.c:3975
memset(ptr, 0, type->size)
zval * val
Definition ffi.c:4262
PHPAPI int php_check_open_basedir(const char *path)
zend_long offset
char * mode
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define bitmask(b)
Definition minilua.c:563
zend_class_entry * curl_multi_ce
Definition multi.c:51
#define memmove(a, b, c)
php_info_print_table_start()
Definition info.c:1064
php_info_print_table_row(2, "PDO Driver for Firebird", "enabled")
php_info_print_table_end()
Definition info.c:1074
#define PHP_FUNCTION
Definition php.h:364
#define PHP_MSHUTDOWN_FUNCTION
Definition php.h:401
#define PHP_MINFO
Definition php.h:396
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define php_memnistr
Definition php.h:344
#define PHP_MSHUTDOWN
Definition php.h:393
#define PHP_MINFO_FUNCTION
Definition php.h:404
#define PHP_MINIT
Definition php.h:392
int line
Definition php_ffi.h:54
#define PG(v)
Definition php_globals.h:31
#define PHP_INI_BEGIN
Definition php_ini.h:52
#define PHP_INI_ENTRY
Definition php_ini.h:62
#define PHP_INI_SYSTEM
Definition php_ini.h:43
#define PHP_INI_END
Definition php_ini.h:53
PHP_JSON_API size_t int options
Definition php_json.h:102
#define PHPWRITE(str, str_len)
zend_stack handlers
Definition php_output.h:139
unsigned char key[REFLECTION_KEY_LEN]
#define php_stream_cast(stream, as, ret, show_err)
struct _php_stream php_stream
Definition php_streams.h:96
#define REPORT_ERRORS
#define php_stream_read(stream, buf, count)
#define IGNORE_PATH
#define php_stream_seek(stream, offset, whence)
#define php_stream_flush(stream)
#define php_stream_close(stream)
#define php_stream_open_wrapper(path, mode, options, opened)
PHPAPI int php_file_le_pstream(void)
Definition streams.c:47
#define php_stream_stat(stream, ssb)
#define STREAM_MUST_SEEK
#define PHP_STREAM_AS_STDIO
struct _php_stream_statbuf php_stream_statbuf
PHPAPI int php_file_le_stream(void)
Definition streams.c:42
zend_constant * data
zval * current
Definition session.c:1024
zval rv
Definition session.c:1024
p
Definition session.c:1105
CURLSH * share
zend_object std
php_stream_filter_chain readfilters
char mode[16]
uint32_t handle
Definition zend_types.h:558
Definition file.h:177
php_stream * stream
Definition interface.c:974
zend_string * filename
Definition interface.c:973
zend_fcall_info_cache fnmatch
zend_fcall_info_cache progress
php_curl_write * write
php_curl_read * read
zend_fcall_info_cache debug
php_curl_write * write_header
zend_fcall_info_cache xferinfo
zend_resource * res
zend_fcall_info_cache fcc
zend_fcall_info_cache fcc
smart_str buf
CURL * cp
zval private_data
zval postfields
struct _php_curl_free * to_free
zend_object std
uint32_t * clone
php_curl_handlers handlers
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_type_error(const char *format,...)
Definition zend.c:1824
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
ZEND_API zval * zend_read_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, bool silent, zval *rv)
Definition zend_API.c:5187
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
Definition zend_API.c:1849
ZEND_API zval * zend_read_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, bool silent, zval *rv)
Definition zend_API.c:5201
ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type)
Definition zend_API.c:1688
ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error)
Definition zend_API.c:4271
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:423
ZEND_API zend_result add_next_index_string(zval *arg, const char *str)
Definition zend_API.c:2186
ZEND_API const zend_fcall_info_cache empty_fcall_info_cache
struct _zend_fcall_info_cache zend_fcall_info_cache
#define RETURN_STRING(s)
Definition zend_API.h:1043
#define RETURN_COPY(zv)
Definition zend_API.h:1054
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define RETVAL_STRING(s)
Definition zend_API.h:1017
#define RETURN_DOUBLE(d)
Definition zend_API.h:1038
#define Z_PARAM_STR_OR_NULL(dest)
Definition zend_API.h:2089
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define RETURN_NULL()
Definition zend_API.h:1036
#define ZVAL_STRING(z, s)
Definition zend_API.h:956
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define ZEND_GET_MODULE(name)
Definition zend_API.h:241
#define Z_PARAM_STR(dest)
Definition zend_API.h:2086
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_BOOL(b)
Definition zend_API.h:1035
#define RETURN_THROWS()
Definition zend_API.h:1060
#define HASH_OF(p)
Definition zend_API.h:1062
#define Z_PARAM_LONG_OR_NULL(dest, is_null)
Definition zend_API.h:1899
#define ZEND_FCC_INITIALIZED(fcc)
Definition zend_API.h:341
#define Z_PARAM_OBJECT_OF_CLASS(dest, _ce)
Definition zend_API.h:1976
#define RETURN_EMPTY_STRING()
Definition zend_API.h:1047
#define Z_PARAM_ARRAY(dest)
Definition zend_API.h:1682
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define ZVAL_STRINGL(z, s, l)
Definition zend_API.h:952
#define RETURN_TRUE
Definition zend_API.h:1059
#define RETVAL_STRINGL(s, l)
Definition zend_API.h:1018
#define RETURN_STR_COPY(s)
Definition zend_API.h:1042
#define array_init(arg)
Definition zend_API.h:537
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define efree(ptr)
Definition zend_alloc.h:155
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
zend_string_release_ex(func->internal_function.function_name, 0)
zval * args
#define snprintf
#define E_NOTICE
Definition zend_errors.h:26
#define E_WARNING
Definition zend_errors.h:24
ZEND_API ZEND_COLD zend_object * zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code)
ZEND_API const char * get_active_function_name(void)
union _zend_function zend_function
ZEND_API zend_get_gc_buffer * zend_get_gc_buffer_create(void)
Definition zend_gc.c:2130
#define EG(v)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val)
Definition zend_hash.h:1181
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1102
#define UNREGISTER_INI_ENTRIES()
Definition zend_ini.h:204
#define REGISTER_INI_ENTRIES()
Definition zend_ini.h:203
#define DISPLAY_INI_ENTRIES()
Definition zend_ini.h:205
#define INI_STR(name)
Definition zend_ini.h:195
ZEND_API void * zend_fetch_resource2_ex(zval *res, const char *resource_type_name, int resource_type1, int resource_type2)
Definition zend_list.c:153
ZEND_API void zend_llist_add_element(zend_llist *l, const void *element)
Definition zend_llist.c:34
ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent)
Definition zend_llist.c:24
ZEND_API void zend_llist_clean(zend_llist *l)
Definition zend_llist.c:121
void(* llist_dtor_func_t)(void *)
Definition zend_llist.h:31
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
struct _zend_string zend_string
#define STANDARD_MODULE_HEADER
struct _zend_module_entry zend_module_entry
#define STANDARD_MODULE_PROPERTIES
ZEND_API zend_result zend_std_cast_object_tostring(zend_object *readobj, zval *writeobj, int type)
ZEND_API int zend_objects_not_comparable(zval *o1, zval *o2)
ZEND_API HashTable * zend_std_get_properties(zend_object *zobj)
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
ZEND_API void zend_object_std_dtor(zend_object *object)
#define OBJ_RELEASE(obj)
ZEND_API zend_string *ZEND_FASTCALL zend_long_to_str(zend_long num)
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
#define ZEND_ATTRIBUTE_UNUSED
#define MIN(a, b)
#define ZEND_FALLTHROUGH
#define XtOffsetOf(s_type, field)
#define ZEND_ASSERT(c)
#define UNEXPECTED(condition)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZEND_SIZE_T_INT_OVFL(size)
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_KNOWN(idx)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define zend_string_starts_with_literal_ci(str, prefix)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_UNDEF(z)
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_NULL(z)
#define ZVAL_DEREF(z)
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_ISNULL_P(zval_p)
Definition zend_types.h:960
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_PTR_P(zval_p)
#define GC_ADDREF(p)
Definition zend_types.h:709
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_NULL
Definition zend_types.h:601
#define ZVAL_RES(z, r)
#define Z_OBJCE_P(zval_p)
#define ZVAL_OBJ(z, o)
#define Z_STRVAL(zval)
Definition zend_types.h:974
@ FAILURE
Definition zend_types.h:61
#define Z_STRLEN(zval)
Definition zend_types.h:977
#define IS_OBJECT
Definition zend_types.h:608
#define Z_ADDREF(z)
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_COPY(z, v)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define Z_RES_P(zval_p)
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define Z_LVAL(zval)
Definition zend_types.h:965
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
#define MAXPATHLEN
zval retval
zval * return_value
zend_string * name
bool result
zval * ret
out($f, $s)