RSS Feeds for FTP Servers
by Mark Woodman
|
Pages: 1, 2, 3, 4
The scanDirectory() Function
Now we are ready to write the scanDirectory() function, which is called from our exploreFtpServer() described above. The purpose of this function is to scan an FTP directory for files and subdirectories, adding the former to a list and recursing through the latter. The parameters to pass in are the FTP connection ID ($cid) and a starting directory ($dir). We'll also declare a static variable $fileList which will be used to retain our file list across recursive calls to the function.
To get the contents of a given directory in FTP, we'll use the ftp_nlist() function. Unfortunately, this function isn't perfect. On most FTP servers I have tested, it will return a list of file and directory names. But there are a few, like WU-FTPD, which only return a listing of filenames. On such servers our script can monitor only the initial directory provided; no subdirectories will be monitored.
The alternative to ftp_nlist() is ftp_rawlist(), which should provide all directory contents regardless of type. Unfortunately, the format of data returned by ftp_rawlist() does not seem to be standardized, so any attempt to come up with a "universal parser" is a daunting task. (Read the user comments on ftp_rawlist() to see what I mean.) Thus, for the sake of the tutorial, we'll stick with the imperfect but much simpler ftp_nlist().
function scanDirectory($cid, $dir)
{
// Use static value to collect results
static $fileList=array();
// Get a listing of directory contents
$contents = ftp_nlist($cid, $dir);
The $contents variable is now populated with a simple array of file and directory names. Depending on the server, these items may or may not contain the path of the file itself. (We may get "foo.txt", or we may get "/i/pity/the/foo.txt".)
This next section of scanDirectory() will iterate through each name and use ftp_size() to determine whether the name is a file or directory. (This is a cheap trick: directories return a size of -1.) If the item is a file, we'll prepend a leading slash if needed to keep our paths consistent, then use the ftp_mdtm() function to get its modification timestamp. We'll then add the filename as the key in our $fileList associative array, and use its timestamp as the value:
// Iterate through the directory contents
if($contents!=null)
{
foreach ($contents as $item)
{
// Is the item a file?
if (ftp_size($cid, $item)>=0)
{
// Prepend slash if not present
if($item[0]!="/") $item = "/" . $item;
// Add file and modify timestamp to results
$fileList[$item] = ftp_mdtm($cid, $item);
}
Now we'll need to deal with an item returned by ftp_nlist() that is a directory. We'll be sure to ignore aliases to the same or parent directory. If we have a usable directory name, we can call scanDirectory() to recurse into it. (This requires some extra logic to handle variations among servers that use full or relative paths.) With both files and directories handled, we can return the $fileList containing every file found thus far. Here's how it all looks:
else
// Item is a directory
{
// Exclude self/parent aliases
if($item!="." && $item!=".." && $item!="/")
{
// Server uses full path names
if($item==strstr($item, $dir))
{
scanDirectory($cid, $item);
}
else
{
// Server uses relative path names
if($dir=="/")
{
scanDirectory($cid, $dir . $item);
}
else
{
scanDirectory($cid, $dir . "/" . $item);
}
}
}
}
}
}
// Return the results
return $fileList;
}