PHP Conference Japan 2024

ftp_get

(PHP 4, PHP 5, PHP 7, PHP 8)

ftp_get從 FTP 伺服器下載檔案

描述

ftp_get(
    FTP\Connection $ftp,
    string $local_filename,
    string $remote_filename,
    int $mode = FTP_BINARY,
    int $offset = 0
): bool

ftp_get() 從 FTP 伺服器擷取遠端檔案,並將其儲存到本機檔案中。

參數

ftp

一個 FTP\Connection 實例。

local_filename

本機檔案路徑(如果檔案已存在,將會被覆蓋)。

remote_filename

遠端檔案路徑。

mode

傳輸模式。必須是 FTP_ASCIIFTP_BINARY 其中之一。

offset

開始下載的遠端檔案位置。

回傳值

成功時回傳 true,失敗時回傳 false

變更記錄

版本 描述
8.1.0 ftp 參數現在需要一個 FTP\Connection 實例;先前需要一個 resource
7.3.0 mode 參數現在為選用。先前為必要參數。

範例

範例 1 ftp_get() 範例

<?php

// 定義一些變數
$local_file = 'local.zip';
$server_file = 'server.zip';

// 設定基本連線
$ftp = ftp_connect($ftp_server);

// 使用使用者名稱和密碼登入
$login_result = ftp_login($ftp, $ftp_user_name, $ftp_user_pass);

// 嘗試下載 $server_file 並儲存到 $local_file
if (ftp_get($ftp, $local_file, $server_file, FTP_BINARY)) {
echo
"成功寫入 $local_file\n";
} else {
echo
"發生問題\n";
}

// 關閉連線
ftp_close($ftp);

?>

參見

  • ftp_pasv() - 開啟或關閉被動模式
  • ftp_fget() - 從 FTP 伺服器下載檔案並儲存到開啟的檔案
  • ftp_nb_get() - 從 FTP 伺服器擷取檔案並寫入本機檔案(非阻塞)
  • ftp_nb_fget() - 從 FTP 伺服器擷取檔案並寫入開啟的檔案(非阻塞)

新增註解

使用者貢獻的註解 14 則註解

36
CuDi
15 年前
我今天嘗試從我的網路伺服器 ftp 下載一個 7MB 的檔案。

我直接複製這個範例,它告訴我。

Port 命令成功
「發生問題」

我以為是因為檔案大小。
但我猜想可能是因為我的防火牆。

所以我將 ftp 連線設定為被動模式

<?PHP

...
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
ftp_pasv($conn_id, true);

?>

再次執行腳本 & 它運作良好。

希望這對某些人有幫助
36
bob at notallhere dot com
11 年前
不想使用中間檔案?使用 'php://output' 作為檔案名稱,然後使用輸出緩衝捕獲輸出。

ob_start();
$result = ftp_get($ftp, "php://output", $file, FTP_BINARY);
$data = ob_get_contents();
ob_end_clean();

別忘了檢查 $result 以確保沒有錯誤。之後,隨您喜歡操作 $data 變數。
14
ramiro at qusarcr dot com
22 年前
請記住,如果您的本機電腦上有同名的檔案,ftp_get 會覆蓋該檔案。
10
anomie at users dot sf dot net
17 年前
我不知道為什麼沒有「ftp_get_contents」函式。要模擬一個需要一點工夫,但這是可行的。
<?php
function ftp_get_contents($ftp_stream, $remote_file, $mode, $resume_pos=null){
$pipes=stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
if(
$pipes===false) return false;
if(!
stream_set_blocking($pipes[1], 0)){
fclose($pipes[0]); fclose($pipes[1]);
return
false;
}
$fail=false;
$data='';
if(
is_null($resume_pos)){
$ret=ftp_nb_fget($ftp_stream, $pipes[0], $remote_file, $mode);
} else {
$ret=ftp_nb_fget($ftp_stream, $pipes[0], $remote_file, $mode, $resume_pos);
}
while(
$ret==FTP_MOREDATA){
while(!
$fail && !feof($pipes[1])){
$r=fread($pipes[1], 8192);
if(
$r==='') break;
if(
$r===false){ $fail=true; break; }
$data.=$r;
}
$ret=ftp_nb_continue($ftp_stream);
}
while(!
$fail && !feof($pipes[1])){
$r=fread($pipes[1], 8192);
if(
$r==='') break;
if(
$r===false){ $fail=true; break; }
$data.=$r;
}
fclose($pipes[0]); fclose($pipes[1]);
if(
$fail || $ret!=FTP_FINISHED) return false;
return
$data;
}
?>

類似的方式也可以用來寫入 ftp_put_contents 函式。
4
來自 ruggfamily.com 的 Nate
16 年前
這裡有一個快速的函式,可以根據檔案的副檔名來判斷要使用的正確模式。

<?php
function get_ftp_mode($file)
{
$path_parts = pathinfo($file);

if (!isset(
$path_parts['extension'])) return FTP_BINARY;
switch (
strtolower($path_parts['extension'])) {
case
'am':case 'asp':case 'bat':case 'c':case 'cfm':case 'cgi':case 'conf':
case
'cpp':case 'css':case 'dhtml':case 'diz':case 'h':case 'hpp':case 'htm':
case
'html':case 'in':case 'inc':case 'js':case 'm4':case 'mak':case 'nfs':
case
'nsi':case 'pas':case 'patch':case 'php':case 'php3':case 'php4':case 'php5':
case
'phtml':case 'pl':case 'po':case 'py':case 'qmail':case 'sh':case 'shtml':
case
'sql':case 'tcl':case 'tpl':case 'txt':case 'vbs':case 'xml':case 'xrc':
return
FTP_ASCII;
}
return
FTP_BINARY;
}

// 範例用法
ftp_get($conn_id, $local_file, $server_file, get_ftp_mode($server_file));
?>
7
mroerick at gmx dot net
15 年前
ftp_sync 是一種在伺服器上走訪目錄結構,並將每個目錄和檔案複製到本地相同位置的方法。

<?php
$ftp_server
= "ftp.example.com";
$conn_id = ftp_connect ($ftp_server)
or die(
"無法連線到 $ftp_server");

$login_result = ftp_login($conn_id, "user", "pass");
if ((!
$conn_id) || (!$login_result))
die(
"FTP 連線失敗");

ftp_sync ("要複製的目錄"); // 如果您在目前目錄,請使用 "."

ftp_close($conn_id);

// ftp_sync - 複製目錄和檔案結構
function ftp_sync ($dir) {

global
$conn_id;

if (
$dir != ".") {
if (
ftp_chdir($conn_id, $dir) == false) {
echo (
"變更目錄失敗:$dir<BR>\r\n");
return;
}
if (!(
is_dir($dir)))
mkdir($dir);
chdir ($dir);
}

$contents = ftp_nlist($conn_id, ".");
foreach (
$contents as $file) {

if (
$file == '.' || $file == '..')
continue;

if (@
ftp_chdir($conn_id, $file)) {
ftp_chdir ($conn_id, "..");
ftp_sync ($file);
}
else
ftp_get($conn_id, $file, $file, FTP_BINARY);
}

ftp_chdir ($conn_id, "..");
chdir ("..");

}
?>
1
Aditya P dot Bhatt (adityabhai at gmail dot com)
16 年前
<?php
// 定義一些變數
$folder_path = "你的資料夾路徑";
$local_file = "本機檔案路徑";
$server_file = "伺服器檔案路徑";

//-- 連線設定
$ftp_server = "IP 位址"; // FTP 伺服器位址。
$ftp_user_name = "使用者名稱"; // 使用者名稱
$ftp_user_pass = "密碼"; // 密碼
#$destination_file = "檔案路徑";

// 建立基本連線
$conn_id = ftp_connect($ftp_server);

// 使用者名稱和密碼登入
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);

// 嘗試下載 $server_file 並儲存至 $local_file
if (ftp_get($conn_id, $local_file, $server_file, FTP_BINARY)) {
echo
"成功寫入 $local_file\n";
} else {
echo
"發生問題\n";
}

// 關閉連線
ftp_close($conn_id);
?>
0
mpatnode at yahoo dot com
6 年前
請注意,PHP 預設仍然使用 FTP 主動模式,由於防火牆的出現,現在幾乎不再使用。別忘了在 `ftp_login` 之後加入 `ftp_pasv($conn, true)`。
0
anomie at users dot sf dot net
17 年前
糟糕。`_nb_` 只指的是從 FTP 伺服器讀取,而 socket pair 中的緩衝區只有大約 364 位元組。因此,它不適用於大於該大小的檔案。
0
thivierr at telus dot net
21 年前
如果您之前已經下載過檔案(例如一個很大的網頁日誌),而只想取得剩餘部分,請執行以下操作

`$local_file_size = filesize($local_file_path);`
`$get_result = ftp_get($conn_id, $local_file_path, $remote_file_path, FTP_BINARY, $local_file_size);`

無論本機檔案是否已存在,此程式碼都有效。您應該先測試以確保本機檔案不大於遠端檔案。
-1
administrator at gesoft dot org
18 年前
大家好,

如果有人想將檔案下載到同一個本機檔案(一些暫存檔),就像這裡顯示的那樣

<?php
foreach ($files as $key=>$path) {
...
$result = ftp_get($ftpConnId, 'temp.tmp', $path, FTP_BINARY);
...
}
?>

請考慮到您在下載(取得)完整檔案時會遇到很大的問題。換句話說,`temp.tmp` 檔案的大小將始終與第一個下載的檔案大小相同,而不管下載檔案的實際大小。我不知道是什麼原因!

如果有人認為問題只是在於取得正確的檔案大小(您可以使用 filesize() 函數取得),那他就錯了。下載的檔案大小在實質上不等於來源檔案的大小,這意味著 fflush() 函數無法解決此問題(我也嘗試過了)。

最後,找到了解決方案:在下載檔案之前,您需要刪除本機檔案(如果存在 `temp.tmp` 的話)。所以可行的程式碼將會是這樣

<?php
foreach ($files as $key=>$path) {
...
if (
file_exists('temp.tmp')) {
unlink('temp.tmp');
}
$result = ftp_get($ftpConnId, 'temp.tmp', $path, FTP_BINARY);
...
}
?>

祝您腳本編寫順利 :-)

Vitali Simsive
-1
miki at epoch dot co dot il
11 年前
如果您執行範例後發現 90 秒後失敗(逾時)。

然後嘗試新增
<?php
ftp_pasv
($ftp_conn, true);
?>
-2
corey-holzer at nyc dot rr dot com
20 年前
零大小的檔案不是副作用。當 `ftp_get` 開始時,它做的第一件事就是建立將要串流資料的 inode/檔案,而這是一個零大小的檔案,其名稱是您為本機檔案指定的名稱。當下載失敗時,它會將檔案保留在原地。
-3
scott dot chu at udngroup dot com
8 年前
我建議使用 `ftp_fget()` 而不是 `ftp_get()`,因為後者只會傳回 TRUE 或 FALSE,而且沒有明顯的方法可以取得失敗的原因。

使用 `ftp_fget`,您必須傳遞一個檔案處理代碼作為本機檔案,因此您必須先執行 `fopen()`。透過這種方式,您可以在呼叫 `fopen()` 時發現「權限遭拒」的問題。如果您使用 `ftp_get()`,則沒有辦法找到此錯誤原因。

在我的情況下,我使用「nobody」執行 httpd,並使用「haha」建立 ftp 本機資料夾。當時我花了很長時間才找到「權限遭拒」的問題,因為我使用的是 `ftp_get()`。
To Top