Search code examples
phpftp

PHP ftp_nlist always returning false


I'm trying to get a list of files from an FTP directory but the ftp_nlist function repeatedly returns false. I've tried this on 3 different FTP servers with the same result. In each case, I was able to connect and download files using ftp_fget, but ftp_nlist never works. Any ideas why? Here is the code:

<?php

$ftp_server = "myhost";
$ftp_user_name = "myuser";
$ftp_user_pass = "mypass";

$remote_dir = "test/"; // The directory on the FTP server
$local_dir = "test/"; // Local directory to save the files

// Connect to the FTP server
$conn_id = ftp_connect($ftp_server);

if (!$conn_id) {
    die("Could not connect to FTP server $ftp_server");
}

// Log in to the server
if (!ftp_login($conn_id, $ftp_user_name, $ftp_user_pass)) {
    die("Could not log in to FTP server with provided credentials.");
}

// Enable passive mode
ftp_pasv($conn_id, true);

if (!ftp_chdir($conn_id, $remote_dir)) {
    ftp_close($conn_id);
    die("Could not change to directory: $remote_dir");
}

// Check if the local directory exists, if not create it
if (!is_dir($local_dir)) {
    if (!mkdir($local_dir, 0777, true)) {
        die("Failed to create local directory: $local_dir");
    }
}

// Download a file - THIS WORKS!
$remote_file='test.txt';
$local_file='test.txt';
$handle = fopen($local_file, 'w');
if (ftp_fget($conn_id, $handle, $remote_file, FTP_ASCII, 0)) {
 echo "successfully written to $local_file\n";
} else {
 echo "There was a problem while downloading $remote_file to $local_file\n";
}

// Get the list of files in the remote directory
$files = ftp_nlist($conn_id, $remote_dir);
//$files = ftp_nlist($conn_id, '');

if ($files === false) {
    die("Could not list files in the remote directory: $remote_dir");
}

foreach ($files as $file) {
    // Get the base name of the file
    $basename = basename($file);

    // Build the local file path
    $local_file = $local_dir . $basename;

    // Attempt to download the file
    if (ftp_get($conn_id, $local_file, $file, FTP_BINARY)) {
        echo "Successfully downloaded $file to $local_file\n";
    } else {
        echo "Failed to download $file\n";
    }
}

// Close the FTP connection
ftp_close($conn_id);

echo "FTP download completed.\n";
?>

Solution

  • A very small reproduceable example of your problem is below

    $remote_dir = "test/";   
    ftp_chdir($conn_id, $remote_dir);
    var_dump(ftp_nlist($conn_id, $remote_dir));
    

    The second line changes the FTP connection's remote directory to test/. Note that there is no leading / so it is relative to whatever the current CWD is. You are then asking for a directory listing using the same variable which means it is relative to the last call that changed CWD, effectively test/test/.

    There's a couple of possible fixes that I can think of.

    The easiest probably is as @Olivier pointed out in the comments and just use . as the second argument to ftp_nlist which would mean "give me the list of files in the current directory":

    var_dump(ftp_nlist($conn_id, '.'));
    

    The second option is to just not issue the ftp_chdir command in the first place. This mostly depends on what else you are doing, and whether you care about the CWD at all, which I think your code does. So possibly this is not for you.

    The last option is to just use absolute directories, so instead of test/ use /test/. This would allow you to use ftp_chdir both ftp_nlist with the same variable and talk about the same directory. The choice to do this, once again, depends on the intentions of your code.