const char *args);
/* wrapper around send/recv to handle timeouts */
-static int my_send(int s, void *buf, size_t len);
-static int my_recv(int s, void *buf, size_t len);
-static int my_connect(int s, const struct sockaddr *addr,
+static int my_send(ftpbuf_t *ftp, int s, void *buf, size_t len);
+static int my_recv(ftpbuf_t *ftp, int s, void *buf, size_t len);
+static int my_connect(ftpbuf_t *ftp, int s, const struct sockaddr *addr,
int addrlen);
-static int my_accept(int s, struct sockaddr *addr, int *addrlen);
+static int my_accept(ftpbuf_t *ftp, int s, struct sockaddr *addr,
+ int *addrlen);
/* reads a line the socket , returns true on success, false on error */
static int ftp_readline(ftpbuf_t *ftp);
static databuf_t* ftp_getdata(ftpbuf_t *ftp);
/* accepts the data connection, returns updated data buffer */
-static databuf_t* data_accept(databuf_t *data);
+static databuf_t* data_accept(databuf_t *data, ftpbuf_t *ftp);
/* closes the data connection, returns NULL */
static databuf_t* data_close(databuf_t *data);
/* {{{ ftp_open
*/
ftpbuf_t*
-ftp_open(const char *host, short port)
+ftp_open(const char *host, short port, long timeout_sec)
{
int fd = -1;
ftpbuf_t *ftp;
return NULL;
}
+ /* Default Settings */
+ ftp->timeout_sec = timeout_sec;
+
/* connect */
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
goto bail;
}
- if (my_connect(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
+ if (my_connect(ftp, fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
perror("connect");
goto bail;
}
if (ftp == NULL)
return 0;
- if (!ftp_type(ftp, type))
+ if (!ftp_type(ftp, type)) {
goto bail;
+ }
- if ((data = ftp_getdata(ftp)) == NULL)
+ if ((data = ftp_getdata(ftp)) == NULL) {
goto bail;
+ }
- if (!ftp_putcmd(ftp, "RETR", path))
+ if (!ftp_putcmd(ftp, "RETR", path)) {
goto bail;
- if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125))
+ }
+ if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
goto bail;
+ }
- if ((data = data_accept(data)) == NULL)
+ if ((data = data_accept(data, ftp)) == NULL) {
goto bail;
+ }
lastch = 0;
- while ((rcvd = my_recv(data->fd, data->buf, FTP_BUFSIZE))) {
- if (rcvd == -1)
+ while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
+ if (rcvd == -1) {
goto bail;
+ }
if (type == FTPTYPE_ASCII) {
for (ptr = data->buf; rcvd; rcvd--, ptr++) {
data = data_close(data);
- if (ferror(outfp))
+ if (ferror(outfp)) {
goto bail;
+ }
- if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250))
+ if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
goto bail;
+ }
return 1;
bail:
if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125))
goto bail;
- if ((data = data_accept(data)) == NULL)
+ if ((data = data_accept(data, ftp)) == NULL)
goto bail;
size = 0;
while ((ch = FP_FGETC(insocket, infp, issock))!=EOF && !FP_FEOF(insocket, infp, issock)) {
/* flush if necessary */
if (FTP_BUFSIZE - size < 2) {
- if (my_send(data->fd, data->buf, size) != size)
+ if (my_send(ftp, data->fd, data->buf, size) != size)
goto bail;
ptr = data->buf;
size = 0;
size++;
}
- if (size && my_send(data->fd, data->buf, size) != size)
+ if (size && my_send(ftp, data->fd, data->buf, size) != size)
goto bail;
if (!issock && ferror(infp))
}
data = ftp->outbuf;
- if (my_send(ftp->fd, data, size) != size)
+ if (my_send(ftp, ftp->fd, data, size) != size)
return 0;
return 1;
}
data = eol;
- if ((rcvd = my_recv(ftp->fd, data, size)) < 1)
+ if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) {
return 0;
+ }
} while (size);
return 0;
/* {{{ my_send
*/
int
-my_send(int s, void *buf, size_t len)
+my_send(ftpbuf_t *ftp, int s, void *buf, size_t len)
{
fd_set write_set;
struct timeval tv;
size = len;
while (size) {
- tv.tv_sec = FTP_TIMEOUT;
+ tv.tv_sec = ftp->timeout_sec;
tv.tv_usec = 0;
FD_ZERO(&write_set);
/* {{{ my_recv
*/
int
-my_recv(int s, void *buf, size_t len)
+my_recv(ftpbuf_t *ftp, int s, void *buf, size_t len)
{
fd_set read_set;
struct timeval tv;
int n;
- tv.tv_sec = FTP_TIMEOUT;
+ tv.tv_sec = ftp->timeout_sec;
tv.tv_usec = 0;
FD_ZERO(&read_set);
/* {{{ my_connect
*/
int
-my_connect(int s, const struct sockaddr *addr, int addrlen)
+my_connect(ftpbuf_t *ftp, int s, const struct sockaddr *addr, int addrlen)
#ifndef PHP_WIN32
{
fd_set conn_set;
FD_ZERO(&conn_set);
FD_SET(s, &conn_set);
- tv.tv_sec = FTP_TIMEOUT;
+ tv.tv_sec = ftp->timeout_sec;
tv.tv_usec = 0;
n = select(s + 1, &conn_set, &conn_set, NULL, &tv);
/* {{{ my_accept
*/
int
-my_accept(int s, struct sockaddr *addr, int *addrlen)
+my_accept(ftpbuf_t *ftp, int s, struct sockaddr *addr, int *addrlen)
{
fd_set accept_set;
struct timeval tv;
int n;
- tv.tv_sec = FTP_TIMEOUT;
+ tv.tv_sec = ftp->timeout_sec;
tv.tv_usec = 0;
FD_ZERO(&accept_set);
FD_SET(s, &accept_set);
ftp->pasv = 1;
/* connect */
- if (my_connect(fd, (struct sockaddr*) &ftp->pasvaddr,
+ if (my_connect(ftp, fd, (struct sockaddr*) &ftp->pasvaddr,
sizeof(ftp->pasvaddr)) == -1)
{
perror("connect");
/* {{{ data_accept
*/
databuf_t*
-data_accept(databuf_t *data)
+data_accept(databuf_t *data, ftpbuf_t *ftp)
{
struct sockaddr_in addr;
int size;
return data;
size = sizeof(addr);
- data->fd = my_accept(data->listener, (struct sockaddr*) &addr, &size);
+ data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size);
closesocket(data->listener);
data->listener = -1;
goto bail;
/* pull data buffer into tmpfile */
- if ((data = data_accept(data)) == NULL)
+ if ((data = data_accept(data, ftp)) == NULL)
goto bail;
size = 0;
lines = 0;
lastch = 0;
- while ((rcvd = my_recv(data->fd, data->buf, FTP_BUFSIZE))) {
+ while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
if (rcvd == -1)
goto bail;
PHP_FE(ftp_delete, NULL)
PHP_FE(ftp_site, NULL)
PHP_FE(ftp_close, NULL)
+ PHP_FE(ftp_set_option, NULL)
+ PHP_FE(ftp_get_option, NULL)
PHP_FALIAS(ftp_quit, ftp_close, NULL)
{NULL, NULL, NULL}
};
PHP_MINIT_FUNCTION(ftp)
{
- le_ftpbuf = zend_register_list_destructors_ex(ftp_destructor_ftpbuf, NULL, "ftp", module_number);
- REGISTER_LONG_CONSTANT("FTP_ASCII", FTPTYPE_ASCII,
- CONST_PERSISTENT | CONST_CS);
- REGISTER_LONG_CONSTANT("FTP_BINARY", FTPTYPE_IMAGE,
- CONST_PERSISTENT | CONST_CS);
- REGISTER_LONG_CONSTANT("FTP_IMAGE", FTPTYPE_IMAGE,
- CONST_PERSISTENT | CONST_CS);
- REGISTER_LONG_CONSTANT("FTP_TEXT", FTPTYPE_ASCII,
- CONST_PERSISTENT | CONST_CS);
+ le_ftpbuf = zend_register_list_destructors_ex(ftp_destructor_ftpbuf, NULL, le_ftpbuf_name, module_number);
+ REGISTER_LONG_CONSTANT("FTP_ASCII", FTPTYPE_ASCII, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("FTP_TEXT", FTPTYPE_ASCII, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("FTP_BINARY", FTPTYPE_IMAGE, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("FTP_IMAGE", FTPTYPE_IMAGE, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("FTP_TIMEOUT_SEC", PHP_FTP_OPT_TIMEOUT_SEC, CONST_PERSISTENT | CONST_CS);
return SUCCESS;
}
{
ftpbuf_t *ftp;
char *host;
- int host_len, port = 21;
+ int host_len, port = 0;
+ long timeout_sec = FTP_DEFAULT_TIMEOUT;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &host, &host_len, &port) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &host, &host_len, &port, &timeout_sec) == FAILURE) {
return;
}
+ if (timeout_sec <= 0) {
+ php_error(E_WARNING, "%s(): timeout has to be greater than 0",
+ get_active_function_name(TSRMLS_C));
+ RETURN_FALSE;
+ }
+
/* connect */
- ftp = ftp_open(host, htons((short)port));
+ ftp = ftp_open(host, htons((short)port), timeout_sec);
if (ftp == NULL) {
RETURN_FALSE;
}
zend_list_delete(Z_LVAL_P(z_ftp));
}
/* }}} */
+
+/* Temporarely copied over from zend_API.c until it gets exposed */
+static char *ze_zval_type_name(zval *arg)
+{
+ switch (Z_TYPE_P(arg)) {
+ case IS_NULL:
+ return "null";
+
+ case IS_LONG:
+ return "integer";
+
+ case IS_DOUBLE:
+ return "double";
+
+ case IS_STRING:
+ return "string";
+
+ case IS_ARRAY:
+ return "array";
+
+ case IS_OBJECT:
+ return "object";
+
+ case IS_BOOL:
+ return "boolean";
+
+ case IS_RESOURCE:
+ return "resource";
+
+ default:
+ return "unknown";
+ }
+}
+
+
+/* {{{ proto bool ftp_set_option(resource stream, int option, mixed value)
+ Sets an FTP option. */
+PHP_FUNCTION(ftp_set_option)
+{
+ zval *z_ftp, *z_value;
+ long option;
+ ftpbuf_t *ftp;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &z_ftp, &option, &z_value) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+
+ switch (option) {
+ case PHP_FTP_OPT_TIMEOUT_SEC:
+ if (Z_TYPE_P(z_value) != IS_LONG) {
+ php_error(E_WARNING, "%s(): option TIMEOUT_SEC expects value of type long, %s given",
+ get_active_function_name(TSRMLS_C), ze_zval_type_name(z_value));
+ RETURN_FALSE;
+ }
+ if (Z_LVAL_P(z_value) <= 0) {
+ php_error(E_WARNING, "%s(): timeout has to be greater than 0",
+ get_active_function_name(TSRMLS_C));
+ RETURN_FALSE;
+ }
+ ftp->timeout_sec = Z_LVAL_P(z_value);
+ RETURN_TRUE;
+ break;
+ default:
+ php_error(E_WARNING, "%s(): unknown option '%d'", get_active_function_name(TSRMLS_C), option);
+ RETURN_FALSE;
+ break;
+ }
+}
+/* }}} */
+
+/* {{{ proto mixed ftp_get_option(resource stream, int option)
+ Gets an FTP option. */
+PHP_FUNCTION(ftp_get_option)
+{
+ zval *z_ftp;
+ long option;
+ ftpbuf_t *ftp;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &z_ftp, &option) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+
+ switch (option) {
+ case PHP_FTP_OPT_TIMEOUT_SEC:
+ RETURN_LONG(ftp->timeout_sec);
+ break;
+ default:
+ php_error(E_WARNING, "%s(): unknown option '%d'", get_active_function_name(TSRMLS_C), option);
+ RETURN_FALSE;
+ break;
+ }
+}
+/* }}} */
#endif /* HAVE_FTP */