本文作者:DurkBlue

PHP实现文件夹压缩、解压功能推荐

DurkBlue 2023-06-20 24614
PHP实现文件夹压缩、解压功能摘要: 如果有两个项目分布在两台服务器上,并且需要经常的传递文件夹或者文件,那么就需要考虑将文件夹或者大文件压缩后进行传输。压缩与解压代码如下:...

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


压缩与解压代码如下:


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


此篇文章由DurkBlue发布,请自觉转载请注明来处
文章版权及转载声明

作者:DurkBlue本文地址:https://hepuhua.cn/post/897.html发布于 2023-06-20
文章转载或复制请以超链接形式并注明出处DurkBlue博客

赞(1)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

阅读
分享