]> granicus.if.org Git - php/commitdiff
# Ok, big ass change list. Most of the changes are NEW's worthy, so
authorSterling Hughes <sterling@php.net>
Mon, 30 Apr 2001 14:36:19 +0000 (14:36 +0000)
committerSterling Hughes <sterling@php.net>
Mon, 30 Apr 2001 14:36:19 +0000 (14:36 +0000)
# I'll enter them directly there, not here....  The non-newsworthy code
# is:

Added REGISTER_CURL_CONSTANT() a wrapper around REGISTER_LONG_CONSTANT()
Re-vamp the internal php_curl structure.
Properly free allocated slist's and HttpPost structures
many whitespace changes
speed improvements (in the post handling and slist area's)

# Furthermore, as a side note, while the code I'm committing is correct,
# no one will be able to compile it yet and test it, as it requires a
# patched version of curl (if you really want to try it out and can't
# wait a day or two, send me a private mail)

ext/curl/curl.c
ext/curl/php_curl.h

index d4685b4121bd9895905a30755ae93880d65eb314..627ea5937070d92f47a43c60a2ba4176694a29f7 100644 (file)
 
 #if HAVE_CURL
 
-/* Standard Includes */
 #include <stdio.h>
 #include <string.h>
-#include <sys/stat.h>
-
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
 
 #ifdef PHP_WIN32
 #include <winsock.h>
 #include <sys/types.h>
-#define fstat(handle, buff) _fstat(handle, buff)
-#define stat _stat
 #endif
 
-/* CURL Includes */
 #include <curl/curl.h>
 #include <curl/easy.h>
 
-/* PHP Includes */
 #include "ext/standard/info.h"
 #include "ext/standard/file.h"
 #include "php_curl.h"
 
-static int le_curl;
+static int  le_curl;
+static char le_curl_name[] = "cURL handle";
 
 static void _php_curl_close(zend_rsrc_list_entry *rsrc);
-#define SAVE_CURL_ERROR(__handle, __err) \
-       __handle->cerrno = (int)__err;
+
+#define SAVE_CURL_ERROR(__handle, __err) (__handle)->err.no = (int) __err;
 
 #ifdef PHP_WIN32
 /* {{{ win32_cleanup()
@@ -95,11 +86,7 @@ function_entry curl_functions[] = {
        PHP_FE(curl_version,  NULL)
        PHP_FE(curl_setopt,   NULL)
        PHP_FE(curl_exec,     NULL)
-#if LIBCURL_VERSION_NUM >= 0x070401
        PHP_FE(curl_getinfo,  NULL)
-#else
-       PHP_FALIAS(curl_getinfo, warn_not_available, NULL)
-#endif
        PHP_FE(curl_error,    NULL)
        PHP_FE(curl_errno,    NULL)
        PHP_FE(curl_close,    NULL)
@@ -129,129 +116,147 @@ PHP_MINFO_FUNCTION(curl)
        php_info_print_table_end();
 }
 
+#define REGISTER_CURL_CONSTANT(name, value) REGISTER_LONG_CONSTANT(name, value, CONST_CS | CONST_PERSISTENT)
+
 PHP_MINIT_FUNCTION(curl)
 {
        le_curl = zend_register_list_destructors_ex(_php_curl_close, NULL, "curl", module_number);
        
        /* Constants for curl_setopt() */
-       REGISTER_LONG_CONSTANT("CURLOPT_PORT", CURLOPT_PORT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_FILE", CURLOPT_FILE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_INFILE", CURLOPT_INFILE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_INFILESIZE", CURLOPT_INFILESIZE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_URL", CURLOPT_URL, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_PROXY", CURLOPT_PROXY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_VERBOSE", CURLOPT_VERBOSE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_HEADER", CURLOPT_HEADER, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_HTTPHEADER", CURLOPT_HTTPHEADER, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_NOPROGRESS", CURLOPT_NOPROGRESS, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_NOBODY", CURLOPT_NOBODY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_FAILONERROR", CURLOPT_FAILONERROR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_UPLOAD", CURLOPT_UPLOAD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_POST", CURLOPT_POST, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_FTPLISTONLY", CURLOPT_FTPLISTONLY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_FTPAPPEND", CURLOPT_FTPAPPEND, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_NETRC", CURLOPT_NETRC, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_FOLLOWLOCATION", CURLOPT_FOLLOWLOCATION, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_FTPASCII", CURLOPT_FTPASCII, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_PUT", CURLOPT_PUT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_MUTE", CURLOPT_MUTE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_USERPWD", CURLOPT_USERPWD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_RANGE", CURLOPT_RANGE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_TIMEOUT", CURLOPT_TIMEOUT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_POSTFIELDS", CURLOPT_POSTFIELDS, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_REFERER", CURLOPT_REFERER, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_USERAGENT", CURLOPT_USERAGENT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_FTPPORT", CURLOPT_FTPPORT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_LOW_SPEED_LIMIT", CURLOPT_LOW_SPEED_LIMIT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_LOW_SPEED_TIME", CURLOPT_LOW_SPEED_TIME, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_RESUME_FROM", CURLOPT_RESUME_FROM, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_COOKIE", CURLOPT_COOKIE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_SSLCERT", CURLOPT_SSLCERT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_SSLCERTPASSWD", CURLOPT_SSLCERTPASSWD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_WRITEHEADER", CURLOPT_WRITEHEADER, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_COOKIEFILE", CURLOPT_COOKIEFILE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_SSLVERSION", CURLOPT_SSLVERSION, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_TIMECONDITION", CURLOPT_TIMECONDITION, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_TIMEVALUE", CURLOPT_TIMEVALUE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_CUSTOMREQUEST", CURLOPT_CUSTOMREQUEST, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_STDERR", CURLOPT_STDERR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_TRANSFERTEXT", CURLOPT_TRANSFERTEXT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_RETURNTRANSFER", CURLOPT_RETURNTRANSFER, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_QUOTE", CURLOPT_QUOTE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_POSTQUOTE", CURLOPT_POSTQUOTE, CONST_CS | CONST_PERSISTENT);
-#if LIBCURL_VERSION_NUM >= 0x070300
-       REGISTER_LONG_CONSTANT("CURLOPT_INTERFACE", CURLOPT_INTERFACE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_KRB4LEVEL", CURLOPT_KRB4LEVEL, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLOPT_HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CONST_CS | CONST_PERSISTENT);
-#endif
+       REGISTER_CURL_CONSTANT("CURLOPT_PORT",            CURLOPT_PORT);
+       REGISTER_CURL_CONSTANT("CURLOPT_FILE",            CURLOPT_FILE);
+       REGISTER_CURL_CONSTANT("CURLOPT_INFILE",          CURLOPT_INFILE);
+       REGISTER_CURL_CONSTANT("CURLOPT_INFILESIZE",      CURLOPT_INFILESIZE);
+       REGISTER_CURL_CONSTANT("CURLOPT_URL",             CURLOPT_URL);
+       REGISTER_CURL_CONSTANT("CURLOPT_PROXY",           CURLOPT_PROXY);
+       REGISTER_CURL_CONSTANT("CURLOPT_VERBOSE",         CURLOPT_VERBOSE);
+       REGISTER_CURL_CONSTANT("CURLOPT_HEADER",          CURLOPT_HEADER);
+       REGISTER_CURL_CONSTANT("CURLOPT_HTTPHEADER",      CURLOPT_HTTPHEADER);
+       REGISTER_CURL_CONSTANT("CURLOPT_NOPROGRESS",      CURLOPT_NOPROGRESS);
+       REGISTER_CURL_CONSTANT("CURLOPT_NOBODY",          CURLOPT_NOBODY);
+       REGISTER_CURL_CONSTANT("CURLOPT_FAILONERROR",     CURLOPT_FAILONERROR);
+       REGISTER_CURL_CONSTANT("CURLOPT_UPLOAD",          CURLOPT_UPLOAD);
+       REGISTER_CURL_CONSTANT("CURLOPT_POST",            CURLOPT_POST);
+       REGISTER_CURL_CONSTANT("CURLOPT_FTPLISTONLY",     CURLOPT_FTPLISTONLY);
+       REGISTER_CURL_CONSTANT("CURLOPT_FTPAPPEND",       CURLOPT_FTPAPPEND);
+       REGISTER_CURL_CONSTANT("CURLOPT_NETRC",           CURLOPT_NETRC);
+       REGISTER_CURL_CONSTANT("CURLOPT_FOLLOWLOCATION",  CURLOPT_FOLLOWLOCATION);
+       REGISTER_CURL_CONSTANT("CURLOPT_FTPASCII",        CURLOPT_FTPASCII);
+       REGISTER_CURL_CONSTANT("CURLOPT_PUT",             CURLOPT_PUT);
+       REGISTER_CURL_CONSTANT("CURLOPT_MUTE",            CURLOPT_MUTE);
+       REGISTER_CURL_CONSTANT("CURLOPT_USERPWD",         CURLOPT_USERPWD);
+       REGISTER_CURL_CONSTANT("CURLOPT_PROXYUSERPWD",    CURLOPT_PROXYUSERPWD);
+       REGISTER_CURL_CONSTANT("CURLOPT_RANGE",           CURLOPT_RANGE);
+       REGISTER_CURL_CONSTANT("CURLOPT_TIMEOUT",         CURLOPT_TIMEOUT);
+       REGISTER_CURL_CONSTANT("CURLOPT_POSTFIELDS",      CURLOPT_POSTFIELDS);
+       REGISTER_CURL_CONSTANT("CURLOPT_REFERER",         CURLOPT_REFERER);
+       REGISTER_CURL_CONSTANT("CURLOPT_USERAGENT",       CURLOPT_USERAGENT);
+       REGISTER_CURL_CONSTANT("CURLOPT_FTPPORT",         CURLOPT_FTPPORT);
+       REGISTER_CURL_CONSTANT("CURLOPT_LOW_SPEED_LIMIT", CURLOPT_LOW_SPEED_LIMIT);
+       REGISTER_CURL_CONSTANT("CURLOPT_LOW_SPEED_TIME",  CURLOPT_LOW_SPEED_TIME);
+       REGISTER_CURL_CONSTANT("CURLOPT_RESUME_FROM",     CURLOPT_RESUME_FROM);
+       REGISTER_CURL_CONSTANT("CURLOPT_COOKIE",          CURLOPT_COOKIE);
+       REGISTER_CURL_CONSTANT("CURLOPT_SSLCERT",         CURLOPT_SSLCERT);
+       REGISTER_CURL_CONSTANT("CURLOPT_SSLCERTPASSWD",   CURLOPT_SSLCERTPASSWD);
+       REGISTER_CURL_CONSTANT("CURLOPT_WRITEHEADER",     CURLOPT_WRITEHEADER);
+       REGISTER_CURL_CONSTANT("CURLOPT_COOKIEFILE",      CURLOPT_COOKIEFILE);
+       REGISTER_CURL_CONSTANT("CURLOPT_SSLVERSION",      CURLOPT_SSLVERSION);
+       REGISTER_CURL_CONSTANT("CURLOPT_TIMECONDITION",   CURLOPT_TIMECONDITION);
+       REGISTER_CURL_CONSTANT("CURLOPT_TIMEVALUE",       CURLOPT_TIMEVALUE);
+       REGISTER_CURL_CONSTANT("CURLOPT_CUSTOMREQUEST",   CURLOPT_CUSTOMREQUEST);
+       REGISTER_CURL_CONSTANT("CURLOPT_STDERR",          CURLOPT_STDERR);
+       REGISTER_CURL_CONSTANT("CURLOPT_TRANSFERTEXT",    CURLOPT_TRANSFERTEXT);
+       REGISTER_CURL_CONSTANT("CURLOPT_RETURNTRANSFER",  CURLOPT_RETURNTRANSFER);
+       REGISTER_CURL_CONSTANT("CURLOPT_QUOTE",           CURLOPT_QUOTE);
+       REGISTER_CURL_CONSTANT("CURLOPT_POSTQUOTE",       CURLOPT_POSTQUOTE);
+       REGISTER_CURL_CONSTANT("CURLOPT_INTERFACE",       CURLOPT_INTERFACE);
+       REGISTER_CURL_CONSTANT("CURLOPT_KRB4LEVEL",       CURLOPT_KRB4LEVEL);
+       REGISTER_CURL_CONSTANT("CURLOPT_HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL);
+       REGISTER_CURL_CONSTANT("CURLOPT_FILETIME",        CURLOPT_FILETIME);
+       REGISTER_CURL_CONSTANT("CURLOPT_WRITEFUNCTION",   CURLOPT_WRITEFUNCTION);
+       REGISTER_CURL_CONSTANT("CURLOPT_MAXREDIRS",       CURLOPT_MAXREDIRS);
+       REGISTER_CURL_CONSTANT("CURLOPT_MAXCONNECTS",     CURLOPT_MAXCONNECTS);
+       REGISTER_CURL_CONSTANT("CURLOPT_CLOSEPOLICY",     CURLOPT_CLOSEPOLICY);
+       REGISTER_CURL_CONSTANT("CURLOPT_FRESH_CONNECT",   CURLOPT_FRESH_CONNECT);
+       REGISTER_CURL_CONSTANT("CURLOPT_FORBID_REUSE",    CURLOPT_FORBID_REUSE);
+       REGISTER_CURL_CONSTANT("CURLOPT_RANDOM_FILE",     CURLOPT_RANDOM_FILE);
+       REGISTER_CURL_CONSTANT("CURLOPT_EGDSOCKET",       CURLOPT_EGDSOCKET);
+       REGISTER_CURL_CONSTANT("CURLOPT_CONNECTTIMEOUT",  CURLOPT_CONNECTTIMEOUT);
+       REGISTER_CURL_CONSTANT("CURLOPT_SSL_VERIFYPEER",  CURLOPT_SSL_VERIFYPEER);
+       REGISTER_CURL_CONSTANT("CURLOPT_CAINFO",          CURLOPT_CAINFO);
+
+       /* Constants effecting the way CURLOPT_CLOSEPOLICY works */
+       REGISTER_CURL_CONSTANT("CURLCLOSEPOLICY_LEAST_RECENTLY_USED", CURLCLOSEPOLICY_LEAST_RECENTLY_USED);
+       REGISTER_CURL_CONSTANT("CURLCLOSEPOLICY_OLDEST",              CURLCLOSEPOLICY_OLDEST);
 
-
-#if LIBCURL_VERSION_NUM >= 0x070401
        /* Info constants */
-       REGISTER_LONG_CONSTANT("CURLINFO_EFFECTIVE_URL", CURLINFO_EFFECTIVE_URL, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_HTTP_CODE", CURLINFO_HTTP_CODE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_HEADER_SIZE", CURLINFO_HEADER_SIZE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_REQUEST_SIZE", CURLINFO_REQUEST_SIZE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_TOTAL_TIME", CURLINFO_TOTAL_TIME, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_NAMELOOKUP_TIME", CURLINFO_NAMELOOKUP_TIME, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_CONNECT_TIME", CURLINFO_CONNECT_TIME, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_PRETRANSFER_TIME", CURLINFO_PRETRANSFER_TIME, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_SIZE_UPLOAD", CURLINFO_SIZE_UPLOAD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_SIZE_DOWNLOAD", CURLINFO_SIZE_DOWNLOAD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_SPEED_DOWNLOAD", CURLINFO_SPEED_DOWNLOAD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLINFO_SPEED_UPLOAD", CURLINFO_SPEED_UPLOAD, CONST_CS | CONST_PERSISTENT);
-
-#endif
+       REGISTER_CURL_CONSTANT("CURLINFO_EFFECTIVE_URL",    CURLINFO_EFFECTIVE_URL);
+       REGISTER_CURL_CONSTANT("CURLINFO_HTTP_CODE",        CURLINFO_HTTP_CODE);
+       REGISTER_CURL_CONSTANT("CURLINFO_HEADER_SIZE",      CURLINFO_HEADER_SIZE);
+       REGISTER_CURL_CONSTANT("CURLINFO_REQUEST_SIZE",     CURLINFO_REQUEST_SIZE);
+       REGISTER_CURL_CONSTANT("CURLINFO_TOTAL_TIME",       CURLINFO_TOTAL_TIME);
+       REGISTER_CURL_CONSTANT("CURLINFO_NAMELOOKUP_TIME",  CURLINFO_NAMELOOKUP_TIME);
+       REGISTER_CURL_CONSTANT("CURLINFO_CONNECT_TIME",     CURLINFO_CONNECT_TIME);
+       REGISTER_CURL_CONSTANT("CURLINFO_PRETRANSFER_TIME", CURLINFO_PRETRANSFER_TIME);
+       REGISTER_CURL_CONSTANT("CURLINFO_SIZE_UPLOAD",      CURLINFO_SIZE_UPLOAD);
+       REGISTER_CURL_CONSTANT("CURLINFO_SIZE_DOWNLOAD",    CURLINFO_SIZE_DOWNLOAD);
+       REGISTER_CURL_CONSTANT("CURLINFO_SPEED_DOWNLOAD",   CURLINFO_SPEED_DOWNLOAD);
+       REGISTER_CURL_CONSTANT("CURLINFO_SPEED_UPLOAD",     CURLINFO_SPEED_UPLOAD);
+       REGISTER_CURL_CONSTANT("CURLINFO_FILETIME",         CURLINFO_FILETIME);
 
        /* Error Constants */
-       REGISTER_LONG_CONSTANT("CURLE_OK", CURLE_OK, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_UNSUPPORTED_PROTOCOL", CURLE_UNSUPPORTED_PROTOCOL, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FAILED_INIT", CURLE_FAILED_INIT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_URL_MALFORMAT", CURLE_URL_MALFORMAT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_URL_MALFORMAT_USER", CURLE_URL_MALFORMAT_USER, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_COULDNT_RESOLVE_PROXY", CURLE_COULDNT_RESOLVE_PROXY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_COULDNT_RESOLVE_HOST", CURLE_COULDNT_RESOLVE_HOST, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_COULDNT_CONNECT", CURLE_COULDNT_CONNECT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_WEIRD_SERVER_REPLY", CURLE_FTP_WEIRD_SERVER_REPLY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_ACCESS_DENIED", CURLE_FTP_ACCESS_DENIED, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_USER_PASSWORD_INCORRECT", CURLE_FTP_USER_PASSWORD_INCORRECT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_WEIRD_PASS_REPLY", CURLE_FTP_WEIRD_PASS_REPLY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_WEIRD_USER_REPLY", CURLE_FTP_WEIRD_USER_REPLY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_WEIRD_PASV_REPLY", CURLE_FTP_WEIRD_PASV_REPLY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_WEIRD_227_FORMAT", CURLE_FTP_WEIRD_227_FORMAT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_CANT_GET_HOST", CURLE_FTP_CANT_GET_HOST, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_CANT_RECONNECT", CURLE_FTP_CANT_RECONNECT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_COULDNT_SET_BINARY", CURLE_FTP_COULDNT_SET_BINARY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_PARTIAL_FILE", CURLE_PARTIAL_FILE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_COULDNT_RETR_FILE", CURLE_FTP_COULDNT_RETR_FILE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_WRITE_ERROR", CURLE_FTP_WRITE_ERROR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_QUOTE_ERROR", CURLE_FTP_QUOTE_ERROR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_HTTP_NOT_FOUND", CURLE_HTTP_NOT_FOUND, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_WRITE_ERROR", CURLE_WRITE_ERROR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_MALFORMAT_USER", CURLE_MALFORMAT_USER, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_COULDNT_STOR_FILE", CURLE_FTP_COULDNT_STOR_FILE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_READ_ERROR", CURLE_READ_ERROR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_OUT_OF_MEMORY", CURLE_OUT_OF_MEMORY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_OPERATION_TIMEOUTED", CURLE_OPERATION_TIMEOUTED, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_COULDNT_SET_ASCII", CURLE_FTP_COULDNT_SET_ASCII, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_PORT_FAILED", CURLE_FTP_PORT_FAILED, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_COULDNT_USE_REST", CURLE_FTP_COULDNT_USE_REST, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_COULDNT_GET_SIZE", CURLE_FTP_COULDNT_GET_SIZE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_HTTP_RANGE_ERROR", CURLE_HTTP_RANGE_ERROR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_HTTP_POST_ERROR", CURLE_HTTP_POST_ERROR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_SSL_CONNECT_ERROR", CURLE_SSL_CONNECT_ERROR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FTP_BAD_DOWNLOAD_RESUME", CURLE_FTP_BAD_DOWNLOAD_RESUME, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FILE_COULDNT_READ_FILE", CURLE_FILE_COULDNT_READ_FILE, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_LDAP_CANNOT_BIND", CURLE_LDAP_CANNOT_BIND, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_LDAP_SEARCH_FAILED", CURLE_LDAP_SEARCH_FAILED, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_LIBRARY_NOT_FOUND", CURLE_LIBRARY_NOT_FOUND, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_FUNCTION_NOT_FOUND", CURLE_FUNCTION_NOT_FOUND, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_ABORTED_BY_CALLBACK", CURLE_ABORTED_BY_CALLBACK, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_BAD_FUNCTION_ARGUMENT", CURLE_BAD_FUNCTION_ARGUMENT, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURLE_BAD_CALLING_ORDER", CURLE_BAD_CALLING_ORDER, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("CURL_LAST", CURL_LAST, CONST_CS | CONST_PERSISTENT);
-               
+       REGISTER_CURL_CONSTANT("CURLE_OK",                          CURLE_OK);
+       REGISTER_CURL_CONSTANT("CURLE_UNSUPPORTED_PROTOCOL",        CURLE_UNSUPPORTED_PROTOCOL);
+       REGISTER_CURL_CONSTANT("CURLE_FAILED_INIT",                 CURLE_FAILED_INIT);
+       REGISTER_CURL_CONSTANT("CURLE_URL_MALFORMAT",               CURLE_URL_MALFORMAT);
+       REGISTER_CURL_CONSTANT("CURLE_URL_MALFORMAT_USER",          CURLE_URL_MALFORMAT_USER);
+       REGISTER_CURL_CONSTANT("CURLE_COULDNT_RESOLVE_PROXY",       CURLE_COULDNT_RESOLVE_PROXY);
+       REGISTER_CURL_CONSTANT("CURLE_COULDNT_RESOLVE_HOST",        CURLE_COULDNT_RESOLVE_HOST);
+       REGISTER_CURL_CONSTANT("CURLE_COULDNT_CONNECT",             CURLE_COULDNT_CONNECT);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_WEIRD_SERVER_REPLY",      CURLE_FTP_WEIRD_SERVER_REPLY);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_ACCESS_DENIED",           CURLE_FTP_ACCESS_DENIED);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_USER_PASSWORD_INCORRECT", CURLE_FTP_USER_PASSWORD_INCORRECT);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_WEIRD_PASS_REPLY",        CURLE_FTP_WEIRD_PASS_REPLY);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_WEIRD_USER_REPLY",        CURLE_FTP_WEIRD_USER_REPLY);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_WEIRD_PASV_REPLY",        CURLE_FTP_WEIRD_PASV_REPLY);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_WEIRD_227_FORMAT",        CURLE_FTP_WEIRD_227_FORMAT);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_CANT_GET_HOST",           CURLE_FTP_CANT_GET_HOST);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_CANT_RECONNECT",          CURLE_FTP_CANT_RECONNECT);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_COULDNT_SET_BINARY",      CURLE_FTP_COULDNT_SET_BINARY);
+       REGISTER_CURL_CONSTANT("CURLE_PARTIAL_FILE",                CURLE_PARTIAL_FILE);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_COULDNT_RETR_FILE",       CURLE_FTP_COULDNT_RETR_FILE);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_WRITE_ERROR",             CURLE_FTP_WRITE_ERROR);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_QUOTE_ERROR",             CURLE_FTP_QUOTE_ERROR);
+       REGISTER_CURL_CONSTANT("CURLE_HTTP_NOT_FOUND",              CURLE_HTTP_NOT_FOUND);
+       REGISTER_CURL_CONSTANT("CURLE_WRITE_ERROR",                 CURLE_WRITE_ERROR);
+       REGISTER_CURL_CONSTANT("CURLE_MALFORMAT_USER",              CURLE_MALFORMAT_USER);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_COULDNT_STOR_FILE",       CURLE_FTP_COULDNT_STOR_FILE);
+       REGISTER_CURL_CONSTANT("CURLE_READ_ERROR",                  CURLE_READ_ERROR);
+       REGISTER_CURL_CONSTANT("CURLE_OUT_OF_MEMORY",               CURLE_OUT_OF_MEMORY);
+       REGISTER_CURL_CONSTANT("CURLE_OPERATION_TIMEOUTED",         CURLE_OPERATION_TIMEOUTED);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_COULDNT_SET_ASCII",       CURLE_FTP_COULDNT_SET_ASCII);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_PORT_FAILED",             CURLE_FTP_PORT_FAILED);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_COULDNT_USE_REST",        CURLE_FTP_COULDNT_USE_REST);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_COULDNT_GET_SIZE",        CURLE_FTP_COULDNT_GET_SIZE);
+       REGISTER_CURL_CONSTANT("CURLE_HTTP_RANGE_ERROR",            CURLE_HTTP_RANGE_ERROR);
+       REGISTER_CURL_CONSTANT("CURLE_HTTP_POST_ERROR",             CURLE_HTTP_POST_ERROR);
+       REGISTER_CURL_CONSTANT("CURLE_SSL_CONNECT_ERROR",           CURLE_SSL_CONNECT_ERROR);
+       REGISTER_CURL_CONSTANT("CURLE_FTP_BAD_DOWNLOAD_RESUME",     CURLE_FTP_BAD_DOWNLOAD_RESUME);
+       REGISTER_CURL_CONSTANT("CURLE_FILE_COULDNT_READ_FILE",      CURLE_FILE_COULDNT_READ_FILE);
+       REGISTER_CURL_CONSTANT("CURLE_LDAP_CANNOT_BIND",            CURLE_LDAP_CANNOT_BIND);
+       REGISTER_CURL_CONSTANT("CURLE_LDAP_SEARCH_FAILED",          CURLE_LDAP_SEARCH_FAILED);
+       REGISTER_CURL_CONSTANT("CURLE_LIBRARY_NOT_FOUND",           CURLE_LIBRARY_NOT_FOUND);
+       REGISTER_CURL_CONSTANT("CURLE_FUNCTION_NOT_FOUND",          CURLE_FUNCTION_NOT_FOUND);
+       REGISTER_CURL_CONSTANT("CURLE_ABORTED_BY_CALLBACK",         CURLE_ABORTED_BY_CALLBACK);
+       REGISTER_CURL_CONSTANT("CURLE_BAD_FUNCTION_ARGUMENT",       CURLE_BAD_FUNCTION_ARGUMENT);
+       REGISTER_CURL_CONSTANT("CURLE_BAD_CALLING_ORDER",           CURLE_BAD_CALLING_ORDER);
+       REGISTER_CURL_CONSTANT("CURLE_HTTP_PORT_FAILED",            CURLE_HTTP_PORT_FAILED);
+       REGISTER_CURL_CONSTANT("CURLE_BAD_PASSWORD_ENTERED",        CURLE_BAD_PASSWORD_ENTERED);
+       REGISTER_CURL_CONSTANT("CURLE_TOO_MANY_REDIRECTS",          CURLE_TOO_MANY_REDIRECTS);
+       REGISTER_CURL_CONSTANT("CURLE_UNKOWN_TELNET_OPTION",        CURLE_UNKNOWN_TELNET_OPTION);
+       REGISTER_CURL_CONSTANT("CURLE_TELNET_OPTION_SYNTAX",        CURLE_TELNET_OPTION_SYNTAX);
+       REGISTER_CURL_CONSTANT("CURLE_ALREADY_COMPLETE",            CURLE_ALREADY_COMPLETE);
+
        if (win32_init() != CURLE_OK) {
                return FAILURE;
        }
@@ -265,10 +270,204 @@ PHP_MSHUTDOWN_FUNCTION(curl)
        return SUCCESS;
 }
 
-static void curl_free_string(void **string) {
+#define PHP_CURL_STDOUT 0
+#define PHP_CURL_FILE   1
+#define PHP_CURL_USER   2
+#define PHP_CURL_DIRECT 3
+#define PHP_CURL_RETURN 4
+
+static size_t curl_write(void *ctx, char *data, size_t size, size_t nmemb, FILE *fp)
+{
+       php_curl       *ch     = (php_curl *) ctx;
+       php_curl_write *t      = ch->write;
+       size_t          length = size * nmemb;
+
+       switch (t->method) {
+       case PHP_CURL_FILE:
+               return fwrite(data, size, nmemb, fp);
+       case PHP_CURL_RETURN:
+       case PHP_CURL_STDOUT:
+               smart_str_appendl(&t->buf, data, (int) length);
+               break;
+       case PHP_CURL_USER: {
+               zval *argv[2];
+               zval *retval;
+               int   error;
+               ELS_FETCH();
+
+               MAKE_STD_ZVAL(argv[0]);
+               MAKE_STD_ZVAL(argv[1]);
+               MAKE_STD_ZVAL(retval);
+
+               ZVAL_RESOURCE(argv[0], ch->id);
+               zend_list_addref(ch->id);
+               ZVAL_STRINGL(argv[1], data, (int) length, 1);
+
+               error = call_user_function(EG(function_table),
+                                          NULL,
+                                          t->func,
+                                          retval, 2, argv);
+               if (error == FAILURE) {
+                       php_error(E_WARNING, "Cannot call the CURLOPT_WRITEFUNCTION");
+                       return -1;
+               }
+
+               length = Z_LVAL_P(retval);
+
+               zval_ptr_dtor(&argv[0]);
+               zval_ptr_dtor(&argv[1]);
+               zval_ptr_dtor(&retval);
+
+               break;
+       }
+       }
+
+       return length;
+}
+
+static size_t curl_read(void *ctx, char *data, size_t size, size_t nmemb, FILE *fp)
+{
+       php_curl       *ch = (php_curl *) ctx;
+       php_curl_read  *t  = ch->read;
+       int             length = -1;
+
+       switch (t->method) {
+       case PHP_CURL_DIRECT:
+               length = fread(data, size, nmemb, fp);
+       case PHP_CURL_USER: {
+               zval *argv[3];
+               zval *retval;
+               int   length;
+               int   error;
+
+               MAKE_STD_ZVAL(argv[0]);
+               MAKE_STD_ZVAL(argv[1]);
+               MAKE_STD_ZVAL(argv[2]);
+               MAKE_STD_ZVAL(retval);
+
+               ZVAL_RESOURCE(argv[0], ch->id);
+               zend_list_addref(ch->id);
+               ZVAL_RESOURCE(argv[1], t->fd);
+               zend_list_addref(t->fd);
+               ZVAL_LONG(argv[2], size * nmemb);
+
+               error = call_user_function(EG(function_table),
+                                          NULL,
+                                          t->func,
+                                          retval, 3, argv);
+               if (error == FAILURE) {
+                       php_error(E_WARNING, "Cannot call the CURLOPT_READFUNCTION");
+                       break;
+               }
+
+               data = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
+               length = Z_STRLEN_P(retval);
+
+               zval_ptr_dtor(&argv[0]);
+               zval_ptr_dtor(&argv[1]);
+               zval_ptr_dtor(&argv[2]);
+               zval_ptr_dtor(&retval);
+
+               break;
+       }
+       }
+
+       return length;
+}
+
+static size_t _php_curl_write_header(void *ctx, char *data, size_t size, size_t nmemb, FILE *fp)
+{
+       php_curl   *ch   = (php_curl *) ctx;
+       zval       *func = ch->handlers->write_header;
+       zval       *argv[2];
+       zval       *retval;
+       int         error;
+       int         length;
+
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(retval);
+
+       ZVAL_RESOURCE(argv[0], ch->id);
+       zend_list_addref(ch->id);
+       ZVAL_STRINGL(argv[0], data, size * nmemb, 1);
+
+       error = call_user_function(EG(function_table), 
+                                  NULL,
+                                  func,
+                                  retval, 2, argv);
+       if (error == FAILURE) {
+               php_error(E_WARNING, "Couldn't call the CURLOPT_HEADERFUNCTION");
+               return -1;
+       }
+
+       length = Z_LVAL_P(retval);
+
+       zval_ptr_dtor(&argv[0]);
+       zval_ptr_dtor(&argv[1]);
+       zval_ptr_dtor(&retval);
+
+       return length;
+}
+
+static size_t _php_curl_passwd(void *ctx, char *prompt, char *buf, int buflen)
+{
+       php_curl    *ch   = (php_curl *) ctx;
+       zval        *func = ch->handlers->passwd;
+       zval        *argv[3];
+       zval        *retval;
+       int          error;
+
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(argv[2]);
+
+       ZVAL_RESOURCE(argv[0], ch->id);
+       zend_list_addref(ch->id);
+       ZVAL_STRING(argv[1], prompt, 1);
+       ZVAL_LONG(argv[2], buflen);
+
+       error = call_user_function(EG(function_table),
+                                  NULL,
+                                  func,
+                                  retval, 2, argv);
+       if (error == FAILURE) {
+               php_error(E_WARNING, "Couldn't call the CURLOPT_PASSWDFUNCTION");
+               return -1;
+       }
+
+       if (Z_STRLEN_P(retval) > buflen) {
+               php_error(E_WARNING, "Returned password is too long for libcurl to handle");
+               return -1;
+       }
+
+       strncpy(buf, Z_STRVAL_P(retval), Z_STRLEN_P(retval));
+
+       zval_ptr_dtor(&argv[0]);
+       zval_ptr_dtor(&argv[1]);
+       zval_ptr_dtor(&argv[2]);
+       zval_ptr_dtor(&retval);
+
+       return 0;
+}
+       
+       
+
+static void curl_free_string(void **string)
+{
        efree(*string);
 }
 
+static void curl_free_post(void **post)
+{
+       curl_formfree((struct HttpPost *) *post);
+}
+
+static void curl_free_slist(void **slist)
+{
+       curl_slist_free_all((struct curl_slist *) *slist);
+}
+
 /* {{{ proto string curl_version(void)
    Return the CURL version string. */
 PHP_FUNCTION(curl_version)
@@ -281,43 +480,57 @@ PHP_FUNCTION(curl_version)
    Initialize a CURL session */
 PHP_FUNCTION(curl_init)
 {
-       zval **url;
-       php_curl *curl_handle = NULL;
-       int argc = ZEND_NUM_ARGS();
-       
+       zval       **url;
+       php_curl    *ch;
+       int          argc = ZEND_NUM_ARGS();
+
        if (argc < 0 || argc > 1 ||
            zend_get_parameters_ex(argc, &url) == FAILURE) {
                WRONG_PARAM_COUNT;
        }
-       
-       curl_handle = (php_curl *)emalloc(sizeof(php_curl));
-       memset(curl_handle, 0, sizeof(php_curl));
-
-       zend_llist_init(&curl_handle->to_free, sizeof(char *), (void(*)(void *))curl_free_string, 0);
 
-       curl_handle->cp = curl_easy_init();
-       if (!curl_handle->cp) {
-               php_error(E_ERROR, "Cannot initialize CURL Handle");
+       ch = emalloc(sizeof(php_curl));
+       ch->write    = emalloc(sizeof(php_curl_write));
+       ch->read     = emalloc(sizeof(php_curl_read));
+       ch->handlers = emalloc(sizeof(php_curl_handlers));
+       memset(ch->write, 0, sizeof(php_curl_write));
+       memset(ch->read,  0, sizeof(php_curl_read));
+       memset(ch->handlers, 0, sizeof(php_curl_handlers));
+
+       zend_llist_init(&ch->to_free.str, sizeof(char *), 
+                       (void(*)(void *)) curl_free_string, 0);
+       zend_llist_init(&ch->to_free.slist, sizeof(struct curl_slist),
+                       (void(*)(void *)) curl_free_slist, 0);
+       zend_llist_init(&ch->to_free.post, sizeof(struct HttpPost),
+                       (void(*)(void *)) curl_free_post, 0);
+
+       ch->cp = curl_easy_init();
+       if (! ch->cp) {
+               php_error(E_WARNING, "Cannot initialize a new cURL handle");
                RETURN_FALSE;
        }
-       
+
+       ch->write->method = PHP_CURL_STDOUT;
+       ch->read->method  = PHP_CURL_DIRECT;
+
+       curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS,        1);
+       curl_easy_setopt(ch->cp, CURLOPT_VERBOSE,           0);
+       curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER,       ch->err.str);
+       curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION,     curl_write);
+       curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTIONDATA, (void *) ch);
+       curl_easy_setopt(ch->cp, CURLOPT_READFUNCTION,      curl_read);
+       curl_easy_setopt(ch->cp, CURLOPT_READFUNCTIONDATA,  (void *) ch);
        if (argc > 0) {
-               char *urlstr;
+               char *urlcopy;
                convert_to_string_ex(url);
 
-               urlstr = estrndup(Z_STRVAL_PP(url), Z_STRLEN_PP(url));
-               curl_easy_setopt(curl_handle->cp, CURLOPT_URL, urlstr);
-               zend_llist_add_element(&curl_handle->to_free, &urlstr);
+               urlcopy = estrndup(Z_STRVAL_PP(url), Z_STRLEN_PP(url));
+               curl_easy_setopt(ch->cp, CURLOPT_URL, urlcopy);
+               zend_llist_add_element(&ch->to_free.str, &urlcopy);
        }
 
-       curl_easy_setopt(curl_handle->cp, CURLOPT_NOPROGRESS, 1);
-       curl_easy_setopt(curl_handle->cp, CURLOPT_VERBOSE,    0);
-       curl_easy_setopt(curl_handle->cp, CURLOPT_ERRORBUFFER, curl_handle->error);
-
-       curl_handle->output_file = 0;
-       curl_handle->php_stdout  = 1;
-
-       ZEND_REGISTER_RESOURCE(return_value, curl_handle, le_curl);
+       ZEND_REGISTER_RESOURCE(return_value, ch, le_curl);
+       ch->id = Z_LVAL_P(return_value);
 }
 /* }}} */
 
@@ -325,227 +538,223 @@ PHP_FUNCTION(curl_init)
    Set an option for a CURL transfer */
 PHP_FUNCTION(curl_setopt)
 {
-       zval **curl_id, 
-            **curl_option, 
-            **curl_value;
-       php_curl *curl_handle;
-       CURLcode ret;
-       int option;
+       zval       **zid, 
+                  **zoption, 
+                  **zvalue;
+       php_curl    *ch;
+       CURLcode     error;
+       int          option;
        
        if (ZEND_NUM_ARGS() != 3 ||
-           zend_get_parameters_ex(3, &curl_id, &curl_option, &curl_value) == FAILURE) {
+           zend_get_parameters_ex(3, &zid, &zoption, &zvalue) == FAILURE) {
                WRONG_PARAM_COUNT;
        }
+       ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
+       convert_to_long_ex(zoption);
 
-       ZEND_FETCH_RESOURCE(curl_handle, php_curl *, curl_id, -1, "CURL Handle", le_curl);
+       option = Z_LVAL_PP(zoption);
+       switch (option) {
+       case CURLOPT_INFILESIZE:
+       case CURLOPT_VERBOSE:
+       case CURLOPT_HEADER:
+       case CURLOPT_NOPROGRESS:
+       case CURLOPT_NOBODY:
+       case CURLOPT_FAILONERROR:
+       case CURLOPT_UPLOAD:
+       case CURLOPT_POST:
+       case CURLOPT_FTPLISTONLY:
+       case CURLOPT_FTPAPPEND:
+       case CURLOPT_NETRC:
+       case CURLOPT_FOLLOWLOCATION:
+       case CURLOPT_PUT:
+       case CURLOPT_MUTE:
+       case CURLOPT_TIMEOUT:
+       case CURLOPT_LOW_SPEED_LIMIT:
+       case CURLOPT_SSLVERSION:
+       case CURLOPT_LOW_SPEED_TIME:
+       case CURLOPT_RESUME_FROM:
+       case CURLOPT_TIMEVALUE:
+       case CURLOPT_TIMECONDITION:
+       case CURLOPT_TRANSFERTEXT:
+       case CURLOPT_HTTPPROXYTUNNEL:
+       case CURLOPT_FILETIME:
+       case CURLOPT_MAXREDIRS:
+       case CURLOPT_MAXCONNECTS:
+       case CURLOPT_CLOSEPOLICY:
+       case CURLOPT_FRESH_CONNECT:
+       case CURLOPT_FORBID_REUSE:
+       case CURLOPT_CONNECTTIMEOUT:
+       case CURLOPT_SSL_VERIFYPEER:
+               convert_to_long_ex(zvalue);
+               error = curl_easy_setopt(ch->cp, option, Z_LVAL_PP(zvalue));
+               break;
+       case CURLOPT_URL:
+       case CURLOPT_PROXY:
+       case CURLOPT_USERPWD:
+       case CURLOPT_PROXYUSERPWD:
+       case CURLOPT_RANGE:
+       case CURLOPT_CUSTOMREQUEST:
+       case CURLOPT_USERAGENT:
+       case CURLOPT_FTPPORT:
+       case CURLOPT_COOKIE:
+       case CURLOPT_SSLCERT:
+       case CURLOPT_SSLCERTPASSWD:
+       case CURLOPT_COOKIEFILE:
+       case CURLOPT_REFERER:
+       case CURLOPT_INTERFACE:
+       case CURLOPT_KRB4LEVEL: 
+       case CURLOPT_RANDOM_FILE:
+       case CURLOPT_EGDSOCKET:
+       case CURLOPT_CAINFO: {
+               char *copystr = NULL;
        
-       convert_to_long_ex(curl_option);
-       option = Z_LVAL_PP(curl_option);
+               convert_to_string_ex(zvalue);
+               copystr = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue));
+
+               error = curl_easy_setopt(ch->cp, option, copystr);
+               zend_llist_add_element(&ch->to_free.str, &copystr);
+
+               break;
+       }
+       case CURLOPT_FILE:   
+       case CURLOPT_INFILE: 
+       case CURLOPT_WRITEHEADER:
+       case CURLOPT_STDERR: {
+               FILE *fp;
+               ZEND_FETCH_RESOURCE(fp, FILE *, zvalue, -1, "File-Handle", php_file_le_fopen());
+
+               error = curl_easy_setopt(ch->cp, option, fp);
+               if (option == CURLOPT_FILE) {
+                       ch->write->method = PHP_CURL_FILE;
+               }
+
+               if (option == CURLOPT_INFILE) {
+                       ch->read->fd = Z_LVAL_PP(zvalue);
+               }
+
+               break;
+       }
+       case CURLOPT_RETURNTRANSFER:
+               convert_to_long_ex(zvalue);
+
+               if (Z_LVAL_PP(zvalue)) {
+                       ch->write->method = PHP_CURL_RETURN;
+               }
+               break;
+       case CURLOPT_WRITEFUNCTION:
+               zval_add_ref(zvalue);
+               ch->write->func = *zvalue;
+               ch->write->method = PHP_CURL_USER;
+               break;
+       case CURLOPT_READFUNCTION:
+               zval_add_ref(zvalue);
+               ch->read->func   = *zvalue;
+               ch->read->method = PHP_CURL_USER;
+               break;
+       case CURLOPT_HEADERFUNCTION:
+               zval_add_ref(zvalue);
+               ch->handlers->write_header = *zvalue;
+               error = curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, _php_curl_write_header);
+               error = curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTIONDATA, (void *) ch);
+               break;
+       case CURLOPT_PASSWDFUNCTION:
+               zval_add_ref(zvalue);
+               ch->handlers->passwd = *zvalue;
+               error = curl_easy_setopt(ch->cp, CURLOPT_PASSWDFUNCTION, _php_curl_passwd);
+               error = curl_easy_setopt(ch->cp, CURLOPT_PASSWDDATA,     (void *) ch);
+               break;
+       case CURLOPT_POSTFIELDS:
+               if (Z_TYPE_PP(zvalue) == IS_ARRAY || Z_TYPE_PP(zvalue) == IS_OBJECT) {
+                       zval            **current;
+                       HashTable        *postfields;
+                       struct HttpPost  *first = NULL;
+                       struct HttpPost  *last  = NULL;
        
-       switch (option) {
-               case CURLOPT_INFILESIZE:      case CURLOPT_VERBOSE:    case CURLOPT_HEADER:
-               case CURLOPT_NOPROGRESS:      case CURLOPT_NOBODY:     case CURLOPT_FAILONERROR:
-               case CURLOPT_UPLOAD:          case CURLOPT_POST:       case CURLOPT_FTPLISTONLY:
-               case CURLOPT_FTPAPPEND:       case CURLOPT_NETRC:      case CURLOPT_FOLLOWLOCATION:
-               case CURLOPT_PUT:             case CURLOPT_MUTE:       case CURLOPT_TIMEOUT:
-               case CURLOPT_LOW_SPEED_LIMIT: case CURLOPT_SSLVERSION: case CURLOPT_LOW_SPEED_TIME:
-               case CURLOPT_RESUME_FROM:     case CURLOPT_TIMEVALUE:  case CURLOPT_TIMECONDITION:
-               case CURLOPT_TRANSFERTEXT:
-#if LIBCURL_VERSION_NUM >= 0x070300
-               case CURLOPT_HTTPPROXYTUNNEL:
-#endif
-               
-                       convert_to_long_ex(curl_value);
-                       ret = curl_easy_setopt(curl_handle->cp, option, Z_LVAL_PP(curl_value));
-                       break;
-               
-               case CURLOPT_URL:           case CURLOPT_PROXY:         case CURLOPT_USERPWD:
-               case CURLOPT_PROXYUSERPWD:  case CURLOPT_RANGE:         case CURLOPT_CUSTOMREQUEST:
-               case CURLOPT_USERAGENT:     case CURLOPT_FTPPORT:       case CURLOPT_COOKIE:
-               case CURLOPT_SSLCERT:       case CURLOPT_SSLCERTPASSWD: case CURLOPT_COOKIEFILE:
-               case CURLOPT_REFERER:
-#if LIBCURL_VERSION_NUM >= 0x070300
-               case CURLOPT_INTERFACE: case CURLOPT_KRB4LEVEL:
-#endif
-               
-                       {
-                               char *copystr = NULL;
-                               
-                               convert_to_string_ex(curl_value);
-                               copystr = estrndup(Z_STRVAL_PP(curl_value), Z_STRLEN_PP(curl_value));
-                               
-                               ret = curl_easy_setopt(curl_handle->cp, option, copystr);
-                               zend_llist_add_element(&curl_handle->to_free, &copystr);
-                       }
-                       break;
-                       
-               case CURLOPT_FILE:   
-               case CURLOPT_INFILE: 
-               case CURLOPT_WRITEHEADER:
-               case CURLOPT_STDERR: 
-
-                       {
-                               FILE *fp;
-                           
-                               ZEND_FETCH_RESOURCE(fp, FILE *, curl_value, -1, "File-Handle", php_file_le_fopen());
-                               ret = curl_easy_setopt(curl_handle->cp, option, fp);
-                           
-                               if (option & CURLOPT_FILE) {
-                                       curl_handle->output_file = Z_LVAL_PP(curl_value);
-                                       curl_handle->php_stdout  = 0;
-                               }
+                       postfields = HASH_OF(*zvalue);
+                       if (! postfields) {
+                               php_error(E_WARNING, "Couldn't get HashTable in CURLOPT_POSTFIELDS");
+                               RETURN_FALSE;
                        }
-                       break;
-               
-               case CURLOPT_RETURNTRANSFER:
-                       
-                       convert_to_long_ex(curl_value);
-
-                       curl_handle->return_transfer = Z_LVAL_PP(curl_value);
-                       curl_handle->php_stdout      = !Z_LVAL_PP(curl_value);
-                       break;
-               
-               case CURLOPT_POSTFIELDS:
-               
-                       if (Z_TYPE_PP(curl_value) == IS_ARRAY ||
-                           Z_TYPE_PP(curl_value) == IS_OBJECT) {
-                               
-                               zval **current;
-                               HashTable *u_post = HASH_OF(*curl_value);
 
-                               struct HttpPost *first = NULL, 
-                                               *last  = NULL;
-                               
-                               for (zend_hash_internal_pointer_reset(u_post);
-                                    zend_hash_get_current_data(u_post, (void **)&current) == SUCCESS;
-                                    zend_hash_move_forward(u_post)) {
-
-                                       char *string_key = NULL, 
-                                            *str        = NULL, 
-                                                *val_str    = NULL;
-                                       ulong num_key;
-                                       
-                                       SEPARATE_ZVAL(current);
-                                       convert_to_string_ex(current);
-                                       
-                                       if (zend_hash_get_current_key(u_post, &string_key, &num_key, 0) == HASH_KEY_IS_LONG) {
-                                               string_key = emalloc(20);
-                                               sprintf(string_key, "%d", num_key);
-                                       }
-                                       
-                                       val_str = estrndup(Z_STRVAL_PP(current), Z_STRLEN_PP(current));
-                                       
-                                       str = emalloc(strlen(string_key) + strlen(val_str) + 1 + 2);
-                                       sprintf(str, "%s=%s", string_key, val_str);
+                       for (zend_hash_internal_pointer_reset(postfields);
+                            zend_hash_get_current_data(postfields, (void **) &current) == SUCCESS;
+                            zend_hash_move_forward(postfields)) {
+                               char  *string_key = NULL;
+                               char  *postval    = NULL;
+                               ulong  num_key;
 
-                                       ret = curl_formparse(str, &first, &last);
+                               SEPARATE_ZVAL(current);
+                               convert_to_string_ex(current);
 
-                                       efree(string_key);
-                                       efree(val_str);
-                               }
-                               
-                               if (ret != CURLE_OK) {
-                                       SAVE_CURL_ERROR(curl_handle, ret);
-                                       RETURN_FALSE;
-                               }
-                               
-                               ret = curl_easy_setopt(curl_handle->cp, CURLOPT_HTTPPOST, first);
-                       } else {
-                               
-                               char *post_str = NULL;
+                               zend_hash_get_current_key(postfields, &string_key, &num_key, 0);
 
-                               convert_to_string_ex(curl_value);
-                               post_str = estrndup(Z_STRVAL_PP(curl_value), Z_STRLEN_PP(curl_value));
+                               postval = emalloc(strlen(string_key) + Z_STRLEN_PP(current) + 1);
+                               sprintf(postval, "%s=%s", string_key, Z_STRVAL_PP(current));
 
-                               ret = curl_easy_setopt(curl_handle->cp, CURLOPT_POSTFIELDS, post_str);
-#if LIBCURL_VERSION_NUM >= 0x070300
-                               ret = curl_easy_setopt(curl_handle->cp, CURLOPT_POSTFIELDSIZE, Z_STRLEN_PP(curl_value));
-#endif
-                               if (ret != CURLE_OK) {
-                                       SAVE_CURL_ERROR(curl_handle, ret);
-                                       RETURN_FALSE;
-                               }
-                               
-                               ret = curl_easy_setopt(curl_handle->cp, CURLOPT_POSTFIELDSIZE, Z_STRLEN_PP(curl_value));
-                               break;
-                       
+                               error = curl_formparse(postval, &first, &last);
                        }
-                       break;
-               
-               case CURLOPT_HTTPHEADER:
-               
-                       {
-                               zval **current;
-                               HashTable *headers = HASH_OF(*curl_value);
-                               struct curl_slist *header = NULL;
-                               
-                               if (!headers) {
-                                       RETURN_FALSE;
-                               }
-                               
-                               for (zend_hash_internal_pointer_reset(headers);
-                                    zend_hash_get_current_data(headers, (void **)&current) == SUCCESS;
-                                        zend_hash_move_forward(headers)) {
-                                       char *indiv_header = NULL;
-                               
-                                       SEPARATE_ZVAL(current);
-                                       convert_to_string_ex(current);
-                                       
-                                       indiv_header = estrndup(Z_STRVAL_PP(current), Z_STRLEN_PP(current));
-                                       header = curl_slist_append(header, indiv_header);
-                                       if (!header) {
-                                               php_error(E_WARNING, "Couldn't build header from %s()", get_active_function_name());
-                                               efree(indiv_header);
-                                               RETURN_FALSE;
-                                       }
-
-                               }
-                               
-                               ret = curl_easy_setopt(curl_handle->cp, CURLOPT_HTTPHEADER, header);
+
+                       if (error != CURLE_OK) {
+                               SAVE_CURL_ERROR(ch, error);
+                               RETURN_FALSE;
                        }
-                       break;
-               
-               case CURLOPT_QUOTE: 
-               case CURLOPT_POSTQUOTE:
-               
-                       {
-                               zval **current;
-                               HashTable *php_commands = HASH_OF(*curl_value);
-                               struct curl_slist *commands = NULL;
-                               
-                               if (!php_commands) {
-                                       RETURN_FALSE;
-                               }
-
-                               for (zend_hash_internal_pointer_reset(php_commands);
-                                    zend_hash_get_current_data(php_commands, (void **)&current) == SUCCESS;
-                                        zend_hash_move_forward(php_commands)) {
-                                       char *indiv_command = NULL;
-                                       
-                                       SEPARATE_ZVAL(current);
-                                       convert_to_string_ex(current);
-                                       
-                                       if (Z_STRLEN_PP(current) < 1) {
-                                               continue;
-                                       }
-
-                                       indiv_command = estrndup(Z_STRVAL_PP(current), Z_STRLEN_PP(current));
-                                       commands = curl_slist_append(commands, indiv_command);
-                                       if (!commands) {
-                                               php_error(E_WARNING, "Couldn't build command list from %s()", get_active_function_name());
-                                               efree(indiv_command);
-                                               RETURN_FALSE;
-                                       }
-                                       
-                               }
-                               
-                               ret = curl_easy_setopt(curl_handle->cp, option, commands); 
+
+                       zend_llist_add_element(&ch->to_free.post, &first);
+                       error = curl_easy_setopt(ch->cp, CURLOPT_HTTPPOST, &first);
+               }
+               else {
+                       char *post = NULL;
+
+                       convert_to_string_ex(zvalue);
+                       post = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue));
+                       zend_llist_add_element(&ch->to_free.str, &post);
+
+                       error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, post);
+                       error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, Z_STRLEN_PP(zvalue));
+               }
+
+               break;
+       case CURLOPT_HTTPHEADER: 
+       case CURLOPT_QUOTE:
+       case CURLOPT_POSTQUOTE: {
+               zval              **current;
+               HashTable          *hash;
+               struct curl_slist  *slist = NULL;
+
+               hash = HASH_OF(*zvalue);
+               if (! hash) {
+                       php_error(E_WARNING, 
+                                 "You must pass either an object or an array with the CURLOPT_HTTPHEADER, CURLOPT_QUOTE and CURLOPT_POSTQUOTE arguments");
+                       RETURN_FALSE;
+               }
+
+               for (zend_hash_internal_pointer_reset(hash);
+                    zend_hash_get_current_data(hash, (void **) &current) == SUCCESS;
+                    zend_hash_move_forward(hash)) {
+                       char *indiv = NULL;
+
+                       SEPARATE_ZVAL(current);
+                       convert_to_string_ex(current);
+
+                       indiv = estrndup(Z_STRVAL_PP(current), Z_STRLEN_PP(current));
+                       slist = curl_slist_append(slist, indiv);
+                       if (! slist) {
+                               efree(indiv);
+                               php_error(E_WARNING, "Couldn't build curl_slist from curl_setopt()");
+                               RETURN_FALSE;
                        }
-                       break;
+                       zend_llist_add_element(&ch->to_free.str, &indiv);
+               }
+               zend_llist_add_element(&ch->to_free.slist, &slist);
+
+               error = curl_easy_setopt(ch->cp, option, slist);
+
+               break;
+       }
        }
        
-       if (ret != CURLE_OK) {
-               SAVE_CURL_ERROR(curl_handle, ret);
+       if (error != CURLE_OK) {
+               SAVE_CURL_ERROR(ch, error);
                RETURN_FALSE;
        } else {
                RETURN_TRUE;
@@ -557,209 +766,142 @@ PHP_FUNCTION(curl_setopt)
    Perform a CURL session */
 PHP_FUNCTION(curl_exec)
 {
-       zval **curl_id;
-       php_curl *curl_handle;
-       CURLcode ret;
-       FILE *fp;
-       char buf[4096];
-       int b,
-           is_temp_file;
-       unsigned long pos = 0;
-       
+       zval      **zid;
+       php_curl   *ch;
+       CURLcode    error;
+
        if (ZEND_NUM_ARGS() != 1 ||
-           zend_get_parameters_ex(1, &curl_id) == FAILURE) {
+           zend_get_parameters_ex(1, &zid) == FAILURE) {
                WRONG_PARAM_COUNT;
        }
-       
-       ZEND_FETCH_RESOURCE(curl_handle, php_curl *, curl_id, -1, "CURL Handle", le_curl);
-       
-       if ((curl_handle->return_transfer &&
-           !curl_handle->output_file) || curl_handle->php_stdout) {
-               
-               if ((fp = tmpfile()) == NULL) {
-                       php_error(E_WARNING, "Cannot initialize temporary file to save output from %s()", get_active_function_name());
-                       RETURN_FALSE;
-               }
-               curl_handle->tmp_fp = fp;
-
-               curl_easy_setopt(curl_handle->cp, CURLOPT_FILE, fp);            
-       
-               is_temp_file = 1;
-       
-       } else if (curl_handle->return_transfer &&
-                  curl_handle->output_file) {
-
-               ZEND_FETCH_RESOURCE(fp, FILE *, (zval **) NULL, curl_handle->output_file, "File-Handle", php_file_le_fopen());
+       ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
 
+       error = curl_easy_perform(ch->cp);
+       if (error != CURLE_OK) {
+               SAVE_CURL_ERROR(ch, error);
+               RETURN_FALSE;
        }
-       
-       ret = curl_easy_perform(curl_handle->cp);
-       
-       if ((!curl_handle->return_transfer && !curl_handle->php_stdout) ||
-           (ret != CURLE_OK)) {
-       
-               if (ret != CURLE_OK) {
-                       SAVE_CURL_ERROR(curl_handle, ret);
-                       RETVAL_FALSE;
-               } else {
-                       RETVAL_TRUE;
-               }
-               
-               if (fp && is_temp_file) 
-                       fclose(fp);
 
-               return;
+       if (ch->write->method == PHP_CURL_RETURN) {
+               smart_str_0(&ch->write->buf);
+               RETURN_STRINGL(ch->write->buf.c, ch->write->buf.len, 1);
+               smart_str_free(&ch->write->buf);
        }
-       
-       fseek(fp, 0, SEEK_SET);
-
-       if (curl_handle->php_stdout) {
-               
-               while ((b = fread(buf, 1, sizeof(buf), fp)) > 0) {
-                       php_write(buf, b);
-               }
-
-               if (is_temp_file)
-                       fclose(fp);
-
-       } else {
-
-               char *ret_data;
-               struct stat stat_sb;
-
-               if (fstat(fileno(fp), &stat_sb)) {
-                       if (is_temp_file) {
-                               fclose(fp);
-                       }
-                       RETURN_FALSE;
-               }
-                               
-               ret_data = (char *) emalloc(stat_sb.st_size + 1);
-
-               while ((b = fread(buf, 1, sizeof(buf), fp)) > 0) {
-                       memcpy(ret_data + pos, buf, b);
-                       pos += b;
-               }
-               ret_data[stat_sb.st_size] = '\0';
-
-               if (is_temp_file)
-                       fclose(fp);
-
-               RETURN_STRINGL(ret_data, stat_sb.st_size + 1, 0);
-
+       else if (ch->write->method == PHP_CURL_STDOUT) {
+               smart_str_0(&ch->write->buf);
+               PUTS(ch->write->buf.c);
+               smart_str_free(&ch->write->buf);
        }
 
+       RETURN_TRUE;
 }
 /* }}} */
 
-#if LIBCURL_VERSION_NUM >= 0x070401
 /* {{{ proto string curl_getinfo(int ch, int opt)
    Get information regarding a specific transfer */
 PHP_FUNCTION(curl_getinfo)
 {
-       zval **curl_id, **curl_opt;
-       php_curl *curl_handle;
-       int opt,
-           argc = ZEND_NUM_ARGS();
-       
+       zval       **zid, 
+                  **zoption;
+       php_curl    *ch;
+       int          option,
+                    argc = ZEND_NUM_ARGS();
+
        if (argc < 1 || argc > 2 ||
-           zend_get_parameters_ex(argc, &curl_id, &curl_opt) == FAILURE) {
+           zend_get_parameters_ex(argc, &zid, &zoption) == FAILURE) {
                WRONG_PARAM_COUNT;
        }
-       ZEND_FETCH_RESOURCE(curl_handle, php_curl *, curl_id, -1, "CURL Handle", le_curl);
+       ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
 
        if (argc < 2) {
-               char *url;
-               long l_code;
-               double d_code;
+               char   *url;
+               long    l_code;
+               double  d_code;
 
                array_init(return_value);
 
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_EFFECTIVE_URL, &url);
+               curl_easy_getinfo(ch->cp, CURLINFO_EFFECTIVE_URL, &url);
                add_assoc_string(return_value, "url", url, 1);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_HTTP_CODE, &l_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_HTTP_CODE, &l_code);
                add_assoc_long(return_value, "http_code", l_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_HEADER_SIZE, &l_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_HEADER_SIZE, &l_code);
                add_assoc_long(return_value, "header_size", l_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_REQUEST_SIZE, &l_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_REQUEST_SIZE, &l_code);
                add_assoc_long(return_value, "request_size", l_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_TOTAL_TIME, &d_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_FILETIME, &l_code);
+               add_assoc_long(return_value, "filetime", l_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_TOTAL_TIME, &d_code);
                add_assoc_double(return_value, "total_time", d_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_NAMELOOKUP_TIME, &d_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_NAMELOOKUP_TIME, &d_code);
                add_assoc_double(return_value, "namelookup_time", d_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_CONNECT_TIME, &d_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_CONNECT_TIME, &d_code);
                add_assoc_double(return_value, "connect_time", d_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_PRETRANSFER_TIME, &d_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_PRETRANSFER_TIME, &d_code);
                add_assoc_double(return_value, "pretransfer_time", d_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_SIZE_UPLOAD, &d_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_SIZE_UPLOAD, &d_code);
                add_assoc_double(return_value, "size_upload", d_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_SIZE_DOWNLOAD, &d_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_SIZE_DOWNLOAD, &d_code);
                add_assoc_double(return_value, "size_download", d_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_SPEED_DOWNLOAD, &d_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_SPEED_DOWNLOAD, &d_code);
                add_assoc_double(return_value, "speed_download", d_code);
-
-               curl_easy_getinfo(curl_handle->cp, CURLINFO_SPEED_UPLOAD, &d_code);
+               curl_easy_getinfo(ch->cp, CURLINFO_SPEED_UPLOAD, &d_code);
                add_assoc_double(return_value, "speed_upload", d_code);
        } else {
-               opt = Z_LVAL_PP(curl_opt);
-               switch (opt) {
-                       case CURLINFO_EFFECTIVE_URL:
-                               {
-                                       char *url;
-       
-                                       curl_easy_getinfo(curl_handle->cp, opt, &url);
-       
-                                       RETURN_STRING(url, 1);
-                               }
-                               break;
-                       case CURLINFO_HTTP_CODE: case CURLINFO_HEADER_SIZE: case CURLINFO_REQUEST_SIZE:
-                               {
-                                       long code;
+               option = Z_LVAL_PP(zoption);
+               switch (option) {
+               case CURLINFO_EFFECTIVE_URL: {
+                       char *url;
+
+                       curl_easy_getinfo(ch->cp, option, &url);
+                       RETURN_STRING(url, 1);
+
+                       break;
+               }
+               case CURLINFO_HTTP_CODE: 
+               case CURLINFO_HEADER_SIZE: 
+               case CURLINFO_REQUEST_SIZE: 
+               case CURLINFO_FILETIME: {
+                       long code;
                                        
-                                       curl_easy_getinfo(curl_handle->cp, opt, &code);
-                                       RETURN_LONG(code);
-                               }
-                               break;
-                       case CURLINFO_TOTAL_TIME: case CURLINFO_NAMELOOKUP_TIME: case CURLINFO_CONNECT_TIME:
-                       case CURLINFO_PRETRANSFER_TIME: case CURLINFO_SIZE_UPLOAD: case CURLINFO_SIZE_DOWNLOAD:
-                       case CURLINFO_SPEED_DOWNLOAD: case CURLINFO_SPEED_UPLOAD:
-                               {
-                                       double code;
+                       curl_easy_getinfo(ch->cp, option, &code);
+                       RETURN_LONG(code);
+                               
+                       break;
+               }
+               case CURLINFO_TOTAL_TIME: 
+               case CURLINFO_NAMELOOKUP_TIME: 
+               case CURLINFO_CONNECT_TIME:
+               case CURLINFO_PRETRANSFER_TIME: 
+               case CURLINFO_SIZE_UPLOAD: 
+               case CURLINFO_SIZE_DOWNLOAD:
+               case CURLINFO_SPEED_DOWNLOAD: 
+               case CURLINFO_SPEED_UPLOAD: {
+                       double code;
        
-                                       curl_easy_getinfo(curl_handle->cp, opt, &code);
-                                       RETURN_DOUBLE(code);
-                               }
-                               break;
+                       curl_easy_getinfo(ch->cp, option, &code);
+                       RETURN_DOUBLE(code);
+
+                       break;
+               }
                }
        }                       
 }
 /* }}} */
-#endif
 
 /* {{{ proto string curl_error(int ch)
    Return a string contain the last error for the current session */
 PHP_FUNCTION(curl_error)
 {
-       zval **curl_id;
-       php_curl *curl_handle;
+       zval      **zid;
+       php_curl   *ch;
        
        if (ZEND_NUM_ARGS() != 1 ||
-           zend_get_parameters_ex(1, &curl_id) == FAILURE) {
+           zend_get_parameters_ex(1, &zid) == FAILURE) {
                WRONG_PARAM_COUNT;
        }
+       ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
 
-       ZEND_FETCH_RESOURCE(curl_handle, php_curl *, curl_id, -1, "CURL Handle", le_curl);
-       RETURN_STRING(curl_handle->error, 1);
+       RETURN_STRING(ch->err.str, 1);
 }
 /* }}} */
 
@@ -767,16 +909,16 @@ PHP_FUNCTION(curl_error)
    Return an integer containing the last error number */
 PHP_FUNCTION(curl_errno)
 {
-       zval **curl_id;
-       php_curl *curl_handle;
-       
+       zval      **zid;
+       php_curl   *ch;
+
        if (ZEND_NUM_ARGS() != 1 ||
-           zend_get_parameters_ex(1, &curl_id) == FAILURE) {
+           zend_get_parameters_ex(1, &zid) == FAILURE) {
                WRONG_PARAM_COUNT;
        }
-       
-       ZEND_FETCH_RESOURCE(curl_handle, php_curl *, curl_id, -1, "CURL Handle", le_curl);
-       RETURN_LONG(curl_handle->cerrno);
+       ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
+
+       RETURN_LONG(ch->err.no);
 }
 /* }}} */
 
@@ -784,17 +926,16 @@ PHP_FUNCTION(curl_errno)
    Close a CURL session */
 PHP_FUNCTION(curl_close)
 {
-       zval **curl_id;
-       php_curl *curl_handle;
-       
+       zval      **zid;
+       php_curl   *ch;
+
        if (ZEND_NUM_ARGS() != 1 ||
-           zend_get_parameters_ex(1, &curl_id) == FAILURE) {
+           zend_get_parameters_ex(1, &zid) == FAILURE) {
                WRONG_PARAM_COUNT;
        }
+       ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
        
-       ZEND_FETCH_RESOURCE(curl_handle, php_curl *, curl_id, -1, "CURL Handle", le_curl);
-       
-       zend_list_delete(Z_LVAL_PP(curl_id));
+       zend_list_delete(Z_LVAL_PP(zid));
 }
 /* }}} */
 
@@ -802,12 +943,23 @@ PHP_FUNCTION(curl_close)
    List destructor for curl handles */
 static void _php_curl_close(zend_rsrc_list_entry *rsrc)
 {
-       php_curl *curl_handle = (php_curl *)rsrc->ptr;
-       curl_easy_cleanup(curl_handle->cp);
-       if (curl_handle->tmp_fp) fclose(curl_handle->tmp_fp);
-       zend_llist_clean(&curl_handle->to_free);
-       efree(curl_handle);
-}
+       php_curl *ch = (php_curl *) rsrc->ptr;
+
+       curl_easy_cleanup(ch->cp);
+       zend_llist_clean(&ch->to_free.str);
+       zend_llist_clean(&ch->to_free.slist);
+       zend_llist_clean(&ch->to_free.post);
+
+       if (ch->write->func) zval_ptr_dtor(&ch->write->func);
+       if (ch->read->func)  zval_ptr_dtor(&ch->read->func);
+       if (ch->handlers->write_header) zval_ptr_dtor(&ch->handlers->write_header);
+       if (ch->handlers->passwd) zval_ptr_dtor(&ch->handlers->passwd);
+
+       efree(ch->write);
+       efree(ch->read);
+       efree(ch->handlers);
+       efree(ch);
+}      
 /* }}} */
 
 #endif
index 58ee10aa2be842af150819792eeac3ccd06f23eb..326318e75acb713058731ad8749d7a2311571aee 100644 (file)
@@ -21,6 +21,9 @@
 #ifndef _PHP_CURL_H
 #define _PHP_CURL_H
 
+#include "php.h"
+#include "ext/standard/php_smart_str.h"
+
 #ifdef COMPILE_DL_CURL
 #undef HAVE_CURL
 #define HAVE_CURL 1
@@ -30,6 +33,7 @@
 
 #include <curl/curl.h>
 
+
 extern zend_module_entry curl_module_entry;
 #define curl_module_ptr &curl_module_entry
 
@@ -42,22 +46,47 @@ PHP_FUNCTION(curl_version);
 PHP_FUNCTION(curl_init);
 PHP_FUNCTION(curl_setopt);
 PHP_FUNCTION(curl_exec);
-#if LIBCURL_VERSION_NUM >= 0x070401
 PHP_FUNCTION(curl_getinfo);
-#endif
 PHP_FUNCTION(curl_error);
 PHP_FUNCTION(curl_errno);
 PHP_FUNCTION(curl_close);
 
 typedef struct {
-       int return_transfer;
-       int output_file;
-       int php_stdout;
-       int cerrno;
-       char error[CURL_ERROR_SIZE+1];
-       FILE *tmp_fp;
-       CURL *cp;
-       zend_llist to_free;
+       zval         *func;
+       smart_str     buf;
+       int           method;
+} php_curl_write;
+
+typedef struct {
+       zval         *func;
+       long          fd;
+       int           method;
+} php_curl_read;
+
+typedef struct {
+       zval *write_header;
+       zval *passwd;
+} php_curl_handlers;
+
+struct _php_curl_error  {
+       char str[CURL_ERROR_SIZE + 1];
+       int  no;
+};
+
+struct _php_curl_free {
+       zend_llist str;
+       zend_llist post;
+       zend_llist slist;
+};
+
+typedef struct {
+       CURL                    *cp;
+       php_curl_write          *write;
+       php_curl_read           *read;
+       php_curl_handlers       *handlers;
+       struct _php_curl_error   err;
+       struct _php_curl_free    to_free;
+       long                     id;
 } php_curl;