To overcome the 2 GB limitation, the ftp_raw solution below is probably the nicest. You can also perform this command using regular FTP commands:
<?php
$response = ftp_raw($ftpConnection, "SIZE $filename");
$filesize = floatval(str_replace('213 ', '', $response[0]));
?>
[However, this] is insufficient for use on directories. As per RFC 3659 (http://tools.ietf.org/html/rfc959) dictates that the returned string always consists of exactly 3 digits, followed by 1 space, followed by some text. (Multi-line text is allowed, but I am ignoring that.) So it is probably better to split the string with substr, or even a regular expression.
<?php
$response = ftp_raw($ftp, "SIZE $filename");
$responseCode = substr($response[0], 0, 3);
$responseMessage = substr($response[0], 4);
?>
Or with a regular expression:
<?php
$response = ftp_raw($ftp, "SIZE $filename");
if (preg_match("/^(\\d{3}) (.*)$/", $response[0], $matches) == 0)
throw new Exception("Unable to parse FTP reply: ".$response[0]);
list($response, $responseCode, $responseMessage) = $matches;
?>
You could then decide to assume that response code '550' means that it's a directory. I guess that's just as 'dangerous' as assuming that ftp_size -1 means that it's a directory.