]> granicus.if.org Git - php/commitdiff
ftp_mlsd(): Parse the MLSD response
authorAndreas Treichel <gmblar+github@gmail.com>
Thu, 2 Feb 2017 00:09:31 +0000 (01:09 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 17 Feb 2017 20:31:18 +0000 (21:31 +0100)
ext/ftp/ftp.c
ext/ftp/ftp.h
ext/ftp/php_ftp.c
ext/ftp/tests/ftp_mlsd.phpt [new file with mode: 0644]
ext/ftp/tests/ftp_mlsd_empty_directory.phpt
ext/ftp/tests/server.inc

index 4f682e709d9962e51080717963ef3d8d5900079b..499a8b40b20794e3a233ed10bd8d5eedec70b06b 100644 (file)
@@ -707,6 +707,50 @@ ftp_mlsd(ftpbuf_t *ftp, const char *path, const size_t path_len)
 }
 /* }}} */
 
+/* {{{ ftp_mlsd_parse_line
+ */
+int
+ftp_mlsd_parse_line(HashTable *ht, const char *input) {
+
+       zval zstr;
+       const char *end = input + strlen(input);
+
+       const char *sp = memchr(input, ' ', end - input);
+       if (!sp) {
+               php_error_docref(NULL, E_WARNING, "Missing pathname in MLSD response");
+               return FAILURE;
+       }
+
+       /* Extract pathname */
+       ZVAL_STRINGL(&zstr, sp + 1, end - sp - 1);
+       zend_hash_str_update(ht, "name", sizeof("name")-1, &zstr);
+       end = sp;
+
+       while (input < end) {
+               const char *semi, *eq;
+
+               /* Find end of fact */
+               semi = memchr(input, ';', end - input);
+               if (!semi) {
+                       php_error_docref(NULL, E_WARNING, "Malformed fact in MLSD response");
+                       return FAILURE;
+               }
+
+               /* Separate fact key and value */
+               eq = memchr(input, '=', semi - input);
+               if (!eq) {
+                       php_error_docref(NULL, E_WARNING, "Malformed fact in MLSD response");
+                       return FAILURE;
+               }
+
+               ZVAL_STRINGL(&zstr, eq + 1, semi - eq - 1);
+               zend_hash_str_update(ht, input, eq - input, &zstr);
+               input = semi + 1;
+       }
+
+       return SUCCESS;
+}
+/* }}} */
 
 /* {{{ ftp_type
  */
index 494c527ca1b405cf296a549b780b9a4f97bc136a..d1576f0a8aac9221d3f7d55657bb818c2bc5131f 100644 (file)
@@ -163,6 +163,11 @@ char**             ftp_nlist(ftpbuf_t *ftp, const char *path, const size_t path_len);
  */
 char**         ftp_list(ftpbuf_t *ftp, const char *path, const size_t path_len, int recursive);
 
+/* populates a hashtable with the facts contained in one line of
+ * an MLSD response.
+ */
+int                    ftp_mlsd_parse_line(HashTable *ht, const char *input);
+
 /* returns a NULL-terminated array of lines returned by the ftp
  * MLSD command for the given path or NULL on error.  the return
  * array must be freed (but don't
index dc7351ff8298c26bdadc9bf23f32e8bc6f0a297c..bad56900393c9e8aaaf477cd70696beb8a663776 100644 (file)
@@ -755,13 +755,14 @@ PHP_FUNCTION(ftp_rawlist)
 /* }}} */
 
 /* {{{ proto array ftp_mlsd(resource stream, string directory)
-   Returns a detailed listing of a directory as an array of output lines */
+   Returns a detailed listing of a directory as an array of parsed output lines */
 PHP_FUNCTION(ftp_mlsd)
 {
        zval            *z_ftp;
        ftpbuf_t        *ftp;
        char            **llist, **ptr, *dir;
        size_t          dir_len;
+       zval            entry;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &dir, &dir_len) == FAILURE) {
                return;
@@ -778,8 +779,14 @@ PHP_FUNCTION(ftp_mlsd)
 
        array_init(return_value);
        for (ptr = llist; *ptr; ptr++) {
-               add_next_index_string(return_value, *ptr);
+               array_init(&entry);
+               if (ftp_mlsd_parse_line(Z_ARRVAL_P(&entry), *ptr) == SUCCESS) {
+                       zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &entry);
+               } else {
+                       zval_ptr_dtor(&entry);
+               }
        }
+
        efree(llist);
 }
 /* }}} */
diff --git a/ext/ftp/tests/ftp_mlsd.phpt b/ext/ftp/tests/ftp_mlsd.phpt
new file mode 100644 (file)
index 0000000..85da6b8
--- /dev/null
@@ -0,0 +1,97 @@
+--TEST--
+ftp_mlsd() return parsed lines
+--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'));
+
+var_dump(ftp_mlsd($ftp, '.'));
+
+ftp_close($ftp);
+?>
+--EXPECTF--
+bool(true)
+
+Warning: ftp_mlsd(): Missing pathname in MLSD response in %s on line %d
+
+Warning: ftp_mlsd(): Malformed fact in MLSD response in %s on line %d
+
+Warning: ftp_mlsd(): Malformed fact in MLSD response in %s on line %d
+array(4) {
+  [0]=>
+  array(8) {
+    ["name"]=>
+    string(1) "."
+    ["modify"]=>
+    string(14) "20170127230002"
+    ["perm"]=>
+    string(7) "flcdmpe"
+    ["type"]=>
+    string(4) "cdir"
+    ["unique"]=>
+    string(11) "811U4340002"
+    ["UNIX.group"]=>
+    string(2) "33"
+    ["UNIX.mode"]=>
+    string(4) "0755"
+    ["UNIX.owner"]=>
+    string(2) "33"
+  }
+  [1]=>
+  array(8) {
+    ["name"]=>
+    string(2) ".."
+    ["modify"]=>
+    string(14) "20170127230002"
+    ["perm"]=>
+    string(7) "flcdmpe"
+    ["type"]=>
+    string(4) "pdir"
+    ["unique"]=>
+    string(11) "811U4340002"
+    ["UNIX.group"]=>
+    string(2) "33"
+    ["UNIX.mode"]=>
+    string(4) "0755"
+    ["UNIX.owner"]=>
+    string(2) "33"
+  }
+  [2]=>
+  array(9) {
+    ["name"]=>
+    string(6) "foobar"
+    ["modify"]=>
+    string(14) "20170126121225"
+    ["perm"]=>
+    string(5) "adfrw"
+    ["size"]=>
+    string(4) "4729"
+    ["type"]=>
+    string(4) "file"
+    ["unique"]=>
+    string(11) "811U4340CB9"
+    ["UNIX.group"]=>
+    string(2) "33"
+    ["UNIX.mode"]=>
+    string(4) "0644"
+    ["UNIX.owner"]=>
+    string(2) "33"
+  }
+  [3]=>
+  array(3) {
+    ["name"]=>
+    string(9) "path;name"
+    ["fact"]=>
+    string(6) "val=ue"
+    ["empty"]=>
+    string(0) ""
+  }
+}
index c9c278a11e208da5fcc9193cb33bf01c6ba2fcad..d646d76a98a3477ffa5972d7cd7adda25fd8f9a3 100644 (file)
@@ -13,7 +13,6 @@ if (!$ftp) die("Couldn't connect to the server");
 
 var_dump(ftp_login($ftp, 'user', 'pass'));
 
-var_dump(ftp_mlsd($ftp, ''));
 var_dump(ftp_mlsd($ftp, 'emptydir'));
 var_dump(ftp_mlsd($ftp, 'bogusdir'));
 
@@ -21,14 +20,6 @@ ftp_close($ftp);
 ?>
 --EXPECT--
 bool(true)
-array(3) {
-  [0]=>
-  string(109) "modify=20170127230002;perm=flcdmpe;type=cdir;unique=811U4340002;UNIX.group=33;UNIX.mode=0755;UNIX.owner=33; ."
-  [1]=>
-  string(110) "modify=20170127230002;perm=flcdmpe;type=pdir;unique=811U4340002;UNIX.group=33;UNIX.mode=0755;UNIX.owner=33; .."
-  [2]=>
-  string(122) "modify=20170126121225;perm=adfrw;size=4729;type=file;unique=811U4340CB9;UNIX.group=33;UNIX.mode=0644;UNIX.owner=33; foobar"
-}
 array(0) {
 }
 bool(false)
index ac2e0a3b632d4d3a4f7e6d667f1a0461164a7b87..5f003cc04d00eb3b5c34420df3aa68ae980429b2 100644 (file)
@@ -489,6 +489,10 @@ if ($pid) {
                                fputs($fs, "modify=20170127230002;perm=flcdmpe;type=cdir;unique=811U4340002;UNIX.group=33;UNIX.mode=0755;UNIX.owner=33; .\r\n");
                                fputs($fs, "modify=20170127230002;perm=flcdmpe;type=pdir;unique=811U4340002;UNIX.group=33;UNIX.mode=0755;UNIX.owner=33; ..\r\n");
                                fputs($fs, "modify=20170126121225;perm=adfrw;size=4729;type=file;unique=811U4340CB9;UNIX.group=33;UNIX.mode=0644;UNIX.owner=33; foobar\r\n");
+                               fputs($fs, "fact=val=ue;empty=; path;name\r\n");
+                               fputs($fs, "no_space\r\n");
+                               fputs($fs, "no_semi pathname\r\n");
+                               fputs($fs, "no_eq; pathname\r\n");
                        }
 
                        fputs($s, "226 Closing data Connection.\r\n");