diff --git a/app/admin/controller/Upgrade.php b/app/admin/controller/Upgrade.php index d90522d..6495447 100644 --- a/app/admin/controller/Upgrade.php +++ b/app/admin/controller/Upgrade.php @@ -19,17 +19,17 @@ use think\facade\View; use think\facade\Request; use think\facade\Db; use think\exception\ValidateException; -use app\admin\controller\Uzip; use think\facade\Cache; use taoler\com\Api; use taoler\com\Str; +use taoler\com\Files; use think\facade\Config; +use think\facade\Log; +use app\common\lib\ZipFile; +use app\common\lib\SetConf; class Upgrade extends AdminController { - public $update_log = "../runtime/update/update_log.log"; //系统升级日志 - public $return_log = "../runtime/update/return_log.log"; //系统回滚日志 - public $progress_log = "../runtime/update/progress_log.log"; //记录进度 public $root_dir = "../"; //站点代码的根目录 public $backup_dir = "../runtime/update/backup_dir/"; //备份目录 public $upload_dir = "../runtime/update/upload_dir/"; //升级包目录 @@ -94,29 +94,25 @@ class Upgrade extends AdminController } //升级前的版本检测 - public function check($url) + public function check() { - $url = $url.'?ver='.$this->sys_version; - //$versions = json_decode(Api::urlGet($url)); + $url = $this->sys['upcheck_url'].'?ver='.$this->sys_version; $versions = Api::urlGet($url); - //var_dump($versions); - + //判断服务器状态 $version_code = $versions->code; if($version_code == -1){ - return json(['code'=>$version_code,'msg'=>$versions->msg]); + $res = json(['code'=>$version_code,'msg'=>$versions->msg]); } - if($version_code == 1){ - return json(['code'=>$versions->code,'msg'=>$versions->msg,'version'=>$versions->version,'upnum'=>$versions->up_num]); + $res = json(['code'=>$versions->code,'msg'=>$versions->msg,'version'=>$versions->version,'upnum'=>$versions->up_num]); } - if($version_code == 0){ - return json(['code'=>$versions->code,'msg'=>$versions->msg]); + $res = json(['code'=>$versions->code,'msg'=>$versions->msg]); + } - - //版本比较 -/* + +/* //版本比较 $version_num = $versions->version; //最新版本 $up_num =$versions->up_num; //可更新版本数 $res = version_compare($version_num,$this->sys_version_num,'>'); @@ -125,7 +121,8 @@ class Upgrade extends AdminController } else { return json(['code'=>0,'msg'=>'暂时还没更新哦! ==8']); } -*/ +*/ + return $res; } @@ -134,78 +131,151 @@ class Upgrade extends AdminController */ public function upload() { - $data = Request::only(['url','key']); - - if(empty($data['key'])){ - return json(["code"=>0,"msg"=>"请配置正确升级key"]); - } - $url = $data['url'].'?url='.$this->sys['domain'].'&key='.$data['key'].'&ver='.$this->sys_version; -//var_dump($url); + $url = $this->sys['upgrade_url'].'?url='.$this->sys['domain'].'&key='.$this->sys['key'].'&ver='.$this->sys_version; $versions = Api::urlGet($url); - + Log::channel('update')->info('update:{type} {progress} {msg}',['type'=>'check','progress'=>'0%','msg'=>'---------------升级检测开始---------------']); //判断服务器状态 $version_code = $versions->code; if($version_code == -1){ + Log::channel('update')->info('update:{type} {progress} {msg}',['type'=>'check eroor','progress'=>'5%','msg'=>'---------------服务器链接失败---------------']); return json(['code'=>$version_code,'msg'=>$versions->msg]); } - + $version_num = $versions->version; $file_url = $versions->src; - + halt($version_num); //判断远程文件是否可用存在 $header = get_headers($file_url, true); if(!isset($header[0]) && (strpos($header[0], '200') || strpos($header[0], '304'))){ return json(["code"=>-1,"msg"=>"获取远程文件失败"]); } - - if(!is_dir($this->upload_dir)){ - $this->create_dirs($this->upload_dir); - } - //把远程文件放入本地 - $package_file = $this->upload_dir.'tao_'.$version_num.'.zip'; + + //把远程文件放入本地 + + //拼接路径 + //$upload_dir = substr($this->upload_dir,-1) == '/' ? $this->upload_dir : $this->upload_dir.'/'; + $upload_dir = Files::getDirPath($this->upload_dir); + Files::mkdirs($upload_dir); + + $package_file = $upload_dir.'taoler_'.$version_num.'.zip'; //升级的压缩包文件 $cpfile = copy($file_url,$package_file); + if(!$cpfile) { return json(["code"=>-1,"msg"=>"下载升级文件失败"]); - } - + } //记录下日志 - $this->save_log("上传升级包成功!"); - $this->update_progress("20%"); - - //升级前备份代码 - $ex = array('app','view'); - $backup_code_res = $this->copydir('../', $this->backup_dir, $ex); + Log::channel('update')->info('update:{type} {progress} {msg}',['type'=>'success','progress'=>'20%','msg'=>'上传升级包成功!']); +/* + //升级前备份代码 + $ex = array('.git','.idea','runtime','data','addons','config','extend'); // 排除备份文件夹 + $backup_code_res = Files::copydirs('../', $this->backup_dir, $ex); if(!$backup_code_res){ - $this->save_log("备份失败!"); + Log::channel('update')->info('update:{type} {progress} {msg}',['type'=>'error','progress'=>'25%','msg'=>'备份失败!']); return json(["code"=>0,"msg"=>"备份失败"]); } - $this->update_progress("30%"); - + Log::channel('update')->info('update:{type} {progress} {msg}',['type'=>'success','progress'=>'30%','msg'=>'执行文件备份成功!']); + +*/ //执行升级 $upres = $this->execute_update($package_file); //更新版本 - Db::name('system')->update(['sys_version_num'=>$version_num,'id'=>1]); - //$res = Config::set(['version' => $version_num,'salt' => 'taoler'], 'taoler'); - //var_dump($res); + //Db::name('system')->update(['sys_version_num'=>$version_num,'id'=>1]); + //$res = Config::set(['version' => $version_num], 'taoler'); + $value = [ + 'version' => $version_num + ]; + $setconf = new SetConf; + $res = $setconf->setconfig('taoler',$value); + var_dump($res); if($upres){ return json(["code"=>0,"msg"=>"升级成功"]); }else { return json(["code"=>-1,"msg"=>"升级失败"]); } } - + + /** + * @param string $package_file + * @return bool|\think\response\Json + */ + private function execute_update(string $package_file) + { + //解压 zip文件有密码的话需要解密 + $uzip = new ZipFile(); + $zipDir = strstr($package_file, '.zip',true); //返回文件名后缀前的字符串 + $zipPath = Files::getDirPath($zipDir); //转换为带/的路径 压缩文件解压到的路径 + $unzip_res = $uzip->unzip($package_file,$zipPath,true); + + if(!$unzip_res) + { + $this->save_log("解压失败"); + return json(["code"=>0,"msg"=>"解压失败"]); + } + //解压成功,得到文件夹 + //$package_name = str_replace(".zip","",$package_file); + + Log::channel('update')->info('update:{type} {progress} {msg}',['type'=>'success','progress'=>'50%','msg'=>'升级文件解压成功!']); + + /* + //升级mysql + if(file_exists($this->upload_dir.'/'.$package_file."/mysql/mysql_update.sql")) + { + $result = $this->database_operation($this->upload_dir.'/'.$package_file."/mysql/mysql_update.sql"); + if(!$result['code']) + { + echo json($result);die; + } + } + */ + Log::channel('update')->info('update:{type} {progress} {msg}',['type'=>'success','progress'=>'70%','msg'=>'升级文件解压成功!']); + + if(is_dir($zipPath)) + { + //升级PHP + $cp_res = Files::copyDirs($zipPath,$this->root_dir); + if(!$cp_res) + { + $this->save_log("php更新失败"); + //数据库回滚 + if(file_exists($this->upload_dir.'/'.$package_file."/mysql/mysql_rockback.sql")) + { + $this->save_log("数据库回滚"); + $this->database_operation($this->upload_dir.'/'.$package_file."/mysql/mysql_rockback.sql"); + + } + + //php代码回滚 升级前备份的代码 + + $backup_code_res = Files::copydirs($this->backup_dir, $this->root_dir); + if($backup_code_res){ + return json(["code"=>0,"msg"=>"php更新失败"]); + } + } + } + + //把解压的升级包清除 + //$del_zip = unlink($package_file); + Files::delDirAndFile($this->upload_dir); + Files::delDirAndFile($this->backup_dir); + + Log::channel('update')->info('update:{type} {progress} {msg}',['type'=>'success','progress'=>'100%','msg'=>'升级成功!']); + //更新系统的版本号了 + //更新php的版本号了(应该跟svn/git的版本号一致) + //更新数据库的版本号了(应该跟svn/git的版本号一致) + + return true; + } + /** * 处理升级包上传 */ public function uploadZip() { $files = request()->file('file'); - if($files) { $name = $files->getOriginalName(); - if(!$name) { return json(["code"=>0,"msg"=>"请上传升级包文件"]); @@ -217,9 +287,7 @@ class Upgrade extends AdminController if($ext != 'zip') { return json(["code"=>0,"msg"=>"请上传文件格式不对"]); - } - //对比版本号 $astr = explode('_',$name); $version_num = str_replace(".zip", '',array_pop($astr)); @@ -227,7 +295,6 @@ class Upgrade extends AdminController if(!$version_num) { return json(["code"=>0,"msg"=>"获取版本号失败"]); - } //对比 if(!$this->compare_version($version_num)) @@ -247,10 +314,6 @@ class Upgrade extends AdminController return json(["code"=>0,"msg"=>"上传文件失败"]); } - //记录下日志 - $this->save_log("上传升级包成功!"); - $this->update_progress("20%"); - //升级前备份代码 $ex = array('app','view'); $backup_code_res = $this->copydir('../', $this->backup_dir, $ex); @@ -258,7 +321,6 @@ class Upgrade extends AdminController $this->save_log("备份失败!"); return json(["code"=>0,"msg"=>"备份失败"]); } - $this->update_progress("30%"); //执行升级 $upres = $this->execute_update($package_file); @@ -273,81 +335,6 @@ class Upgrade extends AdminController } } - /** - * 升级操作 - * @return [type] [description] - */ - private function execute_update($package_file) - { - //解压 如何使用zip加密压缩,这里解压缩的时候注意要解密 - $uzip = new Uzip(); - $unzip_res = $uzip->uzip($package_file,$this->upload_dir,true); - if(!$unzip_res) - { - $this->save_log("解压失败"); - return json(["code"=>0,"msg"=>"解压失败"]); - } - //解压成功,得到文件夹 - $package_name = str_replace(".zip","",$package_file); -//var_dump($package_name); - $this->update_progress("50%"); - -/* - //升级mysql - if(file_exists($this->upload_dir.'/'.$package_file."/mysql/mysql_update.sql")) - { - $result = $this->database_operation($this->upload_dir.'/'.$package_file."/mysql/mysql_update.sql"); - if(!$result['code']) - { - echo json($result);die; - } - } -*/ - - $this->update_progress("70%"); - - - if(is_dir($package_name.'/')) - { - - //升级PHP - $cp_res = $this->copydir($package_name.'/', $this->root_dir); - if(!$cp_res) - { - $this->save_log("php更新失败"); - //数据库回滚 - if(file_exists($this->upload_dir.'/'.$package_file."/mysql/mysql_rockback.sql")) - { - $this->save_log("数据库回滚"); - $this->database_operation($this->upload_dir.'/'.$package_file."/mysql/mysql_rockback.sql"); - - } - - //php代码回滚 升级前备份的代码 - - $backup_code_res = $this->copydir($this->backup_dir, $this->zip_dir); - if($backup_code_res){ - $this->save_log("php回滚"); - return json(["code"=>0,"msg"=>"php更新失败"]); - } - } - } - - //把解压的升级包清除 - //$del_zip = unlink($package_file); - $this->delDirAndFile($this->upload_dir); - $this->delDirAndFile($this->backup_dir); - - $this->update_progress("100%"); - //更新系统的版本号了 - //更新php的版本号了(应该跟svn/git的版本号一致) - //更新数据库的版本号了(应该跟svn/git的版本号一致) - - return true; - } - - - /** * 比较代码版本 * @return [type] [description] @@ -375,14 +362,7 @@ class Upgrade extends AdminController return ["code"=>1,"msg"=>"数据库操作OK"]; } - /** - * 返回系统升级的进度 - */ - public function update_progress($progress) - { - exec(" echo '".$progress."' > $this->progress_log "); - - } + /** * 记录日志 */ @@ -413,15 +393,10 @@ class Upgrade extends AdminController if (( $file != '.' ) && ( $file != '..' )) { if ( is_dir($source . $file) ) { - - if(count($ex) != 0){ - if(in_array($file,$ex)){ - - $this->copydir($source . $file.'/', $dest . $file.'/'); - } - }else{ - $this->copydir($source . $file.'/', $dest . $file.'/'); - } + //拷贝排除的文件夹 + if(!in_array($file,$ex)){ + self::copyDirs($source . $file.'/', $dest . $file.'/'); + } } else { copy($source. $file, $dest . $file); } @@ -435,45 +410,6 @@ class Upgrade extends AdminController return true; } - /** - * 删除文件夹及内容 - * @param $dirPath - * @param $nowDir 是否删除当前文件夹$dirPath true false - */ - public function delDirAndFile( $dirPath, $nowDir=false ) - - { - if ( $handle = opendir($dirPath) ) { - - while ( false !== ( $item = readdir( $handle ) ) ) { - - if ( $item != '.' && $item != '..' ) { - - $path = $dirPath.$item; - //var_dump($path); - if (is_dir($path)) { - $this->delDirAndFile($path.'/'); - rmdir($path.'/'); - } else { - unlink($path); - } - } - } - - closedir( $handle ); -/* - if($nowDir == true){ - if(!rmdir($dirPath)){ - return false; - } - } -*/ - } else { - return false; - } - return true; - } - //创建多文件夹 public function create_dirs($path) { diff --git a/app/admin/view/upgrade/index.html b/app/admin/view/upgrade/index.html index e70cf33..e2f504e 100644 --- a/app/admin/view/upgrade/index.html +++ b/app/admin/view/upgrade/index.html @@ -34,7 +34,7 @@
-
当前版本:Taole v_{:config('taoler.version')}
+
当前版本:Taoler v_{:config('taoler.version')}
{if condition="checkRuleButton('admin/Upgrade/check')"} @@ -87,100 +87,53 @@ ,layer = layui.layer ,form = layui.form ,upload = layui.upload; - - //手动更新,选完文件后不自动上传 - upload.render({ - elem: '#select-file' - ,url: '/admin/upgrade/uploadzip' - ,accept: 'file' - ,field: 'file' - ,auto: false - ,exts: 'zip|rar|7z' - ,size: 10000 - //,multiple: true - ,bindAction: '#upgrade-sys-button' - ,before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。 - layer.load(); //上传loading - } - ,done: function(res){ - layer.closeAll('loading'); //关闭loading - if(res.code == 1){ - layer.msg(res.msg,{ - icon:6, - tiye:2000 - },function(){ - location.reload(); - }); - } else { - layer.open({ - title:"上传失败", - content:res.msg, - icon:5, - anim:6 - }); - } - } - }); - + //检测并更新系统 $('#upload-check').on('click',function(){ - var url = $(this).attr('data-url'), - loading = layer.load(2, { + var loading = layer.load(2, { shade: [0.2, '#000'], //time: 2000, }); - $.ajax({ - type:"post", - url:"{:url('admin/upgrade/check')}", - data:{"url":url}, - daType:"json", - success:function (data){ - if (data.code == 0) { - //已件最新版本 - layer.close(loading); - layer.msg(data.msg,{ - icon:6, - time:2000 - }); - - } else if (data.code == 1) { - //可升级 - layer.close(loading); - $('div#ver_nums').after('
发现'+data.upnum+'个新版本:可更新至v'+data.version+'
'); - //$('div#ver_nums').after('
发现'+data.upnum+'个新版本:可更新至v'+data.version+'
'); - $('button#upload-check').hide(); - - //更新系统 - layer.confirm('可更新至v'+data.version+' 确定升级?',{icon: 3, title:'升级系统'}, function(index){ - uploads(); //更新 - layer.close(index); //关闭load加载层 + $.get("{:url('admin/upgrade/check')}",function (data){ + if (data.code == 0) { + //已件最新版本 + layer.close(loading); + layer.msg(data.msg,{ + icon:6, + time:2000 }); - } else { - //服务器错误 - layer.close(loading); - layer.open({ - title:'服务错误', - content:data.msg, - icon:5, - anim:6 - }); - } + + } else if (data.code == 1) { + //可升级 + layer.close(loading); + $('div#ver_nums').after('
发现'+data.upnum+'个新版本:可更新至v'+data.version+'
'); + //$('div#ver_nums').after('
发现'+data.upnum+'个新版本:可更新至v'+data.version+'
'); + $('button#upload-check').hide(); + + //更新系统 + layer.confirm('可更新至v'+data.version+' 确定升级?',{icon: 3, title:'升级系统'}, function(index){ + uploads(); //更新 + layer.close(index); //关闭load加载层 + }); + } else { + //服务器错误 + layer.close(loading); + layer.open({ + title:'服务错误', + content:data.msg, + icon:5, + anim:6 + }); } - }); + } + ); return false; }); //更新 function uploads(){ - var url = "{$ver_num.upgrade_url}", - key = $('input[name=key]').attr("value"), - load = layer.load(); //loading - $.ajax({ - type:"post", - url:"{:url('admin/upgrade/upload')}", - data:{"url":url,"key":key}, - daType:"json", - success:function (data){ + var load = layer.load(); //loading + $.get("{:url('admin/upgrade/upload')}",function (data){ if (data.code == 0) { layer.close(load); layer.msg(data.msg,{ @@ -199,9 +152,43 @@ }); } } - }); + ); } + //手动更新,选完文件后不自动上传 + upload.render({ + elem: '#select-file' + ,url: "{:url('admin/upgrade/uploadzip')}" + ,accept: 'file' + ,field: 'file' + ,auto: false + ,exts: 'zip|rar|7z' + ,size: 10000 + //,multiple: true + ,bindAction: '#upgrade-sys-button' + ,before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。 + layer.load(); //上传loading + } + ,done: function(res){ + layer.closeAll('loading'); //关闭loading + if(res.code == 1){ + layer.msg(res.msg,{ + icon:6, + tiye:2000 + },function(){ + location.reload(); + }); + } else { + layer.open({ + title:"上传失败", + content:res.msg, + icon:5, + anim:6 + }); + } + } + }); + //确定升级操作 $(document).on('click','#update_system',function(){ //var url = $(this).attr('data-url'), diff --git a/app/common/lib/SetConf.php b/app/common/lib/SetConf.php new file mode 100644 index 0000000..08f5e91 --- /dev/null +++ b/app/common/lib/SetConf.php @@ -0,0 +1,35 @@ +getConfigPath() . $file.".php"; + //var_dump( $fileurl); + $string = file_get_contents($fileurl); //加载配置文件 + foreach ($data as $key => $value) { + $pats = '/\'' . $key . '\'(.*?)\',/'; + $reps = "'". $key. "'". " => " . "'".$value ."',"; + $string = preg_replace($pats, $reps, $string); // 正则查找然后替换 + } + file_put_contents($fileurl, $string); // 写入配置文件 + return true; + }else{ + return false; + } + } +} diff --git a/app/common/lib/ZipFile.php b/app/common/lib/ZipFile.php new file mode 100644 index 0000000..a01517a --- /dev/null +++ b/app/common/lib/ZipFile.php @@ -0,0 +1,100 @@ +create_dirs($dir); + } + + if(file_exists($filename)) { + $resource = zip_open($filename); + + while($zip = zip_read($resource)) { + if(zip_entry_open($resource, $zip)) { + + //获得文件名,mac压缩成zip,解压需要过滤资源库隐藏文件 + $file_content = zip_entry_name($zip); + + + // 如果文件不在根目录中 + $pos_last_slash = strrpos($file_content, "/"); + $file_name = substr($file_content, $pos_last_slash+1); + + if(empty($file_name)){ + + $pt = $this->create_dirs($dir.$file_content); + } + + if($file_name) { + + $save_path = $dir.$file_content; + + if(file_exists($save_path)) { + if($overwrite === true){ + echo $file_name . '
';	
+								$file_size = zip_entry_filesize($zip);
+								$file = zip_entry_read($zip, $file_size);
+								$fpc = file_put_contents($save_path, $file);
+								//zip_entry_close($zip);	
+							}else{
+								//echo '文件夹内已存在文件 "' . $file_name . '" 
';
+								return json(['code'=>0,'msg'=>'文件夹内已存在文件']);
+							}
+							
+						}else {
+							//echo $file_name . '
';	
+							$file_size = zip_entry_filesize($zip);
+							$file = zip_entry_read($zip, $file_size);
+							$fpc = file_put_contents($save_path, $file);
+							//zip_entry_close($zip);
+						}
+					
+					}
+				zip_entry_close($zip);	
+				}
+			}
+			zip_close($resource);
+			
+		}else{
+			return false;
+		}
+		return true;
+	}
+
+    /**
+     * 创建文件夹及子文件夹
+     * @param $path
+     * @return bool
+     */
+	public function create_dirs($path)
+	{
+	  if (!is_dir($path))
+	  {
+		$directory_path = "";
+		$directories = explode("/",$path);
+		array_pop($directories);
+	   
+		foreach($directories as $directory)
+		{
+		  $directory_path .= $directory."/";
+		  if (!is_dir($directory_path))
+		  {
+			mkdir($directory_path);
+			chmod($directory_path, 0777);
+		  }
+		}
+	  }
+	}
+}
\ No newline at end of file
diff --git a/config/log.php b/config/log.php
index ef8af09..7b80b59 100644
--- a/config/log.php
+++ b/config/log.php
@@ -72,6 +72,22 @@ return [
             // 是否实时写入
             'realtime_write' => true,
         ],
+        'update' => [
+            // 日志记录方式
+            'type'           => 'File',
+            // 日志保存目录
+            'path'           => '../runtime/update/log/',
+            // 单文件日志写入
+            'single'         => false,
+            // 最大日志文件数量
+            'max_files'      => 0,
+            // 日志处理
+            'processor'      => null,
+            // 日志输出格式化
+            'format'         => '[%s][%s] %s',
+            // 是否实时写入
+            'realtime_write' => true,
+        ],
     ],
 
 ];
diff --git a/config/taoler.php b/config/taoler.php
index ba5679b..88e5d49 100644
--- a/config/taoler.php
+++ b/config/taoler.php
@@ -5,6 +5,6 @@
 
 return [
     //版本配置
-    'version'	=> '1.6.6',
+    'version'	=> '1.6.7',
 	'salt'		=> 'taoler'
 ];
\ No newline at end of file
diff --git a/extend/taoler/com/Files.php b/extend/taoler/com/Files.php
index ef7afc3..77ea35b 100644
--- a/extend/taoler/com/Files.php
+++ b/extend/taoler/com/Files.php
@@ -5,9 +5,19 @@ use RecursiveIteratorIterator;
 use RecursiveDirectoryIterator;
 class Files
 {
+    /**
+     * 转换为/结尾的路径
+     * @param $path string 文件夹路径
+     * @return string
+     */
+    public static function getDirPath($path)
+    {
+        return substr($path,-1) == '/' ? $path : $path.'/';
+    }
+
     /**
      * 获取目录下子目录名
-     * @param $path 目录
+     * @param $path string 目录
      * @return array
      */
 	public static function getDirName($path)
@@ -47,17 +57,20 @@ class Files
 			chmod($directory_path, 0777);
 		  }
 		}
-	  }
-	  return true;
+		return true;
+	  }else {
+          return false;
+      }
+
 	}
 
     /**
      * 删除文件夹及内容
-     * @param $dirPath  所删除的目录
-     * @param bool $nowDir  是否删除当前文件夹$dirPath true false
+     * @param string $dirPath
+     * @param bool $nowDir 是否删除当前文件夹目录 true false
      * @return bool
      */
-	public static function delDirAndFile( $dirPath, $nowDir=false ) 
+	public static function delDirAndFile(string $dirPath, $nowDir=false )
 	{ 
 		if ( $handle = opendir($dirPath) ) { 
 
@@ -94,23 +107,19 @@ class Files
      * @param array $ex 指定只复制$source下的目录,默认全复制
      * @return bool
      */
-	public function copyDirs($source, $dest, $ex=array())
+	public static function copyDirs($source, $dest, $ex=array())
 	{
-		$count = count($ex);
 		if (!file_exists($dest)) mkdir($dest);
 			if($handle = opendir($source)){
 				while (($file = readdir($handle)) !== false) {
 					if (( $file != '.' ) && ( $file != '..' )) {
-						if ( is_dir($source . $file) ) {
-							//ָ���ļ���
-							if($count != 0){
-								if(in_array($file,$ex)){
-									self::copyDirs($source . $file.'/', $dest . $file.'/');
-								}
-							} else {
-								self::copyDirs($source . $file.'/', $dest . $file.'/');
-							}
+						if (is_dir($source . $file) ) {
+							//拷贝排除的文件夹
+                            if(!in_array($file,$ex)){
+                                self::copyDirs($source . $file.'/', $dest . $file.'/');
+                            }
 						} else {
+						    //拷贝文件
 							copy($source. $file, $dest . $file);
 						}
 					}