com php-src: ftp_mlsd(): Parse the MLSD respons e: ext/ftp/ftp.c ext/ftp/ftp.h ext/ftp/php_ftp. c ext/ftp/tests/ftp_mlsd.phpt ext/ftp/tests/ftp_mlsd _empty_directory.phpt ext/ftp/tests/server.inc

[email protected] (Nikita Popov)
Newsgroups php.cvs
Message-ID <[email protected]>
Commit:    5b1300b6c94b346310c0dd1eb3f89fd786229da4
Author:    Andreas Treichel <[email protected]>         Thu, 2 Feb 2017 01:09:31 +0100
Committer: Nikita Popov <[email protected]>      Fri, 17 Feb 2017 21:31:18 +0100
Parents:   efefb5276b18f11871bf5405209013c11e5c9e20
Branches:  master

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=5b1300b6c94b346310c0dd1eb3f89fd786229da4

Log:
ftp_mlsd(): Parse the MLSD response

Changed paths:
  M  ext/ftp/ftp.c
  M  ext/ftp/ftp.h
  M  ext/ftp/php_ftp.c
  A  ext/ftp/tests/ftp_mlsd.phpt
  M  ext/ftp/tests/ftp_mlsd_empty_directory.phpt
  M  ext/ftp/tests/server.inc


Diff:
diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c
index 4f682e7..499a8b4 100644
--- a/ext/ftp/ftp.c
+++ b/ext/ftp/ftp.c
@@ -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
  */
diff --git a/ext/ftp/ftp.h b/ext/ftp/ftp.h
index 494c527..d1576f0 100644
--- a/ext/ftp/ftp.h
+++ b/ext/ftp/ftp.h
@@ -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
diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c
index dc7351f..bad5690 100644
--- a/ext/ftp/php_ftp.c
+++ b/ext/ftp/php_ftp.c
@@ -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
index 0000000..85da6b8
--- /dev/null
+++ b/ext/ftp/tests/ftp_mlsd.phpt
@@ -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) ""
+  }
+}
diff --git a/ext/ftp/tests/ftp_mlsd_empty_directory.phpt b/ext/ftp/tests/ftp_mlsd_empty_directory.phpt
index c9c278a..d646d76 100644
--- a/ext/ftp/tests/ftp_mlsd_empty_directory.phpt
+++ b/ext/ftp/tests/ftp_mlsd_empty_directory.phpt
@@ -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)
diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc
index ac2e0a3..5f003cc 100644
--- a/ext/ftp/tests/server.inc
+++ b/ext/ftp/tests/server.inc
@@ -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");
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.