You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2057 lines
60 KiB

21 years ago
26 years ago
25 years ago
20 years ago
25 years ago
24 years ago
24 years ago
24 years ago
20 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
20 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
23 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
19 years ago
19 years ago
24 years ago
24 years ago
23 years ago
24 years ago
23 years ago
23 years ago
26 years ago
24 years ago
24 years ago
26 years ago
26 years ago
25 years ago
20 years ago
24 years ago
24 years ago
19 years ago
20 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
19 years ago
20 years ago
20 years ago
24 years ago
25 years ago
20 years ago
24 years ago
24 years ago
26 years ago
24 years ago
24 years ago
24 years ago
18 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
25 years ago
24 years ago
24 years ago
25 years ago
24 years ago
24 years ago
25 years ago
20 years ago
24 years ago
24 years ago
20 years ago
24 years ago
24 years ago
24 years ago
24 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2009 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. /* $Id$ */
  19. #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include "php.h"
  24. #if HAVE_CURL
  25. #include <stdio.h>
  26. #include <string.h>
  27. #ifdef PHP_WIN32
  28. #include <winsock2.h>
  29. #include <sys/types.h>
  30. #endif
  31. #include <curl/curl.h>
  32. #include <curl/easy.h>
  33. /* As of curl 7.11.1 this is no longer defined inside curl.h */
  34. #ifndef HttpPost
  35. #define HttpPost curl_httppost
  36. #endif
  37. /* {{{ cruft for thread safe SSL crypto locks */
  38. #if defined(ZTS) && defined(HAVE_CURL_SSL)
  39. # ifdef PHP_WIN32
  40. # define PHP_CURL_NEED_OPENSSL_TSL
  41. # include <openssl/crypto.h>
  42. # else /* !PHP_WIN32 */
  43. # if defined(HAVE_CURL_OPENSSL)
  44. # if defined(HAVE_OPENSSL_CRYPTO_H)
  45. # define PHP_CURL_NEED_OPENSSL_TSL
  46. # include <openssl/crypto.h>
  47. # else
  48. # warning \
  49. "libcurl was compiled with OpenSSL support, but configure could not find " \
  50. "openssl/crypto.h; thus no SSL crypto locking callbacks will be set, which may " \
  51. "cause random crashes on SSL requests"
  52. # endif
  53. # elif defined(HAVE_CURL_GNUTLS)
  54. # if defined(HAVE_GCRYPT_H)
  55. # define PHP_CURL_NEED_GNUTLS_TSL
  56. # include <gcrypt.h>
  57. # else
  58. # warning \
  59. "libcurl was compiled with GnuTLS support, but configure could not find " \
  60. "gcrypt.h; thus no SSL crypto locking callbacks will be set, which may " \
  61. "cause random crashes on SSL requests"
  62. # endif
  63. # else
  64. # warning \
  65. "libcurl was compiled with SSL support, but configure could not determine which" \
  66. "library was used; thus no SSL crypto locking callbacks will be set, which may " \
  67. "cause random crashes on SSL requests"
  68. # endif /* HAVE_CURL_OPENSSL || HAVE_CURL_GNUTLS */
  69. # endif /* PHP_WIN32 */
  70. #endif /* ZTS && HAVE_CURL_SSL */
  71. /* }}} */
  72. #define SMART_STR_PREALLOC 4096
  73. #include "ext/standard/php_smart_str.h"
  74. #include "ext/standard/info.h"
  75. #include "ext/standard/file.h"
  76. #include "ext/standard/url.h"
  77. #include "php_curl.h"
  78. int le_curl;
  79. int le_curl_multi_handle;
  80. #ifdef PHP_CURL_NEED_OPENSSL_TSL /* {{{ */
  81. static MUTEX_T *php_curl_openssl_tsl = NULL;
  82. static void php_curl_ssl_lock(int mode, int n, const char * file, int line)
  83. {
  84. if (mode & CRYPTO_LOCK) {
  85. tsrm_mutex_lock(php_curl_openssl_tsl[n]);
  86. } else {
  87. tsrm_mutex_unlock(php_curl_openssl_tsl[n]);
  88. }
  89. }
  90. static unsigned long php_curl_ssl_id(void)
  91. {
  92. return (unsigned long) tsrm_thread_id();
  93. }
  94. #endif
  95. /* }}} */
  96. #ifdef PHP_CURL_NEED_GNUTLS_TSL /* {{{ */
  97. static int php_curl_ssl_mutex_create(void **m)
  98. {
  99. if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) {
  100. return SUCCESS;
  101. } else {
  102. return FAILURE;
  103. }
  104. }
  105. static int php_curl_ssl_mutex_destroy(void **m)
  106. {
  107. tsrm_mutex_free(*((MUTEX_T *) m));
  108. return SUCCESS;
  109. }
  110. static int php_curl_ssl_mutex_lock(void **m)
  111. {
  112. return tsrm_mutex_lock(*((MUTEX_T *) m));
  113. }
  114. static int php_curl_ssl_mutex_unlock(void **m)
  115. {
  116. return tsrm_mutex_unlock(*((MUTEX_T *) m));
  117. }
  118. static struct gcry_thread_cbs php_curl_gnutls_tsl = {
  119. GCRY_THREAD_OPTION_USER,
  120. NULL,
  121. php_curl_ssl_mutex_create,
  122. php_curl_ssl_mutex_destroy,
  123. php_curl_ssl_mutex_lock,
  124. php_curl_ssl_mutex_unlock
  125. };
  126. #endif
  127. /* }}} */
  128. static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC);
  129. #define SAVE_CURL_ERROR(__handle, __err) (__handle)->err.no = (int) __err;
  130. #define CAAL(s, v) add_assoc_long_ex(return_value, s, sizeof(s), (long) v);
  131. #define CAAD(s, v) add_assoc_double_ex(return_value, s, sizeof(s), (double) v);
  132. #define CAAS(s, v) add_assoc_string_ex(return_value, s, sizeof(s), (char *) (v ? v : ""), 1);
  133. #define CAAZ(s, v) add_assoc_zval_ex(return_value, s, sizeof(s), (zval *) v);
  134. #if defined(PHP_WIN32) || defined(__GNUC__)
  135. #define php_curl_ret(__ret) RETVAL_FALSE; return __ret;
  136. #else
  137. #define php_curl_ret(__ret) RETVAL_FALSE; return;
  138. #endif
  139. #define PHP_CURL_CHECK_OPEN_BASEDIR(str, len, __ret) \
  140. if (((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) && \
  141. strncasecmp(str, "file:", sizeof("file:") - 1) == 0) \
  142. { \
  143. php_url *tmp_url; \
  144. \
  145. if (!(tmp_url = php_url_parse_ex(str, len))) { \
  146. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid URL '%s'", str); \
  147. php_curl_ret(__ret); \
  148. } \
  149. \
  150. if (tmp_url->host || !php_memnstr(str, tmp_url->path, strlen(tmp_url->path), str + len)) { \
  151. php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL '%s' contains unencoded control characters", str); \
  152. php_url_free(tmp_url); \
  153. php_curl_ret(__ret); \
  154. } \
  155. \
  156. if (tmp_url->query || tmp_url->fragment || php_check_open_basedir(tmp_url->path TSRMLS_CC) || \
  157. (PG(safe_mode) && !php_checkuid(tmp_url->path, "rb+", CHECKUID_CHECK_MODE_PARAM)) \
  158. ) { \
  159. php_url_free(tmp_url); \
  160. php_curl_ret(__ret); \
  161. } \
  162. php_url_free(tmp_url); \
  163. }
  164. /* {{{ arginfo */
  165. static
  166. ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_version, 0, 0, 0)
  167. ZEND_ARG_INFO(0, version)
  168. ZEND_END_ARG_INFO()
  169. static
  170. ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_init, 0, 0, 0)
  171. ZEND_ARG_INFO(0, url)
  172. ZEND_END_ARG_INFO()
  173. static
  174. ZEND_BEGIN_ARG_INFO(arginfo_curl_copy_handle, 0)
  175. ZEND_ARG_INFO(0, ch)
  176. ZEND_END_ARG_INFO()
  177. static
  178. ZEND_BEGIN_ARG_INFO(arginfo_curl_setopt, 0)
  179. ZEND_ARG_INFO(0, ch)
  180. ZEND_ARG_INFO(0, option)
  181. ZEND_ARG_INFO(0, value)
  182. ZEND_END_ARG_INFO()
  183. static
  184. ZEND_BEGIN_ARG_INFO(arginfo_curl_setopt_array, 0)
  185. ZEND_ARG_INFO(0, ch)
  186. ZEND_ARG_INFO(0, options)/* ARRAY_INFO(0, options, 0) */
  187. ZEND_END_ARG_INFO()
  188. static
  189. ZEND_BEGIN_ARG_INFO(arginfo_curl_exec, 0)
  190. ZEND_ARG_INFO(0, ch)
  191. ZEND_END_ARG_INFO()
  192. static
  193. ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_getinfo, 0, 0, 1)
  194. ZEND_ARG_INFO(0, ch)
  195. ZEND_ARG_INFO(0, option)
  196. ZEND_END_ARG_INFO()
  197. static
  198. ZEND_BEGIN_ARG_INFO(arginfo_curl_error, 0)
  199. ZEND_ARG_INFO(0, ch)
  200. ZEND_END_ARG_INFO()
  201. static
  202. ZEND_BEGIN_ARG_INFO(arginfo_curl_errno, 0)
  203. ZEND_ARG_INFO(0, ch)
  204. ZEND_END_ARG_INFO()
  205. static
  206. ZEND_BEGIN_ARG_INFO(arginfo_curl_close, 0)
  207. ZEND_ARG_INFO(0, ch)
  208. ZEND_END_ARG_INFO()
  209. static
  210. ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_init, 0)
  211. ZEND_END_ARG_INFO()
  212. static
  213. ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_add_handle, 0)
  214. ZEND_ARG_INFO(0, mh)
  215. ZEND_ARG_INFO(0, ch)
  216. ZEND_END_ARG_INFO()
  217. static
  218. ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_remove_handle, 0)
  219. ZEND_ARG_INFO(0, mh)
  220. ZEND_ARG_INFO(0, ch)
  221. ZEND_END_ARG_INFO()
  222. static
  223. ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_select, 0, 0, 1)
  224. ZEND_ARG_INFO(0, mh)
  225. ZEND_ARG_INFO(0, timeout)
  226. ZEND_END_ARG_INFO()
  227. static
  228. ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_exec, 0, 0, 1)
  229. ZEND_ARG_INFO(0, mh)
  230. ZEND_ARG_INFO(1, still_running)
  231. ZEND_END_ARG_INFO()
  232. static
  233. ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_getcontent, 0)
  234. ZEND_ARG_INFO(0, ch)
  235. ZEND_END_ARG_INFO()
  236. static
  237. ZEND_BEGIN_ARG_INFO_EX(arginfo_curl_multi_info_read, 0, 0, 1)
  238. ZEND_ARG_INFO(0, mh)
  239. ZEND_ARG_INFO(0, msgs_in_queue)
  240. ZEND_END_ARG_INFO()
  241. static
  242. ZEND_BEGIN_ARG_INFO(arginfo_curl_multi_close, 0)
  243. ZEND_ARG_INFO(0, mh)
  244. ZEND_END_ARG_INFO()
  245. /* }}} */
  246. /* {{{ curl_functions[]
  247. */
  248. zend_function_entry curl_functions[] = {
  249. PHP_FE(curl_init, arginfo_curl_init)
  250. PHP_FE(curl_copy_handle, arginfo_curl_copy_handle)
  251. PHP_FE(curl_version, arginfo_curl_version)
  252. PHP_FE(curl_setopt, arginfo_curl_setopt)
  253. PHP_FE(curl_setopt_array, arginfo_curl_setopt_array)
  254. PHP_FE(curl_exec, arginfo_curl_exec)
  255. PHP_FE(curl_getinfo, arginfo_curl_getinfo)
  256. PHP_FE(curl_error, arginfo_curl_error)
  257. PHP_FE(curl_errno, arginfo_curl_errno)
  258. PHP_FE(curl_close, arginfo_curl_close)
  259. PHP_FE(curl_multi_init, arginfo_curl_multi_init)
  260. PHP_FE(curl_multi_add_handle, arginfo_curl_multi_add_handle)
  261. PHP_FE(curl_multi_remove_handle, arginfo_curl_multi_remove_handle)
  262. PHP_FE(curl_multi_select, arginfo_curl_multi_select)
  263. PHP_FE(curl_multi_exec, arginfo_curl_multi_exec)
  264. PHP_FE(curl_multi_getcontent, arginfo_curl_multi_getcontent)
  265. PHP_FE(curl_multi_info_read, arginfo_curl_multi_info_read)
  266. PHP_FE(curl_multi_close, arginfo_curl_multi_close)
  267. {NULL, NULL, NULL}
  268. };
  269. /* }}} */
  270. /* {{{ curl_module_entry
  271. */
  272. zend_module_entry curl_module_entry = {
  273. STANDARD_MODULE_HEADER,
  274. "curl",
  275. curl_functions,
  276. PHP_MINIT(curl),
  277. PHP_MSHUTDOWN(curl),
  278. NULL,
  279. NULL,
  280. PHP_MINFO(curl),
  281. NO_VERSION_YET,
  282. STANDARD_MODULE_PROPERTIES
  283. };
  284. /* }}} */
  285. #ifdef COMPILE_DL_CURL
  286. ZEND_GET_MODULE (curl)
  287. #endif
  288. /* {{{ PHP_MINFO_FUNCTION
  289. */
  290. PHP_MINFO_FUNCTION(curl)
  291. {
  292. php_info_print_table_start();
  293. php_info_print_table_row(2, "cURL support", "enabled");
  294. php_info_print_table_row(2, "cURL Information", curl_version());
  295. php_info_print_table_end();
  296. }
  297. /* }}} */
  298. #define REGISTER_CURL_CONSTANT(__c) REGISTER_LONG_CONSTANT(#__c, __c, CONST_CS | CONST_PERSISTENT)
  299. /* {{{ PHP_MINIT_FUNCTION
  300. */
  301. PHP_MINIT_FUNCTION(curl)
  302. {
  303. le_curl = zend_register_list_destructors_ex(_php_curl_close, NULL, "curl", module_number);
  304. le_curl_multi_handle = zend_register_list_destructors_ex(_php_curl_multi_close, NULL, "curl", module_number);
  305. /* Constants for curl_setopt() */
  306. REGISTER_CURL_CONSTANT(CURLOPT_DNS_USE_GLOBAL_CACHE);
  307. REGISTER_CURL_CONSTANT(CURLOPT_DNS_CACHE_TIMEOUT);
  308. REGISTER_CURL_CONSTANT(CURLOPT_PORT);
  309. REGISTER_CURL_CONSTANT(CURLOPT_FILE);
  310. REGISTER_CURL_CONSTANT(CURLOPT_READDATA);
  311. REGISTER_CURL_CONSTANT(CURLOPT_INFILE);
  312. REGISTER_CURL_CONSTANT(CURLOPT_INFILESIZE);
  313. REGISTER_CURL_CONSTANT(CURLOPT_URL);
  314. REGISTER_CURL_CONSTANT(CURLOPT_PROXY);
  315. REGISTER_CURL_CONSTANT(CURLOPT_VERBOSE);
  316. REGISTER_CURL_CONSTANT(CURLOPT_HEADER);
  317. REGISTER_CURL_CONSTANT(CURLOPT_HTTPHEADER);
  318. REGISTER_CURL_CONSTANT(CURLOPT_NOPROGRESS);
  319. REGISTER_CURL_CONSTANT(CURLOPT_NOBODY);
  320. REGISTER_CURL_CONSTANT(CURLOPT_FAILONERROR);
  321. REGISTER_CURL_CONSTANT(CURLOPT_UPLOAD);
  322. REGISTER_CURL_CONSTANT(CURLOPT_POST);
  323. REGISTER_CURL_CONSTANT(CURLOPT_FTPLISTONLY);
  324. REGISTER_CURL_CONSTANT(CURLOPT_FTPAPPEND);
  325. REGISTER_CURL_CONSTANT(CURLOPT_NETRC);
  326. REGISTER_CURL_CONSTANT(CURLOPT_FOLLOWLOCATION);
  327. #if CURLOPT_FTPASCII != 0
  328. REGISTER_CURL_CONSTANT(CURLOPT_FTPASCII);
  329. #endif
  330. REGISTER_CURL_CONSTANT(CURLOPT_PUT);
  331. #if CURLOPT_MUTE != 0
  332. REGISTER_CURL_CONSTANT(CURLOPT_MUTE);
  333. #endif
  334. REGISTER_CURL_CONSTANT(CURLOPT_USERPWD);
  335. REGISTER_CURL_CONSTANT(CURLOPT_PROXYUSERPWD);
  336. REGISTER_CURL_CONSTANT(CURLOPT_RANGE);
  337. REGISTER_CURL_CONSTANT(CURLOPT_TIMEOUT);
  338. #if LIBCURL_VERSION_NUM > 0x071002
  339. REGISTER_CURL_CONSTANT(CURLOPT_TIMEOUT_MS);
  340. #endif
  341. REGISTER_CURL_CONSTANT(CURLOPT_POSTFIELDS);
  342. REGISTER_CURL_CONSTANT(CURLOPT_REFERER);
  343. REGISTER_CURL_CONSTANT(CURLOPT_USERAGENT);
  344. REGISTER_CURL_CONSTANT(CURLOPT_FTPPORT);
  345. REGISTER_CURL_CONSTANT(CURLOPT_FTP_USE_EPSV);
  346. REGISTER_CURL_CONSTANT(CURLOPT_LOW_SPEED_LIMIT);
  347. REGISTER_CURL_CONSTANT(CURLOPT_LOW_SPEED_TIME);
  348. REGISTER_CURL_CONSTANT(CURLOPT_RESUME_FROM);
  349. REGISTER_CURL_CONSTANT(CURLOPT_COOKIE);
  350. REGISTER_CURL_CONSTANT(CURLOPT_COOKIESESSION);
  351. REGISTER_CURL_CONSTANT(CURLOPT_AUTOREFERER);
  352. REGISTER_CURL_CONSTANT(CURLOPT_SSLCERT);
  353. REGISTER_CURL_CONSTANT(CURLOPT_SSLCERTPASSWD);
  354. REGISTER_CURL_CONSTANT(CURLOPT_WRITEHEADER);
  355. REGISTER_CURL_CONSTANT(CURLOPT_SSL_VERIFYHOST);
  356. REGISTER_CURL_CONSTANT(CURLOPT_COOKIEFILE);
  357. REGISTER_CURL_CONSTANT(CURLOPT_SSLVERSION);
  358. REGISTER_CURL_CONSTANT(CURLOPT_TIMECONDITION);
  359. REGISTER_CURL_CONSTANT(CURLOPT_TIMEVALUE);
  360. REGISTER_CURL_CONSTANT(CURLOPT_CUSTOMREQUEST);
  361. REGISTER_CURL_CONSTANT(CURLOPT_STDERR);
  362. REGISTER_CURL_CONSTANT(CURLOPT_TRANSFERTEXT);
  363. REGISTER_CURL_CONSTANT(CURLOPT_RETURNTRANSFER);
  364. REGISTER_CURL_CONSTANT(CURLOPT_QUOTE);
  365. REGISTER_CURL_CONSTANT(CURLOPT_POSTQUOTE);
  366. REGISTER_CURL_CONSTANT(CURLOPT_INTERFACE);
  367. REGISTER_CURL_CONSTANT(CURLOPT_KRB4LEVEL);
  368. REGISTER_CURL_CONSTANT(CURLOPT_HTTPPROXYTUNNEL);
  369. REGISTER_CURL_CONSTANT(CURLOPT_FILETIME);
  370. REGISTER_CURL_CONSTANT(CURLOPT_WRITEFUNCTION);
  371. REGISTER_CURL_CONSTANT(CURLOPT_READFUNCTION);
  372. #if CURLOPT_PASSWDFUNCTION != 0
  373. REGISTER_CURL_CONSTANT(CURLOPT_PASSWDFUNCTION);
  374. #endif
  375. REGISTER_CURL_CONSTANT(CURLOPT_HEADERFUNCTION);
  376. REGISTER_CURL_CONSTANT(CURLOPT_MAXREDIRS);
  377. REGISTER_CURL_CONSTANT(CURLOPT_MAXCONNECTS);
  378. REGISTER_CURL_CONSTANT(CURLOPT_CLOSEPOLICY);
  379. REGISTER_CURL_CONSTANT(CURLOPT_FRESH_CONNECT);
  380. REGISTER_CURL_CONSTANT(CURLOPT_FORBID_REUSE);
  381. REGISTER_CURL_CONSTANT(CURLOPT_RANDOM_FILE);
  382. REGISTER_CURL_CONSTANT(CURLOPT_EGDSOCKET);
  383. REGISTER_CURL_CONSTANT(CURLOPT_CONNECTTIMEOUT);
  384. #if LIBCURL_VERSION_NUM > 0x071002
  385. REGISTER_CURL_CONSTANT(CURLOPT_CONNECTTIMEOUT_MS);
  386. #endif
  387. REGISTER_CURL_CONSTANT(CURLOPT_SSL_VERIFYPEER);
  388. REGISTER_CURL_CONSTANT(CURLOPT_CAINFO);
  389. REGISTER_CURL_CONSTANT(CURLOPT_CAPATH);
  390. REGISTER_CURL_CONSTANT(CURLOPT_COOKIEJAR);
  391. REGISTER_CURL_CONSTANT(CURLOPT_SSL_CIPHER_LIST);
  392. REGISTER_CURL_CONSTANT(CURLOPT_BINARYTRANSFER);
  393. REGISTER_CURL_CONSTANT(CURLOPT_NOSIGNAL);
  394. REGISTER_CURL_CONSTANT(CURLOPT_PROXYTYPE);
  395. REGISTER_CURL_CONSTANT(CURLOPT_BUFFERSIZE);
  396. REGISTER_CURL_CONSTANT(CURLOPT_HTTPGET);
  397. REGISTER_CURL_CONSTANT(CURLOPT_HTTP_VERSION);
  398. REGISTER_CURL_CONSTANT(CURLOPT_SSLKEY);
  399. REGISTER_CURL_CONSTANT(CURLOPT_SSLKEYTYPE);
  400. REGISTER_CURL_CONSTANT(CURLOPT_SSLKEYPASSWD);
  401. REGISTER_CURL_CONSTANT(CURLOPT_SSLENGINE);
  402. REGISTER_CURL_CONSTANT(CURLOPT_SSLENGINE_DEFAULT);
  403. REGISTER_CURL_CONSTANT(CURLOPT_SSLCERTTYPE);
  404. REGISTER_CURL_CONSTANT(CURLOPT_CRLF);
  405. REGISTER_CURL_CONSTANT(CURLOPT_ENCODING);
  406. REGISTER_CURL_CONSTANT(CURLOPT_PROXYPORT);
  407. REGISTER_CURL_CONSTANT(CURLOPT_UNRESTRICTED_AUTH);
  408. REGISTER_CURL_CONSTANT(CURLOPT_FTP_USE_EPRT);
  409. #if LIBCURL_VERSION_NUM > 0x070b01 /* CURLOPT_TCP_NODELAY is available since curl 7.11.2 */
  410. REGISTER_CURL_CONSTANT(CURLOPT_TCP_NODELAY);
  411. #endif
  412. REGISTER_CURL_CONSTANT(CURLOPT_HTTP200ALIASES);
  413. REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFMODSINCE);
  414. REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFUNMODSINCE);
  415. REGISTER_CURL_CONSTANT(CURL_TIMECOND_LASTMOD);
  416. #if LIBCURL_VERSION_NUM > 0x070a05 /* CURLOPT_HTTPAUTH is available since curl 7.10.6 */
  417. REGISTER_CURL_CONSTANT(CURLOPT_HTTPAUTH);
  418. /* http authentication options */
  419. REGISTER_CURL_CONSTANT(CURLAUTH_BASIC);
  420. REGISTER_CURL_CONSTANT(CURLAUTH_DIGEST);
  421. REGISTER_CURL_CONSTANT(CURLAUTH_GSSNEGOTIATE);
  422. REGISTER_CURL_CONSTANT(CURLAUTH_NTLM);
  423. REGISTER_CURL_CONSTANT(CURLAUTH_ANY);
  424. REGISTER_CURL_CONSTANT(CURLAUTH_ANYSAFE);
  425. #endif
  426. #if LIBCURL_VERSION_NUM > 0x070a06 /* CURLOPT_PROXYAUTH & CURLOPT_FTP_CREATE_MISSING_DIRS are available since curl 7.10.7 */
  427. REGISTER_CURL_CONSTANT(CURLOPT_PROXYAUTH);
  428. REGISTER_CURL_CONSTANT(CURLOPT_FTP_CREATE_MISSING_DIRS);
  429. #endif
  430. REGISTER_CURL_CONSTANT(CURLOPT_PRIVATE);
  431. /* Constants effecting the way CURLOPT_CLOSEPOLICY works */
  432. REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_LEAST_RECENTLY_USED);
  433. REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_LEAST_TRAFFIC);
  434. REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_SLOWEST);
  435. REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_CALLBACK);
  436. REGISTER_CURL_CONSTANT(CURLCLOSEPOLICY_OLDEST);
  437. /* Info constants */
  438. REGISTER_CURL_CONSTANT(CURLINFO_EFFECTIVE_URL);
  439. REGISTER_CURL_CONSTANT(CURLINFO_HTTP_CODE);
  440. REGISTER_CURL_CONSTANT(CURLINFO_HEADER_SIZE);
  441. REGISTER_CURL_CONSTANT(CURLINFO_REQUEST_SIZE);
  442. REGISTER_CURL_CONSTANT(CURLINFO_TOTAL_TIME);
  443. REGISTER_CURL_CONSTANT(CURLINFO_NAMELOOKUP_TIME);
  444. REGISTER_CURL_CONSTANT(CURLINFO_CONNECT_TIME);
  445. REGISTER_CURL_CONSTANT(CURLINFO_PRETRANSFER_TIME);
  446. REGISTER_CURL_CONSTANT(CURLINFO_SIZE_UPLOAD);
  447. REGISTER_CURL_CONSTANT(CURLINFO_SIZE_DOWNLOAD);
  448. REGISTER_CURL_CONSTANT(CURLINFO_SPEED_DOWNLOAD);
  449. REGISTER_CURL_CONSTANT(CURLINFO_SPEED_UPLOAD);
  450. REGISTER_CURL_CONSTANT(CURLINFO_FILETIME);
  451. REGISTER_CURL_CONSTANT(CURLINFO_SSL_VERIFYRESULT);
  452. REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_LENGTH_DOWNLOAD);
  453. REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_LENGTH_UPLOAD);
  454. REGISTER_CURL_CONSTANT(CURLINFO_STARTTRANSFER_TIME);
  455. REGISTER_CURL_CONSTANT(CURLINFO_CONTENT_TYPE);
  456. REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_TIME);
  457. REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_COUNT);
  458. REGISTER_CURL_CONSTANT(CURLINFO_HEADER_OUT);
  459. REGISTER_CURL_CONSTANT(CURLINFO_PRIVATE);
  460. /* cURL protocol constants (curl_version) */
  461. REGISTER_CURL_CONSTANT(CURL_VERSION_IPV6);
  462. REGISTER_CURL_CONSTANT(CURL_VERSION_KERBEROS4);
  463. REGISTER_CURL_CONSTANT(CURL_VERSION_SSL);
  464. REGISTER_CURL_CONSTANT(CURL_VERSION_LIBZ);
  465. /* version constants */
  466. REGISTER_CURL_CONSTANT(CURLVERSION_NOW);
  467. /* Error Constants */
  468. REGISTER_CURL_CONSTANT(CURLE_OK);
  469. REGISTER_CURL_CONSTANT(CURLE_UNSUPPORTED_PROTOCOL);
  470. REGISTER_CURL_CONSTANT(CURLE_FAILED_INIT);
  471. REGISTER_CURL_CONSTANT(CURLE_URL_MALFORMAT);
  472. REGISTER_CURL_CONSTANT(CURLE_URL_MALFORMAT_USER);
  473. REGISTER_CURL_CONSTANT(CURLE_COULDNT_RESOLVE_PROXY);
  474. REGISTER_CURL_CONSTANT(CURLE_COULDNT_RESOLVE_HOST);
  475. REGISTER_CURL_CONSTANT(CURLE_COULDNT_CONNECT);
  476. REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_SERVER_REPLY);
  477. REGISTER_CURL_CONSTANT(CURLE_FTP_ACCESS_DENIED);
  478. REGISTER_CURL_CONSTANT(CURLE_FTP_USER_PASSWORD_INCORRECT);
  479. REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_PASS_REPLY);
  480. REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_USER_REPLY);
  481. REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_PASV_REPLY);
  482. REGISTER_CURL_CONSTANT(CURLE_FTP_WEIRD_227_FORMAT);
  483. REGISTER_CURL_CONSTANT(CURLE_FTP_CANT_GET_HOST);
  484. REGISTER_CURL_CONSTANT(CURLE_FTP_CANT_RECONNECT);
  485. REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_SET_BINARY);
  486. REGISTER_CURL_CONSTANT(CURLE_PARTIAL_FILE);
  487. REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_RETR_FILE);
  488. REGISTER_CURL_CONSTANT(CURLE_FTP_WRITE_ERROR);
  489. REGISTER_CURL_CONSTANT(CURLE_FTP_QUOTE_ERROR);
  490. REGISTER_CURL_CONSTANT(CURLE_HTTP_NOT_FOUND);
  491. REGISTER_CURL_CONSTANT(CURLE_WRITE_ERROR);
  492. REGISTER_CURL_CONSTANT(CURLE_MALFORMAT_USER);
  493. REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_STOR_FILE);
  494. REGISTER_CURL_CONSTANT(CURLE_READ_ERROR);
  495. REGISTER_CURL_CONSTANT(CURLE_OUT_OF_MEMORY);
  496. REGISTER_CURL_CONSTANT(CURLE_OPERATION_TIMEOUTED);
  497. REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_SET_ASCII);
  498. REGISTER_CURL_CONSTANT(CURLE_FTP_PORT_FAILED);
  499. REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_USE_REST);
  500. REGISTER_CURL_CONSTANT(CURLE_FTP_COULDNT_GET_SIZE);
  501. REGISTER_CURL_CONSTANT(CURLE_HTTP_RANGE_ERROR);
  502. REGISTER_CURL_CONSTANT(CURLE_HTTP_POST_ERROR);
  503. REGISTER_CURL_CONSTANT(CURLE_SSL_CONNECT_ERROR);
  504. REGISTER_CURL_CONSTANT(CURLE_FTP_BAD_DOWNLOAD_RESUME);
  505. REGISTER_CURL_CONSTANT(CURLE_FILE_COULDNT_READ_FILE);
  506. REGISTER_CURL_CONSTANT(CURLE_LDAP_CANNOT_BIND);
  507. REGISTER_CURL_CONSTANT(CURLE_LDAP_SEARCH_FAILED);
  508. REGISTER_CURL_CONSTANT(CURLE_LIBRARY_NOT_FOUND);
  509. REGISTER_CURL_CONSTANT(CURLE_FUNCTION_NOT_FOUND);
  510. REGISTER_CURL_CONSTANT(CURLE_ABORTED_BY_CALLBACK);
  511. REGISTER_CURL_CONSTANT(CURLE_BAD_FUNCTION_ARGUMENT);
  512. REGISTER_CURL_CONSTANT(CURLE_BAD_CALLING_ORDER);
  513. REGISTER_CURL_CONSTANT(CURLE_HTTP_PORT_FAILED);
  514. REGISTER_CURL_CONSTANT(CURLE_BAD_PASSWORD_ENTERED);
  515. REGISTER_CURL_CONSTANT(CURLE_TOO_MANY_REDIRECTS);
  516. REGISTER_CURL_CONSTANT(CURLE_UNKNOWN_TELNET_OPTION);
  517. REGISTER_CURL_CONSTANT(CURLE_TELNET_OPTION_SYNTAX);
  518. REGISTER_CURL_CONSTANT(CURLE_OBSOLETE);
  519. REGISTER_CURL_CONSTANT(CURLE_SSL_PEER_CERTIFICATE);
  520. REGISTER_CURL_CONSTANT(CURLE_GOT_NOTHING);
  521. REGISTER_CURL_CONSTANT(CURLE_SSL_ENGINE_NOTFOUND);
  522. REGISTER_CURL_CONSTANT(CURLE_SSL_ENGINE_SETFAILED);
  523. REGISTER_CURL_CONSTANT(CURLE_SEND_ERROR);
  524. REGISTER_CURL_CONSTANT(CURLE_RECV_ERROR);
  525. REGISTER_CURL_CONSTANT(CURLE_SHARE_IN_USE);
  526. REGISTER_CURL_CONSTANT(CURLE_SSL_CERTPROBLEM);
  527. REGISTER_CURL_CONSTANT(CURLE_SSL_CIPHER);
  528. REGISTER_CURL_CONSTANT(CURLE_SSL_CACERT);
  529. REGISTER_CURL_CONSTANT(CURLE_BAD_CONTENT_ENCODING);
  530. #if LIBCURL_VERSION_NUM >= 0x070a08
  531. REGISTER_CURL_CONSTANT(CURLE_LDAP_INVALID_URL);
  532. REGISTER_CURL_CONSTANT(CURLE_FILESIZE_EXCEEDED);
  533. #endif
  534. #if LIBCURL_VERSION_NUM >= 0x070b00
  535. REGISTER_CURL_CONSTANT(CURLE_FTP_SSL_FAILED);
  536. #endif
  537. REGISTER_CURL_CONSTANT(CURLPROXY_HTTP);
  538. REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5);
  539. REGISTER_CURL_CONSTANT(CURL_NETRC_OPTIONAL);
  540. REGISTER_CURL_CONSTANT(CURL_NETRC_IGNORED);
  541. REGISTER_CURL_CONSTANT(CURL_NETRC_REQUIRED);
  542. REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_NONE);
  543. REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_0);
  544. REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_1);
  545. REGISTER_CURL_CONSTANT(CURLM_CALL_MULTI_PERFORM);
  546. REGISTER_CURL_CONSTANT(CURLM_OK);
  547. REGISTER_CURL_CONSTANT(CURLM_BAD_HANDLE);
  548. REGISTER_CURL_CONSTANT(CURLM_BAD_EASY_HANDLE);
  549. REGISTER_CURL_CONSTANT(CURLM_OUT_OF_MEMORY);
  550. REGISTER_CURL_CONSTANT(CURLM_INTERNAL_ERROR);
  551. REGISTER_CURL_CONSTANT(CURLMSG_DONE);
  552. #if LIBCURL_VERSION_NUM >= 0x070c02
  553. REGISTER_CURL_CONSTANT(CURLOPT_FTPSSLAUTH);
  554. REGISTER_CURL_CONSTANT(CURLFTPAUTH_DEFAULT);
  555. REGISTER_CURL_CONSTANT(CURLFTPAUTH_SSL);
  556. REGISTER_CURL_CONSTANT(CURLFTPAUTH_TLS);
  557. #endif
  558. #if LIBCURL_VERSION_NUM > 0x070b00
  559. REGISTER_CURL_CONSTANT(CURLOPT_FTP_SSL);
  560. REGISTER_CURL_CONSTANT(CURLFTPSSL_NONE);
  561. REGISTER_CURL_CONSTANT(CURLFTPSSL_TRY);
  562. REGISTER_CURL_CONSTANT(CURLFTPSSL_CONTROL);
  563. REGISTER_CURL_CONSTANT(CURLFTPSSL_ALL);
  564. #endif
  565. #if LIBCURL_VERSION_NUM >= 0x071304
  566. REGISTER_CURL_CONSTANT(CURLOPT_REDIR_PROTOCOLS);
  567. REGISTER_CURL_CONSTANT(CURLOPT_PROTOCOLS);
  568. REGISTER_CURL_CONSTANT(CURLPROTO_HTTP);
  569. REGISTER_CURL_CONSTANT(CURLPROTO_HTTPS);
  570. REGISTER_CURL_CONSTANT(CURLPROTO_FTP);
  571. REGISTER_CURL_CONSTANT(CURLPROTO_FTPS);
  572. REGISTER_CURL_CONSTANT(CURLPROTO_SCP);
  573. REGISTER_CURL_CONSTANT(CURLPROTO_SFTP);
  574. REGISTER_CURL_CONSTANT(CURLPROTO_TELNET);
  575. REGISTER_CURL_CONSTANT(CURLPROTO_LDAP);
  576. REGISTER_CURL_CONSTANT(CURLPROTO_LDAPS);
  577. REGISTER_CURL_CONSTANT(CURLPROTO_DICT);
  578. REGISTER_CURL_CONSTANT(CURLPROTO_FILE);
  579. REGISTER_CURL_CONSTANT(CURLPROTO_TFTP);
  580. REGISTER_CURL_CONSTANT(CURLPROTO_ALL);
  581. #endif
  582. #ifdef PHP_CURL_NEED_OPENSSL_TSL
  583. if (!CRYPTO_get_id_callback()) {
  584. int i, c = CRYPTO_num_locks();
  585. php_curl_openssl_tsl = malloc(c * sizeof(MUTEX_T));
  586. for (i = 0; i < c; ++i) {
  587. php_curl_openssl_tsl[i] = tsrm_mutex_alloc();
  588. }
  589. CRYPTO_set_id_callback(php_curl_ssl_id);
  590. CRYPTO_set_locking_callback(php_curl_ssl_lock);
  591. }
  592. #endif
  593. #ifdef PHP_CURL_NEED_GNUTLS_TSL
  594. gcry_control(GCRYCTL_SET_THREAD_CBS, &php_curl_gnutls_tsl);
  595. #endif
  596. if (curl_global_init(CURL_GLOBAL_SSL) != CURLE_OK) {
  597. return FAILURE;
  598. }
  599. #ifdef PHP_CURL_URL_WRAPPERS
  600. # if HAVE_CURL_VERSION_INFO
  601. {
  602. curl_version_info_data *info = curl_version_info(CURLVERSION_NOW);
  603. char **p = (char **)info->protocols;
  604. while (*p != NULL) {
  605. php_register_url_stream_wrapper(*p++, &php_curl_wrapper TSRMLS_CC);
  606. }
  607. }
  608. # else
  609. php_register_url_stream_wrapper("http", &php_curl_wrapper TSRMLS_CC);
  610. php_register_url_stream_wrapper("https", &php_curl_wrapper TSRMLS_CC);
  611. php_register_url_stream_wrapper("ftp", &php_curl_wrapper TSRMLS_CC);
  612. php_register_url_stream_wrapper("ldap", &php_curl_wrapper TSRMLS_CC);
  613. # endif
  614. #endif
  615. return SUCCESS;
  616. }
  617. /* }}} */
  618. /* {{{ PHP_MSHUTDOWN_FUNCTION
  619. */
  620. PHP_MSHUTDOWN_FUNCTION(curl)
  621. {
  622. #ifdef PHP_CURL_URL_WRAPPERS
  623. php_unregister_url_stream_wrapper("http" TSRMLS_CC);
  624. php_unregister_url_stream_wrapper("https" TSRMLS_CC);
  625. php_unregister_url_stream_wrapper("ftp" TSRMLS_CC);
  626. php_unregister_url_stream_wrapper("ldap" TSRMLS_CC);
  627. #endif
  628. curl_global_cleanup();
  629. #ifdef PHP_CURL_NEED_OPENSSL_TSL
  630. if (php_curl_openssl_tsl) {
  631. int i, c = CRYPTO_num_locks();
  632. CRYPTO_set_id_callback(NULL);
  633. CRYPTO_set_locking_callback(NULL);
  634. for (i = 0; i < c; ++i) {
  635. tsrm_mutex_free(php_curl_openssl_tsl[i]);
  636. }
  637. free(php_curl_openssl_tsl);
  638. php_curl_openssl_tsl = NULL;
  639. }
  640. #endif
  641. return SUCCESS;
  642. }
  643. /* }}} */
  644. /* {{{ curl_write
  645. */
  646. static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
  647. {
  648. php_curl *ch = (php_curl *) ctx;
  649. php_curl_write *t = ch->handlers->write;
  650. size_t length = size * nmemb;
  651. TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
  652. #if PHP_CURL_DEBUG
  653. fprintf(stderr, "curl_write() called\n");
  654. fprintf(stderr, "data = %s, size = %d, nmemb = %d, ctx = %x\n", data, size, nmemb, ctx);
  655. #endif
  656. switch (t->method) {
  657. case PHP_CURL_STDOUT:
  658. PHPWRITE(data, length);
  659. break;
  660. case PHP_CURL_FILE:
  661. return fwrite(data, size, nmemb, t->fp);
  662. case PHP_CURL_RETURN:
  663. if (length > 0) {
  664. smart_str_appendl(&t->buf, data, (int) length);
  665. }
  666. break;
  667. case PHP_CURL_USER: {
  668. zval **argv[2];
  669. zval *retval_ptr = NULL;
  670. zval *handle = NULL;
  671. zval *zdata = NULL;
  672. int error;
  673. zend_fcall_info fci;
  674. MAKE_STD_ZVAL(handle);
  675. ZVAL_RESOURCE(handle, ch->id);
  676. zend_list_addref(ch->id);
  677. argv[0] = &handle;
  678. MAKE_STD_ZVAL(zdata);
  679. ZVAL_STRINGL(zdata, data, length, 1);
  680. argv[1] = &zdata;
  681. fci.size = sizeof(fci);
  682. fci.function_table = EG(function_table);
  683. fci.object_pp = NULL;
  684. fci.function_name = t->func_name;
  685. fci.retval_ptr_ptr = &retval_ptr;
  686. fci.param_count = 2;
  687. fci.params = argv;
  688. fci.no_separation = 0;
  689. fci.symbol_table = NULL;
  690. ch->in_callback = 1;
  691. error = zend_call_function(&fci, &t->fci_cache TSRMLS_CC);
  692. ch->in_callback = 0;
  693. if (error == FAILURE) {
  694. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the CURLOPT_WRITEFUNCTION");
  695. length = -1;
  696. } else if (retval_ptr) {
  697. if (Z_TYPE_P(retval_ptr) != IS_LONG) {
  698. convert_to_long_ex(&retval_ptr);
  699. }
  700. length = Z_LVAL_P(retval_ptr);
  701. zval_ptr_dtor(&retval_ptr);
  702. }
  703. zval_ptr_dtor(argv[0]);
  704. zval_ptr_dtor(argv[1]);
  705. break;
  706. }
  707. }
  708. return length;
  709. }
  710. /* }}} */
  711. /* {{{ curl_read
  712. */
  713. static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
  714. {
  715. php_curl *ch = (php_curl *) ctx;
  716. php_curl_read *t = ch->handlers->read;
  717. int length = 0;
  718. switch (t->method) {
  719. case PHP_CURL_DIRECT:
  720. if (t->fp) {
  721. length = fread(data, size, nmemb, t->fp);
  722. }
  723. break;
  724. case PHP_CURL_USER: {
  725. zval **argv[3];
  726. zval *handle = NULL;
  727. zval *zfd = NULL;
  728. zval *zlength = NULL;
  729. zval *retval_ptr;
  730. int error;
  731. zend_fcall_info fci;
  732. TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
  733. MAKE_STD_ZVAL(handle);
  734. MAKE_STD_ZVAL(zfd);
  735. MAKE_STD_ZVAL(zlength);
  736. ZVAL_RESOURCE(handle, ch->id);
  737. zend_list_addref(ch->id);
  738. ZVAL_RESOURCE(zfd, t->fd);
  739. zend_list_addref(t->fd);
  740. ZVAL_LONG(zlength, (int) size * nmemb);
  741. argv[0] = &handle;
  742. argv[1] = &zfd;
  743. argv[2] = &zlength;
  744. fci.size = sizeof(fci);
  745. fci.function_table = EG(function_table);
  746. fci.function_name = t->func_name;
  747. fci.object_pp = NULL;
  748. fci.retval_ptr_ptr = &retval_ptr;
  749. fci.param_count = 3;
  750. fci.params = argv;
  751. fci.no_separation = 0;
  752. fci.symbol_table = NULL;
  753. ch->in_callback = 1;
  754. error = zend_call_function(&fci, &t->fci_cache TSRMLS_CC);
  755. ch->in_callback = 0;
  756. if (error == FAILURE) {
  757. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot call the CURLOPT_READFUNCTION");
  758. #if LIBCURL_VERSION_NUM >= 0x070c01 /* 7.12.1 */
  759. length = CURL_READFUNC_ABORT;
  760. #endif
  761. } else if (retval_ptr) {
  762. if (Z_TYPE_P(retval_ptr) == IS_STRING) {
  763. length = MIN(size * nmemb, Z_STRLEN_P(retval_ptr));
  764. memcpy(data, Z_STRVAL_P(retval_ptr), length);
  765. }
  766. zval_ptr_dtor(&retval_ptr);
  767. }
  768. zval_ptr_dtor(argv[0]);
  769. zval_ptr_dtor(argv[1]);
  770. zval_ptr_dtor(argv[2]);
  771. break;
  772. }
  773. }
  774. return length;
  775. }
  776. /* }}} */
  777. /* {{{ curl_write_header
  778. */
  779. static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx)
  780. {
  781. php_curl *ch = (php_curl *) ctx;
  782. php_curl_write *t = ch->handlers->write_header;
  783. size_t length = size * nmemb;
  784. TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
  785. switch (t->method) {
  786. case PHP_CURL_STDOUT:
  787. /* Handle special case write when we're returning the entire transfer
  788. */
  789. if (ch->handlers->write->method == PHP_CURL_RETURN && length > 0) {
  790. smart_str_appendl(&ch->handlers->write->buf, data, (int) length);
  791. } else {
  792. PHPWRITE(data, length);
  793. }
  794. break;
  795. case PHP_CURL_FILE:
  796. return fwrite(data, size, nmemb, t->fp);
  797. case PHP_CURL_USER: {
  798. zval **argv[2];
  799. zval *handle = NULL;
  800. zval *zdata = NULL;
  801. zval *retval_ptr;
  802. int error;
  803. zend_fcall_info fci;
  804. MAKE_STD_ZVAL(handle);
  805. MAKE_STD_ZVAL(zdata);
  806. ZVAL_RESOURCE(handle, ch->id);
  807. zend_list_addref(ch->id);
  808. ZVAL_STRINGL(zdata, data, length, 1);
  809. argv[0] = &handle;
  810. argv[1] = &zdata;
  811. fci.size = sizeof(fci);
  812. fci.function_table = EG(function_table);
  813. fci.function_name = t->func_name;
  814. fci.symbol_table = NULL;
  815. fci.object_pp = NULL;
  816. fci.retval_ptr_ptr = &retval_ptr;
  817. fci.param_count = 2;
  818. fci.params = argv;
  819. fci.no_separation = 0;
  820. ch->in_callback = 1;
  821. error = zend_call_function(&fci, &t->fci_cache TSRMLS_CC);
  822. ch->in_callback = 0;
  823. if (error == FAILURE) {
  824. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the CURLOPT_HEADERFUNCTION");
  825. length = -1;
  826. } else if (retval_ptr) {
  827. if (Z_TYPE_P(retval_ptr) != IS_LONG) {
  828. convert_to_long_ex(&retval_ptr);
  829. }
  830. length = Z_LVAL_P(retval_ptr);
  831. zval_ptr_dtor(&retval_ptr);
  832. }
  833. zval_ptr_dtor(argv[0]);
  834. zval_ptr_dtor(argv[1]);
  835. break;
  836. }
  837. case PHP_CURL_IGNORE:
  838. return length;
  839. default:
  840. return -1;
  841. }
  842. return length;
  843. }
  844. /* }}} */
  845. static int curl_debug(CURL *cp, curl_infotype type, char *buf, size_t buf_len, void *ctx) /* {{{ */
  846. {
  847. php_curl *ch = (php_curl *) ctx;
  848. if (type == CURLINFO_HEADER_OUT) {
  849. if (ch->header.str_len) {
  850. efree(ch->header.str);
  851. }
  852. if (buf_len > 0) {
  853. ch->header.str = estrndup(buf, buf_len);
  854. ch->header.str_len = buf_len;
  855. }
  856. }
  857. return 0;
  858. }
  859. /* }}} */
  860. #if CURLOPT_PASSWDFUNCTION != 0
  861. /* {{{ curl_passwd
  862. */
  863. static size_t curl_passwd(void *ctx, char *prompt, char *buf, int buflen)
  864. {
  865. php_curl *ch = (php_curl *) ctx;
  866. zval *func = ch->handlers->passwd;
  867. zval *argv[3];
  868. zval *retval = NULL;
  869. int error;
  870. int ret = -1;
  871. TSRMLS_FETCH_FROM_CTX(ch->thread_ctx);
  872. MAKE_STD_ZVAL(argv[0]);
  873. MAKE_STD_ZVAL(argv[1]);
  874. MAKE_STD_ZVAL(argv[2]);
  875. ZVAL_RESOURCE(argv[0], ch->id);
  876. zend_list_addref(ch->id);
  877. ZVAL_STRING(argv[1], prompt, 1);
  878. ZVAL_LONG(argv[2], buflen);
  879. error = call_user_function(EG(function_table), NULL, func, retval, 2, argv TSRMLS_CC);
  880. if (error == FAILURE) {
  881. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the CURLOPT_PASSWDFUNCTION");
  882. } else if (Z_TYPE_P(retval) == IS_STRING) {
  883. if (Z_STRLEN_P(retval) > buflen) {
  884. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Returned password is too long for libcurl to handle");
  885. } else {
  886. strlcpy(buf, Z_STRVAL_P(retval), Z_STRLEN_P(retval));
  887. }
  888. } else {
  889. php_error_docref(NULL TSRMLS_CC, E_WARNING, "User handler '%s' did not return a string", Z_STRVAL_P(func));
  890. }
  891. zval_ptr_dtor(&argv[0]);
  892. zval_ptr_dtor(&argv[1]);
  893. zval_ptr_dtor(&argv[2]);
  894. zval_ptr_dtor(&retval);
  895. return ret;
  896. }
  897. /* }}} */
  898. #endif
  899. #if LIBCURL_VERSION_NUM < 0x071101
  900. /* {{{ curl_free_string
  901. */
  902. static void curl_free_string(void **string)
  903. {
  904. efree(*string);
  905. }
  906. /* }}} */
  907. #endif
  908. /* {{{ curl_free_post
  909. */
  910. static void curl_free_post(void **post)
  911. {
  912. curl_formfree((struct HttpPost *) *post);
  913. }
  914. /* }}} */
  915. /* {{{ curl_free_slist
  916. */
  917. static void curl_free_slist(void **slist)
  918. {
  919. curl_slist_free_all((struct curl_slist *) *slist);
  920. }
  921. /* }}} */
  922. /* {{{ proto array curl_version([int version])
  923. Return cURL version information. */
  924. PHP_FUNCTION(curl_version)
  925. {
  926. curl_version_info_data *d;
  927. long uversion = CURLVERSION_NOW;
  928. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &uversion) == FAILURE) {
  929. return;
  930. }
  931. d = curl_version_info(uversion);
  932. if (d == NULL) {
  933. RETURN_FALSE;
  934. }
  935. array_init(return_value);
  936. CAAL("version_number", d->version_num);
  937. CAAL("age", d->age);
  938. CAAL("features", d->features);
  939. CAAL("ssl_version_number", d->ssl_version_num);
  940. CAAS("version", d->version);
  941. CAAS("host", d->host);
  942. CAAS("ssl_version", d->ssl_version);
  943. CAAS("libz_version", d->libz_version);
  944. /* Add an array of protocols */
  945. {
  946. char **p = (char **) d->protocols;
  947. zval *protocol_list = NULL;
  948. MAKE_STD_ZVAL(protocol_list);
  949. array_init(protocol_list);
  950. while (*p != NULL) {
  951. add_next_index_string(protocol_list, *p++, 1);
  952. }
  953. CAAZ("protocols", protocol_list);
  954. }
  955. }
  956. /* }}} */
  957. /* {{{ alloc_curl_handle
  958. */
  959. static void alloc_curl_handle(php_curl **ch)
  960. {
  961. *ch = emalloc(sizeof(php_curl));
  962. (*ch)->handlers = ecalloc(1, sizeof(php_curl_handlers));
  963. (*ch)->handlers->write = ecalloc(1, sizeof(php_curl_write));
  964. (*ch)->handlers->write_header = ecalloc(1, sizeof(php_curl_write));
  965. (*ch)->handlers->read = ecalloc(1, sizeof(php_curl_read));
  966. (*ch)->in_callback = 0;
  967. (*ch)->header.str_len = 0;
  968. memset(&(*ch)->err, 0, sizeof((*ch)->err));
  969. #if LIBCURL_VERSION_NUM < 0x071101
  970. zend_llist_init(&(*ch)->to_free.str, sizeof(char *), (llist_dtor_func_t) curl_free_string, 0);
  971. #endif
  972. zend_llist_init(&(*ch)->to_free.slist, sizeof(struct curl_slist), (llist_dtor_func_t) curl_free_slist, 0);
  973. zend_llist_init(&(*ch)->to_free.post, sizeof(struct HttpPost), (llist_dtor_func_t) curl_free_post, 0);
  974. }
  975. /* }}} */
  976. /* {{{ proto resource curl_init([string url])
  977. Initialize a cURL session */
  978. PHP_FUNCTION(curl_init)
  979. {
  980. zval **url;
  981. php_curl *ch;
  982. CURL *cp;
  983. int argc = ZEND_NUM_ARGS();
  984. if (argc < 0 || argc > 1 || zend_get_parameters_ex(argc, &url) == FAILURE) {
  985. WRONG_PARAM_COUNT;
  986. }
  987. if (argc > 0) {
  988. convert_to_string_ex(url);
  989. PHP_CURL_CHECK_OPEN_BASEDIR(Z_STRVAL_PP(url), Z_STRLEN_PP(url), (void) NULL);
  990. }
  991. cp = curl_easy_init();
  992. if (!cp) {
  993. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize a new cURL handle");
  994. RETURN_FALSE;
  995. }
  996. alloc_curl_handle(&ch);
  997. TSRMLS_SET_CTX(ch->thread_ctx);
  998. ch->cp = cp;
  999. ch->handlers->write->method = PHP_CURL_STDOUT;
  1000. ch->handlers->write->type = PHP_CURL_ASCII;
  1001. ch->handlers->read->method = PHP_CURL_DIRECT;
  1002. ch->handlers->write_header->method = PHP_CURL_IGNORE;
  1003. ch->uses = 0;
  1004. curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS, 1);
  1005. curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0);
  1006. curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str);
  1007. curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write);
  1008. curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch);
  1009. curl_easy_setopt(ch->cp, CURLOPT_READFUNCTION, curl_read);
  1010. curl_easy_setopt(ch->cp, CURLOPT_INFILE, (void *) ch);
  1011. curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_header);
  1012. curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch);
  1013. curl_easy_setopt(ch->cp, CURLOPT_DNS_USE_GLOBAL_CACHE, 1);
  1014. curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120);
  1015. curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20); /* prevent infinite redirects */
  1016. #if defined(ZTS)
  1017. curl_easy_setopt(ch->cp, CURLOPT_NOSIGNAL, 1);
  1018. #endif
  1019. if (argc > 0) {
  1020. #if LIBCURL_VERSION_NUM >= 0x071100
  1021. curl_easy_setopt(ch->cp, CURLOPT_URL, Z_STRVAL_PP(url));
  1022. #else
  1023. char *urlcopy;
  1024. urlcopy = estrndup(Z_STRVAL_PP(url), Z_STRLEN_PP(url));
  1025. curl_easy_setopt(ch->cp, CURLOPT_URL, urlcopy);
  1026. zend_llist_add_element(&ch->to_free.str, &urlcopy);
  1027. #endif
  1028. }
  1029. ZEND_REGISTER_RESOURCE(return_value, ch, le_curl);
  1030. ch->id = Z_LVAL_P(return_value);
  1031. }
  1032. /* }}} */
  1033. /* {{{ proto resource curl_copy_handle(resource ch)
  1034. Copy a cURL handle along with all of it's preferences */
  1035. PHP_FUNCTION(curl_copy_handle)
  1036. {
  1037. zval **zid;
  1038. CURL *cp;
  1039. php_curl *ch;
  1040. php_curl *dupch;
  1041. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zid) == FAILURE) {
  1042. WRONG_PARAM_COUNT;
  1043. }
  1044. ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
  1045. cp = curl_easy_duphandle(ch->cp);
  1046. if (!cp) {
  1047. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot duplicate cURL handle");
  1048. RETURN_FALSE;
  1049. }
  1050. alloc_curl_handle(&dupch);
  1051. TSRMLS_SET_CTX(dupch->thread_ctx);
  1052. dupch->cp = cp;
  1053. dupch->handlers->write->method = ch->handlers->write->method;
  1054. dupch->handlers->write->type = ch->handlers->write->type;
  1055. dupch->handlers->read->method = ch->handlers->read->method;
  1056. dupch->handlers->write_header->method = ch->handlers->write_header->method;
  1057. dupch->handlers->write->fp = ch->handlers->write->fp;
  1058. dupch->handlers->write_header->fp = ch->handlers->write_header->fp;
  1059. dupch->handlers->read->fp = ch->handlers->read->fp;
  1060. dupch->handlers->read->fd = ch->handlers->read->fd;
  1061. #if CURLOPT_PASSWDDATA != 0
  1062. if (ch->handlers->passwd) {
  1063. zval_add_ref(&ch->handlers->passwd);
  1064. dupch->handlers->passwd = ch->handlers->passwd;
  1065. curl_easy_setopt(ch->cp, CURLOPT_PASSWDDATA, (void *) dupch);
  1066. }
  1067. #endif
  1068. if (ch->handlers->write->func_name) {
  1069. zval_add_ref(&ch->handlers->write->func_name);
  1070. dupch->handlers->write->func_name = ch->handlers->write->func_name;
  1071. }
  1072. if (ch->handlers->read->func_name) {
  1073. zval_add_ref(&ch->handlers->read->func_name);
  1074. dupch->handlers->read->func_name = ch->handlers->read->func_name;
  1075. }
  1076. if (ch->handlers->write_header->func_name) {
  1077. zval_add_ref(&ch->handlers->write_header->func_name);
  1078. dupch->handlers->write_header->func_name = ch->handlers->write_header->func_name;
  1079. }
  1080. curl_easy_setopt(dupch->cp, CURLOPT_ERRORBUFFER, dupch->err.str);
  1081. curl_easy_setopt(dupch->cp, CURLOPT_FILE, (void *) dupch);
  1082. curl_easy_setopt(dupch->cp, CURLOPT_INFILE, (void *) dupch);
  1083. curl_easy_setopt(dupch->cp, CURLOPT_WRITEHEADER, (void *) dupch);
  1084. #if LIBCURL_VERSION_NUM < 0x071101
  1085. zend_llist_copy(&dupch->to_free.str, &ch->to_free.str);
  1086. /* Don't try to free copied strings, they're free'd when the original handle is destroyed */
  1087. dupch->to_free.str.dtor = NULL;
  1088. #endif
  1089. zend_llist_copy(&dupch->to_free.slist, &ch->to_free.slist);
  1090. zend_llist_copy(&dupch->to_free.post, &ch->to_free.post);
  1091. ZEND_REGISTER_RESOURCE(return_value, dupch, le_curl);
  1092. dupch->id = Z_LVAL_P(return_value);
  1093. }
  1094. /* }}} */
  1095. static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *return_value TSRMLS_DC) /* {{{ */
  1096. {
  1097. CURLcode error=CURLE_OK;
  1098. switch (option) {
  1099. case CURLOPT_INFILESIZE:
  1100. case CURLOPT_VERBOSE:
  1101. case CURLOPT_HEADER:
  1102. case CURLOPT_NOPROGRESS:
  1103. case CURLOPT_NOBODY:
  1104. case CURLOPT_FAILONERROR:
  1105. case CURLOPT_UPLOAD:
  1106. case CURLOPT_POST:
  1107. case CURLOPT_FTPLISTONLY:
  1108. case CURLOPT_FTPAPPEND:
  1109. case CURLOPT_NETRC:
  1110. case CURLOPT_PUT:
  1111. #if CURLOPT_MUTE != 0
  1112. case CURLOPT_MUTE:
  1113. #endif
  1114. case CURLOPT_TIMEOUT:
  1115. #if LIBCURL_VERSION_NUM > 0x071002
  1116. case CURLOPT_TIMEOUT_MS:
  1117. #endif
  1118. case CURLOPT_FTP_USE_EPSV:
  1119. case CURLOPT_LOW_SPEED_LIMIT:
  1120. case CURLOPT_SSLVERSION:
  1121. case CURLOPT_LOW_SPEED_TIME:
  1122. case CURLOPT_RESUME_FROM:
  1123. case CURLOPT_TIMEVALUE:
  1124. case CURLOPT_TIMECONDITION:
  1125. case CURLOPT_TRANSFERTEXT:
  1126. case CURLOPT_HTTPPROXYTUNNEL:
  1127. case CURLOPT_FILETIME:
  1128. case CURLOPT_MAXREDIRS:
  1129. case CURLOPT_MAXCONNECTS:
  1130. case CURLOPT_CLOSEPOLICY:
  1131. case CURLOPT_FRESH_CONNECT:
  1132. case CURLOPT_FORBID_REUSE:
  1133. case CURLOPT_CONNECTTIMEOUT:
  1134. #if LIBCURL_VERSION_NUM > 0x071002
  1135. case CURLOPT_CONNECTTIMEOUT_MS:
  1136. #endif
  1137. case CURLOPT_SSL_VERIFYHOST:
  1138. case CURLOPT_SSL_VERIFYPEER:
  1139. case CURLOPT_DNS_USE_GLOBAL_CACHE:
  1140. case CURLOPT_NOSIGNAL:
  1141. case CURLOPT_PROXYTYPE:
  1142. case CURLOPT_BUFFERSIZE:
  1143. case CURLOPT_HTTPGET:
  1144. case CURLOPT_HTTP_VERSION:
  1145. case CURLOPT_CRLF:
  1146. case CURLOPT_DNS_CACHE_TIMEOUT:
  1147. case CURLOPT_PROXYPORT:
  1148. case CURLOPT_FTP_USE_EPRT:
  1149. #if LIBCURL_VERSION_NUM > 0x070a05 /* CURLOPT_HTTPAUTH is available since curl 7.10.6 */
  1150. case CURLOPT_HTTPAUTH:
  1151. #endif
  1152. #if LIBCURL_VERSION_NUM > 0x070a06 /* CURLOPT_PROXYAUTH & CURLOPT_FTP_CREATE_MISSING_DIRS are available since curl 7.10.7 */
  1153. case CURLOPT_PROXYAUTH:
  1154. case CURLOPT_FTP_CREATE_MISSING_DIRS:
  1155. #endif
  1156. #if LIBCURL_VERSION_NUM >= 0x070c02
  1157. case CURLOPT_FTPSSLAUTH:
  1158. #endif
  1159. #if LIBCURL_VERSION_NUM > 0x070b00
  1160. case CURLOPT_FTP_SSL:
  1161. #endif
  1162. case CURLOPT_UNRESTRICTED_AUTH:
  1163. case CURLOPT_PORT:
  1164. case CURLOPT_AUTOREFERER:
  1165. case CURLOPT_COOKIESESSION:
  1166. #if LIBCURL_VERSION_NUM > 0x070b01 /* CURLOPT_TCP_NODELAY is available since curl 7.11.2 */
  1167. case CURLOPT_TCP_NODELAY:
  1168. #endif
  1169. #if LIBCURL_VERSION_NUM >= 0x71304
  1170. case CURLOPT_REDIR_PROTOCOLS:
  1171. case CURLOPT_PROTOCOLS:
  1172. #endif
  1173. convert_to_long_ex(zvalue);
  1174. error = curl_easy_setopt(ch->cp, option, Z_LVAL_PP(zvalue));
  1175. break;
  1176. case CURLOPT_FOLLOWLOCATION:
  1177. convert_to_long_ex(zvalue);
  1178. if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) {
  1179. if (Z_LVAL_PP(zvalue) != 0) {
  1180. php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set");
  1181. RETVAL_FALSE;
  1182. return 1;
  1183. }
  1184. }
  1185. error = curl_easy_setopt(ch->cp, option, Z_LVAL_PP(zvalue));
  1186. break;
  1187. case CURLOPT_PRIVATE:
  1188. case CURLOPT_URL:
  1189. case CURLOPT_PROXY:
  1190. case CURLOPT_USERPWD:
  1191. case CURLOPT_PROXYUSERPWD:
  1192. case CURLOPT_RANGE:
  1193. case CURLOPT_CUSTOMREQUEST:
  1194. case CURLOPT_USERAGENT:
  1195. case CURLOPT_FTPPORT:
  1196. case CURLOPT_COOKIE:
  1197. case CURLOPT_REFERER:
  1198. case CURLOPT_INTERFACE:
  1199. case CURLOPT_KRB4LEVEL:
  1200. case CURLOPT_EGDSOCKET:
  1201. case CURLOPT_CAINFO:
  1202. case CURLOPT_CAPATH:
  1203. case CURLOPT_SSL_CIPHER_LIST:
  1204. case CURLOPT_SSLKEY:
  1205. case CURLOPT_SSLKEYTYPE:
  1206. case CURLOPT_SSLKEYPASSWD:
  1207. case CURLOPT_SSLENGINE:
  1208. case CURLOPT_SSLENGINE_DEFAULT:
  1209. case CURLOPT_SSLCERTTYPE:
  1210. case CURLOPT_ENCODING: {
  1211. #if LIBCURL_VERSION_NUM < 0x071100
  1212. char *copystr = NULL;
  1213. #endif
  1214. convert_to_string_ex(zvalue);
  1215. if (option == CURLOPT_URL) {
  1216. PHP_CURL_CHECK_OPEN_BASEDIR(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue), 1);
  1217. }
  1218. #if LIBCURL_VERSION_NUM >= 0x071100
  1219. /* Strings passed to libcurl as ’char *’ arguments, are copied by the library... NOTE: before 7.17.0 strings were not copied. */
  1220. error = curl_easy_setopt(ch->cp, option, Z_STRVAL_PP(zvalue));
  1221. #else
  1222. copystr = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue));
  1223. error = curl_easy_setopt(ch->cp, option, copystr);
  1224. zend_llist_add_element(&ch->to_free.str, &copystr);
  1225. #endif
  1226. break;
  1227. }
  1228. case CURLOPT_FILE:
  1229. case CURLOPT_INFILE:
  1230. case CURLOPT_WRITEHEADER:
  1231. case CURLOPT_STDERR: {
  1232. FILE *fp = NULL;
  1233. int type;
  1234. void * what;
  1235. what = zend_fetch_resource(zvalue TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream());
  1236. if (!what) {
  1237. RETVAL_FALSE;
  1238. return 1;
  1239. }
  1240. if (FAILURE == php_stream_cast((php_stream *) what, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
  1241. RETVAL_FALSE;
  1242. return 1;
  1243. }
  1244. if (!fp) {
  1245. RETVAL_FALSE;
  1246. return 1;
  1247. }
  1248. error = CURLE_OK;
  1249. switch (option) {
  1250. case CURLOPT_FILE:
  1251. ch->handlers->write->fp = fp;
  1252. ch->handlers->write->method = PHP_CURL_FILE;
  1253. break;
  1254. case CURLOPT_WRITEHEADER:
  1255. ch->handlers->write_header->fp = fp;
  1256. ch->handlers->write_header->method = PHP_CURL_FILE;
  1257. break;
  1258. case CURLOPT_INFILE:
  1259. zend_list_addref(Z_LVAL_PP(zvalue));
  1260. ch->handlers->read->fp = fp;
  1261. ch->handlers->read->fd = Z_LVAL_PP(zvalue);
  1262. break;
  1263. default:
  1264. error = curl_easy_setopt(ch->cp, option, fp);
  1265. break;
  1266. }
  1267. break;
  1268. }
  1269. case CURLOPT_RETURNTRANSFER:
  1270. convert_to_long_ex(zvalue);
  1271. if (Z_LVAL_PP(zvalue)) {
  1272. ch->handlers->write->method = PHP_CURL_RETURN;
  1273. } else {
  1274. ch->handlers->write->method = PHP_CURL_STDOUT;
  1275. }
  1276. break;
  1277. case CURLOPT_BINARYTRANSFER:
  1278. convert_to_long_ex(zvalue);
  1279. if (Z_LVAL_PP(zvalue)) {
  1280. ch->handlers->write->type = PHP_CURL_BINARY;
  1281. } else {
  1282. ch->handlers->write->type = PHP_CURL_ASCII;
  1283. }
  1284. break;
  1285. case CURLOPT_WRITEFUNCTION:
  1286. if (ch->handlers->write->func_name) {
  1287. zval_ptr_dtor(&ch->handlers->write->func_name);
  1288. ch->handlers->write->fci_cache = empty_fcall_info_cache;
  1289. }
  1290. zval_add_ref(zvalue);
  1291. ch->handlers->write->func_name = *zvalue;
  1292. ch->handlers->write->method = PHP_CURL_USER;
  1293. break;
  1294. case CURLOPT_READFUNCTION:
  1295. if (ch->handlers->read->func_name) {
  1296. zval_ptr_dtor(&ch->handlers->read->func_name);
  1297. ch->handlers->read->fci_cache = empty_fcall_info_cache;
  1298. }
  1299. zval_add_ref(zvalue);
  1300. ch->handlers->read->func_name = *zvalue;
  1301. ch->handlers->read->method = PHP_CURL_USER;
  1302. break;
  1303. case CURLOPT_HEADERFUNCTION:
  1304. if (ch->handlers->write_header->func_name) {
  1305. zval_ptr_dtor(&ch->handlers->write_header->func_name);
  1306. ch->handlers->write_header->fci_cache = empty_fcall_info_cache;
  1307. }
  1308. zval_add_ref(zvalue);
  1309. ch->handlers->write_header->func_name = *zvalue;
  1310. ch->handlers->write_header->method = PHP_CURL_USER;
  1311. break;
  1312. #if CURLOPT_PASSWDFUNCTION != 0
  1313. case CURLOPT_PASSWDFUNCTION:
  1314. if (ch->handlers->passwd) {
  1315. zval_ptr_dtor(&ch->handlers->passwd);
  1316. }
  1317. zval_add_ref(zvalue);
  1318. ch->handlers->passwd = *zvalue;
  1319. error = curl_easy_setopt(ch->cp, CURLOPT_PASSWDFUNCTION, curl_passwd);
  1320. error = curl_easy_setopt(ch->cp, CURLOPT_PASSWDDATA, (void *) ch);
  1321. break;
  1322. #endif
  1323. case CURLOPT_POSTFIELDS:
  1324. if (Z_TYPE_PP(zvalue) == IS_ARRAY || Z_TYPE_PP(zvalue) == IS_OBJECT) {
  1325. zval **current;
  1326. HashTable *postfields;
  1327. struct HttpPost *first = NULL;
  1328. struct HttpPost *last = NULL;
  1329. char *postval;
  1330. char *string_key = NULL;
  1331. ulong num_key;
  1332. uint string_key_len;
  1333. postfields = HASH_OF(*zvalue);
  1334. if (! postfields) {
  1335. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't get HashTable in CURLOPT_POSTFIELDS");
  1336. RETVAL_FALSE;
  1337. return 1;
  1338. }
  1339. for (zend_hash_internal_pointer_reset(postfields);
  1340. zend_hash_get_current_data(postfields, (void **) &current) == SUCCESS;
  1341. zend_hash_move_forward(postfields)
  1342. ) {
  1343. SEPARATE_ZVAL(current);
  1344. convert_to_string_ex(current);
  1345. zend_hash_get_current_key_ex(postfields, &string_key, &string_key_len, &num_key, 0, NULL);
  1346. postval = Z_STRVAL_PP(current);
  1347. /* The arguments after _NAMELENGTH and _CONTENTSLENGTH
  1348. * must be explicitly cast to long in curl_formadd
  1349. * use since curl needs a long not an int. */
  1350. if (*postval == '@') {
  1351. char *type;
  1352. ++postval;
  1353. if ((type = php_memnstr(postval, ";type=", sizeof(";type=") - 1, postval + strlen(postval)))) {
  1354. *type = '\0';
  1355. }
  1356. /* safe_mode / open_basedir check */
  1357. if (php_check_open_basedir(postval TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(postval, "rb+", CHECKUID_CHECK_MODE_PARAM))) {
  1358. if (type) {
  1359. *type = ';';
  1360. }
  1361. RETVAL_FALSE;
  1362. return 1;
  1363. }
  1364. if (type) {
  1365. error = curl_formadd(&first, &last,
  1366. CURLFORM_COPYNAME, string_key,
  1367. CURLFORM_NAMELENGTH, (long)string_key_len - 1,
  1368. CURLFORM_FILE, postval,
  1369. CURLFORM_CONTENTTYPE, type + sizeof(";type=") - 1,
  1370. CURLFORM_END);
  1371. *type = ';';
  1372. } else {
  1373. error = curl_formadd(&first, &last,
  1374. CURLFORM_COPYNAME, string_key,
  1375. CURLFORM_NAMELENGTH, (long)string_key_len - 1,
  1376. CURLFORM_FILE, postval,
  1377. CURLFORM_END);
  1378. }
  1379. } else {
  1380. error = curl_formadd(&first, &last,
  1381. CURLFORM_COPYNAME, string_key,
  1382. CURLFORM_NAMELENGTH, (long)string_key_len - 1,
  1383. CURLFORM_COPYCONTENTS, postval,
  1384. CURLFORM_CONTENTSLENGTH, (long)Z_STRLEN_PP(current),
  1385. CURLFORM_END);
  1386. }
  1387. }
  1388. SAVE_CURL_ERROR(ch, error);
  1389. if (error != CURLE_OK) {
  1390. RETVAL_FALSE
  1391. return 1;
  1392. }
  1393. zend_llist_add_element(&ch->to_free.post, &first);
  1394. error = curl_easy_setopt(ch->cp, CURLOPT_HTTPPOST, first);
  1395. } else {
  1396. #if LIBCURL_VERSION_NUM >= 0x071101
  1397. /* with curl 7.17.0 and later, we can use COPYPOSTFIELDS, but we have to provide size before */
  1398. error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, Z_STRLEN_PP(zvalue));
  1399. error = curl_easy_setopt(ch->cp, CURLOPT_COPYPOSTFIELDS, Z_STRVAL_PP(zvalue));
  1400. #else
  1401. char *post = NULL;
  1402. convert_to_string_ex(zvalue);
  1403. post = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue));
  1404. zend_llist_add_element(&ch->to_free.str, &post);
  1405. error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, post);
  1406. error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, Z_STRLEN_PP(zvalue));
  1407. #endif
  1408. }
  1409. break;
  1410. case CURLOPT_HTTPHEADER:
  1411. case CURLOPT_QUOTE:
  1412. case CURLOPT_HTTP200ALIASES:
  1413. case CURLOPT_POSTQUOTE: {
  1414. zval **current;
  1415. HashTable *ph;
  1416. struct curl_slist *slist = NULL;
  1417. ph = HASH_OF(*zvalue);
  1418. if (!ph) {
  1419. php_error_docref(NULL TSRMLS_CC, E_WARNING, "You must pass either an object or an array with the CURLOPT_HTTPHEADER, CURLOPT_QUOTE, CURLOPT_HTTP200ALIASES and CURLOPT_POSTQUOTE arguments");
  1420. RETVAL_FALSE;
  1421. return 1;
  1422. }
  1423. for (zend_hash_internal_pointer_reset(ph);
  1424. zend_hash_get_current_data(ph, (void **) &current) == SUCCESS;
  1425. zend_hash_move_forward(ph)
  1426. ) {
  1427. SEPARATE_ZVAL(current);
  1428. convert_to_string_ex(current);
  1429. slist = curl_slist_append(slist, Z_STRVAL_PP(current));
  1430. if (!slist) {
  1431. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not build curl_slist");
  1432. RETVAL_FALSE;
  1433. return 1;
  1434. }
  1435. }
  1436. zend_llist_add_element(&ch->to_free.slist, &slist);
  1437. error = curl_easy_setopt(ch->cp, option, slist);
  1438. break;
  1439. }
  1440. /* the following options deal with files, therefor safe_mode & open_basedir checks
  1441. * are required.
  1442. */
  1443. case CURLOPT_COOKIEJAR:
  1444. case CURLOPT_SSLCERT:
  1445. case CURLOPT_RANDOM_FILE:
  1446. case CURLOPT_COOKIEFILE: {
  1447. #if LIBCURL_VERSION_NUM < 0x071100
  1448. char *copystr = NULL;
  1449. #endif
  1450. convert_to_string_ex(zvalue);
  1451. if (php_check_open_basedir(Z_STRVAL_PP(zvalue) TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(Z_STRVAL_PP(zvalue), "rb+", CHECKUID_CHECK_MODE_PARAM))) {
  1452. RETVAL_FALSE;
  1453. return 1;
  1454. }
  1455. #if LIBCURL_VERSION_NUM >= 0x071100
  1456. error = curl_easy_setopt(ch->cp, option, Z_STRVAL_PP(zvalue));
  1457. #else
  1458. copystr = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue));
  1459. error = curl_easy_setopt(ch->cp, option, copystr);
  1460. zend_llist_add_element(&ch->to_free.str, &copystr);
  1461. #endif
  1462. break;
  1463. }
  1464. case CURLINFO_HEADER_OUT:
  1465. convert_to_long_ex(zvalue);
  1466. if (Z_LVAL_PP(zvalue) == 1) {
  1467. curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, curl_debug);
  1468. curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *)ch);
  1469. curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1);
  1470. } else {
  1471. curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, NULL);
  1472. curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, NULL);
  1473. curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0);
  1474. }
  1475. break;
  1476. }
  1477. SAVE_CURL_ERROR(ch, error);
  1478. if (error != CURLE_OK) {
  1479. return 1;
  1480. } else {
  1481. return 0;
  1482. }
  1483. }
  1484. /* }}} */
  1485. /* {{{ proto bool curl_setopt(resource ch, int option, mixed value)
  1486. Set an option for a cURL transfer */
  1487. PHP_FUNCTION(curl_setopt)
  1488. {
  1489. zval **zid, **zoption, **zvalue;
  1490. php_curl *ch;
  1491. if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &zid, &zoption, &zvalue) == FAILURE) {
  1492. WRONG_PARAM_COUNT;
  1493. }
  1494. ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
  1495. convert_to_long_ex(zoption);
  1496. if (!_php_curl_setopt(ch, Z_LVAL_PP(zoption), zvalue, return_value TSRMLS_CC)) {
  1497. RETURN_TRUE;
  1498. } else {
  1499. RETURN_FALSE;
  1500. }
  1501. }
  1502. /* }}} */
  1503. /* {{{ proto bool curl_setopt_array(resource ch, array options)
  1504. Set an array of option for a cURL transfer */
  1505. PHP_FUNCTION(curl_setopt_array)
  1506. {
  1507. zval *zid, *arr, **entry;
  1508. php_curl *ch;
  1509. long option;
  1510. HashPosition pos;
  1511. char *string_key;
  1512. int str_key_len;
  1513. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za", &zid, &arr) == FAILURE) {
  1514. RETURN_FALSE;
  1515. }
  1516. ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
  1517. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos);
  1518. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **)&entry, &pos) == SUCCESS) {
  1519. if (zend_hash_get_current_key_ex(Z_ARRVAL_P(arr), &string_key, &str_key_len, &option, 0, &pos) == HASH_KEY_IS_STRING) {
  1520. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array keys must be CURLOPT constants or equivalent integer values");
  1521. RETURN_FALSE;
  1522. }
  1523. if (_php_curl_setopt(ch, option, entry, return_value TSRMLS_CC)) {
  1524. RETURN_FALSE;
  1525. }
  1526. zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos);
  1527. }
  1528. RETURN_TRUE;
  1529. }
  1530. /* }}} */
  1531. /* {{{ _php_curl_cleanup_handle(ch)
  1532. Cleanup an execution phase */
  1533. void _php_curl_cleanup_handle(php_curl *ch)
  1534. {
  1535. if (ch->handlers->write->buf.len > 0) {
  1536. smart_str_free(&ch->handlers->write->buf);
  1537. }
  1538. if (ch->header.str_len) {
  1539. efree(ch->header.str);
  1540. ch->header.str_len = 0;
  1541. }
  1542. memset(ch->err.str, 0, CURL_ERROR_SIZE + 1);
  1543. ch->err.no = 0;
  1544. }
  1545. /* }}} */
  1546. /* {{{ proto bool curl_exec(resource ch)
  1547. Perform a cURL session */
  1548. PHP_FUNCTION(curl_exec)
  1549. {
  1550. zval **zid;
  1551. php_curl *ch;
  1552. CURLcode error;
  1553. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zid) == FAILURE) {
  1554. WRONG_PARAM_COUNT;
  1555. }
  1556. ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
  1557. _php_curl_cleanup_handle(ch);
  1558. error = curl_easy_perform(ch->cp);
  1559. SAVE_CURL_ERROR(ch, error);
  1560. /* CURLE_PARTIAL_FILE is returned by HEAD requests */
  1561. if (error != CURLE_OK && error != CURLE_PARTIAL_FILE) {
  1562. if (ch->handlers->write->buf.len > 0) {
  1563. smart_str_free(&ch->handlers->write->buf);
  1564. }
  1565. RETURN_FALSE;
  1566. }
  1567. ch->uses++;
  1568. if (ch->handlers->write->method == PHP_CURL_RETURN && ch->handlers->write->buf.len > 0) {
  1569. --ch->uses;
  1570. smart_str_0(&ch->handlers->write->buf);
  1571. RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 1);
  1572. }
  1573. --ch->uses;
  1574. if (ch->handlers->write->method == PHP_CURL_RETURN) {
  1575. RETURN_EMPTY_STRING();
  1576. } else {
  1577. RETURN_TRUE;
  1578. }
  1579. }
  1580. /* }}} */
  1581. /* {{{ proto mixed curl_getinfo(resource ch [, int option])
  1582. Get information regarding a specific transfer */
  1583. PHP_FUNCTION(curl_getinfo)
  1584. {
  1585. zval **zid,
  1586. **zoption;
  1587. php_curl *ch;
  1588. int option, argc = ZEND_NUM_ARGS();
  1589. if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &zid, &zoption) == FAILURE) {
  1590. WRONG_PARAM_COUNT;
  1591. }
  1592. ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
  1593. if (argc < 2) {
  1594. char *s_code;
  1595. long l_code;
  1596. double d_code;
  1597. array_init(return_value);
  1598. if (curl_easy_getinfo(ch->cp, CURLINFO_EFFECTIVE_URL, &s_code) == CURLE_OK) {
  1599. CAAS("url", s_code);
  1600. }
  1601. if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_TYPE, &s_code) == CURLE_OK) {
  1602. if (s_code != NULL) {
  1603. CAAS("content_type", s_code);
  1604. } else {
  1605. zval *retnull;
  1606. MAKE_STD_ZVAL(retnull);
  1607. ZVAL_NULL(retnull);
  1608. CAAZ("content_type", retnull);
  1609. }
  1610. }
  1611. if (curl_easy_getinfo(ch->cp, CURLINFO_HTTP_CODE, &l_code) == CURLE_OK) {
  1612. CAAL("http_code", l_code);
  1613. }
  1614. if (curl_easy_getinfo(ch->cp, CURLINFO_HEADER_SIZE, &l_code) == CURLE_OK) {
  1615. CAAL("header_size", l_code);
  1616. }
  1617. if (curl_easy_getinfo(ch->cp, CURLINFO_REQUEST_SIZE, &l_code) == CURLE_OK) {
  1618. CAAL("request_size", l_code);
  1619. }
  1620. if (curl_easy_getinfo(ch->cp, CURLINFO_FILETIME, &l_code) == CURLE_OK) {
  1621. CAAL("filetime", l_code);
  1622. }
  1623. if (curl_easy_getinfo(ch->cp, CURLINFO_SSL_VERIFYRESULT, &l_code) == CURLE_OK) {
  1624. CAAL("ssl_verify_result", l_code);
  1625. }
  1626. if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_COUNT, &l_code) == CURLE_OK) {
  1627. CAAL("redirect_count", l_code);
  1628. }
  1629. if (curl_easy_getinfo(ch->cp, CURLINFO_TOTAL_TIME, &d_code) == CURLE_OK) {
  1630. CAAD("total_time", d_code);
  1631. }
  1632. if (curl_easy_getinfo(ch->cp, CURLINFO_NAMELOOKUP_TIME, &d_code) == CURLE_OK) {
  1633. CAAD("namelookup_time", d_code);
  1634. }
  1635. if (curl_easy_getinfo(ch->cp, CURLINFO_CONNECT_TIME, &d_code) == CURLE_OK) {
  1636. CAAD("connect_time", d_code);
  1637. }
  1638. if (curl_easy_getinfo(ch->cp, CURLINFO_PRETRANSFER_TIME, &d_code) == CURLE_OK) {
  1639. CAAD("pretransfer_time", d_code);
  1640. }
  1641. if (curl_easy_getinfo(ch->cp, CURLINFO_SIZE_UPLOAD, &d_code) == CURLE_OK) {
  1642. CAAD("size_upload", d_code);
  1643. }
  1644. if (curl_easy_getinfo(ch->cp, CURLINFO_SIZE_DOWNLOAD, &d_code) == CURLE_OK) {
  1645. CAAD("size_download", d_code);
  1646. }
  1647. if (curl_easy_getinfo(ch->cp, CURLINFO_SPEED_DOWNLOAD, &d_code) == CURLE_OK) {
  1648. CAAD("speed_download", d_code);
  1649. }
  1650. if (curl_easy_getinfo(ch->cp, CURLINFO_SPEED_UPLOAD, &d_code) == CURLE_OK) {
  1651. CAAD("speed_upload", d_code);
  1652. }
  1653. if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d_code) == CURLE_OK) {
  1654. CAAD("download_content_length", d_code);
  1655. }
  1656. if (curl_easy_getinfo(ch->cp, CURLINFO_CONTENT_LENGTH_UPLOAD, &d_code) == CURLE_OK) {
  1657. CAAD("upload_content_length", d_code);
  1658. }
  1659. if (curl_easy_getinfo(ch->cp, CURLINFO_STARTTRANSFER_TIME, &d_code) == CURLE_OK) {
  1660. CAAD("starttransfer_time", d_code);
  1661. }
  1662. if (curl_easy_getinfo(ch->cp, CURLINFO_REDIRECT_TIME, &d_code) == CURLE_OK) {
  1663. CAAD("redirect_time", d_code);
  1664. }
  1665. if (ch->header.str_len > 0) {
  1666. CAAS("request_header", ch->header.str);
  1667. }
  1668. } else {
  1669. option = Z_LVAL_PP(zoption);
  1670. switch (option) {
  1671. case CURLINFO_PRIVATE:
  1672. case CURLINFO_EFFECTIVE_URL:
  1673. case CURLINFO_CONTENT_TYPE: {
  1674. char *s_code = NULL;
  1675. if (curl_easy_getinfo(ch->cp, option, &s_code) == CURLE_OK && s_code) {
  1676. RETURN_STRING(s_code, 1);
  1677. } else {
  1678. RETURN_FALSE;
  1679. }
  1680. break;
  1681. }
  1682. case CURLINFO_HTTP_CODE:
  1683. case CURLINFO_HEADER_SIZE:
  1684. case CURLINFO_REQUEST_SIZE:
  1685. case CURLINFO_FILETIME:
  1686. case CURLINFO_SSL_VERIFYRESULT:
  1687. case CURLINFO_REDIRECT_COUNT: {
  1688. long code = 0;
  1689. if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
  1690. RETURN_LONG(code);
  1691. } else {
  1692. RETURN_FALSE;
  1693. }
  1694. break;
  1695. }
  1696. case CURLINFO_TOTAL_TIME:
  1697. case CURLINFO_NAMELOOKUP_TIME:
  1698. case CURLINFO_CONNECT_TIME:
  1699. case CURLINFO_PRETRANSFER_TIME:
  1700. case CURLINFO_SIZE_UPLOAD:
  1701. case CURLINFO_SIZE_DOWNLOAD:
  1702. case CURLINFO_SPEED_DOWNLOAD:
  1703. case CURLINFO_SPEED_UPLOAD:
  1704. case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
  1705. case CURLINFO_CONTENT_LENGTH_UPLOAD:
  1706. case CURLINFO_STARTTRANSFER_TIME:
  1707. case CURLINFO_REDIRECT_TIME: {
  1708. double code = 0.0;
  1709. if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
  1710. RETURN_DOUBLE(code);
  1711. } else {
  1712. RETURN_FALSE;
  1713. }
  1714. break;
  1715. }
  1716. case CURLINFO_HEADER_OUT:
  1717. if (ch->header.str_len > 0) {
  1718. RETURN_STRINGL(ch->header.str, ch->header.str_len, 1);
  1719. } else {
  1720. RETURN_FALSE;
  1721. }
  1722. }
  1723. }
  1724. }
  1725. /* }}} */
  1726. /* {{{ proto string curl_error(resource ch)
  1727. Return a string contain the last error for the current session */
  1728. PHP_FUNCTION(curl_error)
  1729. {
  1730. zval **zid;
  1731. php_curl *ch;
  1732. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zid) == FAILURE) {
  1733. WRONG_PARAM_COUNT;
  1734. }
  1735. ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
  1736. ch->err.str[CURL_ERROR_SIZE] = 0;
  1737. RETURN_STRING(ch->err.str, 1);
  1738. }
  1739. /* }}} */
  1740. /* {{{ proto int curl_errno(resource ch)
  1741. Return an integer containing the last error number */
  1742. PHP_FUNCTION(curl_errno)
  1743. {
  1744. zval **zid;
  1745. php_curl *ch;
  1746. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zid) == FAILURE) {
  1747. WRONG_PARAM_COUNT;
  1748. }
  1749. ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
  1750. RETURN_LONG(ch->err.no);
  1751. }
  1752. /* }}} */
  1753. /* {{{ proto void curl_close(resource ch)
  1754. Close a cURL session */
  1755. PHP_FUNCTION(curl_close)
  1756. {
  1757. zval **zid;
  1758. php_curl *ch;
  1759. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zid) == FAILURE) {
  1760. WRONG_PARAM_COUNT;
  1761. }
  1762. ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
  1763. if (ch->in_callback) {
  1764. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to close cURL handle from a callback");
  1765. return;
  1766. }
  1767. if (ch->uses) {
  1768. ch->uses--;
  1769. } else {
  1770. zend_list_delete(Z_LVAL_PP(zid));
  1771. }
  1772. }
  1773. /* }}} */
  1774. /* {{{ _php_curl_close()
  1775. List destructor for curl handles */
  1776. static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  1777. {
  1778. php_curl *ch = (php_curl *) rsrc->ptr;
  1779. #if PHP_CURL_DEBUG
  1780. fprintf(stderr, "DTOR CALLED, ch = %x\n", ch);
  1781. #endif
  1782. curl_easy_cleanup(ch->cp);
  1783. #if LIBCURL_VERSION_NUM < 0x071101
  1784. zend_llist_clean(&ch->to_free.str);
  1785. #endif
  1786. zend_llist_clean(&ch->to_free.slist);
  1787. zend_llist_clean(&ch->to_free.post);
  1788. if (ch->handlers->write->buf.len > 0) {
  1789. smart_str_free(&ch->handlers->write->buf);
  1790. }
  1791. if (ch->handlers->write->func_name) {
  1792. zval_ptr_dtor(&ch->handlers->write->func_name);
  1793. }
  1794. if (ch->handlers->read->func_name) {
  1795. zval_ptr_dtor(&ch->handlers->read->func_name);
  1796. }
  1797. if (ch->handlers->write_header->func_name) {
  1798. zval_ptr_dtor(&ch->handlers->write_header->func_name);
  1799. }
  1800. if (ch->handlers->passwd) {
  1801. zval_ptr_dtor(&ch->handlers->passwd);
  1802. }
  1803. if (ch->header.str_len > 0) {
  1804. efree(ch->header.str);
  1805. }
  1806. efree(ch->handlers->write);
  1807. efree(ch->handlers->write_header);
  1808. efree(ch->handlers->read);
  1809. efree(ch->handlers);
  1810. efree(ch);
  1811. }
  1812. /* }}} */
  1813. #endif /* HAVE_CURL */
  1814. /*
  1815. * Local variables:
  1816. * tab-width: 4
  1817. * c-basic-offset: 4
  1818. * End:
  1819. * vim600: fdm=marker
  1820. * vim: noet sw=4 ts=4
  1821. */