摘要:
如果有两个项目分布在两台服务器上,并且需要经常的传递文件夹或者文件,那么就需要考虑将文件夹或者大文件压缩后进行传输。压缩与解压代码如下:...
如果有两个项目分布在两台服务器上,并且需要经常的传递文件夹或者文件,那么就需要考虑将文件夹或者大文件压缩后进行传输。
压缩与解压代码如下:
/** * 将目标文件夹下的内容压缩到zip中(zip包含文件夹目录) * @param $sourcePath *文件夹路径 例: /home/test * @param $outZipPath *zip文件名(包含路径) 例: /home/zip_file/test.zip * @return string */ public static function zipFolder($sourcePath, $outZipPath) { $parentPath = rtrim(substr($sourcePath, 0, strrpos($sourcePath, '/')),"/")."/"; $dirName = ltrim(substr($sourcePath, strrpos($sourcePath, '/')),"/"); $sourcePath=$parentPath.'/'.$dirName;//防止传递'folder'文件夹产生bug $z = new \ZipArchive(); $z->open($outZipPath, \ZIPARCHIVE::CREATE);//建立zip文件 $z->addEmptyDir($dirName);//建立文件夹 self::folderToZip($sourcePath, $z, strlen("$parentPath/")); $z->close(); return $outZipPath; } private static function folderToZip($folder, &$zipFile, $exclusiveLength) { $handle = opendir($folder); while (false !== $f = readdir($handle)) { if ($f != '.' && $f != '..') { $filePath = "$folder/$f"; // 在添加到zip之前从文件路径中删除前缀 $localPath = substr($filePath, $exclusiveLength); if (is_file($filePath)) { $zipFile->addFile($filePath, $localPath); } elseif (is_dir($filePath)) { // 添加子文件夹 $zipFile->addEmptyDir($localPath); self::folderToZip($filePath, $zipFile, $exclusiveLength); } } } closedir($handle); } /** 解压 * @param $zipFileName *zip文件名(包含路径) 例: /home/zip_file/test.zip * @param $unzipPath *解压路径 例: /home/test/ * @return bool */ public static function unzipFile($zipFileName, $unzipPath) { $zip = new \ZipArchive; if ($zip->open($zipFileName) === true) { if(!file_exists($unzipPath)) @mkdir($unzipPath); //将压缩包文件解压到test目录下 $zip->extractTo($unzipPath); // 关闭zip $zip->close(); return true; }else{ return false; } }
假如有两个服务器A/B,A服务器我们称之为本地,B服务器称之为远端。文件的传输由A服务器主动出阿发,这就可以看为:A服务器(本地)上传文件到B服务器(远端),A服务器(本地)从B服务器(远端)下载文件。
在A服务器(本地)中项目代码可以这么写:
//从本地服务器传输到远端服务器
public static function localToRemote($localDir, $remoteDir) { ini_set('max_execution_time', '0'); $start = time(); //本地 -> 远程 $url = '远端接收文件的接口地址'; //若是文件夹,压缩成zip 传输完成,删除本地zip if(is_dir($localDir)){ $filePath = self::zipFolder($localDir, 'zip文件名称.zip'); $isDir = true; }elseif(is_file($localDir)){ //若是文件,直接传到远程 $filePath = $localDir; $isDir = false; }else{ return ['result' => false, 'msg' => '文件|文件夹路径错误']; } $response = self::postRequest($url, [ 'action' => 'upload_file', 'file_path' => $filePath, 'is_dir' => $isDir, 'destination' => $remoteDir, //目的文件夹 ]); $responseArr = json_decode($response, true); //传输成功 if(isset($responseArr['result']) && $responseArr['result']){ //若存在zip文件,删除 if($isDir){ unlink($filePath); } $elapsedTime = time() - $start; return ['result' => true, 'msg' => 'success', 'elapsed_time' => $elapsedTime]; }else{ //传输失败 return ['result' => false, 'msg' => $responseArr['msg'] ?? 'fail']; } } public static function postRequest($url, $data) { if(!is_array($data)){ return false; } //传输文件,必传file_path if(isset($data['file_path'])){ $data['file'] = new \CURLFile($data['file_path']); unset($data['file_path']); } $ch = curl_init(); curl_setopt($ch , CURLOPT_URL , $url); curl_setopt($ch , CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch , CURLOPT_POST, 1); curl_setopt($ch , CURLOPT_CONNECTTIMEOUT, 10); //如果服务器10秒内没有响应,就会断开连接 curl_setopt($ch , CURLOPT_TIMEOUT, 300); //若传输5分钟内还没有下载完成,将会断开连接 curl_setopt($ch , CURLOPT_POSTFIELDS, $data); $output = curl_exec($ch); curl_close($ch); return $output; } //从远端服务器传输文件到本地服务器(从远端下载) public static function remoteToLocal($localDir, $remoteDir) { ini_set('max_execution_time', '0'); $start = time(); //远程 -> 本地 只可以是zip文件,保证传输文件最小 $url = '远端发送文件的接口地址'; $filePath = 'zip文件名称.zip'; self::downloadFile($url, [ 'action' => 'download_file', 'file_path' => $remoteDir //文件名称 或 文件夹目录 ], $filePath); if(is_file($filePath)){ $unzipResult = self::unzipFile($filePath, dirname($localDir)); if($unzipResult){ //解压成功 删除zip文件 unlink($filePath); $elapsedTime = time() - $start; return ['result' => true, 'msg' => 'success', 'elapsed_time' => $elapsedTime]; }else{ return ['result' => false, 'msg' => 'File decompression failure']; } }else{ return ['result' => false, 'msg' => '文件传输失败']; } } /** * 通过curl下载文件 * @param $url *请求url * @param $data *请求数据 * @param $filePath *存储到本地的文件名 例:/home/tmp/file.text * @return bool */ public static function downloadFile($url, $data, $filePath) { //初始化 $curl = curl_init(); //设置抓取的url curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl , CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl , CURLOPT_POST, 1); curl_setopt($curl , CURLOPT_POSTFIELDS, $data); //打开文件描述符 $fp = fopen ($filePath, 'w+'); curl_setopt($curl, CURLOPT_FILE, $fp); //这个选项是意思是跳转,如果你访问的页面跳转到另一个页面,也会模拟访问。 curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); curl_setopt($curl,CURLOPT_TIMEOUT,50); //执行命令 curl_exec($curl); //关闭URL请求 curl_close($curl); //关闭文件描述符 fclose($fp); return true; }
B服务器(远端)上的接口代码示例:(需要结合A服务器上的代码来看)
$action = $_POST['action']; if ($action == 'upload_file') { //A -> B if(isset($_FILES['file']['tmp_name'])){ if($_POST['is_dir']){ $destinationPath = dirname($_POST['destination']); if(!file_exists($destinationPath)){ @mkdir($destinationPath); } $file = $destinationPath . '/' . date("YmdHis") . rand(10000,99999) . 'file.zip'; copy($_FILES['file']['tmp_name'], $file); $unzipResult = unzipFile($file, $destinationPath); if($unzipResult){ unlink($file); }else{ return ['result' => false, 'msg' => 'File decompression failure']; } }else{ copy($_FILES['file']['tmp_name'], $_POST['destination']); } return ['result' => true, 'msg' => 'success']; }else{ return ['result' => false, 'msg' => 'File receiving failure']; } } elseif ($action == 'download_file') { //B -> A $randomName = date("YmdHis") . rand(10000,99999); $zipFileName = dirname($_POST['file_path']) . '/' . $randomName . 'file.zip'; $filePath = zipFolder($_POST['file_path'], $zipFileName); $fileName = basename($filePath); header("Content-Type: application/zip"); header("Content-Disposition: attachment; filename=$fileName"); header("Content-Length: " . filesize($filePath)); readfile($filePath); unlink($filePath); exit; }