如果有两个项目分布在两台服务器上,并且需要经常的传递文件夹或者文件,那么就需要考虑将文件夹或者大文件压缩后进行传输。
压缩与解压代码如下:
/**
* 将目标文件夹下的内容压缩到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;
}