File Transfer 101
Out here at Melonfire, we’re big fans of PHP. We use it for a variety of reasons - Web site development, image generation, database connectivity - and we find it friendly, powerful and easy to use…all factors which come in handy when working against tight delivery deadlines.
You’ve already seen how PHP can be used to create GIF and JPEG images which dynamically respond to content from a database. But that’s just the tip of the iceberg - the newest version of the language also comes with powerful functions that can dramatically ease the task of transferring files over the Web.
In this special two-part article, we’re going to explore how PHP can be used to transfer files over HTTP and FTP connections, together with some simple applications that demonstrate just how powerful this really is. Keep reading!
Out With The Old…
The first thing you should know is that PHP allows file transfer across both HTTP and FTP connections. The ability to upload files over HTTP has been available since PHP3, while the newer FTP functions have made an appearance only in later versions of PHP3 and in PHP4.
Before we begin, you need to make sure that your version of PHP includes FTP support. You can check this by creating a PHP file containing the code
<?php
phpinfo();
?>
and checking the resulting output through your Web browser. There’s a section named “Additional Modules” which lists the modules supported by your build; in case you don’t find the FTP module listed, you’ll need to recompile your build with FTP support.
To start with, let’s refresh your memory of what a typical FTP session looks like:
<?php
// connect to FTP server
$conn = ftp_connect("ftp.server.com");
// log in with username and password
ftp_login($conn, "john", "doe");
// get remote system type
ftp_systype($conn);
// obtain file listing
$filelist = ftp_nlist($conn, ".");
// download file
ftp_get($conn, "data.zip", "data.zip", FTP_BINARY);
// close connection
ftp_quit($conn);
?>
As you can see, the process can be broken down into clearly-identifiable segments. There’s the connection phase (which opens a connection to the FTP server); the authentication phase (where the user identifies himself or herself and is permitted access to the FTP site); the transaction phase (which involves operations like directory navigation, file listing, and file GET or PUT); and the disconnection phase (which terminates the FTP connection cleanly). Nice and symmetrical, right?
…In With The New
Initiating an FTP connection in PHP follows the same basic principles: open an FTP connection, send authentication information, and then use built-in PHP functions to navigate through directories or transfer files. Let’s take a look at the PHP version of the session you just saw.
<?php
// connect to FTP server
$conn = ftp_connect("ftp.server.com");
// log in with username and password
ftp_login($conn, "john", "doe");
// get remote system type
ftp_systype($conn);
// obtain file listing
$filelist = ftp_nlist($conn, ".");
// download file
ftp_get($conn, "data.zip", "data.zip", FTP_BINARY);
// close connection
ftp_quit($conn);
?>
Let’s go through this step by step:
In order to initiate an FTP connection, PHP offers the ftp_connect() function, which takes a host name and port number as parameters. In the example above, the host name is “ftp.server.com”; since a port is not specified, PHP will attempt a connection to the default FTP port, 21.
The ftp_connect() function returns a handle for the FTP connection if successful; this handle is used by all subsequent FTP functions.
<?php
// connect to FTP server
$conn = ftp_connect("ftp.server.com");
?>
Once connected, the ftp_login() function is used to send the FTP server a user name and password. As you can see, ftp_login() also uses the handle returned by ftp_connect() to ensure that the authentication information is transmitted to the correct server.
<?php
// log in with username and password
ftp_login($conn, "john", "doe");
?>
At this point, you can begin playing with some of the other functions available to you, specifically those that provide you with system information and directory listing (they’re covered in detail on the next page).
Once you’re finished, it’s important that you remember to close your FTP session with ftp_quit().
<?php
// close connection
ftp_quit($conn);
?>
Where Am I?
Once logged in to an FTP server, PHP offers a number of functions that can provide system-specific information, together with file and directory information.
First, the ftp_pwd() function comes in very useful if you need to find out where you’re currently located in the directory tree.
<?php
// get current location
$here = ftp_pwd($conn);
?>
In case you need to know the operating system that the FTP server is currently running, ftp_systype() will be able to give you this information.
<?php
// get system type
$server_os = ftp_systype($conn);
?>
In case you need to switch passive (PASV) mode on or off, PHP has the ftp_pasv() function, which acts as a toggle switch, turning PASV mode on and off. In case you don’t know what passive mode…don’t worry about it!
<?php
// turn PASV on
ftp_pasv($conn, 1);
?>
How about a file listing? Well, PHP offers two types of listings - a compact listing containing only file and directory names, and a long listing containing detailed information on file sizes, permissions and timestamps.
The first listing is provided by the ftp_nlist() function, while the second comes via ftp_rawlist(). Both functions require a directory name to be passed as a parameter, and both return the listing as an array. Each element of this array corresponds to one line of text from the listing.
<?php
// obtain file listing
$filelist = ftp_nlist($conn, ".");
?>
And in case you’re curious about file sizes, there’s a very handy ftp_size() function which returns the size of the specified file in bytes. An important point to be noted here is that this function returns a value of -1 on error - a fact which comes in handy if you’re trying to distinguish between files and directories, since this function, when invoked on a directory, typically returns a value of -1. You’ll see this technique being used extensively in the example coming up later.
<?php
// obtain file size of file "data.zip"
$filelist = ftp_size($conn, "data.zip");
?>
GETting It Right
Now that you know where you are and who’s around you, it’s time to start moving around in the directory tree - and the function that lets you do that is ftp_chdir(), which accepts a directory name as parameter.
<?php
// change directory to "public_html"
ftp_chdir($conn, "public_html");
?>
If all you want to do is go up to the parent directory, an alternative way of accomplishing this is the ftp_cdup() command, which transports you one level up from wherever you are currently.
<?php
// go up one level in the directory tree
ftp_cdup($conn);
?>
You can also create and remove directories with ftp_mkdir() and ftp_rmdir(); note that ftp_mkdir() returns the name of the new directory if successful.
<?php
// make the directory "test"
ftp_mkdir($conn, "test");
// remove the directory "test"
ftp_rmdir($conn, "test");
?>
The purpose of opening an FTP session is usually to transfer files - so let’s get to that!
Uploading a file is accomplished by means of the ftp_put() command, which requires you to specify a name for the file on the remote system, the name of the file to be uploaded, and the type of transfer. For example, if you’d like to upload the file “abc.txt” and rename it to “xyz.txt” on the remote system, the command would look something like this:
<?php
// upload
ftp_put($conn, "xyz.txt", "abc.txt", FTP_ASCII);
?>
Alternatively, if you’d like to download a file, the built-in function is ftp_get(), which also needs both remote and local file names, although the order is reversed. If the file to be downloaded is named “his.zip” on the remote system and you plan to save it as “hers.zip” on the local system, the syntax would change to
<?php
// download
ftp_get($conn, "hers.zip", "his.zip", FTP_BINARY);
?>
PHP defines two modes for file transfer - FTP_BINARY and FTP_ASCII - which need to be specified as they are displayed here, without quotes. Note that both ftp_get() and ftp_put() return result codes, indicating whether or not the transfer was successful.
Start Me Up!
Now, that covers the various FTP functions that PHP provides - but, just by itself, it isn’t enough. The true power of these functions becomes visible only when they’re combined into a single application which provides file transfer and file management capabilities. Since we’re talking about FTP functions, it seems obvious that the best application for such a demonstration would be a Web-based FTP client - which is exactly what’s coming up next!
Before we get into a code listing, I should make it clear that the example below is meant only to illustrate the various functions you’ve just learned. While it is functional and can be used as a “real” FTP client, I’ve omitted many basic error checking routines to make it easier to explain, and you should consider this use-at-your-own-risk software if you decide to implement it in a live environment. And cigarette smoking causes cancer. You have been warned.
The application code is separated across three different files:
index.html - the log in screen
actions.php4 - the code for all FTP transactions
include.php4 - the main interface, which displays file listings and control buttons
A complete code listing (with comments) is available at the end of the article - I’ll simply be highlighting the important areas here.
Let’s begin at the top, with “index.html”:
<table border=0 align=center>
<form action="actions.php4" method=post>
<input type=hidden name=action value=CWD>
<tr>
<td>
Server
</td>
<td>
<input type=text name=server>
</td>
</tr>
<tr>
<td>
User
</td>
<td>
<input type=text name=username>
</td>
</tr>
<tr>
<td>
Password
</td>
<td>
<input type=password name=password>
</td>
</tr>
<tr>
<td colspan=2 align=center>
<input type="submit" value="Beam Me Up, Scotty!">
</td>
</tr>
</form>
</table>
``` This is the log-in form, with fields for the FTP server name, the FTP user name and the password; these are stored in the variables $server, $username and $password respectively. Once the form is submitted, it calls the PHP script "actions.php4", which then takes over to initiate the FTP connection.
Note the hidden field, which sends the directive "action=CWD" to "actions.php4" - you'll see what role this plays on the next page.
## Lights! Camera! Action!
The primary workhorse of the application is the file "actions.php4", which is reproduced below:
Available directories: <form action=actions.php4 method=post> <input type=hidden name=username value=> <input type=hidden name=password value=> <input type=hidden name=server value=> <input type=hidden name=cdir value=> </form>
Available files: <form action=actions.php4 method=post> <input type=hidden name=server value=> <input type=hidden name=username value=> <input type=hidden name=password value=> <input type=hidden name=cdir value=> <table border=0 width=100%>
File upload: <form enctype="multipart/form-data" action=actions.php4 method=post> <input type=hidden name=username value=> <input type=hidden name=password value=> <input type=hidden name=server value=> <input type=hidden name=cdir value=>