add multi support and reorganize things a bit...

This commit is contained in:
Sterling Hughes 2002-11-13 22:25:33 +00:00
parent ae1fcb4542
commit 537284418c
7 changed files with 382 additions and 39 deletions

View File

@ -1,2 +1,2 @@
CURL
cURL
Sterling Hughes

View File

@ -1,5 +1,5 @@
dnl
dnl $Id$
dnl $Id$
dnl
PHP_ARG_WITH(curl, for CURL support,
@ -29,7 +29,7 @@ if test "$PHP_CURL" != "no"; then
fi
CURL_CONFIG="curl-config"
AC_MSG_CHECKING(for cURL 7.9.8 or greater)
AC_MSG_CHECKING(for cURL 7.10.2 or greater)
if ${CURL_DIR}/bin/curl-config --libs print > /dev/null 2>&1; then
CURL_CONFIG=${CURL_DIR}/bin/curl-config
@ -41,11 +41,11 @@ if test "$PHP_CURL" != "no"; then
curl_version_full=`$CURL_CONFIG --version`
curl_version=`echo ${curl_version_full} | sed -e 's/libcurl //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
if test "$curl_version" -ge 7009008; then
if test "$curl_version" -ge 7010002; then
AC_MSG_RESULT($curl_version_full)
CURL_LIBS=`$CURL_CONFIG --libs`
else
AC_MSG_ERROR(cURL version 7.9.8 or later is required to compile php with cURL support)
AC_MSG_ERROR(cURL version 7.10.2 or later is required to compile php with cURL support)
fi
PHP_ADD_INCLUDE($CURL_DIR/include)
@ -72,6 +72,6 @@ dnl if test "$PHP_CURLWRAPPERS" != "no" ; then
dnl AC_DEFINE(PHP_CURL_URL_WRAPPERS,1,[ ])
dnl fi
PHP_NEW_EXTENSION(curl, curl.c curlstreams.c, $ext_shared)
PHP_NEW_EXTENSION(curl, interface.c multi.c streams.c, $ext_shared)
PHP_SUBST(CURL_SHARED_LIBADD)
fi

View File

@ -158,8 +158,17 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\curl.c
SOURCE=.\interface.c
# End Source File
# Begin Source File
SOURCE=.\multi.c
# End Source File
# Begin Source File
SOURCE=.\streams.c
# End Source File
# End Group
# Begin Group "Header Files"

View File

@ -44,8 +44,7 @@
#include "ext/standard/file.h"
#include "php_curl.h"
static int le_curl;
#define le_curl_name "cURL handle"
static unsigned char second_arg_force_ref[] = {2, BYREF_NONE, BYREF_FORCE};
static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC);
@ -59,14 +58,22 @@ static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC);
/* {{{ curl_functions[]
*/
function_entry curl_functions[] = {
PHP_FE(curl_init, NULL)
PHP_FE(curl_version, NULL)
PHP_FE(curl_setopt, NULL)
PHP_FE(curl_exec, NULL)
PHP_FE(curl_getinfo, NULL)
PHP_FE(curl_error, NULL)
PHP_FE(curl_errno, NULL)
PHP_FE(curl_close, NULL)
PHP_FE(curl_init, NULL)
PHP_FE(curl_version, NULL)
PHP_FE(curl_setopt, NULL)
PHP_FE(curl_exec, NULL)
PHP_FE(curl_getinfo, NULL)
PHP_FE(curl_error, NULL)
PHP_FE(curl_errno, NULL)
PHP_FE(curl_close, NULL)
PHP_FE(curl_multi_init, NULL)
PHP_FE(curl_multi_add_handle, NULL)
PHP_FE(curl_multi_remove_handle, NULL)
PHP_FE(curl_multi_select, NULL)
PHP_FE(curl_multi_exec, second_arg_force_ref)
PHP_FE(curl_multi_getcontent, NULL)
PHP_FE(curl_multi_info_read, NULL)
PHP_FE(curl_multi_close, NULL)
{NULL, NULL, NULL}
};
/* }}} */
@ -109,6 +116,7 @@ PHP_MINFO_FUNCTION(curl)
PHP_MINIT_FUNCTION(curl)
{
le_curl = zend_register_list_destructors_ex(_php_curl_close, NULL, "curl", module_number);
le_curl_multi_handle = zend_register_list_destructors_ex(_php_curl_multi_close, NULL, "curl", module_number);
/* Constants for curl_setopt() */
REGISTER_CURL_CONSTANT(CURLOPT_DNS_USE_GLOBAL_CACHE);
@ -183,6 +191,9 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLOPT_COOKIEJAR);
REGISTER_CURL_CONSTANT(CURLOPT_SSL_CIPHER_LIST);
REGISTER_CURL_CONSTANT(CURLOPT_BINARYTRANSFER);
REGISTER_CURL_CONSTANT(CURLOPT_NOSIGNAL);
REGISTER_CURL_CONSTANT(CURLOPT_PROXYTYPE);
REGISTER_CURL_CONSTANT(CURLOPT_BUFFERSIZE);
REGISTER_CURL_CONSTANT(CURLOPT_HTTPGET);
REGISTER_CURL_CONSTANT(CURLOPT_HTTP_VERSION);
REGISTER_CURL_CONSTANT(CURLOPT_SSLKEY);
@ -221,6 +232,15 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_TIME);
REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_COUNT);
/* cURL protocol constants (curl_version) */
REGISTER_CURL_CONSTANT(CURL_VERSION_IPV6);
REGISTER_CURL_CONSTANT(CURL_VERSION_KERBEROS4);
REGISTER_CURL_CONSTANT(CURL_VERSION_SSL);
REGISTER_CURL_CONSTANT(CURL_VERSION_LIBZ);
/* version constants */
REGISTER_CURL_CONSTANT(CURLVERSION_NOW);
/* Error Constants */
REGISTER_CURL_CONSTANT(CURLE_OK);
REGISTER_CURL_CONSTANT(CURLE_UNSUPPORTED_PROTOCOL);
@ -275,6 +295,9 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLE_OBSOLETE);
REGISTER_CURL_CONSTANT(CURLE_SSL_PEER_CERTIFICATE);
REGISTER_CURL_CONSTANT(CURLPROXY_HTTP);
REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5);
REGISTER_CURL_CONSTANT(CURL_NETRC_OPTIONAL);
REGISTER_CURL_CONSTANT(CURL_NETRC_IGNORED);
REGISTER_CURL_CONSTANT(CURL_NETRC_REQUIRED);
@ -283,6 +306,14 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_0);
REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_1);
REGISTER_CURL_CONSTANT(CURLM_CALL_MULTI_PERFORM);
REGISTER_CURL_CONSTANT(CURLM_OK);
REGISTER_CURL_CONSTANT(CURLM_BAD_HANDLE);
REGISTER_CURL_CONSTANT(CURLM_BAD_EASY_HANDLE);
REGISTER_CURL_CONSTANT(CURLM_OUT_OF_MEMORY);
REGISTER_CURL_CONSTANT(CURLM_INTERNAL_ERROR);
REGISTER_CURL_CONSTANT(CURLMSG_DONE);
if (curl_global_init(CURL_GLOBAL_SSL) != CURLE_OK) {
return FAILURE;
@ -315,15 +346,6 @@ PHP_MSHUTDOWN_FUNCTION(curl)
}
/* }}} */
#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
#define PHP_CURL_ASCII 5
#define PHP_CURL_BINARY 6
#define PHP_CURL_IGNORE 7
/* {{{ curl_write
*/
static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
@ -333,6 +355,12 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
size_t length = size * nmemb;
TSRMLS_FETCH();
#if PHP_CURL_DEBUG
fprintf(stderr, "curl_write() called\n");
fprintf(stderr, "data = %s, size = %d, nmemb = %d, ctx = %x\n",
data, size, nmemb, ctx);
#endif
switch (t->method) {
case PHP_CURL_STDOUT:
PUTS(data);
@ -569,15 +597,45 @@ static void curl_free_slist(void **slist)
/* }}} */
/* {{{ proto array curl_version(void)
/* {{{ proto array curl_version([int version])
Return cURL version information. */
PHP_FUNCTION(curl_version)
{
if (ZEND_NUM_ARGS() != 0) {
WRONG_PARAM_COUNT;
curl_version_info_data *d;
long uversion = CURLVERSION_NOW;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &uversion) == FAILURE) {
return;
}
RETURN_STRING(curl_version(), 1);
d = curl_version_info(uversion);
if (d == NULL) {
RETURN_FALSE;
}
array_init(return_value);
CAAL("version_number", d->version_num);
CAAL("age", d->age);
CAAL("features", d->features);
CAAL("ssl_version_number", d->ssl_version_num);
CAAS("version", d->version);
CAAS("host", d->host);
CAAS("ssl_version", d->ssl_version);
CAAS("libz_version", d->libz_version);
/* Add an array of protocols */
{
char **p = (char **) d->protocols;
zval *protocol_list = NULL;
MAKE_STD_ZVAL(protocol_list);
array_init(protocol_list);
while (*p != NULL) {
add_next_index_string(protocol_list, *p++, 1);
}
CAAZ("protocols", protocol_list);
}
}
/* }}} */
@ -707,6 +765,9 @@ PHP_FUNCTION(curl_setopt)
case CURLOPT_SSL_VERIFYHOST:
case CURLOPT_SSL_VERIFYPEER:
case CURLOPT_DNS_USE_GLOBAL_CACHE:
case CURLOPT_NOSIGNAL:
case CURLOPT_PROXYTYPE:
case CURLOPT_BUFFERSIZE:
case CURLOPT_HTTPGET:
case CURLOPT_HTTP_VERSION:
case CURLOPT_CRLF:
@ -956,10 +1017,10 @@ PHP_FUNCTION(curl_setopt)
}
/* }}} */
/* {{{ cleanup_handle(ch)
/* {{{ _php_curl_cleanup_handle(ch)
Cleanup an execution phase */
static void
cleanup_handle(php_curl *ch)
void
_php_curl_cleanup_handle(php_curl *ch)
{
if (ch->uses < 1) {
return;
@ -988,7 +1049,7 @@ PHP_FUNCTION(curl_exec)
}
ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
cleanup_handle(ch);
_php_curl_cleanup_handle(ch);
error = curl_easy_perform(ch->cp);
SAVE_CURL_ERROR(ch, error);
@ -1005,7 +1066,7 @@ PHP_FUNCTION(curl_exec)
if (ch->handlers->write->method == PHP_CURL_RETURN && ch->handlers->write->buf.len > 0) {
if (ch->handlers->write->type != PHP_CURL_BINARY)
smart_str_0(&ch->handlers->write->buf);
RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 1);
RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 0);
}
RETURN_TRUE;
@ -1182,6 +1243,10 @@ static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
php_curl *ch = (php_curl *) rsrc->ptr;
#if PHP_CURL_DEBUG
fprintf(stderr, "DTOR CALLED, ch = %x\n", ch);
#endif
curl_easy_cleanup(ch->cp);
zend_llist_clean(&ch->to_free.str);
zend_llist_clean(&ch->to_free.slist);

238
ext/curl/multi.c Normal file
View File

@ -0,0 +1,238 @@
/*
+----------------------------------------------------------------------+
| PHP Version 4 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2002 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.02 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://www.php.net/license/2_02.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Sterling Hughes <sterling@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id: */
#include "php.h"
#if HAVE_CURL
#include "php_curl.h"
#include <curl/curl.h>
#include <curl/multi.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
/* {{{ proto resource curl_multi_init(void)
Returns a new cURL multi handle */
PHP_FUNCTION(curl_multi_init)
{
php_curlm *mh;
if (ZEND_NUM_ARGS() != 0) {
WRONG_PARAM_COUNT;
}
mh = ecalloc(1, sizeof(php_curlm));
mh->multi = curl_multi_init();
ZEND_REGISTER_RESOURCE(return_value, mh, le_curl_multi_handle);
}
/* }}} */
/* {{{ int curl_multi_add_handle(resource multi, resource ch)
Add a normal cURL handle to a cURL multi handle */
PHP_FUNCTION(curl_multi_add_handle)
{
zval *z_mh;
zval *z_ch;
php_curlm *mh;
php_curl *ch;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
le_curl_multi_handle);
ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
zval_add_ref(&z_ch);
_php_curl_cleanup_handle(ch);
ch->uses++;
RETURN_LONG((long) curl_multi_add_handle(mh->multi, ch->cp));
}
/* }}} */
/* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
Remove a multi handle from a set of cURL handles */
PHP_FUNCTION(curl_multi_remove_handle)
{
zval *z_mh;
zval *z_ch;
php_curlm *mh;
php_curl *ch;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
le_curl_multi_handle);
ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
zval_ptr_dtor(&z_ch);
RETURN_LONG((long) curl_multi_remove_handle(mh->multi, ch->cp));
}
/* }}} */
static void _make_timeval_struct(struct timeval *to, double timeout)
{
unsigned long conv;
conv = (unsigned long) (timeout * 1000000.0);
to->tv_sec = conv / 1000000;
to->tv_usec = conv % 1000000;
}
/* {{{ int curl_multi_select(resource mh[, double timeout])
Get all the sockets associated with the cURL extension, which can then be "selected" */
PHP_FUNCTION(curl_multi_select)
{
zval *z_mh;
php_curlm *mh;
fd_set readfds;
fd_set writefds;
fd_set exceptfds;
int maxfd;
double timeout = 1.0;
struct timeval to;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|d", &z_mh,
&timeout) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
le_curl_multi_handle);
_make_timeval_struct(&to, timeout);
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd);
RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to));
}
/* }}} */
/* {{{ proto int curl_multi_exec(resource mh)
Run the sub-connections of the current cURL handle */
PHP_FUNCTION(curl_multi_exec)
{
zval *z_mh;
zval *z_still_running;
php_curlm *mh;
int still_running;
int result;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_mh,
&z_still_running) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
le_curl_multi_handle);
convert_to_long_ex(&z_still_running);
still_running = Z_LVAL_P(z_still_running);
result = curl_multi_perform(mh->multi, &still_running);
ZVAL_LONG(z_still_running, still_running);
RETURN_LONG(result);
}
/* }}} */
/* {{{ proto string curl_multi_getcontent(resource ch)
Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
PHP_FUNCTION(curl_multi_getcontent)
{
zval *z_ch;
php_curl *ch;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ch) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
if (ch->handlers->write->method == PHP_CURL_RETURN &&
ch->handlers->write->buf.len > 0) {
if (ch->handlers->write->type == PHP_CURL_BINARY) {
smart_str_0(&ch->handlers->write->buf);
}
RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 0);
}
}
/* {{{ proto array curl_multi_info_read(resource mh)
Get information about the current transfers */
PHP_FUNCTION(curl_multi_info_read)
{
zval *z_mh;
php_curlm *mh;
CURLMsg *tmp_msg;
int queued_msgs;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_mh) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
le_curl_multi_handle);
tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
if (tmp_msg == NULL) {
RETURN_FALSE;
}
array_init(return_value);
add_assoc_long(return_value, "msg", tmp_msg->msg);
add_assoc_long(return_value, "result", tmp_msg->data.result);
// add_assoc_resource(return_value, "handle", _find_handle(tmp_msg->easy_handle));
add_assoc_string(return_value, "whatever", (char *) tmp_msg->data.whatever, 1);
}
/* }}} */
PHP_FUNCTION(curl_multi_close)
{
zval *z_mh;
php_curlm *mh;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_mh) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
le_curl_multi_handle);
zend_list_delete(Z_LVAL_P(z_mh));
}
void _php_curl_multi_close(zend_rsrc_list_entry *rsrc)
{
php_curlm *mh = (php_curlm *) rsrc->ptr;
curl_multi_cleanup(mh->multi);
// XXX: keep track of all curl handles and zval_ptr_dtor them here
}
#endif

View File

@ -13,7 +13,7 @@
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Sterling Hughes <sterling@php.net> |
| Wez Furlong <wez@thebrainroom.com> |
| Wez Furlong <wez@thebrainroom.com> |
+----------------------------------------------------------------------+
*/
@ -32,14 +32,29 @@
#if HAVE_CURL
#include <curl/curl.h>
#define PHP_CURL_DEBUG 0
#include <curl/curl.h>
#include <curl/multi.h>
extern zend_module_entry curl_module_entry;
#define curl_module_ptr &curl_module_entry
#define CURLOPT_RETURNTRANSFER 19913
#define CURLOPT_BINARYTRANSFER 19914
#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
#define PHP_CURL_ASCII 5
#define PHP_CURL_BINARY 6
#define PHP_CURL_IGNORE 7
int le_curl;
#define le_curl_name "cURL handle"
int le_curl_multi_handle;
#define le_curl_multi_handle_name "cURL Multi Handle"
PHP_MINIT_FUNCTION(curl);
PHP_MSHUTDOWN_FUNCTION(curl);
@ -52,6 +67,15 @@ PHP_FUNCTION(curl_getinfo);
PHP_FUNCTION(curl_error);
PHP_FUNCTION(curl_errno);
PHP_FUNCTION(curl_close);
PHP_FUNCTION(curl_multi_init);
PHP_FUNCTION(curl_multi_add_handle);
PHP_FUNCTION(curl_multi_remove_handle);
PHP_FUNCTION(curl_multi_select);
PHP_FUNCTION(curl_multi_exec);
PHP_FUNCTION(curl_multi_getcontent);
PHP_FUNCTION(curl_multi_info_read);
PHP_FUNCTION(curl_multi_close);
void _php_curl_multi_close(zend_rsrc_list_entry *);
typedef struct {
zval *func;
@ -87,14 +111,21 @@ struct _php_curl_free {
};
typedef struct {
CURL *cp;
php_curl_handlers *handlers;
struct _php_curl_error err;
struct _php_curl_free to_free;
CURL *cp;
php_curl_handlers *handlers;
long id;
unsigned int uses;
} php_curl;
typedef struct {
int still_running;
CURLM *multi;
} php_curlm;
void _php_curl_cleanup_handle(php_curl *);
/* streams support */
PHPAPI extern php_stream_ops php_curl_stream_ops;