FTP 擴展簡介
PHP FTP 擴展提供完整的 FTP 客戶端功能:連線認證、檔案上傳下載、目錄操作、權限修改、非阻塞傳輸、SSL/TLS 加密連線。Windows 版 PHP 內建,Linux 需編譯時加入 --enable-ftp。
安裝驗證
# Linux 編譯參數
./configure --enable-ftp
# 驗證
php -m | grep ftp
php -r "var_dump(function_exists('ftp_connect'));"
核心函數分類速查
連線與認證
| 函數 | 說明 |
ftp_connect(host, port=21, timeout=90) | 建立 FTP 連線 |
ftp_ssl_connect(host, port=990, timeout=90) | 建立 SSL/TLS 加密連線 (FTPS) |
ftp_login(conn, username, password) | 用戶認證 |
ftp_pasv(conn, true/false) | 開啟/關閉被動模式(穿透防火牆/NAT 必開) |
ftp_close(conn) | 關閉連線 |
ftp_quit(conn) | ftp_close 別名 |
目錄操作
| 函數 | 說明 |
ftp_pwd(conn) | 取得當前目錄 |
ftp_chdir(conn, directory) | 切換目錄 |
ftp_cdup(conn) | 切換到上層目錄 |
ftp_mkdir(conn, directory) | 建立目錄 |
ftp_rmdir(conn, directory) | 刪除空目錄 |
ftp_nlist(conn, directory) | 列出目錄檔名陣列 |
ftp_rawlist(conn, directory) | 列出詳細資訊(含權限、大小、時間) |
檔案操作
| 函數 | 說明 |
ftp_put(conn, remote, local, mode) | 上傳檔案 |
ftp_fput(conn, remote, handle, mode) | 上傳開啟的檔案指標 |
ftp_get(conn, local, remote, mode) | 下載檔案 |
ftp_fget(conn, handle, remote, mode) | 下載到開啟的檔案指標 |
ftp_delete(conn, path) | 刪除檔案 |
ftp_rename(conn, old, new) | 重命名/移動 |
ftp_chmod(conn, mode, path) | 修改權限 (如 0644) |
ftp_size(conn, path) | 取得檔案大小(位元組),失敗回 -1 |
ftp_mdtm(conn, path) | 取得最後修改時間 (Unix timestamp) |
ftp_site(conn, command) | 發送 SITE 指令(伺服器專用) |
傳輸模式常數
FTP_ASCII / FTP_TEXT:文本模式(換行轉換)
FTP_BINARY / FTP_IMAGE:二進制模式(圖片、壓縮檔、執行檔必須用此模式)
非阻塞傳輸(大檔案/斷點續傳核心)
| 函數 | 說明 |
ftp_nb_put/get/fput/fget(...) | 啟動非阻塞傳輸 |
ftp_nb_continue(conn) | 繼續傳輸,回傳 FTP_MOREDATA/FTP_FINISHED/FTP_FAILED |
FTP_AUTORESUME | 自動斷點續傳(配合 ftp_nb_get/put) |
實戰範例
1. 基礎上傳下載封裝類
<?php
class FtpClient {
private $conn;
private $config;
public function __construct(array $config) {
$this->config = $config;
}
public function connect() {
$this->conn = $this->config['ssl']
? @ftp_ssl_connect($this->config['host'], $this->config['port'] ?? 990, 30)
: @ftp_connect($this->config['host'], $this->config['port'] ?? 21, 30);
if (!$this->conn) throw new Exception("連線失敗: {$this->config['host']}");
if (!@ftp_login($this->conn, $this->config['user'], $this->config['pass'])) {
throw new Exception("認證失敗");
}
ftp_pasv($this->conn, true); // 被動模式
return $this;
}
public function upload($localPath, $remotePath, $mode = FTP_BINARY) {
return ftp_put($this->conn, $remotePath, $localPath, $mode);
}
public function download($remotePath, $localPath, $mode = FTP_BINARY) {
return ftp_get($this->conn, $localPath, $remotePath, $mode);
}
public function delete($remotePath) {
return ftp_delete($this->conn, $remotePath);
}
public function listFiles($dir = '.') {
return ftp_nlist($this->conn, $dir);
}
public function __destruct() {
if ($this->conn) @ftp_close($this->conn);
}
}
// 使用
$ftp = new FtpClient([
'host' => 'ftp.example.com',
'user' => 'username',
'pass' => 'password',
'ssl' => true, // FTPS
]);
$ftp->connect()->upload('local.jpg', '/remote/images/photo.jpg');
$ftp->download('/remote/backup.sql', 'backup.sql');
2. 非阻塞大檔案下載(含進度條邏輯)
<?php
function downloadLarge($ftp, $remote, $local) {
$fp = fopen($local, 'w');
$ret = ftp_nb_fget($ftp, $fp, $remote, FTP_BINARY, 0); // 0 = 從頭開始
$total = ftp_size($ftp, $remote);
$downloaded = 0;
while ($ret === FTP_MOREDATA) {
// 這裡可以更新進度條、寫入日誌、處理其他任務
$downloaded = ftell($fp);
echo "\r進度: " . round($downloaded/$total*100, 1) . "%";
$ret = ftp_nb_continue($ftp);
}
fclose($fp);
if ($ret !== FTP_FINISHED) {
unlink($local); // 失敗刪除不完整檔案
throw new Exception("下載失敗");
}
echo "\n下載完成\n";
}
3. 斷點續傳上傳
<?php
function uploadResume($ftp, $local, $remote) {
$localSize = filesize($local);
$remoteSize = ftp_size($ftp, $remote);
if ($remoteSize >= $localSize) return true; // 已完成
$fp = fopen($local, 'r');
fseek($fp, $remoteSize); // 跳過已上傳部分
$ret = ftp_nb_fput($ftp, $remote, $fp, FTP_BINARY, $remoteSize);
while ($ret === FTP_MOREDATA) {
$ret = ftp_nb_continue($ftp);
}
fclose($fp);
return $ret === FTP_FINISHED;
}
常見問題與最佳實踐
| 問題 | 解決方案 |
| 連線逾時/失敗 | 檢查防火牆、確認主機支援被動模式、增加 ftp_connect timeout 參數 |
| 上傳檔案損壞/為 0 位元組 | 二進制檔案必須用 FTP_BINARY 模式 |
| 中文檔名亂碼 | FTP 協議不規定編碼,建議檔名用 URL 編碼或 Base64,或確認伺服器支援 UTF-8 (RFC 2640) |
| 權限不足無法建立目錄 | 確認 FTP 用戶有寫入權限,或用 ftp_site($conn, 'CHMOD 755 dir') |
| 長連線被伺服器斷開 | 實作重連機制,或定期發送 ftp_pwd() 保持心跳 |
安全建議
- 優先使用
ftp_ssl_connect (FTPS) 或 SFTP (需 ssh2 擴展或 phpseclib)
- 避免在代碼中硬編碼密碼,使用環境變數或密碼管理器
- 限制 FTP 用戶權限:僅開放必要目錄,禁止 Shell 登入
- 記錄所有 FTP 操作日誌(IP、用戶、操作、檔案、結果)