php中本地文件拷贝至远程服务器的实现方式
需要解决的问题:本地文件搬移至远程服务器
前提:在linux服务器之间拷贝
以下作为备忘和整理记录下来
因为在linux上拷贝文件,同事提醒用scp来做,搜索php scp之后发现php官方提供了使用scp向远程服务器拷贝文件以及相应的ssh连接方法。
使用方法如下:
$ip = XXX; $port = XXX; $user = XXX; $pass = XXX; $material_path = "material_api.txt"; $target_path = "/data/aa/a"; $connection = ssh2_connect($ip, $port); ssh2_auth_password($connection, $user, $pass); $sftp = ssh2_sftp($connection); $result = ssh2_scp_send($connection, $material_path, $target_path."/".$material_path, 0777); echo "拷贝文件结果".$result." ";测试以上方法,报错
Call to undefined function ssh2_connect()
检查需要在服务器上安装ssh扩展,需要libssh2、ssh2。
安装扩展之后,测试上面代码成功。
实际需要拷贝的文件是视频文件,于是换为视频文件。
程序报错
Failed copying file
多次尝试都失败,换为demo中的txt文件,执行成功。
猜测是文件类型或文件大小的原因。
找了一个小的视频文件,发现可以拷贝,文件大小增大之后,同样报错:Failed copying file
查看文件系统,复制的文件大小小于实际文件。
查看官方网站的说明,没有对ssh2_scp_send方法的传输文件的大小的说明。
再查网上只找到一个类似情况的提问,说遇到大文件的时候,拷贝文件失败。
后来在php官网看到用户贡献的使用方法中提到使用fopen、fwrite作为替代,方法如下:
<?php $srcFile = "/var/tmp/dir1/file_to_send.txt"; $dstFile = "/var/tmp/dir2/file_received.txt"; // Create connection the the remote host $conn = ssh2_connect("my.server.com", 22); // Create SFTP session $sftp = ssh2_sftp($conn); $sftpStream = @fopen("ssh2.sftp://".$sftp.$dstFile, "w"); try { if (!$sftpStream) { throw new Exception("Could not open remote file: $dstFile"); } $data_to_send = @file_get_contents($srcFile); if ($data_to_send === false) { throw new Exception("Could not open local file: $srcFile."); } if (@fwrite($sftpStream, $data_to_send) === false) { throw new Exception("Could not send data from file: $srcFile."); } fclose($sftpStream); } catch (Exception $e) { error_log("Exception: " . $e->getMessage()); fclose($sftpStream); } ?>测试小文件方法可用,100+MB的视频也可以拷贝,300+MB的视频同样不能拷贝成功,但没有错误信息。
后来在程序中打上log,发现拷贝大文件的时候程序执行到@file_get_contents($srcFile)就不向下执行,但也没有错误信息。
猜测file_get_contents()方法将文件内容读为一个字符串,当文件大小比较大时,方法处理时会有问题。
同事提醒php中有原生的执行命令的方法,可以试试直接使用命令拷贝文件。方法如下:
$user = XXX; $ip = XXX; $source_path= "material_api.txt"; $target_path = "/data/aa/a"; $dest = $user."@".$ip.":".$target_path."/".$source_path; exec("scp ".$source_path." ".$dest , $output, $return);方法使用spc命令直接向远程服务器拷贝文件。
测试上述代码发现执行时,需要身份验证。
再通过资料查找建立了server1和server2之间的信任关系,使server1向server2执行scp不再需要每次都输入密码。
再测试以上代码,当拷贝成功的时候$return=0;失败的时候$return=1,完成了本地文件向远程服务器拷贝文件的要求。
ps:后期查找资料发现,对于file_get_contents(filename, use_iclude_path,context,offset,maxlen)读取大文件时,也许能够通过参数offset(文件读取的起始位置)、maxlen(读取的最大长度)的设置来分段读取文件。
如何在server1和server2之间建立信任关系不在这里说明,会另外说明。