W3docs

ftp_mlsd()

Learn the PHP ftp_mlsd() function: list an FTP directory in a structured, machine-readable format. Syntax, return values, examples and error handling.

What is ftp_mlsd()?

ftp_mlsd() is a built-in PHP function (available since PHP 7.2) that lists the contents of a directory on an FTP server using the FTP MLSD command. Unlike older listing functions, it returns a structured, machine-readable result: instead of a raw text blob you have to parse yourself, you get an array of entries where each file or directory carries named attributes such as its type, size and modification time.

This matters because directory listings from FTP servers are notoriously inconsistent — ftp_rawlist() returns lines whose format depends on the server's operating system. MLSD was added to the FTP protocol (RFC 3659) precisely to standardize this, and ftp_mlsd() exposes it directly.

Use ftp_mlsd() when you need to:

  • Enumerate files and know each one's size, type, or timestamp.
  • Reliably tell directories apart from files (the type attribute does this for you).
  • Avoid the brittle string-parsing that ftp_rawlist() forces on you.

If you only need a flat list of file names, ftp_nlist() is simpler. If you must support pre-7.2 servers or servers without MLSD support, fall back to ftp_rawlist().

Syntax of ftp_mlsd()

ftp_mlsd(FTP\Connection $ftp, string $directory): array|false

The function takes two required parameters:

ParameterDescription
$ftpThe FTP connection identifier returned by ftp_connect() (or ftp_ssl_connect()).
$directoryThe path of the directory to list, e.g. /public_html or . for the current directory.
Note

Both parameters are required. The MLSD command always operates on an explicit path — pass . if you want the directory you are currently in.

It returns an array of entries on success, or false on failure (for example, if the path does not exist or the server does not support MLSD).

What ftp_mlsd() returns

Each element of the returned array is an associative array describing one entry. The exact keys depend on what the server reports, but the common ones are:

KeyMeaning
nameThe file or directory name.
typeThe entry type: file, dir, cdir (current dir, .), or pdir (parent dir, ..).
sizeSize in bytes (usually present only for files).
modifyLast-modified timestamp, formatted as YYYYMMDDHHMMSS.
permsPermissions string as reported by the server.
uniqueA server-assigned identifier that is unique per file.

The shape of a single entry looks like this:

[
    'name'   => 'report.pdf',
    'type'   => 'file',
    'size'   => '20480',
    'modify' => '20240115093000', // 2024-01-15 09:30:00
    'perms'  => 'adfr',
]

Usage of ftp_mlsd()

Before listing anything, you connect with ftp_connect() and authenticate with ftp_login(). The full flow looks like this:

<?php

// 1. Open a connection
$ftp = ftp_connect('ftp.example.com');

// 2. Authenticate
ftp_login($ftp, 'username', 'password');

// 3. Switch to passive mode (recommended behind firewalls/NAT)
ftp_pasv($ftp, true);

// 4. Get a structured listing of the directory
$entries = ftp_mlsd($ftp, '/public_html');

// 5. Always close the connection when done
ftp_close($ftp);

Iterating over the listing

The real value of ftp_mlsd() is the structured data. Here we print every file with a human-readable size and skip the . and .. pseudo-entries:

<?php

$entries = ftp_mlsd($ftp, '.');

foreach ($entries as $entry) {
    // Skip the current-dir and parent-dir markers
    if (in_array($entry['type'], ['cdir', 'pdir'], true)) {
        continue;
    }

    if ($entry['type'] === 'dir') {
        echo "[DIR]  {$entry['name']}\n";
    } else {
        $kb = round($entry['size'] / 1024, 1);
        echo "[FILE] {$entry['name']} ({$kb} KB)\n";
    }
}

The modify field is a 14-digit timestamp. You can turn it into a real date with DateTime:

<?php

$modified = DateTime::createFromFormat('YmdHis', $entry['modify']);
echo $modified->format('Y-m-d H:i:s');

Error handling in ftp_mlsd()

ftp_mlsd() returns false on failure, so always check the result before looping over it — calling foreach on false would emit a warning and process nothing.

<?php

$entries = ftp_mlsd($ftp, '/path/that/may/not/exist');

if ($entries === false) {
    echo "Failed to retrieve the directory listing.\n";
} else {
    foreach ($entries as $entry) {
        echo $entry['name'] . "\n";
    }
}
Warning

Use the strict comparison === false. An empty directory returns an empty array [], which is falsy — a loose if (!$entries) check would wrongly treat an empty (but valid) directory as an error.

Common reasons ftp_mlsd() fails:

  • The server does not support the MLSD command (older or minimal FTP servers). Fall back to ftp_rawlist().
  • The directory path is wrong or you lack permission to read it.
  • You are not yet logged in, or the connection has timed out.

ftp_mlsd() vs. other listing functions

FunctionReturnsBest for
ftp_mlsd()Structured array (name, type, size, modify…)Reliable metadata across servers (PHP 7.2+)
ftp_nlist()Flat array of namesA quick list of file names only
ftp_rawlist()Array of raw ls-style linesLegacy servers without MLSD

Conclusion

ftp_mlsd() is the modern, dependable way to list an FTP directory in PHP: it hands you a structured array with each entry's type, size, and modification time, sparing you the fragile text-parsing that older functions require. Pair it with ftp_connect(), ftp_login(), and ftp_close() for a complete, robust FTP listing workflow — and remember to check for === false before iterating.

Practice

Practice
What is the FTP MLSD command used for in PHP?
What is the FTP MLSD command used for in PHP?
Was this page helpful?