| 函數 | 用途 | 關鍵參數 |
|---|---|---|
| ftp_connect | 建立命令通道連接 | host, port=21, timeout=90 |
| ftp_ssl_connect | 建立 FTPS 隱式 SSL 連接 | 同 ftp_connect |
| ftp_login | 用戶名/密碼認證 | conn, user, pass |
| ftp_pasv | 啟用/禁用被動模式 | conn, true|false (默認 true, 穿透防火牆/NAT) |
| ftp_put | 上傳文件 | conn, remote, local, mode=FTP_BINARY, startpos=0 |
| ftp_fput | 從文件指針上傳 (流式) | conn, remote, fp, mode, startpos |
| ftp_get | 下載文件 | conn, local, remote, mode, startpos |
| ftp_nb_put / ftp_nb_fput | 非阻塞上傳 (需循環 ftp_nb_continue) | 支持大文件、進度條、超時控制 |
| ftp_size | 獲取遠程文件大小 | conn, remote |
| ftp_mdtm | 獲取遠程文件修改時間 | conn, remote |
| ftp_chdir / ftp_mkdir / ftp_rmdir | 目錄操作 | - |
| ftp_delete / ftp_rename | 文件刪除/重命名 | - |
| ftp_raw / ftp_rawlist | 發送原始命令 / 詳細列表 | 支持 MLSD (機器可解析) |
| ftp_close | 關閉連接 | - |
config = array_merge([
'host' => '',
'port' => 21,
'user' => '',
'pass' => '',
'timeout' => 30,
'passive' => true,
'ssl' => false, // true = FTPS 隱式
'verify_peer' => true, // FTPS 證書驗證
'cafile' => null, // 自定義 CA
], $config);
}
public function connect(): bool {
$connectFn = $this->config['ssl'] ? 'ftp_ssl_connect' : 'ftp_connect';
$this->conn = $connectFn($this->config['host'], $this->config['port'], $this->config['timeout']);
if (!$this->conn) return false;
if (!ftp_login($this->conn, $this->config['user'], $this->config['pass'])) {
$this->close();
return false;
}
ftp_pasv($this->conn, $this->config['passive']);
return true;
}
public function upload(string $localPath, string $remotePath, callable $progressCallback = null): bool {
if (!is_file($localPath)) return false;
$localSize = filesize($localPath);
if ($localSize === false) return false;
// 確保遠程目錄存在
$this->ensureRemoteDir(dirname($remotePath));
// 斷點續傳:檢查遠程已有大小
$remoteSize = @ftp_size($this->conn, $remotePath);
$resumePos = ($remoteSize !== -1 && $remoteSize < $localSize) ? $remoteSize : 0;
$fp = fopen($localPath, 'rb');
if (!$fp) return false;
if ($resumePos > 0) fseek($fp, $resumePos);
$mode = FTP_BINARY;
$result = false;
if ($progressCallback) {
// 非阻塞上傳 + 進度回調
$ret = ftp_nb_fput($this->conn, $remotePath, $fp, $mode, $resumePos);
while ($ret === FTP_MOREDATA) {
$ret = ftp_nb_continue($this->conn);
$uploaded = $resumePos + ftell($fp);
$progressCallback($uploaded, $localSize);
}
$result = ($ret === FTP_FINISHED);
} else {
// 阻塞上傳
$result = ftp_fput($this->conn, $remotePath, $fp, $mode, $resumePos);
}
fclose($fp);
return $result;
}
public function ensureRemoteDir(string $remoteDir): void {
$dirs = explode('/', ltrim($remoteDir, '/'));
$current = '';
foreach ($dirs as $dir) {
if ($dir === '' || $dir === '.') continue;
$current .= "/$dir";
if (@ftp_chdir($this->conn, $current) === false) {
@ftp_mkdir($this->conn, $current);
@ftp_chdir($this->conn, $current);
}
}
}
public function close(): void {
if ($this->conn) {
@ftp_close($this->conn);
$this->conn = null;
}
}
public function __destruct() {
$this->close();
}
}
// 使用示例
$uploader = new FtpUploader([
'host' => 'ftp.example.com',
'user' => 'backup_user',
'pass' => 'secure_password',
'passive' => true,
'ssl' => true, // FTPS
]);
if ($uploader->connect()) {
$success = $uploader->upload(
'/var/backups/db_20240101.sql.gz',
'/backups/db/db_20240101.sql.gz',
function($uploaded, $total) {
$pct = round($uploaded / $total * 100, 1);
echo "\r上傳進度: {$pct}% ({$uploaded}/{$total} bytes)";
}
);
echo $success ? "\n上傳成功\n" : "\n上傳失敗\n";
$uploader->close();
} else {
echo "FTP 連接失敗\n";
}
主動模式 (PORT):
客戶端 → 告知服務器 "我監聽 IP:Port,請連接我"
服務器 → 從 20 端口主動連接客戶端數據端口
問題:客戶端通常在 NAT/防火牆後,服務器無法主動連入
被動模式 (PASV) (默認、推薦):
客戶端 → 發送 PASV
服務器 → 回應 "我在 IP:Port 等你連接" (隨機高端口)
客戶端 → 主動連接服務器數據端口
優勢:客戶端發起所有連接,易穿透 NAT/防火牆
服務器端配置關鍵:
- 固定 PASV 端口範圍 (如 50000-51000)
- 防火牆開放 21 + PASV 範圍
- 宣告外網 IP (masquerade_address) 而非內網 IP
ftp_ssl_connect + ftp_login 後發送 AUTH TLS,或隱式 FTPS (端口 990)。stream_context_set_option 設置 verify_peer => true, cafile => '/path/to/ca.pem'。ftp_chroot 或 vsftpd chroot_local_user=YES。SFTP (SSH File Transfer Protocol) 運行在 SSH 協議之上 (端口 22),單通道加密,支持公鑰認證、斷點續傳、權限管理。PHP 使用 ssh2_sftp (pecl/ssh2) 或 phpseclib/phpseclib (純 PHP) 實現。ftp_* 函數無法操作 SFTP。
FTP 雖老,但在批量文件交換、跨網段傳輸、嵌入式設備、舊系統集成中仍廣泛使用。掌握 被動模式穿透 NAT、FTPS 加密、斷點續傳、非阻塞進度回調、目錄自動創建、安全加固 等核心技能,能構建穩健的文件傳輸管道。新架構優先考慮 SFTP (SSH) 或 HTTPS/REST API + 對象存儲 (S3/MinIO),以統一協議、簡化運維、提升安全性。