PHP FTP
FTP (File Transfer Protocol) is a standard network protocol used to transfer files from one host to another over a TCP-based network. PHP provides a built-in
Introduction
FTP (File Transfer Protocol) is a standard network protocol for transferring files between a client and a server over a TCP connection. PHP ships with a built-in FTP extension (ext-ftp) that lets your scripts log in to a remote server and move files programmatically — useful for deploying assets, syncing backups, or pulling data feeds from a partner's server.
This chapter covers the full workflow: connecting, logging in, switching to passive mode, uploading and downloading, listing and managing remote files, and finally closing the connection cleanly. It also explains the security caveats you must know before using plain FTP in production.
Security note first. Plain FTP sends your username, password, and file contents unencrypted. For anything sensitive, use
ftp_ssl_connect()(FTP over TLS) or prefer SFTP (SSH File Transfer Protocol), which the FTP extension does not speak — use the PHP SSH2 extension or a library such as phpseclib for SFTP.
The typical FTP workflow
Every FTP script follows the same shape, regardless of which operation you perform:
- Connect to the server —
ftp_connect()(orftp_ssl_connect()for FTPS). - Authenticate —
ftp_login(). - Configure — usually
ftp_pasv($conn, true)to enable passive mode. - Transfer / manage files —
ftp_put(),ftp_get(),ftp_nlist(), etc. - Close —
ftp_close().
Connecting to an FTP Server
Establish a connection with ftp_connect(). It takes the hostname (and optional port and timeout) and returns an FTP\Connection object on success (a resource before PHP 8.1), or false on failure.
<?php
$conn = ftp_connect("ftp.example.com", 21, 10); // host, port, timeout (seconds)
if ($conn === false) {
die("Could not connect to FTP server");
}
echo "Connected.";Note that connecting does not log you in — at this point you have an anonymous, unauthenticated channel. You still have to call ftp_login() before the server will let you do anything useful.
Using FTPS (FTP over TLS)
To encrypt the control and data channels, swap ftp_connect() for ftp_ssl_connect(). The rest of the API is identical:
<?php
$conn = ftp_ssl_connect("ftp.example.com");
if ($conn === false) {
die("Could not open a secure FTP connection");
}Logging In and Passive Mode
After connecting, authenticate with ftp_login(). For public servers that allow anonymous access, use the username anonymous with an email-like password.
<?php
$conn = ftp_connect("ftp.example.com");
if (!ftp_login($conn, "username", "password")) {
ftp_close($conn);
die("Login failed");
}
// Most networks behind a firewall/NAT require passive mode.
ftp_pasv($conn, true);
echo "Logged in.";Why passive mode matters. In active mode the server opens a data connection back to your client, which firewalls and NAT routers almost always block. In passive mode the client opens the data connection to the server instead, so it works behind firewalls. As a rule of thumb, call ftp_pasv($conn, true) right after logging in. It must be set after ftp_login(), not before.
Uploading Files
Use ftp_put() to send a local file to the server. Its signature is ftp_put($conn, $remote_file, $local_file, $mode), where $mode is FTP_BINARY or FTP_ASCII.
<?php
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");
ftp_pasv($conn, true);
if (ftp_put($conn, "/public_html/report.pdf", "report.pdf", FTP_BINARY)) {
echo "Upload successful";
} else {
echo "Upload failed";
}
ftp_close($conn);FTP_BINARY vs FTP_ASCII. Use FTP_BINARY for everything that is not plain text — images, PDFs, archives, executables — because ASCII mode rewrites line endings and will corrupt binary data. Use FTP_ASCII only when you specifically want line endings translated between platforms for text files. When in doubt, choose FTP_BINARY; it is the safe default.
For large files you can upload non-blocking with ftp_nb_put(), which lets your script do other work between chunks.
Downloading Files
ftp_get() retrieves a remote file to the local filesystem. The argument order is ftp_get($conn, $local_file, $remote_file, $mode) — note that the local destination comes first, the opposite of ftp_put(). Mixing these up is the single most common FTP bug.
<?php
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");
ftp_pasv($conn, true);
// local_file first, then remote_file
if (ftp_get($conn, "backup.zip", "/backups/backup.zip", FTP_BINARY)) {
echo "Download successful";
} else {
echo "Download failed";
}
ftp_close($conn);Listing and Managing Remote Files
The FTP extension does much more than transfer files. Common management functions include:
| Function | Purpose |
|---|---|
ftp_nlist($conn, $dir) | Array of file names in a directory |
ftp_rawlist($conn, $dir) | Detailed ls -l-style listing |
ftp_size($conn, $file) | File size in bytes (-1 on error) |
ftp_mkdir($conn, $dir) | Create a directory |
ftp_rmdir($conn, $dir) | Remove an (empty) directory |
ftp_delete($conn, $file) | Delete a file |
ftp_rename($conn, $from, $to) | Rename / move a file |
ftp_chdir($conn, $dir) | Change the working directory |
ftp_pwd($conn) | Current working directory |
ftp_chmod($conn, 0644, $file) | Change file permissions |
<?php
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");
ftp_pasv($conn, true);
$files = ftp_nlist($conn, "/public_html");
foreach ($files as $file) {
echo $file, " — ", ftp_size($conn, $file), " bytes\n";
}
ftp_close($conn);Closing the Connection
Always release the connection with ftp_close() when you are done. Wrapping the workflow in try/finally guarantees the socket is closed even if an error is thrown midway:
<?php
$conn = ftp_connect("ftp.example.com");
if (!$conn || !ftp_login($conn, "username", "password")) {
die("Connection or login failed");
}
try {
ftp_pasv($conn, true);
ftp_put($conn, "/public_html/index.html", "index.html", FTP_BINARY);
} finally {
ftp_close($conn);
}Best Practices and Gotchas
- Prefer FTPS or SFTP. Never send credentials over plain FTP across the public internet.
- Always enable passive mode (
ftp_pasv) unless you have a specific reason not to. - Pick the right transfer mode —
FTP_BINARYfor binary data,FTP_ASCIIonly for text where line-ending translation is wanted. - Watch the argument order —
ftp_putis(remote, local),ftp_getis(local, remote). - Always close the connection with
ftp_close(). - Check every return value. FTP functions return
falseon failure rather than throwing, so silent failures are easy to miss. ext-ftpmust be enabled. Confirm withextension_loaded('ftp'); if it returnsfalse, enable the extension in yourphp.ini.
Related Topics
- PHP File Handling — reading and writing local files.
- PHP File Upload — handling HTTP form uploads.
- PHP Filesystem — the broader filesystem function set.
- PHP Exceptions — structured error handling for
try/finally.