Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP - Check if file exists on FTP server with no SIZE support

Tags:

php

ftp

Yes, I know, it's hard to believe those FTP servers still exist, but they actually do. IBM iSeries machines run such servers.

I've already got an answer which involves ftp_nlist and in_array but, as some of you may have guessed, this is slow when a directory contains a large number of items.

Due to the lack of support of SIZE, fopen always fails when used in read mode (remember that x isn't supported by the FTP wrapper), while ftp_size always returns -1 (that was expected) and file_exists always returns false (maybe because it uses SIZE internally?).

  • ftp_get and ftp_fget do the trick, but they download the whole file if it exists. Not very good. One possible solution involves the use of ftp_fget passing an handler of a file opened in read mode only, and catching the raised warning. It's different when the file doesn't exist, but this solution feels uncouth, and I don't really know if it's feasible (maybe someone can give an example).

  • Another solution uses ftp_nb_get/ftp_nb_fget to try to retrieve the file. If the function returns 0 (FTP_FAILED) then the file presumably doesn't exist. I'd still have to deal with a temporary local file, and it sucks to close and reopen the connection if FTP_MOREDATA is returned (or else other FTP commands couldn't be issued).

Do you have any idea for this?

like image 760
MaxArt Avatar asked Feb 26 '14 11:02

MaxArt


People also ask

How do I find the size of a FTP server?

The ftp_size() function returns the size of a specified file on the FTP server.

How do you create a file if it doesn't exist in PHP?

PHP Create File - fopen() The fopen() function is also used to create a file. Maybe a little confusing, but in PHP, a file is created using the same function used to open files. If you use fopen() on a file that does not exist, it will create it, given that the file is opened for writing (w) or appending (a).

How do you check if a file already exists in PHP?

The file_exists() function checks whether a file or directory exists.


Video Answer


1 Answers

The SIZE command is not required. You can simply use the function ftp_nlist() for that because the FTP LIST command allows to pass a directory as well as file as it's argument.

Although the PHP documentation is missing to mention that it is specified in RFC 959 (page 32) and is working. Here comes an example. (Thanks Debian!)

$server = 'ftp.us.debian.org';
$port   =  21; 
$user   = 'anonymous';
$pwd    = '[email protected]';

$conn = ftp_connect($server);
$ret = ftp_login($conn, $user, $pwd);

foreach(array(
    'debian/README.html',
    'NOT_FOUND.html'
) as $file) {
    $listing = ftp_nlist($conn, $file);
    if(empty($listing)) {
        echo "$file was not found on $server\n";
    } else {
        echo "$file was found on $server\n";
    }
}

Or, expressed as a function:

function ftp_file_exists(
    $server,
    $filename,
    $user = 'anonymous' ,
    $pwd = '',
    $port = 21
) {
    $conn = @ftp_connect($server);
    if($conn === FALSE) {
        die("Failed to connect to $server");
    }

    $ret = @ftp_login($conn, $user, $pwd);
    if($ret === FALSE) {
        die("Failed to login at $server");
    }

    $listing = @ftp_nlist($conn, $file);
    if($listing === FALSE) {
        die("Failed to obtain LIST response from $server");
    }

    return !empty($listing);
}

In comments there came up a discussion how useful and reliable the results of LIST can be. Let me say some additional sentences to that...

Creating files on server

Please be aware of the fact that you should avoid to rely on something like:

if(file_not_exists_on_server($filename)) {
    create_file_on_server($filename);
}

because it is possible that the file will be created by another client between the first and second function. While this is true on local file systems as well, it can happen in distributed client server applications more easily, because of longer response times compared to a local filesystem and because of possibly many, even anonymous clients (like in the example above)

When creating files remotely I would suggest to follow a strong naming scheme in public writable folders in order to avoid collisions. When following this scheme, then just write and don't care. The worst thing which can happen is that you overwrite something which somebody other has created by accident. But who creates something like /client/id/file_name.txt by accident?


Downloading files from server or moving, deleting files on server

When attempting one of those operations, don't care about if the files exists or not before the operation. Just do it. But if it fails, you need to handle the errors properly.

like image 90
hek2mgl Avatar answered Sep 25 '22 20:09

hek2mgl