5Jun2008

I recently had the need to be able to monitor a directory on an FTP server for changes and to then be notified of those changes. I’ve been working a lot in PHP lately so I decided to use that to implement my script.

FTP Access

FTP (file transfer protocol) access in PHP is a breeze. It’s as simple as this:

// Connect to FTP host
$conn = ftp_connect($host, $port) or die("Could not connect to {$host}\n");
 
// Login
if(ftp_login($conn, $user, $pass)) {
  // Retrieve directory listing
  $files = ftp_nlist($conn, $remote_dir);
}
 
// Close Connect
ftp_close($conn);

Easy, right? Of course I left out a few pieces of the puzzle, but I just wanted to show how easy it is to actually get to an FTP server, login and get a directory listing.

Comparisons

After retrieving the listing which is an array I remove out the “.” and “..” listings as they are special system directories meaning “the current directory” and “the parent directory” respectively.

$ftpFiles = array();
foreach($files as $file)
{
  // Get just the filename without directory information
  $thisFile = basename($file);
  if($thisFile != '.' && $thisFile != '..')
  {
    // Append to our new array
    $ftpFiles[] = $thisFile;
  }
}

Now the header for this section is Comparisons, so what exactly are we comparing to? Each time this script runs we store a serialized version of this array out to file. I read the file into an array and compare it with the one we just created from the FTP directory.

$currentFiles = array();
if(file_exists($cache_file))
{
  // Read contents of file
  $handle = fopen($cache_file, "r");
  if($handle)
  {
    $contents = fread($handle, filesize($cache_file));
    fclose($handle);
 
    // Unserialize our array from the file contents
    $currentFiles = unserialize($contents);
  }
}

Now that we have an array of files (and directories) that we just pulled from the FTP server and an array that we saved from the last time we ran we can just compare the two.

$diff = array_diff($ftpFiles, $currentFiles);
if(count($diff) > 0)
{
  // There are changes so do some stuff here.
  // In the download script I actually compile and send an email with the files listed
}

Finally, I write the contents of the new array back out to the cache file so we can use it to compare on the next run.

// Write new file list out to cache
$handle = fopen($cache_file, "w");
fwrite($handle, serialize($ftpFiles));
fflush($handle);
fclose($handle);

Summary and Download

So that’s it! Pretty simple. On my server I pre-pended the following to the file:
#!/usr/bin/env php
and changed the file mode so that it could be executed. I then setup a cron job to run at 8 o’clock every morning like this:

> crontab -e

# This is added to crontab
0 8 * * * ~/ftpMonitor.php

Here is the complete file in a zip file. Open the file in any text editor and you will see a configuration section at the top where you can set your FTP host information and email information.

ftpMonitor.zip

I hope you have enjoyed this short tutorial and may possibly find it useful. If you have any comments or suggestions for improvement please feel free to leave those in the comments section below. Thanks for stopping by!



11 Comments

1

This is a great script, something I have been looking for to monitor changes on my FTP server, however I am having problems running it. I get the error “Warning: Invalid argument supplied for foreach()” on line 34. I am guessing it’s a configuration issue, but I am unable to figure it out. Bear in mind I am not a programmer I just tinker with these things. By the way thanks again for sharing this script, I hope you can help.


2

Hi, I am having issues implementing your script. I’m running it from a Windows PHP installation remotely to a Yahoo hosted website of mine. When I echo $variables to see what we’ve got so far, I’m not getting any file directory listing using echo $files;
Any ideas?
Thank you
Jeff



Have you tried using var_dump($files)? And I’m assuming that you were able to successfully login via the PHP code? Also, have you checked that you can use a standard FTP client (FireFTP) to login and list files on your server?


4

Thanks Jonathan, var_dump outputs this “bool(false)”. But using ftp client or even ftp from dos prompt I can list files/dirs. Could it be the installation of the Servers PHP? do I need the ftp -enabled option set? (which I can’t since its yahoo hosted) What I really need is some code to watch for when a file gets “touched”.



No, it shouldn’t matter what is installed on the server as far as PHP goes. You should definitely make sure your local PHP installation has the FTP modules enabled though.


6

OK, just found out my web hosting company does NOT support FTP functions via PHP. I’ll have to figure something else out. Thanks again.


7

sweeet

could you next provide a PHP ‘fancy’ directory listing app.. that instead of creating for local directory logs in with FTP credentials?

akin to the evoluted script, but better
http://www.evoluted.net/community/code/directorylisting.php


8

I wish this form retained my formatting :|


9

I have tested and I get following problems: Can you throw some light as why these are showing up?

Warning: Invalid argument supplied for foreach() in /home/test/public_html/testmonitor/ftpnitor.php on line 34

Warning: sort() expects parameter 1 to be array, boolean given in /home/test/public_html/testmonitor/ftpnitor.php on line 59

Warning: array_diff() [function.array-diff]: Argument #2 is not an array in /home/test/public_html/testmonitor/ftpnitor.php on line 63

Warning: fopen(ftp_cache) [function.fopen]: failed to open stream: Is a directory in /home/test/public_html/testmonitor/ftpnitor.php on line 87

Warning: fwrite(): supplied argument is not a valid stream resource in /home/test/public_html/testmonitor/ftpnitor.php on line 88

Warning: fflush(): supplied argument is not a valid stream resource in /home/test/public_html/testmonitor/ftpnitor.php on line 89

Warning: fclose(): supplied argument is not a valid stream resource in /home/test/public_html/testmonitor/ftpnitor.php on line 90


10

Any way to make this go more than one directory deep?


11

For example, would there be a way to use ftp_rawlist and extract just the relevant info? I don’t think ftp_nlist allows recursive, which is just stupid on PHP’s part.


 




Leave a comment