From: Andreas Treichel Date: Thu, 2 Feb 2017 00:09:31 +0000 (+0100) Subject: ftp_mlsd(): Parse the MLSD response X-Git-Tag: php-7.2.0alpha1~348 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5b1300b6c94b346310c0dd1eb3f89fd786229da4;p=php ftp_mlsd(): Parse the MLSD response --- 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-- + +--FILE-- + +--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");