1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2016 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: Sterling Hughes <sterling@php.net>                           |
16   +----------------------------------------------------------------------+
17*/
18
19/* $Id$ */
20
21#define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "php.h"
28
29#if HAVE_CURL
30
31#include <stdio.h>
32#include <string.h>
33
34#ifdef PHP_WIN32
35#include <winsock2.h>
36#include <sys/types.h>
37#endif
38
39#include <curl/curl.h>
40#include <curl/easy.h>
41
42/* As of curl 7.11.1 this is no longer defined inside curl.h */
43#ifndef HttpPost
44#define HttpPost curl_httppost
45#endif
46
47/* {{{ cruft for thread safe SSL crypto locks */
48#if defined(ZTS) && defined(HAVE_CURL_SSL)
49# ifdef PHP_WIN32
50#  define PHP_CURL_NEED_OPENSSL_TSL
51#  include <openssl/crypto.h>
52# else /* !PHP_WIN32 */
53#  if defined(HAVE_CURL_OPENSSL)
54#   if defined(HAVE_OPENSSL_CRYPTO_H)
55#    define PHP_CURL_NEED_OPENSSL_TSL
56#    include <openssl/crypto.h>
57#   else
58#    warning \
59	"libcurl was compiled with OpenSSL support, but configure could not find " \
60	"openssl/crypto.h; thus no SSL crypto locking callbacks will be set, which may " \
61	"cause random crashes on SSL requests"
62#   endif
63#  elif defined(HAVE_CURL_GNUTLS)
64#   if defined(HAVE_GCRYPT_H)
65#    define PHP_CURL_NEED_GNUTLS_TSL
66#    include <gcrypt.h>
67#   else
68#    warning \
69	"libcurl was compiled with GnuTLS support, but configure could not find " \
70	"gcrypt.h; thus no SSL crypto locking callbacks will be set, which may " \
71	"cause random crashes on SSL requests"
72#   endif
73#  else
74#   warning \
75	"libcurl was compiled with SSL support, but configure could not determine which" \
76	"library was used; thus no SSL crypto locking callbacks will be set, which may " \
77	"cause random crashes on SSL requests"
78#  endif /* HAVE_CURL_OPENSSL || HAVE_CURL_GNUTLS */
79# endif /* PHP_WIN32 */
80#endif /* ZTS && HAVE_CURL_SSL */
81/* }}} */
82
83#define SMART_STR_PREALLOC 4096
84
85#include "zend_smart_str.h"
86#include "ext/standard/info.h"
87#include "ext/standard/file.h"
88#include "ext/standard/url.h"
89#include "php_curl.h"
90
91int  le_curl;
92int  le_curl_multi_handle;
93int  le_curl_share_handle;
94
95#ifdef PHP_CURL_NEED_OPENSSL_TSL /* {{{ */
96static MUTEX_T *php_curl_openssl_tsl = NULL;
97
98static void php_curl_ssl_lock(int mode, int n, const char * file, int line)
99{
100	if (mode & CRYPTO_LOCK) {
101		tsrm_mutex_lock(php_curl_openssl_tsl[n]);
102	} else {
103		tsrm_mutex_unlock(php_curl_openssl_tsl[n]);
104	}
105}
106
107static unsigned long php_curl_ssl_id(void)
108{
109	return (unsigned long) tsrm_thread_id();
110}
111#endif
112/* }}} */
113
114#ifdef PHP_CURL_NEED_GNUTLS_TSL /* {{{ */
115static int php_curl_ssl_mutex_create(void **m)
116{
117	if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) {
118		return SUCCESS;
119	} else {
120		return FAILURE;
121	}
122}
123
124static int php_curl_ssl_mutex_destroy(void **m)
125{
126	tsrm_mutex_free(*((MUTEX_T *) m));
127	return SUCCESS;
128}
129
130static int php_curl_ssl_mutex_lock(void **m)
131{
132	return tsrm_mutex_lock(*((MUTEX_T *) m));
133}
134
135static int php_curl_ssl_mutex_unlock(void **m)
136{
137	return tsrm_mutex_unlock(*((MUTEX_T *) m));
138}
139
140static struct gcry_thread_cbs php_curl_gnutls_tsl = {
141	GCRY_THREAD_OPTION_USER,
142	NULL,
143	php_curl_ssl_mutex_create,
144	php_curl_ssl_mutex_destroy,
145	php_curl_ssl_mutex_lock,
146	php_curl_ssl_mutex_unlock
147};
148#endif
149/* }}} */
150
151static void _php_curl_close_ex(php_curl *ch);
152static void _php_curl_close(zend_resource *rsrc);
153
154
155#define SAVE_CURL_ERROR(__handle, __err) (__handle)->err.no = (int) __err;
156
157#define CAAL(s, v) add_assoc_long_ex(return_value, s, sizeof(s) - 1, (zend_long) v);
158#define CAAD(s, v) add_assoc_double_ex(return_value, s, sizeof(s) - 1, (double) v);
159#define CAAS(s, v) add_assoc_string_ex(return_value, s, sizeof(s) - 1, (char *) (v ? v : ""));
160#define CAASTR(s, v) add_assoc_str_ex(return_value, s, sizeof(s) - 1, \
161		v ? zend_string_copy(v) : ZSTR_EMPTY_ALLOC());
162#define CAAZ(s, v) add_assoc_zval_ex(return_value, s, sizeof(s) -1 , (zval *) v);
163
164#if defined(PHP_WIN32) || defined(__GNUC__)
165# define php_curl_ret(__ret) RETVAL_FALSE; return __ret;
166#else
167# define php_curl_ret(__ret) RETVAL_FALSE; return;
168#endif
169
170static int php_curl_option_str(php_curl *ch, zend_long option, const char *str, const int len, zend_bool make_copy)
171{
172	CURLcode error = CURLE_OK;
173
174	if (strlen(str) != len) {
175		php_error_docref(NULL, E_WARNING, "Curl option contains invalid characters (\\0)");
176		return FAILURE;
177	}
178
179#if LIBCURL_VERSION_NUM >= 0x071100
180	if (make_copy) {
181#endif
182		char *copystr;
183
184		/* Strings passed to libcurl as 'char *' arguments, are copied by the library since 7.17.0 */
185		copystr = estrndup(str, len);
186		error = curl_easy_setopt(ch->cp, option, copystr);
187		zend_llist_add_element(&ch->to_free->str, &copystr);
188#if LIBCURL_VERSION_NUM >= 0x071100
189	} else {
190		error = curl_easy_setopt(ch->cp, option, str);
191	}
192#endif
193
194	SAVE_CURL_ERROR(ch, error)
195
196	return error == CURLE_OK ? SUCCESS : FAILURE;
197}
198
199static int php_curl_option_url(php_curl *ch, const char *url, const int len) /* {{{ */
200{
201	/* Disable file:// if open_basedir are used */
202	if (PG(open_basedir) && *PG(open_basedir)) {
203#if LIBCURL_VERSION_NUM >= 0x071304
204		curl_easy_setopt(ch->cp, CURLOPT_PROTOCOLS, CURLPROTO_ALL & ~CURLPROTO_FILE);
205#else
206		php_url *uri;
207
208		if (!(uri = php_url_parse_ex(url, len))) {
209			php_error_docref(NULL, E_WARNING, "Invalid URL '%s'", url);
210			return FAILURE;
211		}
212
213		if (uri->scheme && !strncasecmp("file", uri->scheme, sizeof("file"))) {
214			php_error_docref(NULL, E_WARNING, "Protocol 'file' disabled in cURL");
215			php_url_free(uri);
216			return FAILURE;
217		}
218		php_url_free(uri);
219#endif
220	}
221
222	return php_curl_option_str(ch, CURLOPT_URL, url, len, 0);
223}
224/* }}} */
225
226void _php_curl_verify_handlers(php_curl *ch, int reporterror) /* {{{ */
227{
228	php_stream *stream;
229
230	ZEND_ASSERT(ch && ch->handlers);
231
232	if (!Z_ISUNDEF(ch->handlers->std_err)) {
233		stream = (php_stream *)zend_fetch_resource2_ex(&ch->handlers->std_err, NULL, php_file_le_stream(), php_file_le_pstream());
234		if (stream == NULL) {
235			if (reporterror) {
236				php_error_docref(NULL, E_WARNING, "CURLOPT_STDERR resource has gone away, resetting to stderr");
237			}
238			zval_ptr_dtor(&ch->handlers->std_err);
239			ZVAL_UNDEF(&ch->handlers->std_err);
240
241			curl_easy_setopt(ch->cp, CURLOPT_STDERR, stderr);
242		}
243	}
244	if (ch->handlers->read && !Z_ISUNDEF(ch->handlers->read->stream)) {
245		stream = (php_stream *)zend_fetch_resource2_ex(&ch->handlers->read->stream, NULL, php_file_le_stream(), php_file_le_pstream());
246		if (stream == NULL) {
247			if (reporterror) {
248				php_error_docref(NULL, E_WARNING, "CURLOPT_INFILE resource has gone away, resetting to default");
249			}
250			zval_ptr_dtor(&ch->handlers->read->stream);
251			ZVAL_UNDEF(&ch->handlers->read->stream);
252			ch->handlers->read->res = NULL;
253			ch->handlers->read->fp = 0;
254
255			curl_easy_setopt(ch->cp, CURLOPT_INFILE, (void *) ch);
256		}
257	}
258	if (ch->handlers->write_header && !Z_ISUNDEF(ch->handlers->write_header->stream)) {
259		stream = (php_stream *)zend_fetch_resource2_ex(&ch->handlers->write_header->stream, NULL, php_file_le_stream(), php_file_le_pstream());
260		if (stream == NULL) {
261			if (reporterror) {
262				php_error_docref(NULL, E_WARNING, "CURLOPT_WRITEHEADER resource has gone away, resetting to default");
263			}
264			zval_ptr_dtor(&ch->handlers->write_header->stream);
265			ZVAL_UNDEF(&ch->handlers->write_header->stream);
266			ch->handlers->write_header->fp = 0;
267
268			ch->handlers->write_header->method = PHP_CURL_IGNORE;
269			curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch);
270		}
271	}
272	if (ch->handlers->write && !Z_ISUNDEF(ch->handlers->write->stream)) {
273		stream = (php_stream *)zend_fetch_resource2_ex(&ch->handlers->write->stream, NULL, php_file_le_stream(), php_file_le_pstream());
274		if (stream == NULL) {
275			if (reporterror) {
276				php_error_docref(NULL, E_WARNING, "CURLOPT_FILE resource has gone away, resetting to default");
277			}
278			zval_ptr_dtor(&ch->handlers->write->stream);
279			ZVAL_UNDEF(&ch->handlers->write->stream);
280			ch->handlers->write->fp = 0;
281
282			ch->handlers->write->method = PHP_CURL_STDOUT;
283			curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch);
284		}
285	}
286	return;
287}
288/* }}} */
289
290/* {{{ arginfo */
291ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_version, 0, 0, 0)
292	ZEND_ARG_INFO(0, version)
293ZEND_END_ARG_INFO()
294
295ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_init, 0, 0, 0)
296	ZEND_ARG_INFO(0, url)
297ZEND_END_ARG_INFO()
298
299ZEND_BEGIN_ARG_INFO(arginfo_curl_copy_handle, 0)
300	ZEND_ARG_INFO(0, ch)
301ZEND_END_ARG_INFO()
302
303ZEND_BEGIN_ARG_INFO(arginfo_curl_setopt, 0)
304	ZEND_ARG_INFO(0, ch)
305	ZEND_ARG_INFO(0, option)
306	ZEND_ARG_INFO(0, value)
307ZEND_END_ARG_INFO()
308
309ZEND_BEGIN_ARG_INFO(arginfo_curl_setopt_array, 0)
310	ZEND_ARG_INFO(0, ch)
311	ZEND_ARG_ARRAY_INFO(0, options, 0)
312ZEND_END_ARG_INFO()
313
314ZEND_BEGIN_ARG_INFO(arginfo_curl_exec, 0)
315	ZEND_ARG_INFO(0, ch)
316ZEND_END_ARG_INFO()
317
318ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_getinfo, 0, 0, 1)
319	ZEND_ARG_INFO(0, ch)
320	ZEND_ARG_INFO(0, option)
321ZEND_END_ARG_INFO()
322
323ZEND_BEGIN_ARG_INFO(arginfo_curl_error, 0)
324	ZEND_ARG_INFO(0, ch)
325ZEND_END_ARG_INFO()
326
327ZEND_BEGIN_ARG_INFO(arginfo_curl_errno, 0)
328	ZEND_ARG_INFO(0, ch)
329ZEND_END_ARG_INFO()
330
331ZEND_BEGIN_ARG_INFO(arginfo_curl_close, 0)
332	ZEND_ARG_INFO(0, ch)
333ZEND_END_ARG_INFO()
334
335#if LIBCURL_VERSION_NUM >= 0x070c01 /* 7.12.1 */
336ZEND_BEGIN_ARG_INFO(arginfo_curl_reset, 0)
337	ZEND_ARG_INFO(0, ch)
338ZEND_END_ARG_INFO()
339#endif
340
341#if LIBCURL_VERSION_NUM > 0x070f03 /* 7.15.4 */
342ZEND_BEGIN_ARG_INFO(arginfo_curl_escape, 0)
343	ZEND_ARG_INFO(0, ch)
344	ZEND_ARG_INFO(0, str)
345ZEND_END_ARG_INFO()
346
347ZEND_BEGIN_ARG_INFO(arginfo_curl_unescape, 0)
348	ZEND_ARG_INFO(0, ch)
349	ZEND_ARG_INFO(0, str)
350ZEND_END_ARG_INFO()
351
352ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_setopt, 0)
353	ZEND_ARG_INFO(0, sh)
354	ZEND_ARG_INFO(0, option)
355	ZEND_ARG_INFO(0, value)
356ZEND_END_ARG_INFO()
357#endif
358
359ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_init, 0)
360ZEND_END_ARG_INFO()
361
362ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_add_handle, 0)
363	ZEND_ARG_INFO(0, mh)
364	ZEND_ARG_INFO(0, ch)
365ZEND_END_ARG_INFO()
366
367ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_remove_handle, 0)
368	ZEND_ARG_INFO(0, mh)
369	ZEND_ARG_INFO(0, ch)
370ZEND_END_ARG_INFO()
371
372ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_select, 0, 0, 1)
373	ZEND_ARG_INFO(0, mh)
374	ZEND_ARG_INFO(0, timeout)
375ZEND_END_ARG_INFO()
376
377ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_exec, 0, 0, 1)
378	ZEND_ARG_INFO(0, mh)
379	ZEND_ARG_INFO(1, still_running)
380ZEND_END_ARG_INFO()
381
382ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_getcontent, 0)
383	ZEND_ARG_INFO(0, ch)
384ZEND_END_ARG_INFO()
385
386ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_info_read, 0, 0, 1)
387	ZEND_ARG_INFO(0, mh)
388	ZEND_ARG_INFO(1, msgs_in_queue)
389ZEND_END_ARG_INFO()
390
391ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_close, 0)
392	ZEND_ARG_INFO(0, mh)
393ZEND_END_ARG_INFO()
394
395#if LIBCURL_VERSION_NUM >= 0x070c00 /* Available since 7.12.0 */
396ZEND_BEGIN_ARG_INFO(arginfo_curl_strerror, 0)
397	ZEND_ARG_INFO(0, errornum)
398ZEND_END_ARG_INFO()
399
400ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_strerror, 0)
401	ZEND_ARG_INFO(0, errornum)
402ZEND_END_ARG_INFO()
403#endif
404
405ZEND_BEGIN_ARG_INFO(arginfo_curl_share_init, 0)
406ZEND_END_ARG_INFO()
407
408ZEND_BEGIN_ARG_INFO(arginfo_curl_share_close, 0)
409	ZEND_ARG_INFO(0, sh)
410ZEND_END_ARG_INFO()
411
412ZEND_BEGIN_ARG_INFO(arginfo_curl_share_setopt, 0)
413	ZEND_ARG_INFO(0, sh)
414	ZEND_ARG_INFO(0, option)
415	ZEND_ARG_INFO(0, value)
416ZEND_END_ARG_INFO()
417
418#if LIBCURL_VERSION_NUM >= 0x071200 /* Available since 7.18.0 */
419ZEND_BEGIN_ARG_INFO(arginfo_curl_pause, 0)
420	ZEND_ARG_INFO(0, ch)
421	ZEND_ARG_INFO(0, bitmask)
422ZEND_END_ARG_INFO()
423#endif
424
425ZEND_BEGIN_ARG_INFO_EX(arginfo_curlfile_create, 0, 0, 1)
426	ZEND_ARG_INFO(0, filename)
427	ZEND_ARG_INFO(0, mimetype)
428	ZEND_ARG_INFO(0, postname)
429ZEND_END_ARG_INFO()
430/* }}} */
431
432/* {{{ curl_functions[]
433 */
434const zend_function_entry curl_functions[] = {
435	PHP_FE(curl_init,                arginfo_curl_init)
436	PHP_FE(curl_copy_handle,         arginfo_curl_copy_handle)
437	PHP_FE(curl_version,             arginfo_curl_version)
438	PHP_FE(curl_setopt,              arginfo_curl_setopt)
439	PHP_FE(curl_setopt_array,        arginfo_curl_setopt_array)
440	PHP_FE(curl_exec,                arginfo_curl_exec)
441	PHP_FE(curl_getinfo,             arginfo_curl_getinfo)
442	PHP_FE(curl_error,               arginfo_curl_error)
443	PHP_FE(curl_errno,               arginfo_curl_errno)
444	PHP_FE(curl_close,               arginfo_curl_close)
445#if LIBCURL_VERSION_NUM >= 0x070c00 /* 7.12.0 */
446	PHP_FE(curl_strerror,            arginfo_curl_strerror)
447	PHP_FE(curl_multi_strerror,      arginfo_curl_multi_strerror)
448#endif
449#if LIBCURL_VERSION_NUM >= 0x070c01 /* 7.12.1 */
450	PHP_FE(curl_reset,               arginfo_curl_reset)
451#endif
452#if LIBCURL_VERSION_NUM >= 0x070f04 /* 7.15.4 */
453	PHP_FE(curl_escape,              arginfo_curl_escape)
454	PHP_FE(curl_unescape,            arginfo_curl_unescape)
455#endif
456#if LIBCURL_VERSION_NUM >= 0x071200 /* 7.18.0 */
457	PHP_FE(curl_pause,               arginfo_curl_pause)
458#endif
459	PHP_FE(curl_multi_init,          arginfo_curl_multi_init)
460	PHP_FE(curl_multi_add_handle,    arginfo_curl_multi_add_handle)
461	PHP_FE(curl_multi_remove_handle, arginfo_curl_multi_remove_handle)
462	PHP_FE(curl_multi_select,        arginfo_curl_multi_select)
463	PHP_FE(curl_multi_exec,          arginfo_curl_multi_exec)
464	PHP_FE(curl_multi_getcontent,    arginfo_curl_multi_getcontent)
465	PHP_FE(curl_multi_info_read,     arginfo_curl_multi_info_read)
466	PHP_FE(curl_multi_close,         arginfo_curl_multi_close)
467#if LIBCURL_VERSION_NUM >= 0x070f04 /* 7.15.4 */
468	PHP_FE(curl_multi_setopt,        arginfo_curl_multi_setopt)
469#endif
470	PHP_FE(curl_share_init,          arginfo_curl_share_init)
471	PHP_FE(curl_share_close,         arginfo_curl_share_close)
472	PHP_FE(curl_share_setopt,        arginfo_curl_share_setopt)
473	PHP_FE(curl_file_create,         arginfo_curlfile_create)
474	PHP_FE_END
475};
476/* }}} */
477
478/* {{{ curl_module_entry
479 */
480zend_module_entry curl_module_entry = {
481	STANDARD_MODULE_HEADER,
482	"curl",
483	curl_functions,
484	PHP_MINIT(curl),
485	PHP_MSHUTDOWN(curl),
486	NULL,
487	NULL,
488	PHP_MINFO(curl),
489	PHP_CURL_VERSION,
490	STANDARD_MODULE_PROPERTIES
491};
492/* }}} */
493
494#ifdef COMPILE_DL_CURL
495ZEND_GET_MODULE (curl)
496#endif
497
498/* {{{ PHP_INI_BEGIN */
499PHP_INI_BEGIN()
500	PHP_INI_ENTRY("curl.cainfo", "", PHP_INI_SYSTEM, NULL)
501PHP_INI_END()
502/* }}} */
503
504/* {{{ PHP_MINFO_FUNCTION
505 */
506PHP_MINFO_FUNCTION(curl)
507{
508	curl_version_info_data *d;
509	char **p;
510	char str[1024];
511	size_t n = 0;
512
513	d = curl_version_info(CURLVERSION_NOW);
514	php_info_print_table_start();
515	php_info_print_table_row(2, "cURL support",    "enabled");
516	php_info_print_table_row(2, "cURL Information", d->version);
517	sprintf(str, "%d", d->age);
518	php_info_print_table_row(2, "Age", str);
519
520	/* To update on each new cURL release using src/main.c in cURL sources */
521	if (d->features) {
522		struct feat {
523			const char *name;
524			int bitmask;
525		};
526
527		unsigned int i;
528
529		static const struct feat feats[] = {
530#if LIBCURL_VERSION_NUM >= 0x070a07 /* 7.10.7 */
531			{"AsynchDNS", CURL_VERSION_ASYNCHDNS},
532#endif
533#if LIBCURL_VERSION_NUM >= 0x070f04 /* 7.15.4 */
534			{"CharConv", CURL_VERSION_CONV},
535#endif
536#if LIBCURL_VERSION_NUM >= 0x070a06 /* 7.10.6 */
537			{"Debug", CURL_VERSION_DEBUG},
538			{"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
539#endif
540#if LIBCURL_VERSION_NUM >= 0x070c00 /* 7.12.0 */
541			{"IDN", CURL_VERSION_IDN},
542#endif
543			{"IPv6", CURL_VERSION_IPV6},
544			{"krb4", CURL_VERSION_KERBEROS4},
545#if LIBCURL_VERSION_NUM >= 0x070b01 /* 7.11.1 */
546			{"Largefile", CURL_VERSION_LARGEFILE},
547#endif
548			{"libz", CURL_VERSION_LIBZ},
549#if LIBCURL_VERSION_NUM >= 0x070a06 /* 7.10.6 */
550			{"NTLM", CURL_VERSION_NTLM},
551#endif
552#if LIBCURL_VERSION_NUM >= 0x071600 /* 7.22.0 */
553			{"NTLMWB", CURL_VERSION_NTLM_WB},
554#endif
555#if LIBCURL_VERSION_NUM >= 0x070a08 /* 7.10.8 */
556			{"SPNEGO", CURL_VERSION_SPNEGO},
557#endif
558			{"SSL",  CURL_VERSION_SSL},
559#if LIBCURL_VERSION_NUM >= 0x070d02 /* 7.13.2 */
560			{"SSPI",  CURL_VERSION_SSPI},
561#endif
562#if LIBCURL_VERSION_NUM >= 0x071504 /* 7.21.4 */
563			{"TLS-SRP", CURL_VERSION_TLSAUTH_SRP},
564#endif
565#if LIBCURL_VERSION_NUM >= 0x072100 /* 7.33.0 */
566			{"HTTP2", CURL_VERSION_HTTP2},
567#endif
568#if LIBCURL_VERSION_NUM >= 0x072600 /* 7.38.0 */
569			{"GSSAPI", CURL_VERSION_GSSAPI},
570#endif
571			{NULL, 0}
572		};
573
574		php_info_print_table_row(1, "Features");
575		for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
576			if (feats[i].name) {
577				php_info_print_table_row(2, feats[i].name, d->features & feats[i].bitmask ? "Yes" : "No");
578			}
579		}
580	}
581
582	n = 0;
583	p = (char **) d->protocols;
584	while (*p != NULL) {
585			n += sprintf(str + n, "%s%s", *p, *(p + 1) != NULL ? ", " : "");
586			p++;
587	}
588	php_info_print_table_row(2, "Protocols", str);
589
590	php_info_print_table_row(2, "Host", d->host);
591
592	if (d->ssl_version) {
593		php_info_print_table_row(2, "SSL Version", d->ssl_version);
594	}
595
596	if (d->libz_version) {
597		php_info_print_table_row(2, "ZLib Version", d->libz_version);
598	}
599
600#if defined(CURLVERSION_SECOND) && CURLVERSION_NOW >= CURLVERSION_SECOND
601	if (d->ares) {
602		php_info_print_table_row(2, "ZLib Version", d->ares);
603	}
604#endif
605
606#if defined(CURLVERSION_THIRD) && CURLVERSION_NOW >= CURLVERSION_THIRD
607	if (d->libidn) {
608		php_info_print_table_row(2, "libIDN Version", d->libidn);
609	}
610#endif
611
612#if LIBCURL_VERSION_NUM >= 0x071300
613
614	if (d->iconv_ver_num) {
615		php_info_print_table_row(2, "IconV Version", d->iconv_ver_num);
616	}
617
618	if (d->libssh_version) {
619		php_info_print_table_row(2, "libSSH Version", d->libssh_version);
620	}
621#endif
622	php_info_print_table_end();
623}
624/* }}} */
625
626#define REGISTER_CURL_CONSTANT(__c) REGISTER_LONG_CONSTANT(#__c, __c, CONST_CS | CONST_PERSISTENT)
627
628/* {{{ PHP_MINIT_FUNCTION
629 */
630PHP_MINIT_FUNCTION(curl)
631{
632	le_curl = zend_register_list_destructors_ex(_php_curl_close, NULL, "curl", module_number);
633	le_curl_multi_handle = zend_register_list_destructors_ex(_php_curl_multi_close, NULL, "curl_multi", module_number);
634	le_curl_share_handle = zend_register_list_destructors_ex(_php_curl_share_close, NULL, "curl_share", module_number);
635
636	REGISTER_INI_ENTRIES();
637
638	/* See http://curl.haxx.se/lxr/source/docs/libcurl/symbols-in-versions
639	   or curl src/docs/libcurl/symbols-in-versions for a (almost) complete list
640	   of options and which version they were introduced */
641
642	/* Constants for curl_setopt() */
643	REGISTER_CURL_CONSTANT(CURLOPT_AUTOREFERER);
644	REGISTER_CURL_CONSTANT(CURLOPT_BINARYTRANSFER);
645	REGISTER_CURL_CONSTANT(CURLOPT_BUFFERSIZE);
646	REGISTER_CURL_CONSTANT(CURLOPT_CAINFO);
647	REGISTER_CURL_CONSTANT(CURLOPT_CAPATH);
648	REGISTER_CURL_CONSTANT(CURLOPT_CONNECTTIMEOUT);
649	REGISTER_CURL_CONSTANT(CURLOPT_COOKIE);
650	REGISTER_CURL_CONSTANT(CURLOPT_COOKIEFILE);
651	REGISTER_CURL_CONSTANT(CURLOPT_COOKIEJAR);
652	REGISTER_CURL_CONSTANT(CURLOPT_COOKIESESSION);
653	REGISTER_CURL_CONSTANT(CURLOPT_CRLF);
654	REGISTER_CURL_CONSTANT(CURLOPT_CUSTOMREQUEST);
655	REGISTER_CURL_CONSTANT(CURLOPT_DNS_CACHE_TIMEOUT);
656	REGISTER_CURL_CONSTANT(CURLOPT_DNS_USE_GLOBAL_CACHE);
657	REGISTER_CURL_CONSTANT(CURLOPT_EGDSOCKET);
658	REGISTER_CURL_CONSTANT(CURLOPT_ENCODING);
659	REGISTER_CURL_CONSTANT(CURLOPT_FAILONERROR);
660	REGISTER_CURL_CONSTANT(CURLOPT_FILE);
661	REGISTER_CURL_CONSTANT(CURLOPT_FILETIME);
662	REGISTER_CURL_CONSTANT(CURLOPT_FOLLOWLOCATION);
663	REGISTER_CURL_CONSTANT(CURLOPT_FORBID_REUSE);
664	REGISTER_CURL_CONSTANT(CURLOPT_FRESH_CONNECT);
665	REGISTER_CURL_CONSTANT(CURLOPT_FTPAPPEND);
666	REGISTER_CURL_CONSTANT(CURLOPT_FTPLISTONLY);
667	REGISTER_CURL_CONSTANT(CURLOPT_FTPPORT);
668	REGISTER_CURL_CONSTANT(CURLOPT_FTP_USE_EPRT);
669	REGISTER_CURL_CONSTANT(CURLOPT_FTP_USE_EPSV);
670	REGISTER_CURL_CONSTANT(CURLOPT_HEADER);
671	REGISTER_CURL_CONSTANT(CURLOPT_HEADERFUNCTION);
672	REGISTER_CURL_CONSTANT(CURLOPT_HTTP200ALIASES);
673	REGISTER_CURL_CONSTANT(CURLOPT_HTTPGET);
674	REGISTER_CURL_CONSTANT(CURLOPT_HTTPHEADER);
675	REGISTER_CURL_CONSTANT(CURLOPT_HTTPPROXYTUNNEL);
676	REGISTER_CURL_CONSTANT(CURLOPT_HTTP_VERSION);
677	REGISTER_CURL_CONSTANT(CURLOPT_INFILE);
678	REGISTER_CURL_CONSTANT(CURLOPT_INFILESIZE);
679	REGISTER_CURL_CONSTANT(CURLOPT_INTERFACE);
680	REGISTER_CURL_CONSTANT(CURLOPT_KRB4LEVEL);
681	REGISTER_CURL_CONSTANT(CURLOPT_LOW_SPEED_LIMIT);
682	REGISTER_CURL_CONSTANT(CURLOPT_LOW_SPEED_TIME);
683	REGISTER_CURL_CONSTANT(CURLOPT_MAXCONNECTS);
684	REGISTER_CURL_CONSTANT(CURLOPT_MAXREDIRS);
685	REGISTER_CURL_CONSTANT(CURLOPT_NETRC);
686	REGISTER_CURL_CONSTANT(CURLOPT_NOBODY);
687	REGISTER_CURL_CONSTANT(CURLOPT_NOPROGRESS);
688	REGISTER_CURL_CONSTANT(CURLOPT_NOSIGNAL);
689	REGISTER_CURL_CONSTANT(CURLOPT_PORT);
690	REGISTER_CURL_CONSTANT(CURLOPT_POST);
691	REGISTER_CURL_CONSTANT(CURLOPT_POSTFIELDS);
692	REGISTER_CURL_CONSTANT(CURLOPT_POSTQUOTE);
693	REGISTER_CURL_CONSTANT(CURLOPT_PREQUOTE);
694	REGISTER_CURL_CONSTANT(CURLOPT_PRIVATE);
695	REGISTER_CURL_CONSTANT(CURLOPT_PROGRESSFUNCTION);
696	REGISTER_CURL_CONSTANT(CURLOPT_PROXY);
697	REGISTER_CURL_CONSTANT(CURLOPT_PROXYPORT);
698	REGISTER_CURL_CONSTANT(CURLOPT_PROXYTYPE);
699	REGISTER_CURL_CONSTANT(CURLOPT_PROXYUSERPWD);
700	REGISTER_CURL_CONSTANT(CURLOPT_PUT);
701	REGISTER_CURL_CONSTANT(CURLOPT_QUOTE);
702	REGISTER_CURL_CONSTANT(CURLOPT_RANDOM_FILE);
703	REGISTER_CURL_CONSTANT(CURLOPT_RANGE);
704	REGISTER_CURL_CONSTANT(CURLOPT_READDATA);
705	REGISTER_CURL_CONSTANT(CURLOPT_READFUNCTION);
706	REGISTER_CURL_CONSTANT(CURLOPT_REFERER);
707	REGISTER_CURL_CONSTANT(CURLOPT_RESUME_FROM);
708	REGISTER_CURL_CONSTANT(CURLOPT_RETURNTRANSFER);
709	REGISTER_CURL_CONSTANT(CURLOPT_SHARE);
710	REGISTER_CURL_CONSTANT(CURLOPT_SSLCERT);
711	REGISTER_CURL_CONSTANT(CURLOPT_SSLCERTPASSWD);
712	REGISTER_CURL_CONSTANT(CURLOPT_SSLCERTTYPE);
713	REGISTER_CURL_CONSTANT(CURLOPT_SSLENGINE);
714	REGISTER_CURL_CONSTANT(CURLOPT_SSLENGINE_DEFAULT);
715	REGISTER_CURL_CONSTANT(CURLOPT_SSLKEY);
716	REGISTER_CURL_CONSTANT(CURLOPT_SSLKEYPASSWD);
717	REGISTER_CURL_CONSTANT(CURLOPT_SSLKEYTYPE);
718	REGISTER_CURL_CONSTANT(CURLOPT_SSLVERSION);
719	REGISTER_CURL_CONSTANT(CURLOPT_SSL_CIPHER_LIST);
720	REGISTER_CURL_CONSTANT(CURLOPT_SSL_VERIFYHOST);
721	REGISTER_CURL_CONSTANT(CURLOPT_SSL_VERIFYPEER);
722	REGISTER_CURL_CONSTANT(CURLOPT_STDERR);
723	REGISTER_CURL_CONSTANT(CURLOPT_TELNETOPTIONS);
724	REGISTER_CURL_CONSTANT(CURLOPT_TIMECONDITION);
725	REGISTER_CURL_CONSTANT(CURLOPT_TIMEOUT);
726	REGISTER_CURL_CONSTANT(CURLOPT_TIMEVALUE);
727	REGISTER_CURL_CONSTANT(CURLOPT_TRANSFERTEXT);
728	REGISTER_CURL_CONSTANT(CURLOPT_UNRESTRICTED_AUTH);
729	REGISTER_CURL_CONSTANT(CURLOPT_UPLOAD);
730	REGISTER_CURL_CONSTANT(CURLOPT_URL);
731	REGISTER_CURL_CONSTANT(CURLOPT_USERAGENT);
732	REGISTER_CURL_CONSTANT(CURLOPT_USERPWD);
733	REGISTER_CURL_CONSTANT(CURLOPT_VERBOSE);
734	REGISTER_CURL_CONSTANT(CURLOPT_WRITEFUNCTION);
735	REGISTER_CURL_CONSTANT(CURLOPT_WRITEHEADER);
736
737	/* */
738	REGISTER_CURL_CONSTANT(CURLE_ABORTED_BY_CALLBACK);
739	REGISTER_CURL_CONSTANT(CURLE_BAD_CALLING_ORDER);
740	REGISTER_CURL_CONSTANT(CURLE_BAD_CONTENT_ENCODING);
741	REGISTER_CURL_CONSTANT(CURLE_BAD_DOWNLOAD_RESUME);
742	REGISTER_CURL_CONSTANT(CURLE_BAD_FUNCTION_ARGUMENT);
743	REGISTER_CURL_CONSTANT(CURLE_BAD_PASSWORD_ENTERED);
744	REGISTER_CURL_CONSTANT(CURLE_COULDNT_CONNECT);
745	REGISTER_CURL_CONSTANT(CURLE_COULDNT_RESOLVE_HOST);
746	REGISTER_CURL_CONSTANT(CURLE_COULDNT_RESOLVE_PROXY);
747	REGISTER_CURL_CONSTANT(CURLE_FAILED_INIT);
748	REGISTER_CURL_CONSTANT(CURLE_FILE_COULDNT_READ_FILE);
749	REGISTER_CURL_CONSTANT(CURLE_FTP_ACCESS_DENIED);
750	REGISTER_CURL_CONSTANT(CURLE_FTP_BAD_DOWNLOAD_RESUME);
751	REGISTER_CURL_CONSTANT(CURLE_FTP_CANT_GET_HOST);
752	REGISTER_CURL_CONSTANT(CURLE_FTP_CANT_RECONNECT);
753	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_GET_SIZE);
754	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_RETR_FILE);
755	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_SET_ASCII);
756	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_SET_BINARY);
757	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_STOR_FILE);
758	REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_USE_REST);
759	REGISTER_CURL_CONSTANT(CURLE_FTP_PARTIAL_FILE);
760	REGISTER_CURL_CONSTANT(CURLE_FTP_PORT_FAILED);
761	REGISTER_CURL_CONSTANT(CURLE_FTP_QUOTE_ERROR);
762	REGISTER_CURL_CONSTANT(CURLE_FTP_USER_PASSWORD_INCORRECT);
763	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_227_FORMAT);
764	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_PASS_REPLY);
765	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_PASV_REPLY);
766	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_SERVER_REPLY);
767	REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_USER_REPLY);
768	REGISTER_CURL_CONSTANT(CURLE_FTP_WRITE_ERROR);
769	REGISTER_CURL_CONSTANT(CURLE_FUNCTION_NOT_FOUND);
770	REGISTER_CURL_CONSTANT(CURLE_GOT_NOTHING);
771	REGISTER_CURL_CONSTANT(CURLE_HTTP_NOT_FOUND);
772	REGISTER_CURL_CONSTANT(CURLE_HTTP_PORT_FAILED);
773	REGISTER_CURL_CONSTANT(CURLE_HTTP_POST_ERROR);
774	REGISTER_CURL_CONSTANT(CURLE_HTTP_RANGE_ERROR);
775	REGISTER_CURL_CONSTANT(CURLE_HTTP_RETURNED_ERROR);
776	REGISTER_CURL_CONSTANT(CURLE_LDAP_CANNOT_BIND);
777	REGISTER_CURL_CONSTANT(CURLE_LDAP_SEARCH_FAILED);
778	REGISTER_CURL_CONSTANT(CURLE_LIBRARY_NOT_FOUND);
779	REGISTER_CURL_CONSTANT(CURLE_MALFORMAT_USER);
780	REGISTER_CURL_CONSTANT(CURLE_OBSOLETE);
781	REGISTER_CURL_CONSTANT(CURLE_OK);
782	REGISTER_CURL_CONSTANT(CURLE_OPERATION_TIMEDOUT);
783	REGISTER_CURL_CONSTANT(CURLE_OPERATION_TIMEOUTED);
784	REGISTER_CURL_CONSTANT(CURLE_OUT_OF_MEMORY);
785	REGISTER_CURL_CONSTANT(CURLE_PARTIAL_FILE);
786	REGISTER_CURL_CONSTANT(CURLE_READ_ERROR);
787	REGISTER_CURL_CONSTANT(CURLE_RECV_ERROR);
788	REGISTER_CURL_CONSTANT(CURLE_SEND_ERROR);
789	REGISTER_CURL_CONSTANT(CURLE_SHARE_IN_USE);
790	REGISTER_CURL_CONSTANT(CURLE_SSL_CACERT);
791	REGISTER_CURL_CONSTANT(CURLE_SSL_CERTPROBLEM);
792	REGISTER_CURL_CONSTANT(CURLE_SSL_CIPHER);
793	REGISTER_CURL_CONSTANT(CURLE_SSL_CONNECT_ERROR);
794	REGISTER_CURL_CONSTANT(CURLE_SSL_ENGINE_NOTFOUND);
795	REGISTER_CURL_CONSTANT(CURLE_SSL_ENGINE_SETFAILED);
796	REGISTER_CURL_CONSTANT(CURLE_SSL_PEER_CERTIFICATE);
797	REGISTER_CURL_CONSTANT(CURLE_TELNET_OPTION_SYNTAX);
798	REGISTER_CURL_CONSTANT(CURLE_TOO_MANY_REDIRECTS);
799	REGISTER_CURL_CONSTANT(CURLE_UNKNOWN_TELNET_OPTION);
800	REGISTER_CURL_CONSTANT(CURLE_UNSUPPORTED_PROTOCOL);
801	REGISTER_CURL_CONSTANT(CURLE_URL_MALFORMAT);
802	REGISTER_CURL_CONSTANT(CURLE_URL_MALFORMAT_USER);
803	REGISTER_CURL_CONSTANT(CURLE_WRITE_ERROR);
804
805	/* cURL info constants */
806	REGISTER_CURL_CONSTANT(CURLINFO_CONNECT_TIME);
807	REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_LENGTH_DOWNLOAD);
808	REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_LENGTH_UPLOAD);
809	REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_TYPE);
810	REGISTER_CURL_CONSTANT(CURLINFO_EFFECTIVE_URL);
811	REGISTER_CURL_CONSTANT(CURLINFO_FILETIME);
812	REGISTER_CURL_CONSTANT(CURLINFO_HEADER_OUT);
813	REGISTER_CURL_CONSTANT(CURLINFO_HEADER_SIZE);
814	REGISTER_CURL_CONSTANT(CURLINFO_HTTP_CODE);
815	REGISTER_CURL_CONSTANT(CURLINFO_LASTONE);
816	REGISTER_CURL_CONSTANT(CURLINFO_NAMELOOKUP_TIME);
817	REGISTER_CURL_CONSTANT(CURLINFO_PRETRANSFER_TIME);
818	REGISTER_CURL_CONSTANT(CURLINFO_PRIVATE);
819	REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_COUNT);
820	REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_TIME);
821	REGISTER_CURL_CONSTANT(CURLINFO_REQUEST_SIZE);
822	REGISTER_CURL_CONSTANT(CURLINFO_SIZE_DOWNLOAD);
823	REGISTER_CURL_CONSTANT(CURLINFO_SIZE_UPLOAD);
824	REGISTER_CURL_CONSTANT(CURLINFO_SPEED_DOWNLOAD);
825	REGISTER_CURL_CONSTANT(CURLINFO_SPEED_UPLOAD);
826	REGISTER_CURL_CONSTANT(CURLINFO_SSL_VERIFYRESULT);
827	REGISTER_CURL_CONSTANT(CURLINFO_STARTTRANSFER_TIME);
828	REGISTER_CURL_CONSTANT(CURLINFO_TOTAL_TIME);
829
830	/* Other */
831	REGISTER_CURL_CONSTANT(CURLMSG_DONE);
832	REGISTER_CURL_CONSTANT(CURLVERSION_NOW);
833
834	/* Curl Multi Constants */
835	REGISTER_CURL_CONSTANT(CURLM_BAD_EASY_HANDLE);
836	REGISTER_CURL_CONSTANT(CURLM_BAD_HANDLE);
837	REGISTER_CURL_CONSTANT(CURLM_CALL_MULTI_PERFORM);
838	REGISTER_CURL_CONSTANT(CURLM_INTERNAL_ERROR);
839	REGISTER_CURL_CONSTANT(CURLM_OK);
840	REGISTER_CURL_CONSTANT(CURLM_OUT_OF_MEMORY);
841
842	/* Curl proxy constants */
843	REGISTER_CURL_CONSTANT(CURLPROXY_HTTP);
844	REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4);
845	REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5);
846
847#if LIBCURL_VERSION_NUM >= 0x071200 /* Available since 7.18.0 */
848	REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4A);
849	REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5_HOSTNAME);
850#endif
851
852	/* Curl Share constants */
853	REGISTER_CURL_CONSTANT(CURLSHOPT_NONE);
854	REGISTER_CURL_CONSTANT(CURLSHOPT_SHARE);
855	REGISTER_CURL_CONSTANT(CURLSHOPT_UNSHARE);
856
857	/* Curl Http Version constants (CURLOPT_HTTP_VERSION) */
858	REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_0);
859	REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_1);
860#if LIBCURL_VERSION_NUM >= 0x072100 /* 7.33.0 */
861	REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_2_0);
862#endif
863	REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_NONE);
864
865	/* Curl Lock constants */
866	REGISTER_CURL_CONSTANT(CURL_LOCK_DATA_COOKIE);
867	REGISTER_CURL_CONSTANT(CURL_LOCK_DATA_DNS);
868	REGISTER_CURL_CONSTANT(CURL_LOCK_DATA_SSL_SESSION);
869
870	/* Curl NETRC constants (CURLOPT_NETRC) */
871	REGISTER_CURL_CONSTANT(CURL_NETRC_IGNORED);
872	REGISTER_CURL_CONSTANT(CURL_NETRC_OPTIONAL);
873	REGISTER_CURL_CONSTANT(CURL_NETRC_REQUIRED);
874
875	/* Curl SSL Version constants (CURLOPT_SSLVERSION) */
876	REGISTER_CURL_CONSTANT(CURL_SSLVERSION_DEFAULT);
877	REGISTER_CURL_CONSTANT(CURL_SSLVERSION_SSLv2);
878	REGISTER_CURL_CONSTANT(CURL_SSLVERSION_SSLv3);
879	REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1);
880
881	/* Curl TIMECOND constants (CURLOPT_TIMECONDITION) */
882	REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFMODSINCE);
883	REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFUNMODSINCE);
884	REGISTER_CURL_CONSTANT(CURL_TIMECOND_LASTMOD);
885	REGISTER_CURL_CONSTANT(CURL_TIMECOND_NONE);
886
887	/* Curl version constants */
888	REGISTER_CURL_CONSTANT(CURL_VERSION_IPV6);
889	REGISTER_CURL_CONSTANT(CURL_VERSION_KERBEROS4);
890	REGISTER_CURL_CONSTANT(CURL_VERSION_LIBZ);
891	REGISTER_CURL_CONSTANT(CURL_VERSION_SSL);
892#if LIBCURL_VERSION_NUM >= 0x072100 /* 7.33.0 */
893	REGISTER_CURL_CONSTANT(CURL_VERSION_HTTP2);
894#endif
895
896#if LIBCURL_VERSION_NUM >= 0x070a06 /* Available since 7.10.6 */
897	REGISTER_CURL_CONSTANT(CURLOPT_HTTPAUTH);
898	/* http authentication options */
899	REGISTER_CURL_CONSTANT(CURLAUTH_ANY);
900	REGISTER_CURL_CONSTANT(CURLAUTH_ANYSAFE);
901	REGISTER_CURL_CONSTANT(CURLAUTH_BASIC);
902	REGISTER_CURL_CONSTANT(CURLAUTH_DIGEST);
903	REGISTER_CURL_CONSTANT(CURLAUTH_GSSNEGOTIATE);
904	REGISTER_CURL_CONSTANT(CURLAUTH_NONE);
905	REGISTER_CURL_CONSTANT(CURLAUTH_NTLM);
906#endif
907
908#if LIBCURL_VERSION_NUM >= 0x070a07 /* Available since 7.10.7 */
909	REGISTER_CURL_CONSTANT(CURLINFO_HTTP_CONNECTCODE);
910	REGISTER_CURL_CONSTANT(CURLOPT_FTP_CREATE_MISSING_DIRS);
911	REGISTER_CURL_CONSTANT(CURLOPT_PROXYAUTH);
912#endif
913
914#if LIBCURL_VERSION_NUM >= 0x070a08 /* Available since 7.10.8 */
915	REGISTER_CURL_CONSTANT(CURLE_FILESIZE_EXCEEDED);
916	REGISTER_CURL_CONSTANT(CURLE_LDAP_INVALID_URL);
917	REGISTER_CURL_CONSTANT(CURLINFO_HTTPAUTH_AVAIL);
918	REGISTER_CURL_CONSTANT(CURLINFO_RESPONSE_CODE);
919	REGISTER_CURL_CONSTANT(CURLINFO_PROXYAUTH_AVAIL);
920	REGISTER_CURL_CONSTANT(CURLOPT_FTP_RESPONSE_TIMEOUT);
921	REGISTER_CURL_CONSTANT(CURLOPT_IPRESOLVE);
922	REGISTER_CURL_CONSTANT(CURLOPT_MAXFILESIZE);
923	REGISTER_CURL_CONSTANT(CURL_IPRESOLVE_V4);
924	REGISTER_CURL_CONSTANT(CURL_IPRESOLVE_V6);
925	REGISTER_CURL_CONSTANT(CURL_IPRESOLVE_WHATEVER);
926#endif
927
928#if LIBCURL_VERSION_NUM >= 0x070b00 /* Available since 7.11.0 */
929	REGISTER_CURL_CONSTANT(CURLE_FTP_SSL_FAILED);
930	REGISTER_CURL_CONSTANT(CURLFTPSSL_ALL);
931	REGISTER_CURL_CONSTANT(CURLFTPSSL_CONTROL);
932	REGISTER_CURL_CONSTANT(CURLFTPSSL_NONE);
933	REGISTER_CURL_CONSTANT(CURLFTPSSL_TRY);
934	REGISTER_CURL_CONSTANT(CURLOPT_FTP_SSL);
935	REGISTER_CURL_CONSTANT(CURLOPT_NETRC_FILE);
936#endif
937
938#if LIBCURL_VERSION_NUM >= 0x070c02 /* Available since 7.12.2 */
939	REGISTER_CURL_CONSTANT(CURLFTPAUTH_DEFAULT);
940	REGISTER_CURL_CONSTANT(CURLFTPAUTH_SSL);
941	REGISTER_CURL_CONSTANT(CURLFTPAUTH_TLS);
942	REGISTER_CURL_CONSTANT(CURLOPT_FTPSSLAUTH);
943#endif
944
945#if LIBCURL_VERSION_NUM >= 0x070d00 /* Available since 7.13.0 */
946	REGISTER_CURL_CONSTANT(CURLOPT_FTP_ACCOUNT);
947#endif
948
949#if LIBCURL_VERSION_NUM >= 0x070b02 /* Available since 7.11.2 */
950	REGISTER_CURL_CONSTANT(CURLOPT_TCP_NODELAY);
951#endif
952
953#if LIBCURL_VERSION_NUM >= 0x070c02 /* Available since 7.12.2 */
954	REGISTER_CURL_CONSTANT(CURLINFO_OS_ERRNO);
955#endif
956
957#if LIBCURL_VERSION_NUM >= 0x070c03 /* Available since 7.12.3 */
958	REGISTER_CURL_CONSTANT(CURLINFO_NUM_CONNECTS);
959	REGISTER_CURL_CONSTANT(CURLINFO_SSL_ENGINES);
960#endif
961
962#if LIBCURL_VERSION_NUM >= 0x070e01 /* Available since 7.14.1 */
963	REGISTER_CURL_CONSTANT(CURLINFO_COOKIELIST);
964	REGISTER_CURL_CONSTANT(CURLOPT_COOKIELIST);
965	REGISTER_CURL_CONSTANT(CURLOPT_IGNORE_CONTENT_LENGTH);
966#endif
967
968#if LIBCURL_VERSION_NUM >= 0x070f00 /* Available since 7.15.0 */
969	REGISTER_CURL_CONSTANT(CURLOPT_FTP_SKIP_PASV_IP);
970#endif
971
972#if LIBCURL_VERSION_NUM >= 0x070f01 /* Available since 7.15.1 */
973	REGISTER_CURL_CONSTANT(CURLOPT_FTP_FILEMETHOD);
974#endif
975
976#if LIBCURL_VERSION_NUM >= 0x070f02 /* Available since 7.15.2 */
977	REGISTER_CURL_CONSTANT(CURLOPT_CONNECT_ONLY);
978	REGISTER_CURL_CONSTANT(CURLOPT_LOCALPORT);
979	REGISTER_CURL_CONSTANT(CURLOPT_LOCALPORTRANGE);
980#endif
981
982#if LIBCURL_VERSION_NUM >= 0x070f03 /* Available since 7.15.3 */
983	REGISTER_CURL_CONSTANT(CURLFTPMETHOD_MULTICWD);
984	REGISTER_CURL_CONSTANT(CURLFTPMETHOD_NOCWD);
985	REGISTER_CURL_CONSTANT(CURLFTPMETHOD_SINGLECWD);
986#endif
987
988#if LIBCURL_VERSION_NUM >= 0x070f04 /* Available since 7.15.4 */
989	REGISTER_CURL_CONSTANT(CURLINFO_FTP_ENTRY_PATH);
990#endif
991
992#if LIBCURL_VERSION_NUM >= 0x070f05 /* Available since 7.15.5 */
993	REGISTER_CURL_CONSTANT(CURLOPT_FTP_ALTERNATIVE_TO_USER);
994	REGISTER_CURL_CONSTANT(CURLOPT_MAX_RECV_SPEED_LARGE);
995	REGISTER_CURL_CONSTANT(CURLOPT_MAX_SEND_SPEED_LARGE);
996#endif
997
998#if LIBCURL_VERSION_NUM >= 0x071000 /* Available since 7.16.0 */
999	REGISTER_CURL_CONSTANT(CURLOPT_SSL_SESSIONID_CACHE);
1000	REGISTER_CURL_CONSTANT(CURLMOPT_PIPELINING);
1001#endif
1002
1003#if LIBCURL_VERSION_NUM >= 0x071001 /* Available since 7.16.1 */
1004	REGISTER_CURL_CONSTANT(CURLE_SSH);
1005	REGISTER_CURL_CONSTANT(CURLOPT_FTP_SSL_CCC);
1006	REGISTER_CURL_CONSTANT(CURLOPT_SSH_AUTH_TYPES);
1007	REGISTER_CURL_CONSTANT(CURLOPT_SSH_PRIVATE_KEYFILE);
1008	REGISTER_CURL_CONSTANT(CURLOPT_SSH_PUBLIC_KEYFILE);
1009	REGISTER_CURL_CONSTANT(CURLFTPSSL_CCC_ACTIVE);
1010	REGISTER_CURL_CONSTANT(CURLFTPSSL_CCC_NONE);
1011	REGISTER_CURL_CONSTANT(CURLFTPSSL_CCC_PASSIVE);
1012#endif
1013
1014#if LIBCURL_VERSION_NUM >= 0x071002 /* Available since 7.16.2 */
1015	REGISTER_CURL_CONSTANT(CURLOPT_CONNECTTIMEOUT_MS);
1016	REGISTER_CURL_CONSTANT(CURLOPT_HTTP_CONTENT_DECODING);
1017	REGISTER_CURL_CONSTANT(CURLOPT_HTTP_TRANSFER_DECODING);
1018	REGISTER_CURL_CONSTANT(CURLOPT_TIMEOUT_MS);
1019#endif
1020
1021#if LIBCURL_VERSION_NUM >= 0x071003 /* Available since 7.16.3 */
1022	REGISTER_CURL_CONSTANT(CURLMOPT_MAXCONNECTS);
1023#endif
1024
1025#if LIBCURL_VERSION_NUM >= 0x071004 /* Available since 7.16.4 */
1026	REGISTER_CURL_CONSTANT(CURLOPT_KRBLEVEL);
1027	REGISTER_CURL_CONSTANT(CURLOPT_NEW_DIRECTORY_PERMS);
1028	REGISTER_CURL_CONSTANT(CURLOPT_NEW_FILE_PERMS);
1029#endif
1030
1031#if LIBCURL_VERSION_NUM >= 0x071100 /* Available since 7.17.0 */
1032	REGISTER_CURL_CONSTANT(CURLOPT_APPEND);
1033	REGISTER_CURL_CONSTANT(CURLOPT_DIRLISTONLY);
1034	REGISTER_CURL_CONSTANT(CURLOPT_USE_SSL);
1035	/* Curl SSL Constants */
1036	REGISTER_CURL_CONSTANT(CURLUSESSL_ALL);
1037	REGISTER_CURL_CONSTANT(CURLUSESSL_CONTROL);
1038	REGISTER_CURL_CONSTANT(CURLUSESSL_NONE);
1039	REGISTER_CURL_CONSTANT(CURLUSESSL_TRY);
1040#endif
1041
1042#if LIBCURL_VERSION_NUM >= 0x071101 /* Available since 7.17.1 */
1043	REGISTER_CURL_CONSTANT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5);
1044#endif
1045
1046#if LIBCURL_VERSION_NUM >= 0x071200 /* Available since 7.18.0 */
1047	REGISTER_CURL_CONSTANT(CURLOPT_PROXY_TRANSFER_MODE);
1048	REGISTER_CURL_CONSTANT(CURLPAUSE_ALL);
1049	REGISTER_CURL_CONSTANT(CURLPAUSE_CONT);
1050	REGISTER_CURL_CONSTANT(CURLPAUSE_RECV);
1051	REGISTER_CURL_CONSTANT(CURLPAUSE_RECV_CONT);
1052	REGISTER_CURL_CONSTANT(CURLPAUSE_SEND);
1053	REGISTER_CURL_CONSTANT(CURLPAUSE_SEND_CONT);
1054	REGISTER_CURL_CONSTANT(CURL_READFUNC_PAUSE);
1055	REGISTER_CURL_CONSTANT(CURL_WRITEFUNC_PAUSE);
1056#endif
1057
1058#if LIBCURL_VERSION_NUM >= 0x071202 /* Available since 7.18.2 */
1059	REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_URL);
1060#endif
1061
1062#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 */
1063	REGISTER_CURL_CONSTANT(CURLINFO_APPCONNECT_TIME);
1064	REGISTER_CURL_CONSTANT(CURLINFO_PRIMARY_IP);
1065
1066	REGISTER_CURL_CONSTANT(CURLOPT_ADDRESS_SCOPE);
1067	REGISTER_CURL_CONSTANT(CURLOPT_CRLFILE);
1068	REGISTER_CURL_CONSTANT(CURLOPT_ISSUERCERT);
1069	REGISTER_CURL_CONSTANT(CURLOPT_KEYPASSWD);
1070
1071	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_ANY);
1072	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_DEFAULT);
1073	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_HOST);
1074	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_KEYBOARD);
1075	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_NONE);
1076	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_PASSWORD);
1077	REGISTER_CURL_CONSTANT(CURLSSH_AUTH_PUBLICKEY);
1078#endif
1079
1080#if LIBCURL_VERSION_NUM >= 0x071301 /* Available since 7.19.1 */
1081	REGISTER_CURL_CONSTANT(CURLINFO_CERTINFO);
1082	REGISTER_CURL_CONSTANT(CURLOPT_CERTINFO);
1083	REGISTER_CURL_CONSTANT(CURLOPT_PASSWORD);
1084	REGISTER_CURL_CONSTANT(CURLOPT_POSTREDIR);
1085	REGISTER_CURL_CONSTANT(CURLOPT_PROXYPASSWORD);
1086	REGISTER_CURL_CONSTANT(CURLOPT_PROXYUSERNAME);
1087	REGISTER_CURL_CONSTANT(CURLOPT_USERNAME);
1088#endif
1089
1090#if LIBCURL_VERSION_NUM >= 0x071303 /* Available since 7.19.3 */
1091	REGISTER_CURL_CONSTANT(CURLAUTH_DIGEST_IE);
1092#endif
1093
1094#if LIBCURL_VERSION_NUM >= 0x071304 /* Available since 7.19.4 */
1095	REGISTER_CURL_CONSTANT(CURLINFO_CONDITION_UNMET);
1096
1097	REGISTER_CURL_CONSTANT(CURLOPT_NOPROXY);
1098	REGISTER_CURL_CONSTANT(CURLOPT_PROTOCOLS);
1099	REGISTER_CURL_CONSTANT(CURLOPT_REDIR_PROTOCOLS);
1100	REGISTER_CURL_CONSTANT(CURLOPT_SOCKS5_GSSAPI_NEC);
1101	REGISTER_CURL_CONSTANT(CURLOPT_SOCKS5_GSSAPI_SERVICE);
1102	REGISTER_CURL_CONSTANT(CURLOPT_TFTP_BLKSIZE);
1103
1104	REGISTER_CURL_CONSTANT(CURLPROTO_ALL);
1105	REGISTER_CURL_CONSTANT(CURLPROTO_DICT);
1106	REGISTER_CURL_CONSTANT(CURLPROTO_FILE);
1107	REGISTER_CURL_CONSTANT(CURLPROTO_FTP);
1108	REGISTER_CURL_CONSTANT(CURLPROTO_FTPS);
1109	REGISTER_CURL_CONSTANT(CURLPROTO_HTTP);
1110	REGISTER_CURL_CONSTANT(CURLPROTO_HTTPS);
1111	REGISTER_CURL_CONSTANT(CURLPROTO_LDAP);
1112	REGISTER_CURL_CONSTANT(CURLPROTO_LDAPS);
1113	REGISTER_CURL_CONSTANT(CURLPROTO_SCP);
1114	REGISTER_CURL_CONSTANT(CURLPROTO_SFTP);
1115	REGISTER_CURL_CONSTANT(CURLPROTO_TELNET);
1116	REGISTER_CURL_CONSTANT(CURLPROTO_TFTP);
1117#endif
1118
1119#if LIBCURL_VERSION_NUM >= 0x071306 /* Available since 7.19.6 */
1120	REGISTER_CURL_CONSTANT(CURLOPT_SSH_KNOWNHOSTS);
1121#endif
1122
1123#if LIBCURL_VERSION_NUM >= 0x071400 /* Available since 7.20.0 */
1124	REGISTER_CURL_CONSTANT(CURLINFO_RTSP_CLIENT_CSEQ);
1125	REGISTER_CURL_CONSTANT(CURLINFO_RTSP_CSEQ_RECV);
1126	REGISTER_CURL_CONSTANT(CURLINFO_RTSP_SERVER_CSEQ);
1127	REGISTER_CURL_CONSTANT(CURLINFO_RTSP_SESSION_ID);
1128	REGISTER_CURL_CONSTANT(CURLOPT_FTP_USE_PRET);
1129	REGISTER_CURL_CONSTANT(CURLOPT_MAIL_FROM);
1130	REGISTER_CURL_CONSTANT(CURLOPT_MAIL_RCPT);
1131	REGISTER_CURL_CONSTANT(CURLOPT_RTSP_CLIENT_CSEQ);
1132	REGISTER_CURL_CONSTANT(CURLOPT_RTSP_REQUEST);
1133	REGISTER_CURL_CONSTANT(CURLOPT_RTSP_SERVER_CSEQ);
1134	REGISTER_CURL_CONSTANT(CURLOPT_RTSP_SESSION_ID);
1135	REGISTER_CURL_CONSTANT(CURLOPT_RTSP_STREAM_URI);
1136	REGISTER_CURL_CONSTANT(CURLOPT_RTSP_TRANSPORT);
1137	REGISTER_CURL_CONSTANT(CURLPROTO_IMAP);
1138	REGISTER_CURL_CONSTANT(CURLPROTO_IMAPS);
1139	REGISTER_CURL_CONSTANT(CURLPROTO_POP3);
1140	REGISTER_CURL_CONSTANT(CURLPROTO_POP3S);
1141	REGISTER_CURL_CONSTANT(CURLPROTO_RTSP);
1142	REGISTER_CURL_CONSTANT(CURLPROTO_SMTP);
1143	REGISTER_CURL_CONSTANT(CURLPROTO_SMTPS);
1144	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_ANNOUNCE);
1145	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_DESCRIBE);
1146	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_GET_PARAMETER);
1147	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_OPTIONS);
1148	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_PAUSE);
1149	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_PLAY);
1150	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_RECEIVE);
1151	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_RECORD);
1152	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_SETUP);
1153	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_SET_PARAMETER);
1154	REGISTER_CURL_CONSTANT(CURL_RTSPREQ_TEARDOWN);
1155#endif
1156
1157#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
1158	REGISTER_CURL_CONSTANT(CURLINFO_LOCAL_IP);
1159	REGISTER_CURL_CONSTANT(CURLINFO_LOCAL_PORT);
1160	REGISTER_CURL_CONSTANT(CURLINFO_PRIMARY_PORT);
1161	REGISTER_CURL_CONSTANT(CURLOPT_FNMATCH_FUNCTION);
1162	REGISTER_CURL_CONSTANT(CURLOPT_WILDCARDMATCH);
1163	REGISTER_CURL_CONSTANT(CURLPROTO_RTMP);
1164	REGISTER_CURL_CONSTANT(CURLPROTO_RTMPE);
1165	REGISTER_CURL_CONSTANT(CURLPROTO_RTMPS);
1166	REGISTER_CURL_CONSTANT(CURLPROTO_RTMPT);
1167	REGISTER_CURL_CONSTANT(CURLPROTO_RTMPTE);
1168	REGISTER_CURL_CONSTANT(CURLPROTO_RTMPTS);
1169	REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_FAIL);
1170	REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_MATCH);
1171	REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_NOMATCH);
1172#endif
1173
1174#if LIBCURL_VERSION_NUM >= 0x071502 /* Available since 7.21.2 */
1175	REGISTER_CURL_CONSTANT(CURLPROTO_GOPHER);
1176#endif
1177
1178#if LIBCURL_VERSION_NUM >= 0x071503 /* Available since 7.21.3 */
1179	REGISTER_CURL_CONSTANT(CURLAUTH_ONLY);
1180	REGISTER_CURL_CONSTANT(CURLOPT_RESOLVE);
1181#endif
1182
1183#if LIBCURL_VERSION_NUM >= 0x071504 /* Available since 7.21.4 */
1184	REGISTER_CURL_CONSTANT(CURLOPT_TLSAUTH_PASSWORD);
1185	REGISTER_CURL_CONSTANT(CURLOPT_TLSAUTH_TYPE);
1186	REGISTER_CURL_CONSTANT(CURLOPT_TLSAUTH_USERNAME);
1187	REGISTER_CURL_CONSTANT(CURL_TLSAUTH_SRP);
1188#endif
1189
1190#if LIBCURL_VERSION_NUM >= 0x071506 /* Available since 7.21.6 */
1191	REGISTER_CURL_CONSTANT(CURLOPT_ACCEPT_ENCODING);
1192	REGISTER_CURL_CONSTANT(CURLOPT_TRANSFER_ENCODING);
1193#endif
1194
1195#if LIBCURL_VERSION_NUM >= 0x071600 /* Available since 7.22.0 */
1196	REGISTER_CURL_CONSTANT(CURLGSSAPI_DELEGATION_FLAG);
1197	REGISTER_CURL_CONSTANT(CURLGSSAPI_DELEGATION_POLICY_FLAG);
1198	REGISTER_CURL_CONSTANT(CURLOPT_GSSAPI_DELEGATION);
1199#endif
1200
1201#if LIBCURL_VERSION_NUM >= 0x071800 /* Available since 7.24.0 */
1202	REGISTER_CURL_CONSTANT(CURLOPT_ACCEPTTIMEOUT_MS);
1203	REGISTER_CURL_CONSTANT(CURLOPT_DNS_SERVERS);
1204#endif
1205
1206#if LIBCURL_VERSION_NUM >= 0x071900 /* Available since 7.25.0 */
1207	REGISTER_CURL_CONSTANT(CURLOPT_MAIL_AUTH);
1208	REGISTER_CURL_CONSTANT(CURLOPT_SSL_OPTIONS);
1209	REGISTER_CURL_CONSTANT(CURLOPT_TCP_KEEPALIVE);
1210	REGISTER_CURL_CONSTANT(CURLOPT_TCP_KEEPIDLE);
1211	REGISTER_CURL_CONSTANT(CURLOPT_TCP_KEEPINTVL);
1212	REGISTER_CURL_CONSTANT(CURLSSLOPT_ALLOW_BEAST);
1213#endif
1214
1215#if LIBCURL_VERSION_NUM >= 0x072200 /* Available since 7.34.0 */
1216	REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_0);
1217	REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_1);
1218	REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_2);
1219#endif
1220
1221#if LIBCURL_VERSION_NUM >= 0x072B00 /* Available since 7.43.0 */
1222	REGISTER_CURL_CONSTANT(CURLPIPE_NOTHING);
1223	REGISTER_CURL_CONSTANT(CURLPIPE_HTTP1);
1224	REGISTER_CURL_CONSTANT(CURLPIPE_MULTIPLEX);
1225#endif
1226
1227#if CURLOPT_FTPASCII != 0
1228	REGISTER_CURL_CONSTANT(CURLOPT_FTPASCII);
1229#endif
1230#if CURLOPT_MUTE != 0
1231	REGISTER_CURL_CONSTANT(CURLOPT_MUTE);
1232#endif
1233#if CURLOPT_PASSWDFUNCTION != 0
1234	REGISTER_CURL_CONSTANT(CURLOPT_PASSWDFUNCTION);
1235#endif
1236	REGISTER_CURL_CONSTANT(CURLOPT_SAFE_UPLOAD);
1237
1238#ifdef PHP_CURL_NEED_OPENSSL_TSL
1239	if (!CRYPTO_get_id_callback()) {
1240		int i, c = CRYPTO_num_locks();
1241
1242		php_curl_openssl_tsl = malloc(c * sizeof(MUTEX_T));
1243		if (!php_curl_openssl_tsl) {
1244			return FAILURE;
1245		}
1246
1247		for (i = 0; i < c; ++i) {
1248			php_curl_openssl_tsl[i] = tsrm_mutex_alloc();
1249		}
1250
1251		CRYPTO_set_id_callback(php_curl_ssl_id);
1252		CRYPTO_set_locking_callback(php_curl_ssl_lock);
1253	}
1254#endif
1255#ifdef PHP_CURL_NEED_GNUTLS_TSL
1256	gcry_control(GCRYCTL_SET_THREAD_CBS, &php_curl_gnutls_tsl);
1257#endif
1258
1259	if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
1260		return FAILURE;
1261	}
1262
1263	curlfile_register_class();
1264
1265	return SUCCESS;
1266}
1267/* }}} */
1268
1269/* {{{ PHP_MSHUTDOWN_FUNCTION
1270 */
1271PHP_MSHUTDOWN_FUNCTION(curl)
1272{
1273	curl_global_cleanup();
1274#ifdef PHP_CURL_NEED_OPENSSL_TSL
1275	if (php_curl_openssl_tsl) {
1276		int i, c = CRYPTO_num_locks();
1277
1278		CRYPTO_set_id_callback(NULL);
1279		CRYPTO_set_locking_callback(NULL);
1280
1281		for (i = 0; i < c; ++i) {
1282			tsrm_mutex_free(php_curl_openssl_tsl[i]);
1283		}
1284
1285		free(php_curl_openssl_tsl);
1286		php_curl_openssl_tsl = NULL;
1287	}
1288#endif
1289	UNREGISTER_INI_ENTRIES();
1290	return SUCCESS;
1291}
1292/* }}} */
1293
1294/* {{{ curl_write_nothing
1295 * Used as a work around. See _php_curl_close_ex
1296 */
1297static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx)
1298{
1299	return size * nmemb;
1300}
1301/* }}} */
1302
1303/* {{{ curl_write
1304 */
1305static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
1306{
1307	php_curl *ch = (php_curl *) ctx;
1308	php_curl_write *t = ch->handlers->write;
1309	size_t length = size * nmemb;
1310
1311#if PHP_CURL_DEBUG
1312	fprintf(stderr, "curl_write() called\n");
1313	fprintf(stderr, "data = %s, size = %d, nmemb = %d, ctx = %x\n", data, size, nmemb, ctx);
1314#endif
1315
1316	switch (t->method) {
1317		case PHP_CURL_STDOUT:
1318			PHPWRITE(data, length);
1319			break;
1320		case PHP_CURL_FILE:
1321			return fwrite(data, size, nmemb, t->fp);
1322		case PHP_CURL_RETURN:
1323			if (length > 0) {
1324				smart_str_appendl(&t->buf, data, (int) length);
1325			}
1326			break;
1327		case PHP_CURL_USER: {
1328			zval argv[2];
1329			zval retval;
1330			int  error;
1331			zend_fcall_info fci;
1332
1333			ZVAL_RES(&argv[0], ch->res);
1334			Z_ADDREF(argv[0]);
1335			ZVAL_STRINGL(&argv[1], data, length);
1336
1337			fci.size = sizeof(fci);
1338			fci.function_table = EG(function_table);
1339			fci.object = NULL;
1340			ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
1341			fci.retval = &retval;
1342			fci.param_count = 2;
1343			fci.params = argv;
1344			fci.no_separation = 0;
1345			fci.symbol_table = NULL;
1346
1347			ch->in_callback = 1;
1348			error = zend_call_function(&fci, &t->fci_cache);
1349			ch->in_callback = 0;
1350			if (error == FAILURE) {
1351				php_error_docref(NULL, E_WARNING, "Could not call the CURLOPT_WRITEFUNCTION");
1352				length = -1;
1353			} else if (!Z_ISUNDEF(retval)) {
1354				_php_curl_verify_handlers(ch, 1);
1355				length = zval_get_long(&retval);
1356			}
1357
1358			zval_ptr_dtor(&argv[0]);
1359			zval_ptr_dtor(&argv[1]);
1360			break;
1361		}
1362	}
1363
1364	return length;
1365}
1366/* }}} */
1367
1368#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
1369/* {{{ curl_fnmatch
1370 */
1371static int curl_fnmatch(void *ctx, const char *pattern, const char *string)
1372{
1373	php_curl *ch = (php_curl *) ctx;
1374	php_curl_fnmatch *t = ch->handlers->fnmatch;
1375	int rval = CURL_FNMATCHFUNC_FAIL;
1376	switch (t->method) {
1377		case PHP_CURL_USER: {
1378			zval argv[3];
1379			zval retval;
1380			int  error;
1381			zend_fcall_info fci;
1382
1383			ZVAL_RES(&argv[0], ch->res);
1384			Z_ADDREF(argv[0]);
1385			ZVAL_STRING(&argv[1], pattern);
1386			ZVAL_STRING(&argv[2], string);
1387
1388			fci.size = sizeof(fci);
1389			fci.function_table = EG(function_table);
1390			ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
1391			fci.object = NULL;
1392			fci.retval = &retval;
1393			fci.param_count = 3;
1394			fci.params = argv;
1395			fci.no_separation = 0;
1396			fci.symbol_table = NULL;
1397
1398			ch->in_callback = 1;
1399			error = zend_call_function(&fci, &t->fci_cache);
1400			ch->in_callback = 0;
1401			if (error == FAILURE) {
1402				php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_FNMATCH_FUNCTION");
1403			} else if (!Z_ISUNDEF(retval)) {
1404				_php_curl_verify_handlers(ch, 1);
1405				rval = zval_get_long(&retval);
1406			}
1407			zval_ptr_dtor(&argv[0]);
1408			zval_ptr_dtor(&argv[1]);
1409			zval_ptr_dtor(&argv[2]);
1410			break;
1411		}
1412	}
1413	return rval;
1414}
1415/* }}} */
1416#endif
1417
1418/* {{{ curl_progress
1419 */
1420static size_t curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
1421{
1422	php_curl *ch = (php_curl *)clientp;
1423	php_curl_progress *t = ch->handlers->progress;
1424	size_t	rval = 0;
1425
1426#if PHP_CURL_DEBUG
1427	fprintf(stderr, "curl_progress() called\n");
1428	fprintf(stderr, "clientp = %x, dltotal = %f, dlnow = %f, ultotal = %f, ulnow = %f\n", clientp, dltotal, dlnow, ultotal, ulnow);
1429#endif
1430
1431	switch (t->method) {
1432		case PHP_CURL_USER: {
1433			zval argv[5];
1434			zval retval;
1435			int  error;
1436			zend_fcall_info fci;
1437
1438			ZVAL_RES(&argv[0], ch->res);
1439			Z_ADDREF(argv[0]);
1440			ZVAL_LONG(&argv[1], (zend_long)dltotal);
1441			ZVAL_LONG(&argv[2], (zend_long)dlnow);
1442			ZVAL_LONG(&argv[3], (zend_long)ultotal);
1443			ZVAL_LONG(&argv[4], (zend_long)ulnow);
1444
1445			fci.size = sizeof(fci);
1446			fci.function_table = EG(function_table);
1447			ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
1448			fci.object = NULL;
1449			fci.retval = &retval;
1450			fci.param_count = 5;
1451			fci.params = argv;
1452			fci.no_separation = 0;
1453			fci.symbol_table = NULL;
1454
1455			ch->in_callback = 1;
1456			error = zend_call_function(&fci, &t->fci_cache);
1457			ch->in_callback = 0;
1458			if (error == FAILURE) {
1459				php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_PROGRESSFUNCTION");
1460			} else if (!Z_ISUNDEF(retval)) {
1461				_php_curl_verify_handlers(ch, 1);
1462				if (0 != zval_get_long(&retval)) {
1463					rval = 1;
1464				}
1465			}
1466			zval_ptr_dtor(&argv[0]);
1467			zval_ptr_dtor(&argv[1]);
1468			zval_ptr_dtor(&argv[2]);
1469			zval_ptr_dtor(&argv[3]);
1470			zval_ptr_dtor(&argv[4]);
1471			break;
1472		}
1473	}
1474	return rval;
1475}
1476/* }}} */
1477
1478/* {{{ curl_read
1479 */
1480static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
1481{
1482	php_curl *ch = (php_curl *)ctx;
1483	php_curl_read *t = ch->handlers->read;
1484	int length = 0;
1485
1486	switch (t->method) {
1487		case PHP_CURL_DIRECT:
1488			if (t->fp) {
1489				length = fread(data, size, nmemb, t->fp);
1490			}
1491			break;
1492		case PHP_CURL_USER: {
1493			zval argv[3];
1494			zval retval;
1495			int  error;
1496			zend_fcall_info fci;
1497
1498			ZVAL_RES(&argv[0], ch->res);
1499			Z_ADDREF(argv[0]);
1500			if (t->res) {
1501				ZVAL_RES(&argv[1], t->res);
1502				Z_ADDREF(argv[1]);
1503			} else {
1504				ZVAL_NULL(&argv[1]);
1505			}
1506			ZVAL_LONG(&argv[2], (int)size * nmemb);
1507
1508			fci.size = sizeof(fci);
1509			fci.function_table = EG(function_table);
1510			ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
1511			fci.object = NULL;
1512			fci.retval = &retval;
1513			fci.param_count = 3;
1514			fci.params = argv;
1515			fci.no_separation = 0;
1516			fci.symbol_table = NULL;
1517
1518			ch->in_callback = 1;
1519			error = zend_call_function(&fci, &t->fci_cache);
1520			ch->in_callback = 0;
1521			if (error == FAILURE) {
1522				php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_READFUNCTION");
1523#if LIBCURL_VERSION_NUM >= 0x070c01 /* 7.12.1 */
1524				length = CURL_READFUNC_ABORT;
1525#endif
1526			} else if (!Z_ISUNDEF(retval)) {
1527				_php_curl_verify_handlers(ch, 1);
1528				if (Z_TYPE(retval) == IS_STRING) {
1529					length = MIN((int) (size * nmemb), Z_STRLEN(retval));
1530					memcpy(data, Z_STRVAL(retval), length);
1531				}
1532				zval_ptr_dtor(&retval);
1533			}
1534
1535			zval_ptr_dtor(&argv[0]);
1536			zval_ptr_dtor(&argv[1]);
1537			zval_ptr_dtor(&argv[2]);
1538			break;
1539		}
1540	}
1541
1542	return length;
1543}
1544/* }}} */
1545
1546/* {{{ curl_write_header
1547 */
1548static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx)
1549{
1550	php_curl *ch = (php_curl *) ctx;
1551	php_curl_write *t = ch->handlers->write_header;
1552	size_t length = size * nmemb;
1553
1554	switch (t->method) {
1555		case PHP_CURL_STDOUT:
1556			/* Handle special case write when we're returning the entire transfer
1557			 */
1558			if (ch->handlers->write->method == PHP_CURL_RETURN && length > 0) {
1559				smart_str_appendl(&ch->handlers->write->buf, data, (int) length);
1560			} else {
1561				PHPWRITE(data, length);
1562			}
1563			break;
1564		case PHP_CURL_FILE:
1565			return fwrite(data, size, nmemb, t->fp);
1566		case PHP_CURL_USER: {
1567			zval argv[2];
1568			zval retval;
1569			int  error;
1570			zend_fcall_info fci;
1571
1572			ZVAL_RES(&argv[0], ch->res);
1573			Z_ADDREF(argv[0]);
1574			ZVAL_STRINGL(&argv[1], data, length);
1575
1576			fci.size = sizeof(fci);
1577			fci.function_table = EG(function_table);
1578			ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
1579			fci.symbol_table = NULL;
1580			fci.object = NULL;
1581			fci.retval = &retval;
1582			fci.param_count = 2;
1583			fci.params = argv;
1584			fci.no_separation = 0;
1585
1586			ch->in_callback = 1;
1587			error = zend_call_function(&fci, &t->fci_cache);
1588			ch->in_callback = 0;
1589			if (error == FAILURE) {
1590				php_error_docref(NULL, E_WARNING, "Could not call the CURLOPT_HEADERFUNCTION");
1591				length = -1;
1592			} else if (!Z_ISUNDEF(retval)) {
1593				_php_curl_verify_handlers(ch, 1);
1594				length = zval_get_long(&retval);
1595			}
1596			zval_ptr_dtor(&argv[0]);
1597			zval_ptr_dtor(&argv[1]);
1598			break;
1599		}
1600
1601		case PHP_CURL_IGNORE:
1602			return length;
1603
1604		default:
1605			return -1;
1606	}
1607
1608	return length;
1609}
1610/* }}} */
1611
1612static int curl_debug(CURL *cp, curl_infotype type, char *buf, size_t buf_len, void *ctx) /* {{{ */
1613{
1614	php_curl *ch = (php_curl *)ctx;
1615
1616	if (type == CURLINFO_HEADER_OUT) {
1617		if (ch->header.str) {
1618			zend_string_release(ch->header.str);
1619		}
1620		if (buf_len > 0) {
1621			ch->header.str = zend_string_init(buf, buf_len, 0);
1622		}
1623	}
1624
1625	return 0;
1626}
1627/* }}} */
1628
1629#if CURLOPT_PASSWDFUNCTION != 0
1630/* {{{ curl_passwd
1631 */
1632static size_t curl_passwd(void *ctx, char *prompt, char *buf, int buflen)
1633{
1634	php_curl *ch = (php_curl *) ctx;
1635	zval *func = &ch->handlers->passwd;
1636	zval  argv[3];
1637	zval  retval;
1638	int   error;
1639	int   ret = -1;
1640
1641	ZVAL_RES(&argv[0], ch->res);
1642	Z_ADDREF(argv[0]);
1643	ZVAL_STRING(&argv[1], prompt);
1644	ZVAL_LONG(&argv[2], buflen);
1645
1646	error = call_user_function(EG(function_table), NULL, func, &retval, 2, argv);
1647	if (error == FAILURE) {
1648		php_error_docref(NULL, E_WARNING, "Could not call the CURLOPT_PASSWDFUNCTION");
1649	} else if (Z_TYPE(retval) == IS_STRING) {
1650		if (Z_STRLEN(retval) > buflen) {
1651			php_error_docref(NULL, E_WARNING, "Returned password is too long for libcurl to handle");
1652		} else {
1653			memcpy(buf, Z_STRVAL(retval), Z_STRLEN(retval) + 1);
1654		}
1655	} else {
1656		php_error_docref(NULL, E_WARNING, "User handler '%s' did not return a string", Z_STRVAL_P(func));
1657	}
1658
1659	zval_ptr_dtor(&argv[0]);
1660	zval_ptr_dtor(&argv[1]);
1661	zval_ptr_dtor(&argv[2]);
1662	zval_ptr_dtor(&retval);
1663
1664	return ret;
1665}
1666/* }}} */
1667#endif
1668
1669/* {{{ curl_free_string
1670 */
1671static void curl_free_string(void **string)
1672{
1673	efree((char *)*string);
1674}
1675/* }}} */
1676
1677/* {{{ curl_free_post
1678 */
1679static void curl_free_post(void **post)
1680{
1681	curl_formfree((struct HttpPost *)*post);
1682}
1683/* }}} */
1684
1685/* {{{ curl_free_slist
1686 */
1687static void curl_free_slist(zval *el)
1688{
1689	curl_slist_free_all(((struct curl_slist *)Z_PTR_P(el)));
1690}
1691/* }}} */
1692
1693/* {{{ proto array curl_version([int version])
1694   Return cURL version information. */
1695PHP_FUNCTION(curl_version)
1696{
1697	curl_version_info_data *d;
1698	zend_long uversion = CURLVERSION_NOW;
1699
1700	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &uversion) == FAILURE) {
1701		return;
1702	}
1703
1704	d = curl_version_info(uversion);
1705	if (d == NULL) {
1706		RETURN_FALSE;
1707	}
1708
1709	array_init(return_value);
1710
1711	CAAL("version_number", d->version_num);
1712	CAAL("age", d->age);
1713	CAAL("features", d->features);
1714	CAAL("ssl_version_number", d->ssl_version_num);
1715	CAAS("version", d->version);
1716	CAAS("host", d->host);
1717	CAAS("ssl_version", d->ssl_version);
1718	CAAS("libz_version", d->libz_version);
1719	/* Add an array of protocols */
1720	{
1721		char **p = (char **) d->protocols;
1722		zval protocol_list;
1723
1724		array_init(&protocol_list);
1725
1726		while (*p != NULL) {
1727			add_next_index_string(&protocol_list, *p);
1728			p++;
1729		}
1730		CAAZ("protocols", &protocol_list);
1731	}
1732}
1733/* }}} */
1734
1735/* {{{ alloc_curl_handle
1736 */
1737static php_curl *alloc_curl_handle()
1738{
1739	php_curl *ch               = ecalloc(1, sizeof(php_curl));
1740	ch->to_free                = ecalloc(1, sizeof(struct _php_curl_free));
1741	ch->handlers               = ecalloc(1, sizeof(php_curl_handlers));
1742	ch->handlers->write        = ecalloc(1, sizeof(php_curl_write));
1743	ch->handlers->write_header = ecalloc(1, sizeof(php_curl_write));
1744	ch->handlers->read         = ecalloc(1, sizeof(php_curl_read));
1745	ch->handlers->progress     = NULL;
1746#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
1747	ch->handlers->fnmatch      = NULL;
1748#endif
1749	ch->clone 				   = emalloc(sizeof(uint32_t));
1750	*ch->clone                 = 1;
1751
1752	memset(&ch->err, 0, sizeof(struct _php_curl_error));
1753
1754	zend_llist_init(&ch->to_free->str,   sizeof(char *),          (llist_dtor_func_t)curl_free_string, 0);
1755	zend_llist_init(&ch->to_free->post,  sizeof(struct HttpPost *), (llist_dtor_func_t)curl_free_post,   0);
1756
1757	ch->to_free->slist = emalloc(sizeof(HashTable));
1758	zend_hash_init(ch->to_free->slist, 4, NULL, curl_free_slist, 0);
1759
1760	return ch;
1761}
1762/* }}} */
1763
1764#if LIBCURL_VERSION_NUM >= 0x071301 /* Available since 7.19.1 */
1765/* {{{ split_certinfo
1766 */
1767static void split_certinfo(char *string, zval *hash)
1768{
1769	char *org = estrdup(string);
1770	char *s = org;
1771	char *split;
1772
1773	if(org) {
1774		do {
1775			char *key;
1776			char *val;
1777			char *tmp;
1778
1779			split = strstr(s, "; ");
1780			if(split)
1781				*split = '\0';
1782
1783			key = s;
1784			tmp = memchr(key, '=', 64);
1785			if(tmp) {
1786				*tmp = '\0';
1787				val = tmp+1;
1788				add_assoc_string(hash, key, val);
1789			}
1790			s = split+2;
1791		} while(split);
1792		efree(org);
1793	}
1794}
1795/* }}} */
1796
1797/* {{{ create_certinfo
1798 */
1799static void create_certinfo(struct curl_certinfo *ci, zval *listcode)
1800{
1801	int i;
1802
1803	if (ci) {
1804		zval certhash;
1805
1806		for (i=0; i<ci->num_of_certs; i++) {
1807			struct curl_slist *slist;
1808
1809			array_init(&certhash);
1810			for (slist = ci->certinfo[i]; slist; slist = slist->next) {
1811				int len;
1812				char s[64];
1813				char *tmp;
1814				strncpy(s, slist->data, 64);
1815				tmp = memchr(s, ':', 64);
1816				if(tmp) {
1817					*tmp = '\0';
1818					len = strlen(s);
1819					if (!strcmp(s, "Subject") || !strcmp(s, "Issuer")) {
1820						zval hash;
1821
1822						array_init(&hash);
1823
1824						split_certinfo(&slist->data[len+1], &hash);
1825						add_assoc_zval(&certhash, s, &hash);
1826					} else {
1827						add_assoc_string(&certhash, s, &slist->data[len+1]);
1828					}
1829				} else {
1830					php_error_docref(NULL, E_WARNING, "Could not extract hash key from certificate info");
1831				}
1832			}
1833			add_next_index_zval(listcode, &certhash);
1834		}
1835	}
1836}
1837/* }}} */
1838#endif
1839
1840/* {{{ _php_curl_set_default_options()
1841   Set default options for a handle */
1842static void _php_curl_set_default_options(php_curl *ch)
1843{
1844	char *cainfo;
1845
1846	curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS,        1);
1847	curl_easy_setopt(ch->cp, CURLOPT_VERBOSE,           0);
1848	curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER,       ch->err.str);
1849	curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION,     curl_write);
1850	curl_easy_setopt(ch->cp, CURLOPT_FILE,              (void *) ch);
1851	curl_easy_setopt(ch->cp, CURLOPT_READFUNCTION,      curl_read);
1852	curl_easy_setopt(ch->cp, CURLOPT_INFILE,            (void *) ch);
1853	curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION,    curl_write_header);
1854	curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER,       (void *) ch);
1855#if !defined(ZTS)
1856	curl_easy_setopt(ch->cp, CURLOPT_DNS_USE_GLOBAL_CACHE, 1);
1857#endif
1858	curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120);
1859	curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20); /* prevent infinite redirects */
1860
1861	cainfo = INI_STR("openssl.cafile");
1862	if (!(cainfo && cainfo[0] != '\0')) {
1863		cainfo = INI_STR("curl.cainfo");
1864	}
1865	if (cainfo && cainfo[0] != '\0') {
1866		curl_easy_setopt(ch->cp, CURLOPT_CAINFO, cainfo);
1867	}
1868
1869#if defined(ZTS)
1870	curl_easy_setopt(ch->cp, CURLOPT_NOSIGNAL, 1);
1871#endif
1872}
1873/* }}} */
1874
1875/* {{{ proto resource curl_init([string url])
1876   Initialize a cURL session */
1877PHP_FUNCTION(curl_init)
1878{
1879	php_curl *ch;
1880	CURL 	 *cp;
1881	char 	 *url = NULL;
1882	size_t		  url_len = 0;
1883
1884	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &url, &url_len) == FAILURE) {
1885		return;
1886	}
1887
1888	cp = curl_easy_init();
1889	if (!cp) {
1890		php_error_docref(NULL, E_WARNING, "Could not initialize a new cURL handle");
1891		RETURN_FALSE;
1892	}
1893
1894	ch = alloc_curl_handle();
1895
1896	ch->cp = cp;
1897
1898	ch->handlers->write->method = PHP_CURL_STDOUT;
1899	ch->handlers->read->method  = PHP_CURL_DIRECT;
1900	ch->handlers->write_header->method = PHP_CURL_IGNORE;
1901
1902	_php_curl_set_default_options(ch);
1903
1904	if (url) {
1905		if (php_curl_option_url(ch, url, url_len) == FAILURE) {
1906			_php_curl_close_ex(ch);
1907			RETURN_FALSE;
1908		}
1909	}
1910
1911	ZVAL_RES(return_value, zend_register_resource(ch, le_curl));
1912	ch->res = Z_RES_P(return_value);
1913}
1914/* }}} */
1915
1916/* {{{ proto resource curl_copy_handle(resource ch)
1917   Copy a cURL handle along with all of it's preferences */
1918PHP_FUNCTION(curl_copy_handle)
1919{
1920	CURL		*cp;
1921	zval		*zid;
1922	php_curl	*ch, *dupch;
1923
1924	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zid) == FAILURE) {
1925		return;
1926	}
1927
1928	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
1929		RETURN_FALSE;
1930	}
1931
1932	cp = curl_easy_duphandle(ch->cp);
1933	if (!cp) {
1934		php_error_docref(NULL, E_WARNING, "Cannot duplicate cURL handle");
1935		RETURN_FALSE;
1936	}
1937
1938	dupch = alloc_curl_handle();
1939
1940	dupch->cp = cp;
1941	Z_ADDREF_P(zid);
1942	if (!Z_ISUNDEF(ch->handlers->write->stream)) {
1943		Z_ADDREF(ch->handlers->write->stream);
1944	}
1945	dupch->handlers->write->stream = ch->handlers->write->stream;
1946	dupch->handlers->write->method = ch->handlers->write->method;
1947	if (!Z_ISUNDEF(ch->handlers->read->stream)) {
1948		Z_ADDREF(ch->handlers->read->stream);
1949	}
1950	dupch->handlers->read->stream  = ch->handlers->read->stream;
1951	dupch->handlers->read->method  = ch->handlers->read->method;
1952	dupch->handlers->write_header->method = ch->handlers->write_header->method;
1953	if (!Z_ISUNDEF(ch->handlers->write_header->stream)) {
1954		Z_ADDREF(ch->handlers->write_header->stream);
1955	}
1956	dupch->handlers->write_header->stream = ch->handlers->write_header->stream;
1957
1958	dupch->handlers->write->fp = ch->handlers->write->fp;
1959	dupch->handlers->write_header->fp = ch->handlers->write_header->fp;
1960	dupch->handlers->read->fp = ch->handlers->read->fp;
1961	dupch->handlers->read->res = ch->handlers->read->res;
1962#if CURLOPT_PASSWDDATA != 0
1963	if (!Z_ISUNDEF(ch->handlers->passwd)) {
1964		ZVAL_COPY(&dupch->handlers->passwd, &ch->handlers->passwd);
1965		curl_easy_setopt(ch->cp, CURLOPT_PASSWDDATA, (void *) dupch);
1966	}
1967#endif
1968	if (!Z_ISUNDEF(ch->handlers->write->func_name)) {
1969		ZVAL_COPY(&dupch->handlers->write->func_name, &ch->handlers->write->func_name);
1970	}
1971	if (!Z_ISUNDEF(ch->handlers->read->func_name)) {
1972		ZVAL_COPY(&dupch->handlers->read->func_name, &ch->handlers->read->func_name);
1973	}
1974	if (!Z_ISUNDEF(ch->handlers->write_header->func_name)) {
1975		ZVAL_COPY(&dupch->handlers->write_header->func_name, &ch->handlers->write_header->func_name);
1976	}
1977
1978	curl_easy_setopt(dupch->cp, CURLOPT_ERRORBUFFER,       dupch->err.str);
1979	curl_easy_setopt(dupch->cp, CURLOPT_FILE,              (void *) dupch);
1980	curl_easy_setopt(dupch->cp, CURLOPT_INFILE,            (void *) dupch);
1981	curl_easy_setopt(dupch->cp, CURLOPT_WRITEHEADER,       (void *) dupch);
1982
1983	if (ch->handlers->progress) {
1984		dupch->handlers->progress = ecalloc(1, sizeof(php_curl_progress));
1985		if (!Z_ISUNDEF(ch->handlers->progress->func_name)) {
1986			ZVAL_COPY(&dupch->handlers->progress->func_name, &ch->handlers->progress->func_name);
1987		}
1988		dupch->handlers->progress->method = ch->handlers->progress->method;
1989		curl_easy_setopt(dupch->cp, CURLOPT_PROGRESSDATA, (void *) dupch);
1990	}
1991
1992/* Available since 7.21.0 */
1993#if LIBCURL_VERSION_NUM >= 0x071500
1994	if (ch->handlers->fnmatch) {
1995		dupch->handlers->fnmatch = ecalloc(1, sizeof(php_curl_fnmatch));
1996		if (!Z_ISUNDEF(ch->handlers->fnmatch->func_name)) {
1997			ZVAL_COPY(&dupch->handlers->fnmatch->func_name, &ch->handlers->fnmatch->func_name);
1998		}
1999		dupch->handlers->fnmatch->method = ch->handlers->fnmatch->method;
2000		curl_easy_setopt(dupch->cp, CURLOPT_FNMATCH_DATA, (void *) dupch);
2001	}
2002#endif
2003
2004	efree(dupch->to_free->slist);
2005	efree(dupch->to_free);
2006	dupch->to_free = ch->to_free;
2007	efree(dupch->clone);
2008	dupch->clone = ch->clone;
2009
2010	/* Keep track of cloned copies to avoid invoking curl destructors for every clone */
2011	(*ch->clone)++;
2012
2013	ZVAL_RES(return_value, zend_register_resource(dupch, le_curl));
2014	dupch->res = Z_RES_P(return_value);
2015}
2016/* }}} */
2017
2018static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ */
2019{
2020	CURLcode error = CURLE_OK;
2021	zend_long lval;
2022
2023	ZVAL_DEREF(zvalue);
2024	switch (option) {
2025		/* Long options */
2026		case CURLOPT_SSL_VERIFYHOST:
2027			lval = zval_get_long(zvalue);
2028			if (lval == 1) {
2029#if LIBCURL_VERSION_NUM <= 0x071c00 /* 7.28.0 */
2030				php_error_docref(NULL, E_NOTICE, "CURLOPT_SSL_VERIFYHOST with value 1 is deprecated and will be removed as of libcurl 7.28.1. It is recommended to use value 2 instead");
2031#else
2032				php_error_docref(NULL, E_NOTICE, "CURLOPT_SSL_VERIFYHOST no longer accepts the value 1, value 2 will be used instead");
2033				error = curl_easy_setopt(ch->cp, option, 2);
2034				break;
2035#endif
2036			}
2037		case CURLOPT_AUTOREFERER:
2038		case CURLOPT_BUFFERSIZE:
2039		case CURLOPT_CONNECTTIMEOUT:
2040		case CURLOPT_COOKIESESSION:
2041		case CURLOPT_CRLF:
2042		case CURLOPT_DNS_CACHE_TIMEOUT:
2043		case CURLOPT_DNS_USE_GLOBAL_CACHE:
2044		case CURLOPT_FAILONERROR:
2045		case CURLOPT_FILETIME:
2046		case CURLOPT_FORBID_REUSE:
2047		case CURLOPT_FRESH_CONNECT:
2048		case CURLOPT_FTP_USE_EPRT:
2049		case CURLOPT_FTP_USE_EPSV:
2050		case CURLOPT_HEADER:
2051		case CURLOPT_HTTPGET:
2052		case CURLOPT_HTTPPROXYTUNNEL:
2053		case CURLOPT_HTTP_VERSION:
2054		case CURLOPT_INFILESIZE:
2055		case CURLOPT_LOW_SPEED_LIMIT:
2056		case CURLOPT_LOW_SPEED_TIME:
2057		case CURLOPT_MAXCONNECTS:
2058		case CURLOPT_MAXREDIRS:
2059		case CURLOPT_NETRC:
2060		case CURLOPT_NOBODY:
2061		case CURLOPT_NOPROGRESS:
2062		case CURLOPT_NOSIGNAL:
2063		case CURLOPT_PORT:
2064		case CURLOPT_POST:
2065		case CURLOPT_PROXYPORT:
2066		case CURLOPT_PROXYTYPE:
2067		case CURLOPT_PUT:
2068		case CURLOPT_RESUME_FROM:
2069		case CURLOPT_SSLVERSION:
2070		case CURLOPT_SSL_VERIFYPEER:
2071		case CURLOPT_TIMECONDITION:
2072		case CURLOPT_TIMEOUT:
2073		case CURLOPT_TIMEVALUE:
2074		case CURLOPT_TRANSFERTEXT:
2075		case CURLOPT_UNRESTRICTED_AUTH:
2076		case CURLOPT_UPLOAD:
2077		case CURLOPT_VERBOSE:
2078#if LIBCURL_VERSION_NUM >= 0x070a06 /* Available since 7.10.6 */
2079		case CURLOPT_HTTPAUTH:
2080#endif
2081#if LIBCURL_VERSION_NUM >= 0x070a07 /* Available since 7.10.7 */
2082		case CURLOPT_FTP_CREATE_MISSING_DIRS:
2083		case CURLOPT_PROXYAUTH:
2084#endif
2085#if LIBCURL_VERSION_NUM >= 0x070a08 /* Available since 7.10.8 */
2086		case CURLOPT_FTP_RESPONSE_TIMEOUT:
2087		case CURLOPT_IPRESOLVE:
2088		case CURLOPT_MAXFILESIZE:
2089#endif
2090#if LIBCURL_VERSION_NUM >= 0x070b02 /* Available since 7.11.2 */
2091		case CURLOPT_TCP_NODELAY:
2092#endif
2093#if LIBCURL_VERSION_NUM >= 0x070c02 /* Available since 7.12.2 */
2094		case CURLOPT_FTPSSLAUTH:
2095#endif
2096#if LIBCURL_VERSION_NUM >= 0x070e01 /* Available since 7.14.1 */
2097		case CURLOPT_IGNORE_CONTENT_LENGTH:
2098#endif
2099#if LIBCURL_VERSION_NUM >= 0x070f00 /* Available since 7.15.0 */
2100		case CURLOPT_FTP_SKIP_PASV_IP:
2101#endif
2102#if LIBCURL_VERSION_NUM >= 0x070f01 /* Available since 7.15.1 */
2103		case CURLOPT_FTP_FILEMETHOD:
2104#endif
2105#if LIBCURL_VERSION_NUM >= 0x070f02 /* Available since 7.15.2 */
2106		case CURLOPT_CONNECT_ONLY:
2107		case CURLOPT_LOCALPORT:
2108		case CURLOPT_LOCALPORTRANGE:
2109#endif
2110#if LIBCURL_VERSION_NUM >= 0x071000 /* Available since 7.16.0 */
2111		case CURLOPT_SSL_SESSIONID_CACHE:
2112#endif
2113#if LIBCURL_VERSION_NUM >= 0x071001 /* Available since 7.16.1 */
2114		case CURLOPT_FTP_SSL_CCC:
2115		case CURLOPT_SSH_AUTH_TYPES:
2116#endif
2117#if LIBCURL_VERSION_NUM >= 0x071002 /* Available since 7.16.2 */
2118		case CURLOPT_CONNECTTIMEOUT_MS:
2119		case CURLOPT_HTTP_CONTENT_DECODING:
2120		case CURLOPT_HTTP_TRANSFER_DECODING:
2121		case CURLOPT_TIMEOUT_MS:
2122#endif
2123#if LIBCURL_VERSION_NUM >= 0x071004 /* Available since 7.16.4 */
2124		case CURLOPT_NEW_DIRECTORY_PERMS:
2125		case CURLOPT_NEW_FILE_PERMS:
2126#endif
2127#if LIBCURL_VERSION_NUM >= 0x071100 /* Available since 7.17.0 */
2128		case CURLOPT_USE_SSL:
2129#elif LIBCURL_VERSION_NUM >= 0x070b00 /* Available since 7.11.0 */
2130		case CURLOPT_FTP_SSL:
2131#endif
2132#if LIBCURL_VERSION_NUM >= 0x071100 /* Available since 7.17.0 */
2133		case CURLOPT_APPEND:
2134		case CURLOPT_DIRLISTONLY:
2135#else
2136		case CURLOPT_FTPAPPEND:
2137		case CURLOPT_FTPLISTONLY:
2138#endif
2139#if LIBCURL_VERSION_NUM >= 0x071200 /* Available since 7.18.0 */
2140		case CURLOPT_PROXY_TRANSFER_MODE:
2141#endif
2142#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 */
2143		case CURLOPT_ADDRESS_SCOPE:
2144#endif
2145#if LIBCURL_VERSION_NUM >  0x071301 /* Available since 7.19.1 */
2146		case CURLOPT_CERTINFO:
2147#endif
2148#if LIBCURL_VERSION_NUM >= 0x071304 /* Available since 7.19.4 */
2149		case CURLOPT_NOPROXY:
2150		case CURLOPT_PROTOCOLS:
2151		case CURLOPT_REDIR_PROTOCOLS:
2152		case CURLOPT_SOCKS5_GSSAPI_NEC:
2153		case CURLOPT_TFTP_BLKSIZE:
2154#endif
2155#if LIBCURL_VERSION_NUM >= 0x071400 /* Available since 7.20.0 */
2156		case CURLOPT_FTP_USE_PRET:
2157		case CURLOPT_RTSP_CLIENT_CSEQ:
2158		case CURLOPT_RTSP_REQUEST:
2159		case CURLOPT_RTSP_SERVER_CSEQ:
2160#endif
2161#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
2162		case CURLOPT_WILDCARDMATCH:
2163#endif
2164#if LIBCURL_VERSION_NUM >= 0x071504 /* Available since 7.21.4 */
2165		case CURLOPT_TLSAUTH_TYPE:
2166#endif
2167#if LIBCURL_VERSION_NUM >= 0x071600 /* Available since 7.22.0 */
2168		case CURLOPT_GSSAPI_DELEGATION:
2169#endif
2170#if LIBCURL_VERSION_NUM >= 0x071800 /* Available since 7.24.0 */
2171		case CURLOPT_ACCEPTTIMEOUT_MS:
2172#endif
2173#if LIBCURL_VERSION_NUM >= 0x071900 /* Available since 7.25.0 */
2174		case CURLOPT_SSL_OPTIONS:
2175		case CURLOPT_TCP_KEEPALIVE:
2176		case CURLOPT_TCP_KEEPIDLE:
2177		case CURLOPT_TCP_KEEPINTVL:
2178#endif
2179#if CURLOPT_MUTE != 0
2180		case CURLOPT_MUTE:
2181#endif
2182			lval = zval_get_long(zvalue);
2183#if LIBCURL_VERSION_NUM >= 0x71304
2184			if ((option == CURLOPT_PROTOCOLS || option == CURLOPT_REDIR_PROTOCOLS) &&
2185				(PG(open_basedir) && *PG(open_basedir)) && (lval & CURLPROTO_FILE)) {
2186					php_error_docref(NULL, E_WARNING, "CURLPROTO_FILE cannot be activated when an open_basedir is set");
2187					return 1;
2188			}
2189#endif
2190# if defined(ZTS)
2191			if (option == CURLOPT_DNS_USE_GLOBAL_CACHE) {
2192				php_error_docref(NULL, E_WARNING, "CURLOPT_DNS_USE_GLOBAL_CACHE cannot be activated when thread safety is enabled");
2193				return 1;
2194			}
2195# endif
2196			error = curl_easy_setopt(ch->cp, option, lval);
2197			break;
2198		case CURLOPT_SAFE_UPLOAD:
2199			lval = zval_get_long(zvalue);
2200			if (lval == 0) {
2201				php_error_docref(NULL, E_WARNING, "Disabling safe uploads is no longer supported");
2202				return FAILURE;
2203			}
2204			break;
2205
2206		/* String options */
2207		case CURLOPT_CAINFO:
2208		case CURLOPT_CAPATH:
2209		case CURLOPT_COOKIE:
2210		case CURLOPT_EGDSOCKET:
2211		case CURLOPT_INTERFACE:
2212		case CURLOPT_PROXY:
2213		case CURLOPT_PROXYUSERPWD:
2214		case CURLOPT_REFERER:
2215		case CURLOPT_SSLCERTTYPE:
2216		case CURLOPT_SSLENGINE:
2217		case CURLOPT_SSLENGINE_DEFAULT:
2218		case CURLOPT_SSLKEY:
2219		case CURLOPT_SSLKEYPASSWD:
2220		case CURLOPT_SSLKEYTYPE:
2221		case CURLOPT_SSL_CIPHER_LIST:
2222		case CURLOPT_USERAGENT:
2223		case CURLOPT_USERPWD:
2224#if LIBCURL_VERSION_NUM >= 0x070e01 /* Available since 7.14.1 */
2225		case CURLOPT_COOKIELIST:
2226#endif
2227#if LIBCURL_VERSION_NUM >= 0x070f05 /* Available since 7.15.5 */
2228		case CURLOPT_FTP_ALTERNATIVE_TO_USER:
2229#endif
2230#if LIBCURL_VERSION_NUM >= 0x071101 /* Available since 7.17.1 */
2231		case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
2232#endif
2233#if LIBCURL_VERSION_NUM >= 0x071301 /* Available since 7.19.1 */
2234		case CURLOPT_PASSWORD:
2235		case CURLOPT_PROXYPASSWORD:
2236		case CURLOPT_PROXYUSERNAME:
2237		case CURLOPT_USERNAME:
2238#endif
2239#if LIBCURL_VERSION_NUM >= 0x071304 /* Available since 7.19.4 */
2240		case CURLOPT_SOCKS5_GSSAPI_SERVICE:
2241#endif
2242#if LIBCURL_VERSION_NUM >= 0x071400 /* Available since 7.20.0 */
2243		case CURLOPT_MAIL_FROM:
2244		case CURLOPT_RTSP_STREAM_URI:
2245		case CURLOPT_RTSP_TRANSPORT:
2246#endif
2247#if LIBCURL_VERSION_NUM >= 0x071504 /* Available since 7.21.4 */
2248		case CURLOPT_TLSAUTH_PASSWORD:
2249		case CURLOPT_TLSAUTH_USERNAME:
2250#endif
2251#if LIBCURL_VERSION_NUM >= 0x071506 /* Available since 7.21.6 */
2252		case CURLOPT_ACCEPT_ENCODING:
2253		case CURLOPT_TRANSFER_ENCODING:
2254#else
2255		case CURLOPT_ENCODING:
2256#endif
2257#if LIBCURL_VERSION_NUM >= 0x071800 /* Available since 7.24.0 */
2258		case CURLOPT_DNS_SERVERS:
2259#endif
2260#if LIBCURL_VERSION_NUM >= 0x071900 /* Available since 7.25.0 */
2261		case CURLOPT_MAIL_AUTH:
2262#endif
2263		{
2264			zend_string *str = zval_get_string(zvalue);
2265			int ret = php_curl_option_str(ch, option, ZSTR_VAL(str), ZSTR_LEN(str), 0);
2266			zend_string_release(str);
2267			return ret;
2268		}
2269
2270		/* Curl nullable string options */
2271		case CURLOPT_CUSTOMREQUEST:
2272		case CURLOPT_FTPPORT:
2273		case CURLOPT_RANGE:
2274#if LIBCURL_VERSION_NUM >= 0x070d00 /* Available since 7.13.0 */
2275		case CURLOPT_FTP_ACCOUNT:
2276#endif
2277#if LIBCURL_VERSION_NUM >= 0x071400 /* Available since 7.20.0 */
2278		case CURLOPT_RTSP_SESSION_ID:
2279#endif
2280#if LIBCURL_VERSION_NUM >= 0x071004 /* Available since 7.16.4 */
2281		case CURLOPT_KRBLEVEL:
2282#else
2283		case CURLOPT_KRB4LEVEL:
2284#endif
2285		{
2286			if (Z_ISNULL_P(zvalue)) {
2287				error = curl_easy_setopt(ch->cp, option, NULL);
2288			} else {
2289				zend_string *str = zval_get_string(zvalue);
2290				int ret = php_curl_option_str(ch, option, ZSTR_VAL(str), ZSTR_LEN(str), 0);
2291				zend_string_release(str);
2292				return ret;
2293			}
2294			break;
2295		}
2296
2297		/* Curl private option */
2298		case CURLOPT_PRIVATE:
2299		{
2300			zend_string *str = zval_get_string(zvalue);
2301			int ret = php_curl_option_str(ch, option, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2302			zend_string_release(str);
2303			return ret;
2304		}
2305
2306		/* Curl url option */
2307		case CURLOPT_URL:
2308		{
2309			zend_string *str = zval_get_string(zvalue);
2310			int ret = php_curl_option_url(ch, ZSTR_VAL(str), ZSTR_LEN(str));
2311			zend_string_release(str);
2312			return ret;
2313		}
2314
2315		/* Curl file handle options */
2316		case CURLOPT_FILE:
2317		case CURLOPT_INFILE:
2318		case CURLOPT_STDERR:
2319		case CURLOPT_WRITEHEADER: {
2320			FILE *fp = NULL;
2321			php_stream *what = NULL;
2322
2323			if (Z_TYPE_P(zvalue) != IS_NULL) {
2324				what = (php_stream *)zend_fetch_resource2_ex(zvalue, "File-Handle", php_file_le_stream(), php_file_le_pstream());
2325				if (!what) {
2326					return FAILURE;
2327				}
2328
2329				if (FAILURE == php_stream_cast(what, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
2330					return FAILURE;
2331				}
2332
2333				if (!fp) {
2334					return FAILURE;
2335				}
2336			}
2337
2338			error = CURLE_OK;
2339			switch (option) {
2340				case CURLOPT_FILE:
2341					if (!what) {
2342						if (!Z_ISUNDEF(ch->handlers->write->stream)) {
2343							zval_ptr_dtor(&ch->handlers->write->stream);
2344							ZVAL_UNDEF(&ch->handlers->write->stream);
2345						}
2346						ch->handlers->write->fp = NULL;
2347						ch->handlers->write->method = PHP_CURL_STDOUT;
2348					} else if (what->mode[0] != 'r' || what->mode[1] == '+') {
2349						zval_ptr_dtor(&ch->handlers->write->stream);
2350						ch->handlers->write->fp = fp;
2351						ch->handlers->write->method = PHP_CURL_FILE;
2352						ZVAL_COPY(&ch->handlers->write->stream, zvalue);
2353					} else {
2354						php_error_docref(NULL, E_WARNING, "the provided file handle is not writable");
2355						return FAILURE;
2356					}
2357					break;
2358				case CURLOPT_WRITEHEADER:
2359					if (!what) {
2360						if (!Z_ISUNDEF(ch->handlers->write_header->stream)) {
2361							zval_ptr_dtor(&ch->handlers->write_header->stream);
2362							ZVAL_UNDEF(&ch->handlers->write_header->stream);
2363						}
2364						ch->handlers->write_header->fp = NULL;
2365						ch->handlers->write_header->method = PHP_CURL_IGNORE;
2366					} else if (what->mode[0] != 'r' || what->mode[1] == '+') {
2367						zval_ptr_dtor(&ch->handlers->write_header->stream);
2368						ch->handlers->write_header->fp = fp;
2369						ch->handlers->write_header->method = PHP_CURL_FILE;
2370						ZVAL_COPY(&ch->handlers->write_header->stream, zvalue);;
2371					} else {
2372						php_error_docref(NULL, E_WARNING, "the provided file handle is not writable");
2373						return FAILURE;
2374					}
2375					break;
2376				case CURLOPT_INFILE:
2377					if (!what) {
2378						if (!Z_ISUNDEF(ch->handlers->read->stream)) {
2379							zval_ptr_dtor(&ch->handlers->read->stream);
2380							ZVAL_UNDEF(&ch->handlers->read->stream);
2381						}
2382						ch->handlers->read->fp = NULL;
2383						ch->handlers->read->res = NULL;
2384					} else {
2385						zval_ptr_dtor(&ch->handlers->read->stream);
2386						ch->handlers->read->fp = fp;
2387						ch->handlers->read->res = Z_RES_P(zvalue);
2388						ZVAL_COPY(&ch->handlers->read->stream, zvalue);
2389					}
2390					break;
2391				case CURLOPT_STDERR:
2392					if (!what) {
2393						if (!Z_ISUNDEF(ch->handlers->std_err)) {
2394							zval_ptr_dtor(&ch->handlers->std_err);
2395							ZVAL_UNDEF(&ch->handlers->std_err);
2396						}
2397					} else if (what->mode[0] != 'r' || what->mode[1] == '+') {
2398						zval_ptr_dtor(&ch->handlers->std_err);
2399						ZVAL_COPY(&ch->handlers->std_err, zvalue);
2400					} else {
2401						php_error_docref(NULL, E_WARNING, "the provided file handle is not writable");
2402						return FAILURE;
2403					}
2404					/* break omitted intentionally */
2405				default:
2406					error = curl_easy_setopt(ch->cp, option, fp);
2407					break;
2408			}
2409			break;
2410		}
2411
2412		/* Curl linked list options */
2413		case CURLOPT_HTTP200ALIASES:
2414		case CURLOPT_HTTPHEADER:
2415		case CURLOPT_POSTQUOTE:
2416		case CURLOPT_PREQUOTE:
2417		case CURLOPT_QUOTE:
2418		case CURLOPT_TELNETOPTIONS:
2419#if LIBCURL_VERSION_NUM >= 0x071400 /* Available since 7.20.0 */
2420		case CURLOPT_MAIL_RCPT:
2421#endif
2422#if LIBCURL_VERSION_NUM >= 0x071503 /* Available since 7.21.3 */
2423		case CURLOPT_RESOLVE:
2424#endif
2425		{
2426			zval *current;
2427			HashTable *ph;
2428			zend_string *val;
2429			struct curl_slist *slist = NULL;
2430
2431			ph = HASH_OF(zvalue);
2432			if (!ph) {
2433				char *name = NULL;
2434				switch (option) {
2435					case CURLOPT_HTTPHEADER:
2436						name = "CURLOPT_HTTPHEADER";
2437						break;
2438					case CURLOPT_QUOTE:
2439						name = "CURLOPT_QUOTE";
2440						break;
2441					case CURLOPT_HTTP200ALIASES:
2442						name = "CURLOPT_HTTP200ALIASES";
2443						break;
2444					case CURLOPT_POSTQUOTE:
2445						name = "CURLOPT_POSTQUOTE";
2446						break;
2447					case CURLOPT_PREQUOTE:
2448						name = "CURLOPT_PREQUOTE";
2449						break;
2450					case CURLOPT_TELNETOPTIONS:
2451						name = "CURLOPT_TELNETOPTIONS";
2452						break;
2453#if LIBCURL_VERSION_NUM >= 0x071400 /* Available since 7.20.0 */
2454					case CURLOPT_MAIL_RCPT:
2455						name = "CURLOPT_MAIL_RCPT";
2456						break;
2457#endif
2458#if LIBCURL_VERSION_NUM >= 0x071503 /* Available since 7.21.3 */
2459					case CURLOPT_RESOLVE:
2460						name = "CURLOPT_RESOLVE";
2461						break;
2462#endif
2463				}
2464				php_error_docref(NULL, E_WARNING, "You must pass either an object or an array with the %s argument", name);
2465				return FAILURE;
2466			}
2467
2468			ZEND_HASH_FOREACH_VAL(ph, current) {
2469				ZVAL_DEREF(current);
2470				val = zval_get_string(current);
2471				slist = curl_slist_append(slist, ZSTR_VAL(val));
2472				zend_string_release(val);
2473				if (!slist) {
2474					php_error_docref(NULL, E_WARNING, "Could not build curl_slist");
2475					return 1;
2476				}
2477			} ZEND_HASH_FOREACH_END();
2478
2479			if ((*ch->clone) == 1) {
2480				zend_hash_index_update_ptr(ch->to_free->slist, option, slist);
2481			} else {
2482				zend_hash_next_index_insert_ptr(ch->to_free->slist, slist);
2483			}
2484
2485			error = curl_easy_setopt(ch->cp, option, slist);
2486
2487			break;
2488		}
2489
2490		case CURLOPT_BINARYTRANSFER:
2491			/* Do nothing, just backward compatibility */
2492			break;
2493
2494		case CURLOPT_FOLLOWLOCATION:
2495			lval = zval_get_long(zvalue);
2496#if LIBCURL_VERSION_NUM < 0x071304
2497			if (PG(open_basedir) && *PG(open_basedir)) {
2498				if (lval != 0) {
2499					php_error_docref(NULL, E_WARNING, "CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir is set");
2500					return FAILURE;
2501				}
2502			}
2503#endif
2504			error = curl_easy_setopt(ch->cp, option, lval);
2505			break;
2506
2507		case CURLOPT_HEADERFUNCTION:
2508			if (!Z_ISUNDEF(ch->handlers->write_header->func_name)) {
2509				zval_ptr_dtor(&ch->handlers->write_header->func_name);
2510				ch->handlers->write_header->fci_cache = empty_fcall_info_cache;
2511			}
2512			ZVAL_COPY(&ch->handlers->write_header->func_name, zvalue);
2513			ch->handlers->write_header->method = PHP_CURL_USER;
2514			break;
2515
2516		case CURLOPT_POSTFIELDS:
2517			if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
2518				zval *current;
2519				HashTable *postfields;
2520				zend_string *string_key;
2521				zend_ulong  num_key;
2522				struct HttpPost *first = NULL;
2523				struct HttpPost *last  = NULL;
2524				CURLFORMcode form_error;
2525
2526				postfields = HASH_OF(zvalue);
2527				if (!postfields) {
2528					php_error_docref(NULL, E_WARNING, "Couldn't get HashTable in CURLOPT_POSTFIELDS");
2529					return FAILURE;
2530				}
2531
2532				ZEND_HASH_FOREACH_KEY_VAL(postfields, num_key, string_key, current) {
2533					zend_string *postval;
2534					/* Pretend we have a string_key here */
2535					if (!string_key) {
2536						string_key = zend_long_to_str(num_key);
2537					} else {
2538						zend_string_addref(string_key);
2539					}
2540
2541					ZVAL_DEREF(current);
2542					if (Z_TYPE_P(current) == IS_OBJECT &&
2543							instanceof_function(Z_OBJCE_P(current), curl_CURLFile_class)) {
2544						/* new-style file upload */
2545						zval *prop, rv;
2546						char *type = NULL, *filename = NULL;
2547
2548						prop = zend_read_property(curl_CURLFile_class, current, "name", sizeof("name")-1, 0, &rv);
2549						if (Z_TYPE_P(prop) != IS_STRING) {
2550							php_error_docref(NULL, E_WARNING, "Invalid filename for key %s", ZSTR_VAL(string_key));
2551						} else {
2552							postval = Z_STR_P(prop);
2553
2554							if (php_check_open_basedir(ZSTR_VAL(postval))) {
2555								return 1;
2556							}
2557
2558							prop = zend_read_property(curl_CURLFile_class, current, "mime", sizeof("mime")-1, 0, &rv);
2559							if (Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
2560								type = Z_STRVAL_P(prop);
2561							}
2562							prop = zend_read_property(curl_CURLFile_class, current, "postname", sizeof("postname")-1, 0, &rv);
2563							if (Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
2564								filename = Z_STRVAL_P(prop);
2565							}
2566							form_error = curl_formadd(&first, &last,
2567											CURLFORM_COPYNAME, ZSTR_VAL(string_key),
2568											CURLFORM_NAMELENGTH, ZSTR_LEN(string_key),
2569											CURLFORM_FILENAME, filename ? filename : ZSTR_VAL(postval),
2570											CURLFORM_CONTENTTYPE, type ? type : "application/octet-stream",
2571											CURLFORM_FILE, ZSTR_VAL(postval),
2572											CURLFORM_END);
2573							if (form_error != CURL_FORMADD_OK) {
2574								/* Not nice to convert between enums but we only have place for one error type */
2575								error = (CURLcode)form_error;
2576							}
2577						}
2578
2579						zend_string_release(string_key);
2580						continue;
2581					}
2582
2583					postval = zval_get_string(current);
2584
2585					/* The arguments after _NAMELENGTH and _CONTENTSLENGTH
2586					 * must be explicitly cast to long in curl_formadd
2587					 * use since curl needs a long not an int. */
2588					form_error = curl_formadd(&first, &last,
2589										 CURLFORM_COPYNAME, ZSTR_VAL(string_key),
2590										 CURLFORM_NAMELENGTH, ZSTR_LEN(string_key),
2591										 CURLFORM_COPYCONTENTS, ZSTR_VAL(postval),
2592										 CURLFORM_CONTENTSLENGTH, ZSTR_LEN(postval),
2593										 CURLFORM_END);
2594
2595					if (form_error != CURL_FORMADD_OK) {
2596						/* Not nice to convert between enums but we only have place for one error type */
2597						error = (CURLcode)form_error;
2598					}
2599					zend_string_release(postval);
2600					zend_string_release(string_key);
2601				} ZEND_HASH_FOREACH_END();
2602
2603				SAVE_CURL_ERROR(ch, error);
2604				if (error != CURLE_OK) {
2605					return FAILURE;
2606				}
2607
2608				if ((*ch->clone) == 1) {
2609					zend_llist_clean(&ch->to_free->post);
2610				}
2611				zend_llist_add_element(&ch->to_free->post, &first);
2612				error = curl_easy_setopt(ch->cp, CURLOPT_HTTPPOST, first);
2613			} else {
2614#if LIBCURL_VERSION_NUM >= 0x071101
2615				zend_string *str = zval_get_string(zvalue);
2616				/* with curl 7.17.0 and later, we can use COPYPOSTFIELDS, but we have to provide size before */
2617				error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, ZSTR_LEN(str));
2618				error = curl_easy_setopt(ch->cp, CURLOPT_COPYPOSTFIELDS, ZSTR_VAL(str));
2619				zend_string_release(str);
2620#else
2621				char *post = NULL;
2622				zend_string *str = zval_get_string(zvalue);
2623
2624				post = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
2625				zend_llist_add_element(&ch->to_free->str, &post);
2626
2627				curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, post);
2628				error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, ZSTR_LEN(str));
2629				zend_string_release(str);
2630#endif
2631			}
2632			break;
2633
2634		case CURLOPT_PROGRESSFUNCTION:
2635			curl_easy_setopt(ch->cp, CURLOPT_PROGRESSFUNCTION,	curl_progress);
2636			curl_easy_setopt(ch->cp, CURLOPT_PROGRESSDATA, ch);
2637			if (ch->handlers->progress == NULL) {
2638				ch->handlers->progress = ecalloc(1, sizeof(php_curl_progress));
2639			} else if (!Z_ISUNDEF(ch->handlers->progress->func_name)) {
2640				zval_ptr_dtor(&ch->handlers->progress->func_name);
2641				ch->handlers->progress->fci_cache = empty_fcall_info_cache;
2642			}
2643			ZVAL_COPY(&ch->handlers->progress->func_name, zvalue);
2644			ch->handlers->progress->method = PHP_CURL_USER;
2645			break;
2646
2647		case CURLOPT_READFUNCTION:
2648			if (!Z_ISUNDEF(ch->handlers->read->func_name)) {
2649				zval_ptr_dtor(&ch->handlers->read->func_name);
2650				ch->handlers->read->fci_cache = empty_fcall_info_cache;
2651			}
2652			ZVAL_COPY(&ch->handlers->read->func_name, zvalue);
2653			ch->handlers->read->method = PHP_CURL_USER;
2654			break;
2655
2656		case CURLOPT_RETURNTRANSFER:
2657			lval = zval_get_long(zvalue);
2658			if (lval) {
2659				ch->handlers->write->method = PHP_CURL_RETURN;
2660			} else {
2661				ch->handlers->write->method = PHP_CURL_STDOUT;
2662			}
2663			break;
2664
2665		case CURLOPT_WRITEFUNCTION:
2666			if (!Z_ISUNDEF(ch->handlers->write->func_name)) {
2667				zval_ptr_dtor(&ch->handlers->write->func_name);
2668				ch->handlers->write->fci_cache = empty_fcall_info_cache;
2669			}
2670			ZVAL_COPY(&ch->handlers->write->func_name, zvalue);
2671			ch->handlers->write->method = PHP_CURL_USER;
2672			break;
2673
2674#if LIBCURL_VERSION_NUM >= 0x070f05 /* Available since 7.15.5 */
2675		case CURLOPT_MAX_RECV_SPEED_LARGE:
2676		case CURLOPT_MAX_SEND_SPEED_LARGE:
2677			lval = zval_get_long(zvalue);
2678			error = curl_easy_setopt(ch->cp, option, (curl_off_t)lval);
2679			break;
2680#endif
2681
2682#if LIBCURL_VERSION_NUM >= 0x071301 /* Available since 7.19.1 */
2683		case CURLOPT_POSTREDIR:
2684			lval = zval_get_long(zvalue);
2685			error = curl_easy_setopt(ch->cp, CURLOPT_POSTREDIR, lval & CURL_REDIR_POST_ALL);
2686			break;
2687#endif
2688
2689#if CURLOPT_PASSWDFUNCTION != 0
2690		case CURLOPT_PASSWDFUNCTION:
2691			zval_ptr_dtor(&ch->handlers->passwd);
2692			ZVAL_COPY(&ch->handlers->passwd, zvalue);
2693			error = curl_easy_setopt(ch->cp, CURLOPT_PASSWDFUNCTION, curl_passwd);
2694			error = curl_easy_setopt(ch->cp, CURLOPT_PASSWDDATA,     (void *) ch);
2695			break;
2696#endif
2697
2698		/* the following options deal with files, therefore the open_basedir check
2699		 * is required.
2700		 */
2701		case CURLOPT_COOKIEFILE:
2702		case CURLOPT_COOKIEJAR:
2703		case CURLOPT_RANDOM_FILE:
2704		case CURLOPT_SSLCERT:
2705#if LIBCURL_VERSION_NUM >= 0x070b00 /* Available since 7.11.0 */
2706		case CURLOPT_NETRC_FILE:
2707#endif
2708#if LIBCURL_VERSION_NUM >= 0x071001 /* Available since 7.16.1 */
2709		case CURLOPT_SSH_PRIVATE_KEYFILE:
2710		case CURLOPT_SSH_PUBLIC_KEYFILE:
2711#endif
2712#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 */
2713		case CURLOPT_CRLFILE:
2714		case CURLOPT_ISSUERCERT:
2715#endif
2716#if LIBCURL_VERSION_NUM >= 0x071306 /* Available since 7.19.6 */
2717		case CURLOPT_SSH_KNOWNHOSTS:
2718#endif
2719		{
2720			zend_string *str = zval_get_string(zvalue);
2721			int ret;
2722
2723			if (ZSTR_LEN(str) && php_check_open_basedir(ZSTR_VAL(str))) {
2724				zend_string_release(str);
2725				return FAILURE;
2726			}
2727
2728			ret = php_curl_option_str(ch, option, ZSTR_VAL(str), ZSTR_LEN(str), 0);
2729			zend_string_release(str);
2730			return ret;
2731		}
2732
2733		case CURLINFO_HEADER_OUT:
2734			lval = zval_get_long(zvalue);
2735			if (lval == 1) {
2736				curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, curl_debug);
2737				curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *)ch);
2738				curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1);
2739			} else {
2740				curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, NULL);
2741				curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, NULL);
2742				curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0);
2743			}
2744			break;
2745
2746		case CURLOPT_SHARE:
2747			{
2748				php_curlsh *sh;
2749				if ((sh = (php_curlsh *)zend_fetch_resource_ex(zvalue, le_curl_share_handle_name, le_curl_share_handle))) {
2750					curl_easy_setopt(ch->cp, CURLOPT_SHARE, sh->share);
2751				}
2752			}
2753			break;
2754
2755#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
2756		case CURLOPT_FNMATCH_FUNCTION:
2757			curl_easy_setopt(ch->cp, CURLOPT_FNMATCH_FUNCTION, curl_fnmatch);
2758			curl_easy_setopt(ch->cp, CURLOPT_FNMATCH_DATA, ch);
2759			if (ch->handlers->fnmatch == NULL) {
2760				ch->handlers->fnmatch = ecalloc(1, sizeof(php_curl_fnmatch));
2761			} else if (!Z_ISUNDEF(ch->handlers->fnmatch->func_name)) {
2762				zval_ptr_dtor(&ch->handlers->fnmatch->func_name);
2763				ch->handlers->fnmatch->fci_cache = empty_fcall_info_cache;
2764			}
2765			ZVAL_COPY(&ch->handlers->fnmatch->func_name, zvalue);
2766			ch->handlers->fnmatch->method = PHP_CURL_USER;
2767			break;
2768#endif
2769
2770	}
2771
2772	SAVE_CURL_ERROR(ch, error);
2773	if (error != CURLE_OK) {
2774		return FAILURE;
2775	} else {
2776		return SUCCESS;
2777	}
2778}
2779/* }}} */
2780
2781/* {{{ proto bool curl_setopt(resource ch, int option, mixed value)
2782   Set an option for a cURL transfer */
2783PHP_FUNCTION(curl_setopt)
2784{
2785	zval       *zid, *zvalue;
2786	zend_long        options;
2787	php_curl   *ch;
2788
2789	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &zid, &options, &zvalue) == FAILURE) {
2790		return;
2791	}
2792
2793	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
2794		RETURN_FALSE;
2795	}
2796
2797	if (options <= 0 && options != CURLOPT_SAFE_UPLOAD) {
2798		php_error_docref(NULL, E_WARNING, "Invalid curl configuration option");
2799		RETURN_FALSE;
2800	}
2801
2802	if (_php_curl_setopt(ch, options, zvalue) == SUCCESS) {
2803		RETURN_TRUE;
2804	} else {
2805		RETURN_FALSE;
2806	}
2807}
2808/* }}} */
2809
2810/* {{{ proto bool curl_setopt_array(resource ch, array options)
2811   Set an array of option for a cURL transfer */
2812PHP_FUNCTION(curl_setopt_array)
2813{
2814	zval		*zid, *arr, *entry;
2815	php_curl	*ch;
2816	zend_ulong	option;
2817	zend_string	*string_key;
2818
2819	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ra", &zid, &arr) == FAILURE) {
2820		return;
2821	}
2822
2823	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
2824		RETURN_FALSE;
2825	}
2826
2827	ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(arr), option, string_key, entry) {
2828		if (string_key) {
2829			php_error_docref(NULL, E_WARNING,
2830					"Array keys must be CURLOPT constants or equivalent integer values");
2831			RETURN_FALSE;
2832		}
2833		if (_php_curl_setopt(ch, (zend_long) option, entry) == FAILURE) {
2834			RETURN_FALSE;
2835		}
2836	} ZEND_HASH_FOREACH_END();
2837
2838	RETURN_TRUE;
2839}
2840/* }}} */
2841
2842/* {{{ _php_curl_cleanup_handle(ch)
2843   Cleanup an execution phase */
2844void _php_curl_cleanup_handle(php_curl *ch)
2845{
2846	smart_str_free(&ch->handlers->write->buf);
2847	if (ch->header.str) {
2848		zend_string_release(ch->header.str);
2849		ch->header.str = NULL;
2850	}
2851
2852	memset(ch->err.str, 0, CURL_ERROR_SIZE + 1);
2853	ch->err.no = 0;
2854}
2855/* }}} */
2856
2857/* {{{ proto bool curl_exec(resource ch)
2858   Perform a cURL session */
2859PHP_FUNCTION(curl_exec)
2860{
2861	CURLcode	error;
2862	zval		*zid;
2863	php_curl	*ch;
2864
2865	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zid) == FAILURE) {
2866		return;
2867	}
2868
2869	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
2870		RETURN_FALSE;
2871	}
2872
2873	_php_curl_verify_handlers(ch, 1);
2874
2875	_php_curl_cleanup_handle(ch);
2876
2877	error = curl_easy_perform(ch->cp);
2878	SAVE_CURL_ERROR(ch, error);
2879	/* CURLE_PARTIAL_FILE is returned by HEAD requests */
2880	if (error != CURLE_OK && error != CURLE_PARTIAL_FILE) {
2881		smart_str_free(&ch->handlers->write->buf);
2882		RETURN_FALSE;
2883	}
2884
2885	if (!Z_ISUNDEF(ch->handlers->std_err)) {
2886		php_stream  *stream;
2887		stream = (php_stream*)zend_fetch_resource2_ex(&ch->handlers->std_err, NULL, php_file_le_stream(), php_file_le_pstream());
2888		if (stream) {
2889			php_stream_flush(stream);
2890		}
2891	}
2892
2893	if (ch->handlers->write->method == PHP_CURL_RETURN && ch->handlers->write->buf.s) {
2894		smart_str_0(&ch->handlers->write->buf);
2895		RETURN_STR_COPY(ch->handlers->write->buf.s);
2896	}
2897
2898	/* flush the file handle, so any remaining data is synched to disk */
2899	if (ch->handlers->write->method == PHP_CURL_FILE && ch->handlers->write->fp) {
2900		fflush(ch->handlers->write->fp);
2901	}
2902	if (ch->handlers->write_header->method == PHP_CURL_FILE && ch->handlers->write_header->fp) {
2903		fflush(ch->handlers->write_header->fp);
2904	}
2905
2906	if (ch->handlers->write->method == PHP_CURL_RETURN) {
2907		RETURN_EMPTY_STRING();
2908	} else {
2909		RETURN_TRUE;
2910	}
2911}
2912/* }}} */
2913
2914/* {{{ proto mixed curl_getinfo(resource ch [, int option])
2915   Get information regarding a specific transfer */
2916PHP_FUNCTION(curl_getinfo)
2917{
2918	zval		*zid;
2919	php_curl	*ch;
2920	zend_long	option = 0;
2921
2922	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &zid, &option) == FAILURE) {
2923		return;
2924	}
2925
2926	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
2927		RETURN_FALSE;
2928	}
2929
2930	if (ZEND_NUM_ARGS() < 2) {
2931		char *s_code;
2932		/* libcurl expects long datatype. So far no cases are known where
2933		   it would be an issue. Using zend_long would truncate a 64-bit
2934		   var on Win64, so the exact long datatype fits everywhere, as
2935		   long as there's no 32-bit int overflow. */
2936		long l_code;
2937		double d_code;
2938#if LIBCURL_VERSION_NUM >  0x071301
2939		struct curl_certinfo *ci = NULL;
2940		zval listcode;
2941#endif
2942
2943		array_init(return_value);
2944
2945		if (curl_easy_getinfo(ch->cp, CURLINFO_EFFECTIVE_URL, &s_code) == CURLE_OK) {
2946			CAAS("url", s_code);
2947		}
2948		if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_TYPE, &s_code) == CURLE_OK) {
2949			if (s_code != NULL) {
2950				CAAS("content_type", s_code);
2951			} else {
2952				zval retnull;
2953				ZVAL_NULL(&retnull);
2954				CAAZ("content_type", &retnull);
2955			}
2956		}
2957		if (curl_easy_getinfo(ch->cp, CURLINFO_HTTP_CODE, &l_code) == CURLE_OK) {
2958			CAAL("http_code", l_code);
2959		}
2960		if (curl_easy_getinfo(ch->cp, CURLINFO_HEADER_SIZE, &l_code) == CURLE_OK) {
2961			CAAL("header_size", l_code);
2962		}
2963		if (curl_easy_getinfo(ch->cp, CURLINFO_REQUEST_SIZE, &l_code) == CURLE_OK) {
2964			CAAL("request_size", l_code);
2965		}
2966		if (curl_easy_getinfo(ch->cp, CURLINFO_FILETIME, &l_code) == CURLE_OK) {
2967			CAAL("filetime", l_code);
2968		}
2969		if (curl_easy_getinfo(ch->cp, CURLINFO_SSL_VERIFYRESULT, &l_code) == CURLE_OK) {
2970			CAAL("ssl_verify_result", l_code);
2971		}
2972		if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_COUNT, &l_code) == CURLE_OK) {
2973			CAAL("redirect_count", l_code);
2974		}
2975		if (curl_easy_getinfo(ch->cp, CURLINFO_TOTAL_TIME, &d_code) == CURLE_OK) {
2976			CAAD("total_time", d_code);
2977		}
2978		if (curl_easy_getinfo(ch->cp, CURLINFO_NAMELOOKUP_TIME, &d_code) == CURLE_OK) {
2979			CAAD("namelookup_time", d_code);
2980		}
2981		if (curl_easy_getinfo(ch->cp, CURLINFO_CONNECT_TIME, &d_code) == CURLE_OK) {
2982			CAAD("connect_time", d_code);
2983		}
2984		if (curl_easy_getinfo(ch->cp, CURLINFO_PRETRANSFER_TIME, &d_code) == CURLE_OK) {
2985			CAAD("pretransfer_time", d_code);
2986		}
2987		if (curl_easy_getinfo(ch->cp, CURLINFO_SIZE_UPLOAD, &d_code) == CURLE_OK) {
2988			CAAD("size_upload", d_code);
2989		}
2990		if (curl_easy_getinfo(ch->cp, CURLINFO_SIZE_DOWNLOAD, &d_code) == CURLE_OK) {
2991			CAAD("size_download", d_code);
2992		}
2993		if (curl_easy_getinfo(ch->cp, CURLINFO_SPEED_DOWNLOAD, &d_code) == CURLE_OK) {
2994			CAAD("speed_download", d_code);
2995		}
2996		if (curl_easy_getinfo(ch->cp, CURLINFO_SPEED_UPLOAD, &d_code) == CURLE_OK) {
2997			CAAD("speed_upload", d_code);
2998		}
2999		if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d_code) == CURLE_OK) {
3000			CAAD("download_content_length", d_code);
3001		}
3002		if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_LENGTH_UPLOAD, &d_code) == CURLE_OK) {
3003			CAAD("upload_content_length", d_code);
3004		}
3005		if (curl_easy_getinfo(ch->cp, CURLINFO_STARTTRANSFER_TIME, &d_code) == CURLE_OK) {
3006			CAAD("starttransfer_time", d_code);
3007		}
3008		if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_TIME, &d_code) == CURLE_OK) {
3009			CAAD("redirect_time", d_code);
3010		}
3011#if LIBCURL_VERSION_NUM >= 0x071202 /* Available since 7.18.2 */
3012		if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_URL, &s_code) == CURLE_OK) {
3013			CAAS("redirect_url", s_code);
3014		}
3015#endif
3016#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 */
3017		if (curl_easy_getinfo(ch->cp, CURLINFO_PRIMARY_IP, &s_code) == CURLE_OK) {
3018			CAAS("primary_ip", s_code);
3019		}
3020#endif
3021#if LIBCURL_VERSION_NUM >= 0x071301 /* Available since 7.19.1 */
3022		if (curl_easy_getinfo(ch->cp, CURLINFO_CERTINFO, &ci) == CURLE_OK) {
3023			array_init(&listcode);
3024			create_certinfo(ci, &listcode);
3025			CAAZ("certinfo", &listcode);
3026		}
3027#endif
3028#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
3029		if (curl_easy_getinfo(ch->cp, CURLINFO_PRIMARY_PORT, &l_code) == CURLE_OK) {
3030			CAAL("primary_port", l_code);
3031		}
3032		if (curl_easy_getinfo(ch->cp, CURLINFO_LOCAL_IP, &s_code) == CURLE_OK) {
3033			CAAS("local_ip", s_code);
3034		}
3035		if (curl_easy_getinfo(ch->cp, CURLINFO_LOCAL_PORT, &l_code) == CURLE_OK) {
3036			CAAL("local_port", l_code);
3037		}
3038#endif
3039		if (ch->header.str) {
3040			CAASTR("request_header", ch->header.str);
3041		}
3042	} else {
3043		switch (option) {
3044			case CURLINFO_HEADER_OUT:
3045				if (ch->header.str) {
3046					RETURN_STR_COPY(ch->header.str);
3047				} else {
3048					RETURN_FALSE;
3049				}
3050#if LIBCURL_VERSION_NUM >= 0x071301 /* Available since 7.19.1 */
3051			case CURLINFO_CERTINFO: {
3052				struct curl_certinfo *ci = NULL;
3053
3054				array_init(return_value);
3055
3056				if (curl_easy_getinfo(ch->cp, CURLINFO_CERTINFO, &ci) == CURLE_OK) {
3057					create_certinfo(ci, return_value);
3058				} else {
3059					RETURN_FALSE;
3060				}
3061				break;
3062			}
3063#endif
3064			default: {
3065				int type = CURLINFO_TYPEMASK & option;
3066				switch (type) {
3067					case CURLINFO_STRING:
3068					{
3069						char *s_code = NULL;
3070
3071						if (curl_easy_getinfo(ch->cp, option, &s_code) == CURLE_OK && s_code) {
3072							RETURN_STRING(s_code);
3073						} else {
3074							RETURN_FALSE;
3075						}
3076						break;
3077					}
3078					case CURLINFO_LONG:
3079					{
3080						zend_long code = 0;
3081
3082						if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
3083							RETURN_LONG(code);
3084						} else {
3085							RETURN_FALSE;
3086						}
3087						break;
3088					}
3089					case CURLINFO_DOUBLE:
3090					{
3091						double code = 0.0;
3092
3093						if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
3094							RETURN_DOUBLE(code);
3095						} else {
3096							RETURN_FALSE;
3097						}
3098						break;
3099					}
3100#if LIBCURL_VERSION_NUM >= 0x070c03 /* Available since 7.12.3 */
3101					case CURLINFO_SLIST:
3102					{
3103						struct curl_slist *slist;
3104						array_init(return_value);
3105						if (curl_easy_getinfo(ch->cp, option, &slist) == CURLE_OK) {
3106							while (slist) {
3107								add_next_index_string(return_value, slist->data);
3108								slist = slist->next;
3109							}
3110							curl_slist_free_all(slist);
3111						} else {
3112							RETURN_FALSE;
3113						}
3114						break;
3115					}
3116#endif
3117					default:
3118						RETURN_FALSE;
3119				}
3120			}
3121		}
3122	}
3123}
3124/* }}} */
3125
3126/* {{{ proto string curl_error(resource ch)
3127   Return a string contain the last error for the current session */
3128PHP_FUNCTION(curl_error)
3129{
3130	zval		*zid;
3131	php_curl	*ch;
3132
3133	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zid) == FAILURE) {
3134		return;
3135	}
3136
3137	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
3138		RETURN_FALSE;
3139	}
3140
3141	ch->err.str[CURL_ERROR_SIZE] = 0;
3142	RETURN_STRING(ch->err.str);
3143}
3144/* }}} */
3145
3146/* {{{ proto int curl_errno(resource ch)
3147   Return an integer containing the last error number */
3148PHP_FUNCTION(curl_errno)
3149{
3150	zval		*zid;
3151	php_curl	*ch;
3152
3153	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zid) == FAILURE) {
3154		return;
3155	}
3156
3157	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
3158		RETURN_FALSE;
3159	}
3160
3161	RETURN_LONG(ch->err.no);
3162}
3163/* }}} */
3164
3165/* {{{ proto void curl_close(resource ch)
3166   Close a cURL session */
3167PHP_FUNCTION(curl_close)
3168{
3169	zval		*zid;
3170	php_curl	*ch;
3171
3172	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zid) == FAILURE) {
3173		return;
3174	}
3175
3176	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
3177		RETURN_FALSE;
3178	}
3179
3180	if (ch->in_callback) {
3181		php_error_docref(NULL, E_WARNING, "Attempt to close cURL handle from a callback");
3182		return;
3183	}
3184
3185	if (Z_REFCOUNT_P(zid) <= 2) {
3186		zend_list_close(Z_RES_P(zid));
3187	}
3188}
3189/* }}} */
3190
3191/* {{{ _php_curl_close_ex()
3192   List destructor for curl handles */
3193static void _php_curl_close_ex(php_curl *ch)
3194{
3195#if PHP_CURL_DEBUG
3196	fprintf(stderr, "DTOR CALLED, ch = %x\n", ch);
3197#endif
3198
3199	_php_curl_verify_handlers(ch, 0);
3200
3201	/*
3202	 * Libcurl is doing connection caching. When easy handle is cleaned up,
3203	 * if the handle was previously used by the curl_multi_api, the connection
3204	 * remains open un the curl multi handle is cleaned up. Some protocols are
3205	 * sending content like the FTP one, and libcurl try to use the
3206	 * WRITEFUNCTION or the HEADERFUNCTION. Since structures used in those
3207	 * callback are freed, we need to use an other callback to which avoid
3208	 * segfaults.
3209	 *
3210	 * Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2
3211	 */
3212	curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing);
3213	curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing);
3214
3215	curl_easy_cleanup(ch->cp);
3216
3217	/* cURL destructors should be invoked only by last curl handle */
3218	if (--(*ch->clone) == 0) {
3219		zend_llist_clean(&ch->to_free->str);
3220		zend_llist_clean(&ch->to_free->post);
3221		zend_hash_destroy(ch->to_free->slist);
3222		efree(ch->to_free->slist);
3223		efree(ch->to_free);
3224		efree(ch->clone);
3225	}
3226
3227	smart_str_free(&ch->handlers->write->buf);
3228	zval_ptr_dtor(&ch->handlers->write->func_name);
3229	zval_ptr_dtor(&ch->handlers->read->func_name);
3230	zval_ptr_dtor(&ch->handlers->write_header->func_name);
3231#if CURLOPT_PASSWDFUNCTION != 0
3232	zval_ptr_dtor(&ch->handlers->passwd);
3233#endif
3234	zval_ptr_dtor(&ch->handlers->std_err);
3235	if (ch->header.str) {
3236		zend_string_release(ch->header.str);
3237	}
3238
3239	zval_ptr_dtor(&ch->handlers->write_header->stream);
3240	zval_ptr_dtor(&ch->handlers->write->stream);
3241	zval_ptr_dtor(&ch->handlers->read->stream);
3242
3243	efree(ch->handlers->write);
3244	efree(ch->handlers->write_header);
3245	efree(ch->handlers->read);
3246
3247	if (ch->handlers->progress) {
3248		zval_ptr_dtor(&ch->handlers->progress->func_name);
3249		efree(ch->handlers->progress);
3250	}
3251
3252#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
3253	if (ch->handlers->fnmatch) {
3254		zval_ptr_dtor(&ch->handlers->fnmatch->func_name);
3255		efree(ch->handlers->fnmatch);
3256	}
3257#endif
3258
3259	efree(ch->handlers);
3260	efree(ch);
3261}
3262/* }}} */
3263
3264/* {{{ _php_curl_close()
3265   List destructor for curl handles */
3266static void _php_curl_close(zend_resource *rsrc)
3267{
3268	php_curl *ch = (php_curl *) rsrc->ptr;
3269	_php_curl_close_ex(ch);
3270}
3271/* }}} */
3272
3273#if LIBCURL_VERSION_NUM >= 0x070c00 /* Available since 7.12.0 */
3274/* {{{ proto bool curl_strerror(int code)
3275      return string describing error code */
3276PHP_FUNCTION(curl_strerror)
3277{
3278	zend_long code;
3279	const char *str;
3280
3281	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &code) == FAILURE) {
3282		return;
3283	}
3284
3285	str = curl_easy_strerror(code);
3286	if (str) {
3287		RETURN_STRING(str);
3288	} else {
3289		RETURN_NULL();
3290	}
3291}
3292/* }}} */
3293#endif
3294
3295#if LIBCURL_VERSION_NUM >= 0x070c01 /* 7.12.1 */
3296/* {{{ _php_curl_reset_handlers()
3297   Reset all handlers of a given php_curl */
3298static void _php_curl_reset_handlers(php_curl *ch)
3299{
3300	if (!Z_ISUNDEF(ch->handlers->write->stream)) {
3301		zval_ptr_dtor(&ch->handlers->write->stream);
3302		ZVAL_UNDEF(&ch->handlers->write->stream);
3303	}
3304	ch->handlers->write->fp = NULL;
3305	ch->handlers->write->method = PHP_CURL_STDOUT;
3306
3307	if (!Z_ISUNDEF(ch->handlers->write_header->stream)) {
3308		zval_ptr_dtor(&ch->handlers->write_header->stream);
3309		ZVAL_UNDEF(&ch->handlers->write_header->stream);
3310	}
3311	ch->handlers->write_header->fp = NULL;
3312	ch->handlers->write_header->method = PHP_CURL_IGNORE;
3313
3314	if (!Z_ISUNDEF(ch->handlers->read->stream)) {
3315		zval_ptr_dtor(&ch->handlers->read->stream);
3316		ZVAL_UNDEF(&ch->handlers->read->stream);
3317	}
3318	ch->handlers->read->fp = NULL;
3319	ch->handlers->read->res = NULL;
3320	ch->handlers->read->method  = PHP_CURL_DIRECT;
3321
3322	if (!Z_ISUNDEF(ch->handlers->std_err)) {
3323		zval_ptr_dtor(&ch->handlers->std_err);
3324		ZVAL_UNDEF(&ch->handlers->std_err);
3325	}
3326
3327	if (ch->handlers->progress) {
3328		zval_ptr_dtor(&ch->handlers->progress->func_name);
3329		efree(ch->handlers->progress);
3330		ch->handlers->progress = NULL;
3331	}
3332
3333#if LIBCURL_VERSION_NUM >= 0x071500 /* Available since 7.21.0 */
3334	if (ch->handlers->fnmatch) {
3335		zval_ptr_dtor(&ch->handlers->fnmatch->func_name);
3336		efree(ch->handlers->fnmatch);
3337		ch->handlers->fnmatch = NULL;
3338	}
3339#endif
3340
3341}
3342/* }}} */
3343
3344/* {{{ proto void curl_reset(resource ch)
3345   Reset all options of a libcurl session handle */
3346PHP_FUNCTION(curl_reset)
3347{
3348	zval       *zid;
3349	php_curl   *ch;
3350
3351	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zid) == FAILURE) {
3352		return;
3353	}
3354
3355	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
3356		RETURN_FALSE;
3357	}
3358
3359	if (ch->in_callback) {
3360		php_error_docref(NULL, E_WARNING, "Attempt to reset cURL handle from a callback");
3361		return;
3362	}
3363
3364	curl_easy_reset(ch->cp);
3365	_php_curl_reset_handlers(ch);
3366	_php_curl_set_default_options(ch);
3367}
3368/* }}} */
3369#endif
3370
3371#if LIBCURL_VERSION_NUM > 0x070f03 /* 7.15.4 */
3372/* {{{ proto void curl_escape(resource ch, string str)
3373   URL encodes the given string */
3374PHP_FUNCTION(curl_escape)
3375{
3376	char       *str = NULL, *res = NULL;
3377	size_t        str_len = 0;
3378	zval       *zid;
3379	php_curl   *ch;
3380
3381	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &zid, &str, &str_len) == FAILURE) {
3382		return;
3383	}
3384
3385	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
3386		RETURN_FALSE;
3387	}
3388
3389	if ((res = curl_easy_escape(ch->cp, str, str_len))) {
3390		RETVAL_STRING(res);
3391		curl_free(res);
3392	} else {
3393		RETURN_FALSE;
3394	}
3395}
3396/* }}} */
3397
3398/* {{{ proto void curl_unescape(resource ch, string str)
3399   URL decodes the given string */
3400PHP_FUNCTION(curl_unescape)
3401{
3402	char       *str = NULL, *out = NULL;
3403	size_t     str_len = 0;
3404	int        out_len;
3405	zval       *zid;
3406	php_curl   *ch;
3407
3408	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &zid, &str, &str_len) == FAILURE) {
3409		return;
3410	}
3411
3412	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
3413		RETURN_FALSE;
3414	}
3415
3416	if ((out = curl_easy_unescape(ch->cp, str, str_len, &out_len))) {
3417		RETVAL_STRINGL(out, out_len);
3418		curl_free(out);
3419	} else {
3420		RETURN_FALSE;
3421	}
3422}
3423/* }}} */
3424#endif
3425
3426#if LIBCURL_VERSION_NUM >= 0x071200 /* 7.18.0 */
3427/* {{{ proto void curl_pause(resource ch, int bitmask)
3428       pause and unpause a connection */
3429PHP_FUNCTION(curl_pause)
3430{
3431	zend_long       bitmask;
3432	zval       *zid;
3433	php_curl   *ch;
3434
3435	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &zid, &bitmask) == FAILURE) {
3436		return;
3437	}
3438
3439	if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
3440		RETURN_FALSE;
3441	}
3442
3443	RETURN_LONG(curl_easy_pause(ch->cp, bitmask));
3444}
3445/* }}} */
3446#endif
3447
3448#endif /* HAVE_CURL */
3449
3450/*
3451 * Local variables:
3452 * tab-width: 4
3453 * c-basic-offset: 4
3454 * End:
3455 * vim600: fdm=marker
3456 * vim: noet sw=4 ts=4
3457 */
3458