PHP FTP
Connecting, logging in, transfer, and passive mode.
Key PointsFTP sends passwords in clear text — use SFTP or FTPS when possible.
Functions
| Function | Purpose |
|---|---|
| ftp_connect | 连接(默认 21 端口) |
| ftp_ssl_connect | FTPS 显式加密连接 |
| ftp_login | 登录 |
| ftp_pasv | 切换被动模式 |
| ftp_get | 下载文件 |
| ftp_put | 上传文件 |
| ftp_nlist | 列目录(仅文件名) |
| ftp_mlsd | 列目录(含元信息) |
| ftp_delete | 删文件 |
| ftp_mkdir | 建目录 |
| ftp_size | 文件大小 |
| ftp_close | 关闭连接 |
Connect and log in
PHP
<?php
$conn = ftp_connect("ftp.example.com", 21, 5);
if ($conn === false) {
exit("连接失败");
}
$ok = @ftp_login($conn, "user", "password");
if (!$ok) {
ftp_close($conn);
exit("登录失败");
}
// 被动模式:几乎必开
ftp_pasv($conn, true);
echo "已登录,被动模式已开启\n";
ftp_close($conn);Output
已登录,被动模式已开启Passive mode is mandatory. In active mode the server dials back to the client, which fails behind NAT or a firewall — the symptom is "login works, listing hangs".
Transfer
PHP
<?php
$local = __DIR__ . "/upload.txt";
file_put_contents($local, "hello ftp\n");
$conn = ftp_connect("ftp.example.com", 21, 5);
ftp_login($conn, "user", "password");
ftp_pasv($conn, true);
// 上传(FTP_BINARY 传二进制,FTP_ASCII 传文本)
$ok = ftp_put($conn, "/remote/upload.txt", $local, FTP_BINARY);
echo $ok ? "上传成功" : "上传失败", "\n";
// 下载
$back = __DIR__ . "/download.txt";
if (ftp_get($conn, $back, "/remote/upload.txt", FTP_BINARY)) {
echo "下载成功: " . filesize($back) . " 字节\n";
}
ftp_close($conn);
@unlink($local);
@unlink($back);Output
上传成功
下载成功: 10 字节FTP_ASCII converts line endings and suits plain text only. **Images, archives and binaries need FTP_BINARY** or they corrupt.
Directory operations
PHP
<?php
$conn = ftp_connect("ftp.example.com", 21, 5);
ftp_login($conn, "user", "password");
ftp_pasv($conn, true);
$list = ftp_nlist($conn, "/remote");
echo count($list) . " 项\n";
// 带元信息(部分服务器不支持 MLSD)
$mlsd = @ftp_mlsd($conn, "/remote");
if ($mlsd !== false) {
foreach (array_slice($mlsd, 0, 2) as $f) {
echo $f["name"] . " " . $f["type"] . "\n";
}
} else {
echo "服务器不支持 MLSD\n";
}
ftp_close($conn);Output
3 项
upload.txt file
backup dirftp_nlist returns paths, not bare names — which form depends on the server. Apply basename yourself.Security notes
- FTP is plaintext —— passwords travel in the clear; use FTPS or SFTP
- No built-in SFTP —— use
phpseclibor thessh2extension - Never make upload dirs executable —— an uploaded
.phpis a webshell - No hardcoded credentials —— environment variables or a secret manager
A leaked FTP account lets an attacker upload a
.php file and take the server. Scope FTP accounts to a directory with script execution disabled.函数
| 函数 | 作用 |
|---|---|
| ftp_connect | 连接(默认 21 端口) |
| ftp_ssl_connect | FTPS 显式加密连接 |
| ftp_login | 登录 |
| ftp_pasv | 切换被动模式 |
| ftp_get | 下载文件 |
| ftp_put | 上传文件 |
| ftp_nlist | 列目录(仅文件名) |
| ftp_mlsd | 列目录(含元信息) |
| ftp_delete | 删文件 |
| ftp_mkdir | 建目录 |
| ftp_size | 文件大小 |
| ftp_close | 关闭连接 |
连接与登录
PHP
<?php
$conn = ftp_connect("ftp.example.com", 21, 5);
if ($conn === false) {
exit("连接失败");
}
$ok = @ftp_login($conn, "user", "password");
if (!$ok) {
ftp_close($conn);
exit("登录失败");
}
// 被动模式:几乎必开
ftp_pasv($conn, true);
echo "已登录,被动模式已开启\n";
ftp_close($conn);Output
已登录,被动模式已开启被动模式(PASV)必须开。 主动模式下服务器要反向连回客户端,只要客户端在 NAT / 防火墙后面就必然失败,表现是「登录成功但列目录卡死」。
上传与下载
PHP
<?php
$local = __DIR__ . "/upload.txt";
file_put_contents($local, "hello ftp\n");
$conn = ftp_connect("ftp.example.com", 21, 5);
ftp_login($conn, "user", "password");
ftp_pasv($conn, true);
// 上传(FTP_BINARY 传二进制,FTP_ASCII 传文本)
$ok = ftp_put($conn, "/remote/upload.txt", $local, FTP_BINARY);
echo $ok ? "上传成功" : "上传失败", "\n";
// 下载
$back = __DIR__ . "/download.txt";
if (ftp_get($conn, $back, "/remote/upload.txt", FTP_BINARY)) {
echo "下载成功: " . filesize($back) . " 字节\n";
}
ftp_close($conn);
@unlink($local);
@unlink($back);Output
上传成功
下载成功: 10 字节FTP_ASCII 会做换行符转换(\n ↔ \r\n),只适合纯文本。**图片、压缩包、可执行文件一律用 FTP_BINARY**,用错会损坏文件。
目录操作
PHP
<?php
$conn = ftp_connect("ftp.example.com", 21, 5);
ftp_login($conn, "user", "password");
ftp_pasv($conn, true);
$list = ftp_nlist($conn, "/remote");
echo count($list) . " 项\n";
// 带元信息(部分服务器不支持 MLSD)
$mlsd = @ftp_mlsd($conn, "/remote");
if ($mlsd !== false) {
foreach (array_slice($mlsd, 0, 2) as $f) {
echo $f["name"] . " " . $f["type"] . "\n";
}
} else {
echo "服务器不支持 MLSD\n";
}
ftp_close($conn);Output
3 项
upload.txt file
backup dirftp_nlist 返回的是路径(可能是相对或绝对,取决于服务器),不是纯文件名。要文件名得自己 basename。安全提醒
- FTP 明文 —— 密码在网络上是裸的,用
ftp_ssl_connect或 SFTP - PHP 没有内置 SFTP —— 要装
phpseclib或用ssh2扩展 - 上传目录别可执行 —— FTP 上传的
.php就是 webshell - 凭据别写死在代码里 —— 环境变量或密钥管理
FTP 账号一旦泄露,攻击者可以直接上传
.php 文件拿到服务器权限。FTP 账号的权限要限制到具体目录,且该目录必须禁止脚本执行。