當您嘗試使用類似 '~/filename.txt' 的路徑從使用者家目錄取得遠端檔案時,可能會失敗。它似乎不喜歡波浪號,因此請使用完整的檔案路徑。
(PECL ssh2 >= 0.9.0)
ssh2_scp_recv — 透過 SCP 請求檔案
範例 #1 使用 SCP 下載檔案
<?php
$connection = ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');
ssh2_scp_recv($connection, '/remote/filename', '/local/filename');
?>
如果您收到
警告:ssh2_scp_recv():無法接收 /some-php-file.php 第 2 行的遠端檔案
請使用 `stream_get_contents` 函式。
範例
<?php
$stream = @fopen("ssh2.sftp://$sftp$remoteFile", 'r');
if (! $stream) {
throw new \Exception("無法開啟檔案: $remoteFile");
}
$contents = stream_get_contents($stream);
file_put_contents ($localFile, $contents);
@fclose($stream);
?>
嘗試取得名稱中包含空格的遠端檔案?
切記在遠端檔名中使用引號,但在本機檔名中則不要使用。
範例
<?php
$remote_file_name="my name with spaces.ext"
ssh2_scp_recv($cn,$remote_file_name,$local_path."/".$remote_file_name); // 錯誤
ssh2_scp_recv($cn,"\"".$remote_file_name."\"",$local_path."/".$remote_file_name); //正確
ssh2_scp_recv($cn,"\"".$remote_file_name."\"","\"".$local_path."/".$remote_file_name."\""); //錯誤
?>
所以,檔名中的引號僅在遠端需要,本地端不需要。
問題
無法將陣列傳遞給 sftp_scp_rec()
此外:對於 Windows:連線到 Windows 資料夾時,sftp 會出現問題。
例如:sftp_scp_rec($connection, "remote/directory","local/$directory[$i]");
解決方案
陣列會在變數末尾放置空白字元。
trim(" ","",$directory[$i]);
連線到 Windows 資料夾
sftp_scp_rec($connection, "linux/directory","\\windows\share[$i]");
此腳本會根據檔案的修改日期將遠端 Linux 資料夾備份到本機 Windows 資料夾。
其概念是透過 ftp 用戶端等取得完整目錄備份。
然後,當腳本執行時,它只會備份新修改的檔案。
<?php
//error_reporting(0);
$file ='';
$arr2 ='';
$arr1 ='';
$ldir = '';
$remotedirs[0] = "Domain name or IP address/";
$remotedirs[1] = "Domain name or IP address/";
$remotedirs[2] = "Domain name or IP address/";
$remotedirs[3] = "Domain name or IP address/";
$fh = fopen("c:\dirlist.txt","w");
fwrite($fh, " ");
fclose($fh);
foreach ($remotedirs as $val){
echo $remotedir = "/data/www/$val/";
$localdir = "\\\\192.168.0.234\\C$\\xampp\\htdocs\\$val\\";
backupwebsites($remotedir,$localdir);
}
function backupwebsites($remotedir,$localdir){
$connection = ssh2_connect(Host IP or Domain, 22);
$com ="ls -R -lt $remotedir";
ssh2_auth_password($connection, 'user', 'password');
$stream = ssh2_exec($connection, $com );
stream_set_blocking($stream, true);
$output = stream_get_contents($stream);
$fh = fopen("c:\dirlist.txt","a+");
fwrite($fh, $output);
fclose($fh);
$handle = @fopen('c:\dirlist.txt', "r");
if ($handle) {
while (!feof($handle)) {
$lines[] = fgets($handle, 4096);
}
fclose($handle);
}
foreach ($lines as $val)
{
$yr = date('Y-m-d');
$i++;
$arr1=split("200",$val);
$arr2=explode(" ",$arr1[1]);
if("200".$arr2[0]==$yr)
{
//if("200".$arr2[0]=='2008-04-21'){ //for testing
$remotedir = $remotedir.$arr2[2];
$cpy=$arr2[2];
$file = $localdir;
glue($connection,$remotedir,$localdir,$cpy);
}
}
}
//echo $i;
function glue($connection,$remotedir,$localdir,$cpy){
$ldir[0] = "$localdir";
$ldir[1]="$cpy";
$file = $ldir[0].$ldir[1];
$file = trim($file);
$file;
gop($connection,$remotedir,$file);
}
function gop($connection,$remotedir,$file){
echo $file;
ssh2_scp_recv(
$connection,
$remotedir,
$file);
}
?>
如果您未呼叫 ssh2_exec($connection,'exit'),則傳輸的檔案可能會被截斷。即使檔案未完全傳輸,ssh2_scp_send 也會傳回 true。
例如:
ssh2_scp_send($connection, $infile, $remotefile, 0644);
ssh2_exec($connection, 'exit'); // 結束 ssh2 連線
此函數可用於使用 SSH 和 SCP 將所有檔案複製到遠端伺服器上的目錄中。
<?php
$connection = ssh2_connect('host', 22);
ssh2_auth_password($connection, 'user', 'password');
$remote_dir="/remote_dir/";
$local_dir="/local_dir/";
$com ="ls $remote_dir";
$stream = ssh2_exec($connection, $com);
stream_set_blocking($stream,true);
$cmd=fread($stream,4096);
$arr=explode("\n",$cmd);
$total_files=sizeof($arr);
for($i=0;$i<$total_files;$i++){
$file_name=trim($arr[$i]);
if($file_name!=''){
$remote_file=$remote_dir.$file_name;
$local_file=$local_dir.$file_name;
if(ssh2_scp_recv($connection, $remote_file,$local_file)){
echo "File ".$file_name." was copied to $local_dir<br />";
}
}
}
fclose($stream);
?>
我猜測因為它還處於 Beta 階段,所以會有一些古怪的地方。我發現其中一個問題是,如果遠端檔案名稱中包含括號,它就無法正常運作。
我應該將它作為錯誤報告提交,但整個過程真的令人生畏 - 我始終只是一個愚蠢的用戶,不知道自己在說什麼!
但無論如何 - 在下載檔案之前重新命名檔案的解決方法有效。
使用
$_new_path = str_replace("(", "", $_path );
$_new_path = str_replace(")", "", $_new_path );
ssh2_sftp_rename( $sftp, $_path, $_new_path );
老實說,我還沒有確定是左括號、右括號還是兩者都有問題。其他人可以研究一下。
同時,最好能知道所有會造成此函式問題的無效檔名,無疑還有更多。
如果您使用 opendir 和 readdir 掃描透過 ssh2_sftp() 取得路徑的遠端目錄以取得檔案列表,您最終會得到一個包含 ssh2.sftp://$sftp 前綴的完整檔案路徑列表,其中 $sftp 是 ssh2_sftp() 返回的 sftp 資源字串。
如果您之後嘗試使用 ssh2_scp_recv()(即使在同一個連線上!)從遠端路徑複製檔案到本機,複製操作將會失敗,因為 ssh2_scp_recv() 不接受此包裝路徑前綴。它預期遠端檔案參考的根目錄是遠端檔案系統的根目錄(例如「/」)。
重點:ssh2_scp_recv() 接受以遠端機器檔案系統根目錄為根的路徑,而不是完整的網路路徑。這個例程會失敗,並顯示一則關於無法複製檔案的模糊訊息 — 但當您實際查看時,檔案卻可以正常運作。更糟的是,當您連線並從 scp shell session 複製它們時,它也能正常運作。
如果您收到錯誤訊息 - ssh2_scp_recv(): 無法接收遠端檔案
請嘗試使用 file_get_contents("ssh2.sftp://$sftp$fileLocation") 和 file_put_contents() 作為解決方法 — 這是在我嘗試了各種不同的遠端檔案路徑格式都無效之後的作法。
如果在嘗試使用此函式時出現「警告:ssh2_scp_send(): 建立遠端檔案失敗」,請嘗試使用
$data = file_get_contents("ssh2.sftp://$sftp/path/to/file");