PHP实现文件夹压缩、解压及zip文件在服务器之间的传输

如果有两个项目分布在两台服务器上,并且需要经常的传递文件夹或者文件,那么就需要考虑将文件夹或者大文件压缩后进行传输。

压缩与解压代码如下:

/**
     * 将目标文件夹下的内容压缩到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;
        }

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值