]> granicus.if.org Git - php/commitdiff
Add ftp_append to create a new file or append data to an existing file (RFC959)
authorAndreas Treichel <gmblar+github@gmail.com>
Sat, 8 Jul 2017 17:36:22 +0000 (19:36 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 2 Aug 2017 18:52:28 +0000 (20:52 +0200)
NEWS
UPGRADING
ext/ftp/ftp.c
ext/ftp/ftp.h
ext/ftp/php_ftp.c
ext/ftp/php_ftp.h
ext/ftp/tests/ftp_append.phpt [new file with mode: 0644]
ext/ftp/tests/server.inc

diff --git a/NEWS b/NEWS
index dee4a68c925fe61ef5a2b4b1bf71b06de4e75594..463bdb7b2bee255a311ab7f820a37ff1bdd6214d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,9 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? ????, PHP 7.2.0beta3
 
+- FTP:
+  . Added ftp_append() function. (blar)
+
 - Mbstring:
   . Fixed bug #75001 (Wrong reflection on mb_eregi_replace). (Fabien
     Villepinte)
index 9dcfbebb6fefa4512581a629d9bbc59c44c10aa5..888138b0e074cedca7f6ec7fbe91d6c7e73464f7 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -233,6 +233,9 @@ See also: https://wiki.php.net/rfc/deprecations_php_7_2
   . DomNodeList implements Countable, added DomNodeList::count().
   . DOMNamedNodeMap implements Countable, added DOMNamedNodeMap::count().
 
+- FTP:
+  . Added ftp_append().
+
 - GD:
   . Added imagesetclip() and imagegetclip().
   . Added imageopenpolygon().
index 499a8b40b20794e3a233ed10bd8d5eedec70b06b..d1fffc2b2fabf98ac83f0fbf4789ec0e86d9acec 100644 (file)
@@ -1056,6 +1056,74 @@ bail:
 }
 /* }}} */
 
+
+/* {{{ ftp_append
+ */
+int
+ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type)
+{
+       databuf_t               *data = NULL;
+       zend_long                       size;
+       char                    *ptr;
+       int                     ch;
+
+       if (ftp == NULL) {
+               return 0;
+       }
+       if (!ftp_type(ftp, type)) {
+               goto bail;
+       }
+       if ((data = ftp_getdata(ftp)) == NULL) {
+               goto bail;
+       }
+       ftp->data = data;
+
+       if (!ftp_putcmd(ftp, "APPE", sizeof("APPE")-1, path, path_len)) {
+               goto bail;
+       }
+       if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
+               goto bail;
+       }
+       if ((data = data_accept(data, ftp)) == NULL) {
+               goto bail;
+       }
+
+       size = 0;
+       ptr = data->buf;
+       while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) {
+               /* flush if necessary */
+               if (FTP_BUFSIZE - size < 2) {
+                       if (my_send(ftp, data->fd, data->buf, size) != size) {
+                               goto bail;
+                       }
+                       ptr = data->buf;
+                       size = 0;
+               }
+
+               if (ch == '\n' && type == FTPTYPE_ASCII) {
+                       *ptr++ = '\r';
+                       size++;
+               }
+
+               *ptr++ = ch;
+               size++;
+       }
+
+       if (size && my_send(ftp, data->fd, data->buf, size) != size) {
+               goto bail;
+       }
+       ftp->data = data = data_close(ftp, data);
+
+       if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
+               goto bail;
+       }
+       return 1;
+bail:
+       ftp->data = data_close(ftp, data);
+       return 0;
+}
+/* }}} */
+
 /* {{{ ftp_size
  */
 zend_long
index d1576f0a8aac9221d3f7d55657bb818c2bc5131f..38e34acfe2e244a1f64242596bb9f76b9db267bc 100644 (file)
@@ -190,6 +190,11 @@ int                ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_
  */
 int            ftp_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos);
 
+/* append the data from a file, socket, or process as a file on the remote server
+ * returns true on success, false on error
+ */
+int            ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type);
+
 /* returns the size of the given file, or -1 on error */
 zend_long              ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len);
 
index bad56900393c9e8aaaf477cd70696beb8a663776..eb6589ebc2263f8471c8bbeb5cc2548eae02f253 100644 (file)
@@ -191,6 +191,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_put, 0, 0, 4)
        ZEND_ARG_INFO(0, startpos)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_append, 0, 0, 4)
+       ZEND_ARG_INFO(0, ftp)
+       ZEND_ARG_INFO(0, remote_file)
+       ZEND_ARG_INFO(0, local_file)
+       ZEND_ARG_INFO(0, mode)
+ZEND_END_ARG_INFO()
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_nb_put, 0, 0, 4)
        ZEND_ARG_INFO(0, ftp)
        ZEND_ARG_INFO(0, remote_file)
@@ -265,6 +272,7 @@ const zend_function_entry php_ftp_functions[] = {
        PHP_FE(ftp_get,                         arginfo_ftp_get)
        PHP_FE(ftp_fget,                        arginfo_ftp_fget)
        PHP_FE(ftp_put,                         arginfo_ftp_put)
+       PHP_FE(ftp_append,                      arginfo_ftp_append)
        PHP_FE(ftp_fput,                        arginfo_ftp_fput)
        PHP_FE(ftp_size,                        arginfo_ftp_size)
        PHP_FE(ftp_mdtm,                        arginfo_ftp_mdtm)
@@ -1272,6 +1280,41 @@ PHP_FUNCTION(ftp_put)
 }
 /* }}} */
 
+/* {{{ proto bool ftp_append(resource stream, string remote_file, string local_file, int mode)
+   Append content of a file a another file on the FTP server */
+PHP_FUNCTION(ftp_append)
+{
+       zval            *z_ftp;
+       ftpbuf_t        *ftp;
+       ftptype_t       xtype;
+       char            *remote, *local;
+       size_t          remote_len, local_len;
+       zend_long               mode;
+       php_stream      *instream;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS(), "rppl", &z_ftp, &remote, &remote_len, &local, &local_len, &mode) == FAILURE) {
+               return;
+       }
+
+       if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
+               RETURN_FALSE;
+       }
+       XTYPE(xtype, mode);
+
+       if (!(instream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt" : "rb", REPORT_ERRORS, NULL))) {
+               RETURN_FALSE;
+       }
+
+       if (!ftp_append(ftp, remote, remote_len, instream, xtype)) {
+               php_stream_close(instream);
+               php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+       php_stream_close(instream);
+
+       RETURN_TRUE;
+}
+/* }}} */
 
 /* {{{ proto int ftp_nb_put(resource stream, string remote_file, string local_file, int mode[, int startpos])
    Stores a file on the FTP server */
index 37b75f6b9b2a3028ed90c93a4417d2fff3654b50..3927738306f0a00a7b0f7d1a0c5dea265e29fd71 100644 (file)
@@ -60,6 +60,7 @@ PHP_FUNCTION(ftp_pasv);
 PHP_FUNCTION(ftp_get);
 PHP_FUNCTION(ftp_fget);
 PHP_FUNCTION(ftp_put);
+PHP_FUNCTION(ftp_append);
 PHP_FUNCTION(ftp_fput);
 PHP_FUNCTION(ftp_size);
 PHP_FUNCTION(ftp_mdtm);
diff --git a/ext/ftp/tests/ftp_append.phpt b/ext/ftp/tests/ftp_append.phpt
new file mode 100644 (file)
index 0000000..5f52ac9
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+ftp_append() create new file and append something
+--SKIPIF--
+<?php
+require 'skipif.inc';
+?>
+--FILE--
+<?php
+require 'server.inc';
+
+$ftp = ftp_connect('127.0.0.1', $port);
+if (!$ftp) die("Couldn't connect to the server");
+
+var_dump(ftp_login($ftp, 'user', 'pass'));
+
+@unlink(__DIR__.'/ftp_append_foobar');
+
+file_put_contents(__DIR__.'/ftp_append_foo', 'foo');
+var_dump(ftp_append($ftp, 'ftp_append_foobar', __DIR__.'/ftp_append_foo', FTP_BINARY));
+
+file_put_contents(__DIR__.'/ftp_append_bar', 'bar');
+var_dump(ftp_append($ftp, 'ftp_append_foobar', __DIR__.'/ftp_append_bar', FTP_BINARY));
+
+var_dump(file_get_contents(__DIR__.'/ftp_append_foobar'));
+
+ftp_close($ftp);
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+string(6) "foobar"
index 5f003cc04d00eb3b5c34420df3aa68ae980429b2..a1bf074f90c05a47172d77e3d3ae82e18ad51a94 100644 (file)
@@ -267,7 +267,28 @@ if ($pid) {
                                }
                        }
 
-               } elseif (preg_match("~^CWD ([A-Za-z./]+)\r\n$~", $buf, $m)) {
+               } elseif (preg_match("~^APPE ([\w/.-]+)\r\n$~", $buf, $m)) {
+                       fputs($s, "150 File status okay; about to open data connection\r\n");
+
+                       if(empty($pasv))
+                       {
+                               if (!$fs = stream_socket_client("tcp://$host:$port")) {
+                                       fputs($s, "425 Can't open data connection\r\n");
+                                       continue;
+                               }
+
+                               $data = stream_get_contents($fs);
+                               file_put_contents(__DIR__.'/'.$m[1], $data, FILE_APPEND);
+                               fputs($s, "226 Closing data Connection.\r\n");
+                               fclose($fs);
+                       }else{
+                               $data = stream_get_contents($fs);
+                               file_put_contents(__DIR__.'/'.$m[1], $data, FILE_APPEND);
+                               fputs($s, "226 Closing data Connection.\r\n");
+                               fclose($fs);
+            }
+
+               }elseif (preg_match("~^CWD ([A-Za-z./]+)\r\n$~", $buf, $m)) {
                        change_dir($m[1]);
                        fputs($s, "250 CWD command successful.\r\n");