]> granicus.if.org Git - php/commitdiff
[EXPERIMENTAL] Added functions for asynchronous FTP transfers
authorStefan Esser <sesser@php.net>
Fri, 26 Jul 2002 22:00:25 +0000 (22:00 +0000)
committerStefan Esser <sesser@php.net>
Fri, 26 Jul 2002 22:00:25 +0000 (22:00 +0000)
ext/ftp/ftp.c
ext/ftp/ftp.h
ext/ftp/php_ftp.c
ext/ftp/php_ftp.h

index 3effa5fcc486426c94a73d1e1865911d57462d60..573b47902f1cf368cd1b2de25a556eb633d87603 100644 (file)
@@ -126,6 +126,7 @@ ftp_open(const char *host, short port, long timeout_sec)
 
        /* Default Settings */
        ftp->timeout_sec = timeout_sec;
+       ftp->async = 0;
 
        size = sizeof(ftp->localaddr);
        memset(&ftp->localaddr, 0, size);
@@ -232,6 +233,8 @@ ftp_reinit(ftpbuf_t *ftp)
 
        ftp_gc(ftp);
 
+       ftp->async = 0;
+
        if (!ftp_putcmd(ftp, "REIN", NULL))
                return 0;
        if (!ftp_getresp(ftp) || ftp->resp != 220)
@@ -1018,6 +1021,59 @@ my_recv(ftpbuf_t *ftp, int s, void *buf, size_t len)
 }
 /* }}} */
 
+/* {{{ data_available
+ */
+int
+data_available(ftpbuf_t *ftp, int s)
+{
+       fd_set          read_set;
+       struct timeval  tv;
+       int             n;
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 1;
+
+       FD_ZERO(&read_set);
+       FD_SET(s, &read_set);
+       n = select(s + 1, &read_set, NULL, NULL, &tv);
+       if (n < 1) {
+#ifndef PHP_WIN32
+               if (n == 0)
+                       errno = ETIMEDOUT;
+#endif
+               return 0;
+       }
+
+       return 1;
+}
+/* }}} */
+/* {{{ data_writeable
+ */
+int
+data_writeable(ftpbuf_t *ftp, int s)
+{
+       fd_set          write_set;
+       struct timeval  tv;
+       int             n;
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 1;
+
+       FD_ZERO(&write_set);
+       FD_SET(s, &write_set);
+       n = select(s + 1, NULL, &write_set, NULL, &tv);
+       if (n < 1) {
+#ifndef PHP_WIN32
+               if (n == 0)
+                       errno = ETIMEDOUT;
+#endif
+               return 0;
+       }
+
+       return 1;
+}
+/* }}} */
+
 /* {{{ my_accept
  */
 int
@@ -1309,6 +1365,239 @@ bail:
 }
 /* }}} */
 
+/* {{{ ftp_async_get
+ */
+int
+ftp_async_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, int resumepos)
+{
+       databuf_t               *data = NULL;
+       char                    *ptr;
+       int                     lastch;
+       int                     rcvd;
+       char                    arg[11];
+       TSRMLS_FETCH();
+
+       if (ftp == NULL)
+               goto bail;
+
+       if (!ftp_type(ftp, type)) {
+               goto bail;
+       }
+
+       if ((data = ftp_getdata(ftp)) == NULL) {
+               goto bail;
+       }
+
+       if (resumepos>0) {
+               sprintf(arg, "%u", resumepos);
+               if (!ftp_putcmd(ftp, "REST", arg)) {
+                       goto bail;
+               }
+               if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
+                       goto bail;
+               }
+       }
+
+       if (!ftp_putcmd(ftp, "RETR", path)) {
+               goto bail;
+       }
+       if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
+               goto bail;
+       }
+
+       if ((data = data_accept(data, ftp)) == NULL) {
+               goto bail;
+       }
+
+       ftp->data = data;
+       ftp->stream = outstream;
+       ftp->lastch = 0;
+       ftp->async = 1;
+
+       return (ftp_async_continue_read(ftp));
+
+bail:
+       data_close(data);
+       return PHP_FTP_FAILED;
+}
+/* }}} */
+
+/* {{{ ftp_aget
+ */
+int
+ftp_async_continue_read(ftpbuf_t *ftp)
+{
+       databuf_t       *data = NULL;
+       char            *ptr;
+       int                     lastch;
+       int                     rcvd;
+       ftptype_t       type;
+       TSRMLS_FETCH();
+
+       data = ftp->data;
+
+       /* check if there is already more data */
+       if (!data_available(ftp, data->fd)) {
+               return PHP_FTP_MOREDATA;
+       }
+
+       type = ftp->type;
+
+       lastch = ftp->lastch;
+       if (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++) {
+                               if (lastch == '\r' && *ptr != '\n')
+                                       php_stream_putc(ftp->stream, '\r');
+                               if (*ptr != '\r')
+                                       php_stream_putc(ftp->stream, *ptr);
+                               lastch = *ptr;
+                       }
+               }
+               else {
+                       php_stream_write(ftp->stream, data->buf, rcvd);
+               }
+
+               ftp->lastch = lastch;
+               return PHP_FTP_MOREDATA;
+       }
+
+       if (type == FTPTYPE_ASCII && lastch == '\r')
+               php_stream_putc(ftp->stream, '\r');
+
+       data = data_close(data);
+
+       if (php_stream_error(ftp->stream)) {
+               goto bail;
+       }
+
+       if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
+               goto bail;
+       }
+
+       ftp->async = 0;
+       return PHP_FTP_FINISHED;
+bail:
+       ftp->async = 0;
+       data_close(data);
+       return PHP_FTP_FAILED;
+}
+/* }}} */
+
+/* {{{ ftp_async_put
+ */
+int
+ftp_async_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos)
+{
+       databuf_t               *data = NULL;
+       int                     size;
+       char                    *ptr;
+       int                     ch;
+       char                    arg[11];
+       TSRMLS_FETCH();
+
+       if (ftp == NULL)
+               return 0;
+
+       if (!ftp_type(ftp, type))
+               goto bail;
+
+       if ((data = ftp_getdata(ftp)) == NULL)
+               goto bail;
+
+       if (startpos>0) {
+               sprintf(arg, "%u", startpos);
+               if (!ftp_putcmd(ftp, "REST", arg)) {
+                       goto bail;
+               }
+               if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
+                       goto bail;
+               }
+       }
+
+       if (!ftp_putcmd(ftp, "STOR", path))
+               goto bail;
+       if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125))
+               goto bail;
+
+       if ((data = data_accept(data, ftp)) == NULL)
+               goto bail;
+
+       ftp->data = data;
+       ftp->stream = instream;
+       ftp->lastch = 0;
+       ftp->async = 1;
+
+       return (ftp_async_continue_write(ftp));
+
+bail:
+       data_close(data);
+       return PHP_FTP_FAILED;
+
+}
+/* }}} */
+
+
+/* {{{ ftp_async_continue_write
+ */
+int
+ftp_async_continue_write(ftpbuf_t *ftp)
+{
+       int                     size;
+       char                    *ptr;
+       int                     ch;
+
+       /* check if we can write more data */
+       if (!data_writeable(ftp, ftp->data->fd)) {
+               return PHP_FTP_MOREDATA;
+       }
+
+       size = 0;
+       ptr = ftp->data->buf;
+       while ((ch = php_stream_getc(ftp->stream))!=EOF && !php_stream_eof(ftp->stream)) {
+
+               if (ch == '\n' && ftp->type == FTPTYPE_ASCII) {
+                       *ptr++ = '\r';
+                       size++;
+               }
+
+               *ptr++ = ch;
+               size++;
+
+               /* flush if necessary */
+               if (FTP_BUFSIZE - size < 2) {
+                       if (my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size)
+                               goto bail;
+                       return PHP_FTP_MOREDATA;
+               }
+
+       }
+
+       if (size && my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size)
+               goto bail;
+
+       if (php_stream_error(ftp->stream))
+               goto bail;
+
+       ftp->data = data_close(ftp->data);
+
+       if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250))
+               goto bail;
+
+       ftp->async = 0;
+       return PHP_FTP_FINISHED;
+bail:
+       data_close(ftp->data);
+       ftp->async = 0;
+       return PHP_FTP_FAILED;
+}
+/* }}} */
+
+
 #endif /* HAVE_FTP */
 
 /*
index 0dfb304810f77e741f01f16471015a9a9fc5954b..a770dfc4e261b8e2d221f3173922fe18288bfaab 100644 (file)
@@ -31,6 +31,9 @@
 
 #define        FTP_DEFAULT_TIMEOUT     90
 #define FTP_DEFAULT_AUTOSEEK 1
+#define PHP_FTP_FAILED                 0
+#define PHP_FTP_FINISHED               1
+#define PHP_FTP_MOREDATA               2
 
 /* XXX this should be configurable at runtime XXX */
 #define        FTP_BUFSIZE     4096
@@ -40,6 +43,14 @@ typedef enum ftptype {
        FTPTYPE_IMAGE
 } ftptype_t;
 
+typedef struct databuf
+{
+       int             listener;               /* listener socket */
+       int             fd;                     /* data connection */
+       ftptype_t       type;                   /* transfer type */
+       char            buf[FTP_BUFSIZE];       /* data buffer */
+} databuf_t;
+
 typedef struct ftpbuf
 {
        int             fd;                     /* control connection */
@@ -56,15 +67,15 @@ typedef struct ftpbuf
        php_sockaddr_storage    pasvaddr;       /* passive mode address */
        long    timeout_sec;    /* User configureable timeout (seconds) */
        int                     autoseek;       /* User configureable autoseek flag */
+
+       int                             async;  /* asyncronous transfer in progress */
+       databuf_t               *data;  /* Data connection for asyncrounous transfers */
+       php_stream              *stream; /* output stream for asyncrounous transfers */
+       int                             lastch;         /* last char of previous call */
+       int                             direction;      /* recv = 0 / send = 1 */
+       int                             closestream;/* close or not close stream */
 } ftpbuf_t;
 
-typedef struct databuf
-{
-       int             listener;               /* listener socket */
-       int             fd;                     /* data connection */
-       ftptype_t       type;                   /* transfer type */
-       char            buf[FTP_BUFSIZE];       /* data buffer */
-} databuf_t;
 
 
 /* open a FTP connection, returns ftpbuf (NULL on error)
@@ -156,4 +167,24 @@ int                ftp_delete(ftpbuf_t *ftp, const char *path);
 /* sends a SITE command to the server */
 int            ftp_site(ftpbuf_t *ftp, const char *cmd);
 
+/* retrieves part of a file and saves its contents to outfp
+ * returns true on success, false on error
+ */
+int            ftp_async_get(ftpbuf_t *ftp, php_stream *outstream, const char *path,
+                       ftptype_t type, int resumepos);
+
+/* stores the data from a file, socket, or process as a file on the remote server
+ * returns true on success, false on error
+ */
+int            ftp_async_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos);
+
+/* continues a previous async_(f)get command
+ */
+int            ftp_async_continue_read(ftpbuf_t *ftp);
+
+/* continues a previous async_(f)put command
+ */
+int            ftp_async_continue_write(ftpbuf_t *ftp);
+
+
 #endif
index cc51a84ffe566a794819846a7f20d220c6cb2703..1dac9e344363b09b433ccffdc2bf16e11bc73d6c 100644 (file)
@@ -61,6 +61,11 @@ function_entry php_ftp_functions[] = {
        PHP_FE(ftp_close,                       NULL)
        PHP_FE(ftp_set_option,          NULL)
        PHP_FE(ftp_get_option,          NULL)
+       PHP_FE(ftp_async_fget,          NULL)
+       PHP_FE(ftp_async_get,           NULL)
+       PHP_FE(ftp_async_continue,      NULL)
+       PHP_FE(ftp_async_put,           NULL)
+       PHP_FE(ftp_async_fput,          NULL)
        PHP_FALIAS(ftp_quit, ftp_close, NULL)
        {NULL, NULL, NULL}
 };
@@ -99,6 +104,9 @@ PHP_MINIT_FUNCTION(ftp)
        REGISTER_LONG_CONSTANT("FTP_AUTORESUME", PHP_FTP_AUTORESUME, CONST_PERSISTENT | CONST_CS);
        REGISTER_LONG_CONSTANT("FTP_TIMEOUT_SEC", PHP_FTP_OPT_TIMEOUT_SEC, CONST_PERSISTENT | CONST_CS);
        REGISTER_LONG_CONSTANT("FTP_AUTOSEEK", PHP_FTP_OPT_AUTOSEEK, CONST_PERSISTENT | CONST_CS);
+       REGISTER_LONG_CONSTANT("FTP_FAILED", PHP_FTP_FAILED, CONST_PERSISTENT | CONST_CS);
+       REGISTER_LONG_CONSTANT("FTP_FINISHED", PHP_FTP_FINISHED, CONST_PERSISTENT | CONST_CS);
+       REGISTER_LONG_CONSTANT("FTP_MOREDATA", PHP_FTP_MOREDATA, CONST_PERSISTENT | CONST_CS);
        return SUCCESS;
 }
 
@@ -448,6 +456,53 @@ PHP_FUNCTION(ftp_fget)
 }
 /* }}} */
 
+/* {{{ proto bool ftp_async_fget(resource stream, resource fp, string remote_file, int mode[, int resumepos])
+   Retrieves a file from the FTP server asynchronly and writes it to an open file */
+PHP_FUNCTION(ftp_async_fget)
+{
+       zval            *z_ftp, *z_file;
+       ftpbuf_t        *ftp;
+       ftptype_t       xtype;
+       php_stream      *stream;
+       char            *file;
+       int                     file_len, mode, resumepos=0, ret;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrsl|l", &z_ftp, &z_file, &file, &file_len, &mode, &resumepos) == FAILURE) {
+               return;
+       }
+
+       ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+       ZEND_FETCH_RESOURCE(stream, php_stream*, &z_file, -1, "File-Handle", php_file_le_stream());
+       XTYPE(xtype, mode);
+
+       /* ignore autoresume if autoseek is switched off */
+       if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
+               resumepos = 0;
+       }
+
+       if (ftp->autoseek && resumepos) {
+               /* if autoresume is wanted seek to end */
+               if (resumepos == PHP_FTP_AUTORESUME) {
+                       php_stream_seek(stream, 0, SEEK_END);
+                       resumepos = php_stream_tell(stream);
+               } else {
+                       php_stream_seek(stream, resumepos, SEEK_SET);
+               }
+       }
+
+       /* configuration */
+       ftp->direction = 0;   /* recv */
+       ftp->closestream = 0; /* do not close */
+
+       if ((ret = ftp_async_get(ftp, stream, file, xtype, resumepos)) == PHP_FTP_FAILED || php_stream_error(stream)) {
+               php_error(E_WARNING, "%s(): %s", get_active_function_name(TSRMLS_C), ftp->inbuf);
+               RETURN_LONG(ret);
+       }
+
+       RETURN_LONG(ret);
+}
+/* }}} */
+
 /* {{{ proto bool ftp_pasv(resource stream, bool pasv)
    Turns passive mode on or off */
 PHP_FUNCTION(ftp_pasv)
@@ -526,6 +581,107 @@ PHP_FUNCTION(ftp_get)
 }
 /* }}} */
 
+/* {{{ proto inf ftp_async_get(resource stream, string local_file, string remote_file, int mode[, int resume_pos])
+   Retrieves a file from the FTP server asynchronly and writes it to a local file */
+PHP_FUNCTION(ftp_async_get)
+{
+       zval            *z_ftp;
+       ftpbuf_t        *ftp;
+       ftptype_t       xtype;
+       php_stream      *outstream;
+       char            *local, *remote;
+       int                     local_len, remote_len, mode, resumepos=0, ret;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rssl|l", &z_ftp, &local, &local_len, &remote, &remote_len, &mode, &resumepos) == FAILURE) {
+               return;
+       }
+
+       ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+       XTYPE(xtype, mode);
+
+       /* ignore autoresume if autoseek is switched off */
+       if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
+               resumepos = 0;
+       }
+
+       if (ftp->autoseek && resumepos) {
+               outstream = php_stream_fopen(local, "rb+", NULL);
+               if (outstream == NULL) {
+                       outstream = php_stream_fopen(local, "wb", NULL);
+               }
+               if (outstream != NULL) {
+                       /* if autoresume is wanted seek to end */
+                       if (resumepos == PHP_FTP_AUTORESUME) {
+                               php_stream_seek(outstream, 0, SEEK_END);
+                               resumepos = php_stream_tell(outstream);
+                       } else {
+                               php_stream_seek(outstream, resumepos, SEEK_SET);
+                       }
+               }
+       } else {
+               outstream = php_stream_fopen(local, "wb", NULL);
+       }
+
+       if (outstream == NULL)  {
+               php_error(E_WARNING, "%s(): Error opening %s", get_active_function_name(TSRMLS_C), local);
+               RETURN_FALSE;
+       }
+
+       /* configuration */
+       ftp->direction = 0;   /* recv */
+       ftp->closestream = 1; /* do close */
+
+       if ((ret = ftp_async_get(ftp, outstream, remote, xtype, resumepos)) == PHP_FTP_FAILED || php_stream_error(outstream)) {
+               php_stream_close(outstream);
+               php_error(E_WARNING, "%s(): %s", get_active_function_name(TSRMLS_C), ftp->inbuf);
+               RETURN_LONG(PHP_FTP_FAILED);
+       }
+
+       if (ret == PHP_FTP_FINISHED) {
+               php_stream_close(outstream);
+       }
+
+       RETURN_LONG(ret);
+}
+/* }}} */
+
+/* {{{ proto int ftp_async_continue(resource stream)
+   Continues retrieving/sending a file asyncronously */
+PHP_FUNCTION(ftp_async_continue)
+{
+       zval            *z_ftp;
+       ftpbuf_t        *ftp;
+       int                     ret;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ftp) == FAILURE) {
+               return;
+       }
+
+       ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+
+       if (!ftp->async) {
+               php_error(E_WARNING, "%s(): no asyncronous transfer to continue.", get_active_function_name(TSRMLS_C));
+               RETURN_LONG(PHP_FTP_FAILED);
+       }
+
+       if (ftp->direction) {
+               ret=ftp_async_continue_write(ftp);
+       } else {
+               ret=ftp_async_continue_read(ftp);
+       }
+
+       if (ret != PHP_FTP_MOREDATA && ftp->closestream) {
+               php_stream_close(ftp->stream);
+       }
+
+       if (ret == PHP_FTP_FAILED || php_stream_error(ftp->stream)) {
+               php_error(E_WARNING, "%s(): %s", get_active_function_name(TSRMLS_C), ftp->inbuf);
+       }
+
+       RETURN_LONG(ret);
+}
+/* }}} */
+
 /* {{{ proto bool ftp_fput(resource stream, string remote_file, resource fp, int mode[, int startpos])
    Stores a file from an open file to the FTP server */
 PHP_FUNCTION(ftp_fput)
@@ -572,6 +728,57 @@ PHP_FUNCTION(ftp_fput)
 }
 /* }}} */
 
+/* {{{ proto bool ftp_async_fput(resource stream, string remote_file, resource fp, int mode[, int startpos])
+   Stores a file from an open file to the FTP server asyncronly */
+PHP_FUNCTION(ftp_async_fput)
+{
+       zval            *z_ftp, *z_file;
+       ftpbuf_t        *ftp;
+       ftptype_t       xtype;
+       int                     mode, remote_len, startpos=0, ret;
+       php_stream      *stream;
+       char            *remote;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsrl|l", &z_ftp, &remote, &remote_len, &z_file, &mode, &startpos) == FAILURE) {
+               return;
+       }
+
+       ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+       ZEND_FETCH_RESOURCE(stream, php_stream*, &z_file, -1, "File-Handle", php_file_le_stream());
+       XTYPE(xtype, mode);
+
+       /* ignore autoresume if autoseek is switched off */
+       if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
+               startpos = 0;
+       }
+
+       if (ftp->autoseek && startpos) {
+               /* if autoresume is wanted ask for remote size */
+               if (startpos == PHP_FTP_AUTORESUME) {
+                       startpos = ftp_size(ftp, remote);
+                       if (startpos < 0) {
+                               startpos = 0;
+                       }
+               }
+               if (startpos) {
+                       php_stream_seek(stream, startpos, SEEK_SET);
+               }
+       }
+
+       /* configuration */
+       ftp->direction = 1;   /* send */
+       ftp->closestream = 0; /* do not close */
+
+       if (((ret = ftp_async_put(ftp, remote, stream, xtype, startpos)) == PHP_FTP_FAILED) || php_stream_error(stream)) {
+               php_error(E_WARNING, "%s(): %s", get_active_function_name(TSRMLS_C), ftp->inbuf);
+               RETURN_LONG(ret);
+       }
+
+       RETURN_LONG(ret);
+}
+/* }}} */
+
+
 /* {{{ proto bool ftp_put(resource stream, string remote_file, string local_file, int mode[, int startpos])
    Stores a file on the FTP server */
 PHP_FUNCTION(ftp_put)
@@ -580,7 +787,7 @@ PHP_FUNCTION(ftp_put)
        ftpbuf_t        *ftp;
        ftptype_t       xtype;
        char            *remote, *local;
-       int                     remote_len, local_len, mode, startpos=0;
+       int                     remote_len, local_len, mode, startpos=0, ret;
        php_stream * instream;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rssl|l", &z_ftp, &remote, &remote_len, &local, &local_len, &mode, &startpos) == FAILURE) {
@@ -625,6 +832,67 @@ PHP_FUNCTION(ftp_put)
 }
 /* }}} */
 
+
+/* {{{ proto bool ftp_async_put(resource stream, string remote_file, string local_file, int mode[, int startpos])
+   Stores a file on the FTP server */
+PHP_FUNCTION(ftp_async_put)
+{
+       zval            *z_ftp;
+       ftpbuf_t        *ftp;
+       ftptype_t       xtype;
+       char            *remote, *local;
+       int                     remote_len, local_len, mode, startpos=0, ret;
+       php_stream * instream;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rssl|l", &z_ftp, &remote, &remote_len, &local, &local_len, &mode, &startpos) == FAILURE) {
+               return;
+       }
+
+       ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+       XTYPE(xtype, mode);
+
+       instream = php_stream_fopen(local, "rb", NULL);
+
+       if (instream == NULL)   {
+               RETURN_FALSE;
+       }
+
+       /* ignore autoresume if autoseek is switched off */
+       if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
+               startpos = 0;
+       }
+
+       if (ftp->autoseek && startpos) {
+               /* if autoresume is wanted ask for remote size */
+               if (startpos == PHP_FTP_AUTORESUME) {
+                       startpos = ftp_size(ftp, remote);
+                       if (startpos < 0) {
+                               startpos = 0;
+                       }
+               }
+               if (startpos) {
+                       php_stream_seek(instream, startpos, SEEK_SET);
+               }
+       }
+
+       /* configuration */
+       ftp->direction = 1;   /* send */
+       ftp->closestream = 1; /* do close */
+
+       ret = ftp_async_put(ftp, remote, instream, xtype, startpos);
+
+       if (ret != PHP_FTP_MOREDATA) {
+               php_stream_close(instream);
+       }
+
+       if (ret == PHP_FTP_FAILED || php_stream_error(instream)) {
+               php_error(E_WARNING, "%s(): %s", get_active_function_name(TSRMLS_C), ftp->inbuf);
+       }
+
+       RETURN_LONG(ret);
+}
+/* }}} */
+
 /* {{{ proto int ftp_size(resource stream, string filename)
    Returns the size of the file, or -1 on error */
 PHP_FUNCTION(ftp_size)
index fdbb13b3e96c61086d776336476e27a985faa1ab..f22697779cfbaf0a0ac65dd50654163aa5c1e133 100644 (file)
@@ -58,6 +58,11 @@ PHP_FUNCTION(ftp_site);
 PHP_FUNCTION(ftp_close);
 PHP_FUNCTION(ftp_set_option);
 PHP_FUNCTION(ftp_get_option);
+PHP_FUNCTION(ftp_async_get);
+PHP_FUNCTION(ftp_async_fget);
+PHP_FUNCTION(ftp_async_put);
+PHP_FUNCTION(ftp_async_fput);
+PHP_FUNCTION(ftp_async_continue);
 
 #define phpext_ftp_ptr php_ftp_module_ptr