当尝试从用户的 home 目录获取远程文件时,如果使用类似 '~/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] = "域名或IP地址/";
$remotedirs[1] = "域名或IP地址/";
$remotedirs[2] = "域名或IP地址/";
$remotedirs[3] = "域名或IP地址/";
$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(主机IP 或 域名, 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_name." 已复制到 $local_dir<br />";
}
}
}
fclose($stream);
?>
因为还在测试阶段(Beta版),我想它会有一些特性问题。我发现一个问题是,如果远程文件名包含括号,它就无法工作。
我应该把它作为一个bug报告提交,但是整个流程让我觉得很吓人——我一直都觉得自己是个啥也不懂的笨用户!
但无论如何——在下载前重命名文件这种变通方法很有效。
使用
$_new_path = str_replace("(", "", $_path );
$_new_path = str_replace(")", "", $_new_path );
ssh2_sftp_rename( $sftp, $_path, $_new_path );
说实话,我还没确定是左括号、右括号还是两者都有问题。其他人可以调查一下。
同时,最好能知道这个函数无法处理的所有无效文件名字符,毫无疑问,肯定还有更多。
如果你使用从ssh2_sftp()获得的路径,通过opendir和readdir扫描远程目录以获取文件列表,你最终会得到一个包含ssh2.sftp://$sftp前缀的完整文件路径列表,其中$sftp是由ssh2_sftp返回的sftp资源字符串。
如果你稍后尝试使用ssh2_scp_recv()(即使在相同的连接上!)从远程路径本地复制文件,复制操作将会失败,因为ssh2_scp_recv()不喜欢包装路径前缀。它期望远程文件引用位于远程文件系统的根目录(例如,“/”)。
结论:ssh2_scp_recv()喜欢位于远程机器文件系统根目录的路径,而不是完整的网络路径。这个例程会以一条关于无法复制文件的模糊消息失败——然而当你查看时,它却工作正常。更糟糕的是,当你连接并从scp shell会话中复制它们时,它也工作正常。
如果你收到错误 - ssh2_scp_recv(): Unable to receive remote file
尝试使用file_get_contents("ssh2.sftp://$sftp$fileLocation") 和 file_put_contents() 作为变通方法——在我尝试了各种不同的远程文件路径格式都无效之后。
如果你在尝试使用此函数时收到“Warning: ssh2_scp_send(): Failure creating remote file,”错误,请尝试使用
$data = file_get_contents("ssh2.sftp://$sftp/path/to/file");