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."\n";
Call to undefined function ssh2_connect()
檢查需要在伺服器上安裝ssh擴充套件,需要libssh2、ssh2。
安裝擴充套件之後,測試上面程式碼成功。
實際需要拷貝的檔案是視訊檔案,於是換為視訊檔案。
程式報錯
Failed copying file
多次嘗試都失敗,換為demo中的txt檔案,執行成功。
猜測是檔案型別或檔案大小的原因。
找了一個小的視訊檔案,發現可以拷貝,檔案大小增大之後,同樣報錯:Failed copying file
檢視檔案系統,複製的檔案大小小於實際檔案。
檢視官方網站的說明,沒有對ssh2_scp_send方法的傳輸檔案的大小的說明。
再查網上只找到一個類似情況的提問,說遇到大檔案的時候,拷貝檔案失敗。
後來在php官網看到使用者貢獻的使用方法中提到使用fopen、fwrite作為替代,方法如下:
測試小檔案方法可用,100+MB的視訊也可以拷貝,300+MB的視訊同樣不能拷貝成功,但沒有錯誤資訊。<?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); } ?>
後來在程式中打上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之間建立信任關係不在這裡說明,會另外說明。