summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Treichel <gmblar+github@gmail.com>2017-02-02 01:09:31 +0100
committerNikita Popov <nikita.ppv@gmail.com>2017-02-17 21:31:18 +0100
commit5b1300b6c94b346310c0dd1eb3f89fd786229da4 (patch)
tree3fdd22d87ebdaaf4bc031c42e981464f3ed012e6
parentefefb5276b18f11871bf5405209013c11e5c9e20 (diff)
downloadphp-git-5b1300b6c94b346310c0dd1eb3f89fd786229da4.tar.gz
ftp_mlsd(): Parse the MLSD response
-rw-r--r--ext/ftp/ftp.c44
-rw-r--r--ext/ftp/ftp.h5
-rw-r--r--ext/ftp/php_ftp.c11
-rw-r--r--ext/ftp/tests/ftp_mlsd.phpt97
-rw-r--r--ext/ftp/tests/ftp_mlsd_empty_directory.phpt9
-rw-r--r--ext/ftp/tests/server.inc4
6 files changed, 159 insertions, 11 deletions
diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c
index 4f682e709d..499a8b40b2 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 494c527ca1..d1576f0a8a 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 dc7351ff82..bad5690039 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 0000000000..85da6b8028
--- /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 c9c278a11e..d646d76a98 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 ac2e0a3b63..5f003cc04d 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");