FTP Administration with full logging via PHP

Why should you read this article : sometimes, when working on complex projects, you may need to store files on different servers. This can be easily done via FTP. The logging process makes it easier to track all changes.

What you should know before reading this article : working with classes.

What you will know after reading this article : how to create a class that can be used to easily administrate a FTP connection with a server and log the activity.

Full source code : FTP Administration Source Code

1. Defining the class and the members : First, create a file called ftp.class.php . Define a class called “ftp” and 4 private members: $ftp_handler, which will store a handler to the FTP connection, a boolean value $is_logged which will specify if the user is logged in to the FTP server, $log_handler will keep a handler to the file where the activity will be stored and another boolean variable $is_log, specifying if the activity will be logged. Your code should look something like this :

class ftp {

// FTP Connection handler
private $ftp_handler;
// Keep tracking if the user is logged
private $is_logged = false;
// Logging file handler
private $log_handler;
// Enable action logging
private $is_log = true;

2. Writing the constructor of the class : The constructor of the class will have 6 parameters: the $host of the FTP server, the $port that will be used (set by default to 21), the login information ($username and $password), the $timeout (set to default to 90 seconds), and a boolean variable $ssl, which will specify if the connection will be made via Secure Socket Layer (SSL).
First of all, we will have to verify if the parameters passed to the constructor are valid (the $host and the $username should not be empty - Details). If at least one of them is empty, then we output an error (by using the show_err method, which we will define later) and return false. Otherwise, we will connect to the FTP server by using the ftp_connect ( Details ) or ftp_ssl_connect ( Details ). We will pass the $host and the $port to these functions as parameters. The handler to the connection will be stored in the class member $ftp_handler.

// Connect to the FTP server normally or via SSL
if(!$ssl)
$this->ftp_handler = ftp_connect($host, $port);
else
$this->ftp_handler = ftp_ssl_connect($host, $port);

// Check for errors
if(!$this->ftp_handler) {
$this->print_err(”Could not connect to the specified host & port”);
return;
}

Next, we set the timeout for this FTP connection by using the ftp_set_option function ( Details ) and after that log in with ftp_login ( Details ). If the login was successful, we mark this by setting the private member $is_logged to true and switch to passive mode ( Details ).

// Log in
$this->is_logged = ftp_login($this->ftp_handler, $username, $password);

// Check for errors
if(!$this->is_logged) {
$this->print_err(”The username & password do not match”);
return;
}

// Switch to passive mode
if(!ftp_pasv($this->ftp_handler, true)) {
$this->print_err(”Could not switch to passive mode”);
return;
}

If the $is_log variable is set to true, we will open the log file for writing. We will store all the log files in a directory called “ftp_log”. If this folder does not exist, we will create it with mkdir( Details ). There will be 1 log file for 1 day of activity ( e.g. for the 26th of September 2007 the log file will be 26_9_2007.log ). We then create a handler with fopen ( Details ) to the log file for the current date, which will be stored in the $log_handler variable.

// Open log file
if($this->is_log) {
// Check if the folder where the log files will be stored exists, otherwise create it
if(!file_exists(”ftp_log/”))
if(!mkdir(”ftp_log/”, 0777)) {
$this->print_err(”Could not create the ftp_log directory”);
$this->is_log = false;
return;
}
$this->log_handler = fopen(”ftp_log/”.date(”d_n_Y”).”.log”, “a+”);
if(!$this->log_handler) {
// If log file could not be opened, output error and disable error logging
$this->print_err(”Could not open the log file”);
$this->is_log = false;
}
}

In the end we will write to the write to the log that the user has logged in by calling the log method, which I will explain later.

3. Defining the public methods for the class : Most of the methods can be defined using the same pattern (validation of the parameters, checking if the user is connected to the server and logged in and after that calling one of the functions from http://www.php.net/manual/en/ref.ftp.php , depending on what our method needs to perform), this is why I will show you how to create only one.
We will create the “upload” method, which will transfer a file stored on the local server to the FTP server. We will pass 3 parameters to it : $remote_file will be the path where the file will be stored on the FTP server, $local_file will be the path to the local file that will be uploaded, and $more which will specify how the file will be transfered ( can be either FTP_BINARY or FTP_ASCII ).
We will have to verify if the user is logged in and authorized to call this method by using the private validate() method, which I will explain later. If he is not logged in, the function will return false and and error will be outputed. Next we have to check if the $remote_file and $local_file variables are not empty and if the $local_file exists. We will use the file_exists function ( Details ). We also have to check if the $mode variable is set to either FTP_BINARY or FTP_ASCII and after that allocate space on the FTP server to prepare the transfer ( ftp_alloc function - Details ). If one or more conditions do not validate, we output an error and exit the function.

$is_ok = true;
$err = ”;

if(!$this->validate()) {
$this->print_err(”You are not logged in”);
return false;
}

if(empty($remote_file)) {
$err .= “Please enter the path of the remote file”.”<br />”;
$is_ok = false;
}

if(empty($local_file)) {
$err .= “Please enter the path of the local file”.”<br />”;
$is_ok = false;
} elseif(!file_exists($local_file)) {
$err = “The local path is invalid”.”<br />”;
$is_ok = false;
}

if($mode != FTP_BINARY && $mode != FTP_ASCII) {
$err .= “Please enter a valid transfer mode (FTP_ASCII or FTP_BINARY)”.”<br />”;
$is_ok = false;
}

if(!ftp_alloc($this->ftp_handler, filesize($local_file), $result)) {
$err .= “Unable to allocate space on server (”.$result.”)”.”<br />”;
$is_ok = false;
}

if(!$is_ok) {
$this->print_err($err);
return false;
}

Then we try to upload the file, by calling the ftp_put function ( Details ) and, if successful, we log the action to the file and return true.

if(!ftp_put($this->ftp_handler, $remote_file, $local_file, $mode)) {
$this->print_err(”Could not upload the file”);
return false;
}

$this->log(”Uploaded “.$local_file.” ( size: “.filesize($local_file).” ) to “.$remote_file);

4. Defining the private methods : we have 3 private methods.
a) print_err($err) outputs $err to the screen.

$print = ‘<font color=”red”>’;
$print .= $err;
$print .= ‘</font>’;
echo $print;

b) log($msg) writes $msg to the log file with the fwrite function ( Details ) if logging is enables.

if($this->is_log) {
fwrite($this->log_handler, date(”H : i : s”).” : “.$msg.”\r\n”);
}

c) validate() checks if the user is connected to the FTP server and is logged in

return $this->ftp_handler && $this->is_logged;

5. Using the class : create a new file called example.php, include the class file, instantiate the class and use the available methods.
// Example of how to use the FTP Class
// Include the Class File
include(”
ftp.class.php“);

// Disable error reporting
error_reporting(0);

// Instantiate class
$cls = new ftp(”<host>”, <port>, “<username>”, “<password>”);

// Change the current working directory
$cls->set_dir(”/path/to/folder/”);

// Upload a file from the local server to the FTP server in a specified directory
// (relative to the current working directory)
$cls->upload(”path/to/file/remote_file.txt”, “local_file.txt”, FTP_BINARY);

// Download a file from the FTP server to the local server
// The last parameter (true / false) specifies if the overwrite file option is enabled
$cls->download(”remote_file.txt”, “path/to/file/local_file.txt”, FTP_BINARY, true);

// Close the FTP connection
$cls->close();

6. Other methods : you may create other methods as well by following the pattern described at 3. In the class that I did and is attached to this article there are other methods as well. Here’s the full list :
- set_dir($new_dir) - changes the current working directory on a FTP server (function : ftp_chdir - Details ).
- set_parent() - changes to the parent directory on a FTP server (function ftp_cdup - Details )
- get_dir() - get the current working directory (function ftp_pwd - Details )
- del_file($path) - delete a file from the FTP server (function ftp_delete - Details )
- exec_cmd($cmd) - executes a command on the FTP server (not all FTP servers support this method) (function ftp_exec - Details )
- download($remote_path, $local_path, $mode, $overwrite) - downloads a file from the FTP server to the local server (function ftp_get - Details)
- file_time($path) - get the time when a file has been last modified (function ftp_mdtm - Details )
- list_dir($path) - list all the file names in a directory (function ftp_nlist - Details )
- upload($remote_file, $local_file, $mode) - upload a file from the local server to the FTP server (function ftp_put - Details )
- close() - close the connection with the FTP server (function ftp_close - Details )
- rename($old_name, $new_name) - renames a file / directory (function ftp_rename - Details )
- del_dir($path) - deletes a directory from the FTP server (function ftp_rmdir - Details )
- set_opt($option, $value) - sets a miscellaneous runtime FTP option (function ftp_set_option - Details )
- get_opt($option) - gets the value of a miscellaneous runtime FTP option (function ftp_get_option - Details )
- site_cmd($cmd) - executes a SITE command on the FTP server (function ftp_site - Details )
- get_size($path) - gets the size of a file (function ftp_size - Details )
- chmod($path, $mode) - modifies the permissions on a file (function ftp_chmod - Details )
- mkdir($name) - creates a directory on the FTP server (function ftp_mkdir - Details )

For more details on how each of these methods work, please consult the ftp.class.php from the class attached to this article.

4 Responses to “FTP Administration with full logging via PHP”

  1. Adam Says:

    Informative article. Very extensive. One recommendation though is that you utilise Geshi syntax highlighting. I had a bit of a tough time deciphering all the black and white code. Kudos nonetheless!

  2. Jon Says:

    Hey Tudor,

    I was playing around with the FTP class and noticed that when I list the contents of the current working directory [ print_r($cls->list_dir(”my_dir/”)) ], it always displays the “Could not list the files in this directory” err message and then displays the array of files in the directory.

    Any idea on what’s happening there?

    Thanks,
    Jon

  3. Vladimir Says:

    Here is a good class that works with FTP too: http://www.phpclasses.org/browse/package/1743.html

  4. FTP Administration with full logging - Tutorial Collection Says:

    […] View Tutorial No Comment var addthis_pub=”izwan00″; BOOKMARK This entry was posted on Friday, June 5th, 2009 at 6:51 am and is filed under Php Tutorials. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site. […]

Leave a Reply