本文使用 PHP 8.1 實作。
用 Docker 準備 FTP 環境
先參考這篇 [Docker] 使用 Docker 建置 FTP(SFTP) 環境 建立 FTP 環境。
要注意它建立的 FTP Port 為 23,因為也沒有掛上 Volume,所以需要有一個 FTP 客戶端連進去測試,可以使用 Filezilla 或是 Cyberduck。
docker run -d --name ftpd_server -p 23:21 -p 30010-30019:30010-30019 -e "FTP_PASSIVE_PORTS=30010:30019" -e FTP_USER_HOME=/home/miles -e FTP_USER_NAME=miles -e FTP_USER_PASS=123456 -e "PUBLICHOST=localhost" stilliard/pure-ftpd
使用 MLSD 列出 FTP 項目
<?php
function listFtpFiles($hostname, $port, $ftpUsername, $ftpPassword) {
$ftpConnection = ftp_connect($hostname, $port);
if (!$ftpConnection) {
echo "can not connect to ftp server<br>";
return;
}
$login = ftp_login($ftpConnection, $ftpUsername, $ftpPassword);
if (!$login) {
echo "login error!<br>";
return;
}
// pasv
ftp_pasv($ftpConnection, true);
$files = ftp_mlsd($ftpConnection, ".");
ftp_close($ftpConnection);
return $files;
}
實際呼叫:
$files = listFtpFiles(
hostname: '127.0.0.1',
port: 23,
ftpUsername: 'miles',
ftpPassword: '123456'
);
print_r($files);
FTP 連線後,透過 fread 下載檔案
<?php
function ftpDownloadFile($hostname, $port = 21, $ftpUsername, $ftpPassword, $file) {
$ftpConnection = ftp_connect($hostname, $port);
if (!$ftpConnection) {
echo "can not connect to ftp server<br>";
return;
}
$login = ftp_login($ftpConnection, $ftpUsername, $ftpPassword);
if (!$login) {
echo "login error!<br>";
return;
}
// pasv
ftp_pasv($ftpConnection, true);
$remoteFile = fopen("ftp://$ftpUsername:$ftpPassword@$hostname:$port/$file", 'rb');
if (!$remoteFile) {
ftp_close($ftpConnection);
echo "can not download file<br>";
return;
}
// get extension name
$fileExtension = pathinfo($file, PATHINFO_EXTENSION);
switch( $fileExtension ) {
case "pdf": $contentType="application/pdf"; break;
case "exe": $contentType="application/octet-stream"; break;
case "zip": $contentType="application/zip"; break;
case "rar": $contentType="application/x-rar-compressed"; break;
case "doc": $contentType="application/msword"; break;
case "xls": $contentType="application/vnd.ms-excel"; break;
case "ppt": $contentType="application/vnd.ms-powerpoint"; break;
case "gif": $contentType="image/gif"; break;
case "png": $contentType="image/png"; break;
case "jpeg":
case "jpg": $contentType="image/jpg"; break;
case "mp3": $contentType="audio/mpeg"; break;
case "wav": $contentType="audio/x-wav"; break;
case "mpeg":
case "mpg":
case "mpe": $contentType="video/mpeg"; break;
case "mov": $contentType="video/quicktime"; break;
case "avi": $contentType="video/x-msvideo"; break;
//禁止下面幾種類型的檔案被下載
case "php":
case "htm":
case "html":
case "txt": die("Cannot be used for ". $fileExtension ." files!"); break;
default: $contentType="application/force-download";
}
header('Content-Type: ' . $contentType);
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
// read file to download
while (!feof($remoteFile)) {
echo fread($remoteFile, 8192); // 8192
ob_flush();
flush();
}
// close
fclose($remoteFile);
ftp_close($ftpConnection);
return;
}
實際使用
ftpDownloadFile('127.0.0.1', 23, 'miles', '123456', 'example.zip');