#if HAVE_FTP
+#include <stdio.h>
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
/* sets the ftp transfer type */
static int ftp_type(ftpbuf_t *ftp, ftptype_t type);
-/* opens up a port for ftp transfer */
-static databuf_t* ftp_port(ftpbuf_t *ftp);
+/* opens up a data stream */
+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 char** ftp_genlist(ftpbuf_t *ftp,
const char *cmd, const char *path);
+/* IP and port conversion box */
+union ipbox {
+ unsigned long l[2];
+ unsigned short s[4];
+ unsigned char c[8];
+};
+
ftpbuf_t*
ftp_open(const char *host, short port)
}
+int
+ftp_pasv(ftpbuf_t *ftp, int pasv)
+{
+ char *ptr;
+ union ipbox ipbox;
+ unsigned long b[6];
+ int n;
+
+ if (ftp == NULL)
+ return 0;
+
+ if (pasv && ftp->pasv == 2)
+ return 1;
+
+ ftp->pasv = 0;
+ if (!pasv)
+ return 1;
+
+ fprintf(ftp->fp, "PASV\r\n");
+ if (!ftp_getresp(ftp) || ftp->resp != 227)
+ return 0;
+
+ /* parse out the IP and port */
+ for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
+ n = sscanf(ptr, "%u,%u,%u,%u,%u,%u",
+ &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
+ if (n != 6)
+ return 0;
+
+ for (n=0; n<6; n++)
+ ipbox.c[n] = b[n];
+
+ memset(&ftp->pasvaddr, 0, sizeof(ftp->pasvaddr));
+ ftp->pasvaddr.sin_family = AF_INET;
+ ftp->pasvaddr.sin_addr.s_addr = ipbox.l[0];
+ ftp->pasvaddr.sin_port = ipbox.s[2];
+
+ ftp->pasv = 2;
+
+ return 1;
+}
+
+
int
ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, ftptype_t type)
{
if (!ftp_type(ftp, type))
goto bail;
- if ((data = ftp_port(ftp)) == NULL)
+ if ((data = ftp_getdata(ftp)) == NULL)
goto bail;
fprintf(ftp->fp, "RETR %s\r\n", path);
if (!ftp_type(ftp, type))
goto bail;
- if ((data = ftp_port(ftp)) == NULL)
+ if ((data = ftp_getdata(ftp)) == NULL)
goto bail;
fprintf(ftp->fp, "STOR %s\r\n", path);
}
+int
+ftp_size(ftpbuf_t *ftp, const char *path)
+{
+ if (ftp == NULL)
+ return -1;
+
+ fprintf(ftp->fp, "SIZE %s\r\n", path);
+ if (!ftp_getresp(ftp) || ftp->resp != 213)
+ return -1;
+
+ return atoi(ftp->inbuf);
+}
+
+
+time_t
+ftp_mdtm(ftpbuf_t *ftp, const char *path)
+{
+ time_t stamp;
+ struct tm *gmt;
+ struct tm tm;
+ char *ptr;
+ int n;
+
+ if (ftp == NULL)
+ return -1;
+
+ fprintf(ftp->fp, "MDTM %s\r\n", path);
+ if (!ftp_getresp(ftp) || ftp->resp != 213)
+ return -1;
+
+ /* parse out the timestamp */
+ for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
+ n = sscanf(ptr, "%4u%2u%2u%2u%2u%2u",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ if (n != 6)
+ return -1;
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+ tm.tm_isdst = -1;
+
+ /* figure out the GMT offset */
+ stamp = time(NULL);
+ gmt = gmtime(&stamp);
+ gmt->tm_isdst = -1;
+
+ /* apply the GMT offset */
+ tm.tm_sec += stamp - mktime(gmt);
+ tm.tm_isdst = gmt->tm_isdst;
+
+ stamp = mktime(&tm);
+
+ return stamp;
+}
+
+
+/* static functions */
+
databuf_t*
-ftp_port(ftpbuf_t *ftp)
+ftp_getdata(ftpbuf_t *ftp)
{
int fd = -1;
databuf_t *data;
struct sockaddr_in addr;
int size;
- union {
- unsigned long l[1];
- unsigned short s[2];
- unsigned char c[4];
- } ipbox;
+ union ipbox ipbox;
+
+
+ /* ask for a passive connection if we need one */
+ if (ftp->pasv && !ftp_pasv(ftp, 1))
+ return NULL;
/* alloc the data structure */
data = calloc(1, sizeof(*data));
goto bail;
}
+ /* passive connection handler */
+ if (ftp->pasv) {
+ /* clear the ready status */
+ ftp->pasv = 1;
+
+ /* connect */
+ if (connect(fd, (struct sockaddr*) &ftp->pasvaddr,
+ sizeof(ftp->pasvaddr)) == -1)
+ {
+ perror("connect");
+ close(fd);
+ free(data);
+ return NULL;
+ }
+
+ /* wrap fd in a FILE stream */
+ data->fp = fdopen(fd, "r+");
+ if (data->fp == NULL) {
+ perror("fdopen");
+ close(fd);
+ free(data);
+ return NULL;
+ }
+
+ return data;
+ }
+
+
+ /* active (normal) connection */
+
/* bind to a local address */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
/* send the PORT */
ipbox.l[0] = ftp->localaddr.s_addr;
- fprintf(ftp->fp, "PORT %u,%u,%u,%u,",
- ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3]);
- ipbox.s[0] = addr.sin_port;
- fprintf(ftp->fp, "%u,%u\r\n",
- ipbox.c[0], ipbox.c[1]);
+ ipbox.s[2] = addr.sin_port;
+ fprintf(ftp->fp, "PORT %u,%u,%u,%u,%u,%u\r\n",
+ ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3],
+ ipbox.c[4], ipbox.c[5]);
if (!ftp_getresp(ftp) || ftp->resp != 200)
goto bail;
int size;
int fd;
+
+ if (data->fp)
+ return data;
+
size = sizeof(addr);
fd = accept(data->listener, (struct sockaddr*) &addr, &size);
close(data->listener);
if (!ftp_type(ftp, FTPTYPE_ASCII))
goto bail;
- if ((data = ftp_port(ftp)) == NULL)
+ if ((data = ftp_getdata(ftp)) == NULL)
goto bail;
if (path)
PHP_FE(ftp_nlist, NULL)
PHP_FE(ftp_rawlist, NULL)
PHP_FE(ftp_systype, NULL)
+ PHP_FE(ftp_pasv, NULL)
PHP_FE(ftp_get, NULL)
+ PHP_FE(ftp_fget, NULL)
PHP_FE(ftp_put, NULL)
+ PHP_FE(ftp_fput, NULL)
+ PHP_FE(ftp_size, NULL)
+ PHP_FE(ftp_mdtm, NULL)
PHP_FE(ftp_quit, NULL)
{NULL, NULL, NULL}
};
return SUCCESS;
}
+
+#define FTPBUF(ftp, pval) { \
+ int id, type; \
+ convert_to_long(pval); \
+ id = (pval)->value.lval; \
+ (ftp) = php3_list_find(id, &type); \
+ if (!(ftp) || type != le_ftpbuf) { \
+ php_error(E_WARNING, "Unable to find ftpbuf %d", id); \
+ RETURN_FALSE; \
+ } \
+ }
+
+#define XTYPE(xtype, pval) { \
+ convert_to_long(pval); \
+ if ( pval->value.lval != FTPTYPE_ASCII && \
+ pval->value.lval != FTPTYPE_IMAGE) \
+ { \
+ php_error(E_WARNING, "arg4 must be FTP_ASCII or FTP_IMAGE"); \
+ RETURN_FALSE; \
+ } \
+ (xtype) = pval->value.lval; \
+ }
+
+#define FILEP(fp, pval) { \
+ int id, type; \
+ int le_fp; \
+ le_fp = php3i_get_le_fp(); \
+ convert_to_long(pval); \
+ id = (pval)->value.lval; \
+ (fp) = php3_list_find(id, &type); \
+ if (!(fp) || type != le_fp) { \
+ php_error(E_WARNING, "Unable to find fp %d", id); \
+ RETURN_FALSE; \
+ } \
+ }
+
/* {{{ proto int ftp_connect(string host [, int port])
Open a FTP stream */
PHP_FUNCTION(ftp_connect)
{
pval *arg1, *arg2;
- int id;
ftpbuf_t *ftp;
short port = 0;
if (ftp == NULL)
RETURN_FALSE;
- id = php3_list_insert(ftp, le_ftpbuf);
- RETURN_LONG(id);
+ RETURN_LONG(php3_list_insert(ftp, le_ftpbuf));
}
/* }}} */
PHP_FUNCTION(ftp_login)
{
pval *arg1, *arg2, *arg3;
- int id, type;
ftpbuf_t *ftp;
/* arg1 - ftp
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
convert_to_string(arg2);
convert_to_string(arg3);
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
/* log in */
if (!ftp_login(ftp, arg2->value.str.val, arg3->value.str.val)) {
PHP_FUNCTION(ftp_pwd)
{
pval *arg1;
- int id, type;
ftpbuf_t *ftp;
const char *pwd;
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
-
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
pwd = ftp_pwd(ftp);
if (pwd == NULL) {
PHP_FUNCTION(ftp_cdup)
{
pval *arg1;
- int id, type;
ftpbuf_t *ftp;
/* arg1 - ftp
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
-
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
if (!ftp_cdup(ftp)) {
php_error(E_WARNING, "ftp_cdup: %s", ftp->inbuf);
PHP_FUNCTION(ftp_chdir)
{
pval *arg1, *arg2;
- int id, type;
ftpbuf_t *ftp;
/* arg1 - ftp
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
convert_to_string(arg2);
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
/* change directories */
if (!ftp_chdir(ftp, arg2->value.str.val)) {
PHP_FUNCTION(ftp_mkdir)
{
pval *arg1, *arg2;
- int id, type;
ftpbuf_t *ftp;
char *ret, *tmp;
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
convert_to_string(arg2);
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
/* change directories */
tmp = ftp_mkdir(ftp, arg2->value.str.val);
PHP_FUNCTION(ftp_rmdir)
{
pval *arg1, *arg2;
- int id, type;
ftpbuf_t *ftp;
/* arg1 - ftp
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
convert_to_string(arg2);
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
/* change directories */
if (!ftp_rmdir(ftp, arg2->value.str.val)) {
PHP_FUNCTION(ftp_nlist)
{
pval *arg1, *arg2;
- int id, type;
ftpbuf_t *ftp;
char **nlist, **ptr;
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
convert_to_string(arg2);
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
/* get list of files */
nlist = ftp_nlist(ftp, arg2->value.str.val);
PHP_FUNCTION(ftp_rawlist)
{
pval *arg1, *arg2;
- int id, type;
ftpbuf_t *ftp;
char **llist, **ptr;
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
convert_to_string(arg2);
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
/* get directory listing */
llist = ftp_list(ftp, arg2->value.str.val);
PHP_FUNCTION(ftp_systype)
{
pval *arg1;
- int id, type;
ftpbuf_t *ftp;
const char *syst;
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
-
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
+ FTPBUF(ftp, arg1);
syst = ftp_syst(ftp);
if (syst == NULL) {
}
/* }}} */
+/* {{{ proto int ftp_fget(int stream, int fp, string remote_file, int mode)
+ Retrieves a file from the FTP server and writes it to an open file. */
+PHP_FUNCTION(ftp_fget)
+{
+ pval *arg1, *arg2, *arg3, *arg4;
+ ftpbuf_t *ftp;
+ ftptype_t xtype;
+ FILE *fp;
+
+ /* arg1 - ftp
+ * arg2 - fp
+ * arg3 - remote file
+ * arg4 - transfer mode
+ */
+ if ( ARG_COUNT(ht) != 4 ||
+ getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ FTPBUF(ftp, arg1);
+ FILEP(fp, arg2);
+ convert_to_string(arg3);
+ XTYPE(xtype, arg4);
+
+ if (!ftp_get(ftp, fp, arg3->value.str.val, xtype) || ferror(fp)) {
+ php_error(E_WARNING, "ftp_get: %s", ftp->inbuf);
+ RETURN_FALSE;
+ }
+
+ if (ferror(fp)) {
+ php_error(E_WARNING, "error writing %s", arg2->value.str.val);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int ftp_pasv(int stream, int pasv)
+ Turns passive mode on or off. */
+PHP_FUNCTION(ftp_pasv)
+{
+ pval *arg1, *arg2;
+ ftpbuf_t *ftp;
+
+ /* arg1 - ftp
+ * arg2 - pasv
+ */
+ if ( ARG_COUNT(ht) != 2 ||
+ getParameters(ht, 2, &arg1, &arg2) == FAILURE)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ FTPBUF(ftp, arg1);
+ convert_to_long(arg2);
+
+ if (!ftp_pasv(ftp, (arg2->value.lval) ? 1 : 0))
+ RETURN_FALSE;
+
+ RETURN_TRUE;
+}
+/* }}} */
+
/* {{{ proto int ftp_get(int stream, string local_file, string remote_file, int mode)
- Retrieves a file from the FTP server. */
+ Retrieves a file from the FTP server and writes it to a local file. */
PHP_FUNCTION(ftp_get)
{
pval *arg1, *arg2, *arg3, *arg4;
- int id, type;
ftpbuf_t *ftp;
ftptype_t xtype;
FILE *outfp, *tmpfp;
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
+ FTPBUF(ftp, arg1);
convert_to_string(arg2);
convert_to_string(arg3);
- convert_to_long(arg4);
-
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
-
- if ( arg4->value.lval != FTPTYPE_ASCII &&
- arg4->value.lval != FTPTYPE_IMAGE)
- {
- php_error(E_WARNING, "arg4 must be FTP_ASCII or FTP_IMAGE");
- RETURN_FALSE;
- }
-
- xtype = arg4->value.lval;
+ XTYPE(xtype, arg4);
/* get to temporary file, so if there is an error, no existing
* file gets clobbered
}
/* }}} */
+/* {{{ proto int ftp_fput(int stream, string local_file, string remote_file, int mode)
+ Stores a file from an open file to the FTP server. */
+PHP_FUNCTION(ftp_fput)
+{
+ pval *arg1, *arg2, *arg3, *arg4;
+ ftpbuf_t *ftp;
+ ftptype_t xtype;
+ FILE *fp;
+
+ /* arg1 - ftp
+ * arg2 - remote file
+ * arg3 - fp
+ * arg4 - transfer mode
+ */
+ if ( ARG_COUNT(ht) != 4 ||
+ getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ FTPBUF(ftp, arg1);
+ convert_to_string(arg2);
+ FILEP(fp, arg3);
+ XTYPE(xtype, arg4);
+
+ if (!ftp_put(ftp, arg2->value.str.val, fp, xtype)) {
+ php_error(E_WARNING, "ftp_put: %s", ftp->inbuf);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
/* {{{ proto int ftp_put(int stream, string remote_file, string local_file, int mode)
Stores a file on the FTP server */
PHP_FUNCTION(ftp_put)
{
pval *arg1, *arg2, *arg3, *arg4;
- int id, type;
ftpbuf_t *ftp;
ftptype_t xtype;
FILE *infp;
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
+ FTPBUF(ftp, arg1);
convert_to_string(arg2);
convert_to_string(arg3);
- convert_to_long(arg4);
-
- id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
-
- if ( arg4->value.lval != FTPTYPE_ASCII &&
- arg4->value.lval != FTPTYPE_IMAGE)
- {
- php_error(E_WARNING, "arg4 must be FTP_ASCII or FTP_IMAGE");
- RETURN_FALSE;
- }
-
- xtype = arg4->value.lval;
+ XTYPE(xtype, arg4);
if ((infp = fopen(arg3->value.str.val, "r")) == NULL) {
php_error(E_WARNING, "error opening %s", arg3->value.str.val);
}
/* }}} */
+/* {{{ proto int ftp_size(int stream, string path)
+ Returns the size of the file, or -1 on error. */
+PHP_FUNCTION(ftp_size)
+{
+ pval *arg1, *arg2;
+ ftpbuf_t *ftp;
+
+ /* arg1 - ftp
+ * arg2 - path
+ */
+ if ( ARG_COUNT(ht) != 2 ||
+ getParameters(ht, 2, &arg1, &arg2) == FAILURE)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ FTPBUF(ftp, arg1);
+ convert_to_string(arg2);
+
+ /* get file size */
+ RETURN_LONG(ftp_size(ftp, arg2->value.str.val));
+}
+/* }}} */
+
+/* {{{ proto int ftp_mdtm(int stream, string path)
+ Returns the last modification time of the file, or -1 on error */
+PHP_FUNCTION(ftp_mdtm)
+{
+ pval *arg1, *arg2;
+ ftpbuf_t *ftp;
+
+ /* arg1 - ftp
+ * arg2 - path
+ */
+ if ( ARG_COUNT(ht) != 2 ||
+ getParameters(ht, 2, &arg1, &arg2) == FAILURE)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ FTPBUF(ftp, arg1);
+ convert_to_string(arg2);
+
+ /* get file mod time */
+ RETURN_LONG(ftp_mdtm(ftp, arg2->value.str.val));
+}
+/* }}} */
+
/* {{{ proto int ftp_quit(int stream)
Closes the FTP stream */
PHP_FUNCTION(ftp_quit)
{
pval *arg1;
int id, type;
- ftpbuf_t *ftp;
/* arg1 - ftp
*/
WRONG_PARAM_COUNT;
}
- convert_to_long(arg1);
id = arg1->value.lval;
- ftp = php3_list_find(id, &type);
- if (!ftp || type != le_ftpbuf) {
- php_error(E_WARNING, "Unable to find ftpbuf %d", id);
- RETURN_FALSE;
- }
-
- php3_list_delete(id);
+ if (php3_list_find(id, &type) && type == le_ftpbuf)
+ php3_list_delete(id);
RETURN_TRUE;
}