AddonsService.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. <?php
  2. /**
  3. * ----------------------------------------------------------------------------
  4. * 行到水穷处,坐看云起时
  5. * 开发软件,找贵阳云起信息科技,官网地址:https://www.56q7.com/
  6. * ----------------------------------------------------------------------------
  7. * Author: 老成
  8. * email:85556713@qq.com
  9. */
  10. declare(strict_types=1);
  11. namespace app\admin\service\addons;
  12. use app\common\model\AuthRule;
  13. use app\common\model\Config;
  14. use app\common\service\BaseService;
  15. use app\common\library\Http;
  16. use app\common\model\Addons;
  17. use think\facade\Db;
  18. class AddonsService extends BaseService {
  19. private $pluginsPath;
  20. private $pluginsHost;
  21. private $menuid;
  22. protected function init()
  23. {
  24. $this->pluginsPath=root_path().'addons'.DS;
  25. $this->pluginsHost=config('yunqi.plugins_host');
  26. }
  27. public function getAddonsPath(string $type,string $pack)
  28. {
  29. $path=$this->pluginsPath.$type.DS.$pack.DS;
  30. return $path;
  31. }
  32. public function getAddonsPack(string $type,string $pack,string $version)
  33. {
  34. $path=$this->pluginsPath.$type.DS.$pack.DS.$version.'.zip';
  35. return $path;
  36. }
  37. public function delAddons(string $key)
  38. {
  39. /* @var Addons $addon*/
  40. $addon=Addons::where('key',$key)->find();
  41. $addonpath=$this->getAddonsPath($addon['type'],$addon['pack']);
  42. rmdirs($addonpath);
  43. $addon->delete();
  44. }
  45. public function download(array $addon)
  46. {
  47. $packdir=$this->pluginsPath.$addon['type'].DS.$addon['pack'];
  48. if(is_dir($packdir)){
  49. throw new \Exception('存在同名的包【'.$packdir.'】,请先卸载');
  50. }
  51. $savefile=$this->getAddonsPack($addon['type'],$addon['pack'],$addon['version']);
  52. $transaction_id=isset($addon['transaction_id'])?$addon['transaction_id']:'';
  53. $response=Http::download($this->pluginsHost.'/addons/download?key='.$addon['key'].'&transaction_id='.$transaction_id,$savefile);
  54. if(!$response->isSuccess()){
  55. rmdirs($packdir);
  56. throw new \Exception($response->errorMsg);
  57. }
  58. //解压下载文件
  59. $zip = new \ZipArchive();
  60. if ($zip->open($savefile) === TRUE) {
  61. $addonspath=$this->getAddonsPath($addon['type'],$addon['pack']);
  62. $package=$addonspath.'package'.DS;
  63. $zip->extractTo($package);
  64. $zip->close();
  65. $this->copy_file($package.'Install.php',$addonspath.'Install.php');
  66. if(is_file($package.'install.sql')){
  67. $this->copy_file($package.'install.sql',$addonspath.'install.sql');
  68. unlink($package.'install.sql');
  69. }
  70. unlink($package.'Install.php');
  71. (new Addons())->save($addon);
  72. } else {
  73. throw new \Exception('解压失败');
  74. }
  75. }
  76. public function checkPayStatus(string $key,string $out_trade_no)
  77. {
  78. $response=Http::get($this->pluginsHost.'/addons/checkpay?key='.$key.'&out_trade_no='.$out_trade_no);
  79. if(!$response->isSuccess()){
  80. throw new \Exception($response->errorMsg);
  81. }
  82. return $response->content;
  83. }
  84. public function uninstall(string $key,array $actions)
  85. {
  86. $addon=Addons::where('key',$key)->find();
  87. $this->includeInstall($addon);
  88. $addonpath=$this->getAddonsPath($addon['type'],$addon['pack']);
  89. if(!is_file($addonpath.'Install.php')){
  90. throw new \Exception('安装文件不存在');
  91. }
  92. $pack=$this->getAddonsPack($addon['type'],$addon['pack'],$addon['version']);
  93. if(!file_exists($pack)){
  94. throw new \Exception('禁止卸载未打包的扩展');
  95. }
  96. $install='\\addons\\'.$addon['type'].'\\'.$addon['pack'].'\\Install';
  97. try{
  98. Db::startTrans();
  99. //删除菜单
  100. if(in_array('menu',$actions)){
  101. AuthRule::where(['addons'=>$addon['pack']])->delete();
  102. }
  103. //删除配置
  104. if(in_array('config',$actions)){
  105. if($addon['type']=='app'){
  106. Config::where(['group'=>$addon['pack']])->delete();
  107. }else{
  108. Config::where(['addons'=>$addon['pack']])->delete();
  109. }
  110. }
  111. //删除数据表
  112. if(in_array('tables',$actions)){
  113. $tables=$this->parseTable($addonpath);
  114. foreach ($tables as $table){
  115. $sql="drop table {$table};";
  116. Db::execute($sql);
  117. }
  118. }
  119. //卸载文件
  120. foreach ($install::$files as $file){
  121. $path=root_path().$file;
  122. if(is_file($path)){
  123. unlink($path);
  124. }
  125. if(is_dir($path)){
  126. rmdirs($path);
  127. }
  128. }
  129. $install::uninstall();
  130. $addon->install=0;
  131. $addon->save();
  132. Db::commit();
  133. }catch (\Exception $e){
  134. Db::rollback();
  135. throw new \Exception($e->getMessage());
  136. }
  137. }
  138. public function getAddonsInstallInfo(Addons $addons)
  139. {
  140. $this->includeInstall($addons);
  141. $addonpath=$this->getAddonsPath($addons['type'],$addons['pack']);
  142. if(!is_file($addonpath.'Install.php')){
  143. throw new \Exception('安装文件不存在');
  144. }
  145. $install='\\addons\\'.$addons['type'].'\\'.$addons['pack'].'\\Install';
  146. return [
  147. 'files'=>$install::$files,
  148. 'unpack'=>$install::$unpack,
  149. 'menu'=>$install::$menu,
  150. 'require'=>$install::$require,
  151. 'addons'=>isset($install::$addons)?$install::$addons:[],
  152. 'config'=>$install::$config,
  153. 'tables'=>isset($install::$tables)?$install::$tables:[]
  154. ];
  155. }
  156. public function payCode(string $key,string $out_trade_no)
  157. {
  158. $response=Http::get($this->pluginsHost.'/addons/paycode?key='.$key.'&out_trade_no='.$out_trade_no);
  159. if(!$response->isSuccess()){
  160. throw new \Exception($response->errorMsg);
  161. }
  162. return $response->content;
  163. }
  164. public function install(string $key)
  165. {
  166. $addon=Addons::where('key',$key)->find();
  167. $this->includeInstall($addon);
  168. $addonpath=$this->getAddonsPath($addon['type'],$addon['pack']);
  169. if(!is_file($addonpath.'Install.php')){
  170. throw new \Exception('安装文件不存在');
  171. }
  172. if(!is_dir($addonpath.'package')){
  173. throw new \Exception('安装包不存在');
  174. }
  175. $install='\\addons\\'.$addon['type'].'\\'.$addon['pack'].'\\Install';
  176. if(!$this->checkInstallFiles($install::$files,$error)){
  177. throw new \Exception($error);
  178. }
  179. //检测表是否存在
  180. $tables=$this->parseTable($addonpath);
  181. foreach ($tables as $table){
  182. if(!empty(Db::query("SHOW TABLES LIKE '{$table}'"))){
  183. throw new \Exception('表【'.$table.'】已存在');
  184. }
  185. }
  186. //检测配置是否冲突
  187. foreach ($install::$config as &$value){
  188. if($addon['type']=='app'){
  189. $value['addons']=null;
  190. $value['group']=$addon['pack'];
  191. }else{
  192. $value['addons']=$addon['pack'];
  193. $value['group']='addons';
  194. }
  195. $havaconfig=Config::where(['name'=>$value['name'],'group'=>$value['group']])->find();
  196. if($havaconfig){
  197. throw new \Exception('配置【'.$value['title'].'】已存在');
  198. }
  199. $value['can_delete']=1;
  200. $value['value']=$value['value']??'';
  201. unset($value['id']);
  202. }
  203. //检测依赖
  204. foreach ($install::$require as $require){
  205. if(!class_exists($require)){
  206. throw new \Exception('缺少类:'.$require.',请先安装依赖包');
  207. }
  208. }
  209. //检测依赖
  210. if(isset($install::$addons)){
  211. foreach ($install::$addons as $key=>$aons){
  212. if(!addons_installed($key)){
  213. throw new \Exception('缺少依赖扩展:'.$aons.',请先安装依赖扩展');
  214. }
  215. }
  216. }
  217. //安装菜单
  218. $this->menuid=(int)AuthRule::max('id')+1;
  219. $menus=$this->parseMenu($install::$menu,$addon['pack']);
  220. try{
  221. Db::startTrans();
  222. Db::name('auth_rule')->insertAll($menus);
  223. //安装配置
  224. (new Config())->saveAll($install::$config);
  225. if($addon['type']=='app'){
  226. $configgroup=Config::where(['name'=>'configgroup','group'=>'dictionary'])->value('value');
  227. $configgroup=json_decode($configgroup,true);
  228. unset($configgroup['dictionary']);
  229. $configgroup[$addon['pack']]='应用配置';
  230. $configgroup['dictionary']='配置分组';
  231. $configgroup=json_encode($configgroup,JSON_UNESCAPED_UNICODE);
  232. Config::where(['name'=>'configgroup','group'=>'dictionary'])->update(['value'=>$configgroup]);
  233. }
  234. //安装sql
  235. if(is_file($addonpath.'install.sql')){
  236. //直接导入数据库文件
  237. $sql=file_get_contents($addonpath.'install.sql');
  238. $this->installSql($sql);
  239. //修改表名
  240. foreach ($tables as $old=>$newtable){
  241. Db::execute("alter table {$old} rename to {$newtable};");
  242. }
  243. }
  244. //安装文件
  245. $package=$addonpath.'package'.DS;
  246. foreach ($install::$files as $file){
  247. $path=$package.$file;
  248. if(is_dir($path)){
  249. $this->copy_dir($path,root_path().$file);
  250. }
  251. if(is_file($path)){
  252. $this->copy_file($path,root_path().$file);
  253. }
  254. }
  255. $install::install();
  256. $addon->install=1;
  257. $addon->save();
  258. Db::commit();
  259. }catch(\Exception $e){
  260. Db::rollback();
  261. throw new \Exception($e->getMessage());
  262. }
  263. }
  264. //安装sql文件
  265. private function installSql(string $sql)
  266. {
  267. $host=config('database.connections.mysql.hostname');
  268. $port=config('database.connections.mysql.hostport');
  269. $dbname=config('database.connections.mysql.database');
  270. $dbuser=config('database.connections.mysql.username');
  271. $dbpass=config('database.connections.mysql.password');
  272. $dsn="mysql:host={$host};port={$port};dbname={$dbname}";
  273. $pdo = new \PDO($dsn, $dbuser, $dbpass);
  274. $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
  275. $pdo->exec($sql);
  276. }
  277. public function checkTransactionId(string $pack,string $transaction_id)
  278. {
  279. $response=Http::get($this->pluginsHost.'/addons/checktransactionid?pack='.$pack.'&transaction_id='.$transaction_id);
  280. if(!$response->isSuccess()){
  281. throw new \Exception($response->errorMsg);
  282. }
  283. return $response->content;
  284. }
  285. public function create(array $param)
  286. {
  287. include __DIR__.DS.'eof.php';
  288. $pack=$param['pack'];
  289. $type=$param['type'];
  290. $addonspath=$this->getAddonsPath($type,$pack);
  291. if(is_dir($addonspath)){
  292. rmdirs($addonspath);
  293. }
  294. $haddon=Addons::where(function ($query) use ($param,$pack){
  295. $query->where('pack',$pack);
  296. if($param['id']){
  297. $query->where('id','<>',$param['id']);
  298. }
  299. })->find();
  300. if($haddon){
  301. throw new \Exception('包名已经存在,请更换包名');
  302. }
  303. if($param['id']){
  304. $model=Addons::find($param['id']);
  305. if(!Addons::checkKey($model)){
  306. throw new \Exception('不是你的扩展,无法操作');
  307. }
  308. }else{
  309. $model=new Addons();
  310. }
  311. $files=$param['files'];
  312. //将换行符转换为数组
  313. $files=array_map(function ($file){
  314. return trim($file);
  315. },explode("\n",$files));
  316. if(!$this->checkCreateFiles($files,$error)){
  317. throw new \Exception($error);
  318. }
  319. $unpack=$param['unpack'];
  320. $unpack=array_map(function ($file){
  321. return trim($file);
  322. },explode("\n",$unpack));
  323. //设置依赖类
  324. $require=$param['require'];
  325. $require=array_map(function ($class){
  326. return trim($class);
  327. },explode("\n",$require));
  328. //设置依赖扩展
  329. $addons=$param['addons'];
  330. $addons=array_map(function ($class){
  331. return trim($class);
  332. },explode("\n",$addons));
  333. $tables=$param['tables'];
  334. $config=Config::whereIn('id',$param['config'])->select()->toArray();
  335. $menu=AuthRule::getRuleList($param['menu']);
  336. //加密密钥
  337. $param['secret_key']=md5(str_rand(10).rand(1000,9999));
  338. //生成key
  339. $param['key']=md5($param['type'].$param['pack'].$param['author'].$param['version'].$param['secret_key']);
  340. //创建Install文件
  341. $files_txt=rtrim(getFilesTxt($files));
  342. $unpack_txt=rtrim(getUnpackTxt($unpack));
  343. $require_txt=rtrim(getRequireTxt($require));
  344. $addons_txt=rtrim(getAddonsTxt($addons));
  345. $config_txt=rtrim(getConfigTxt($config));
  346. $menu_txt=rtrim(getMenuTxt($menu));
  347. $tables_txt=rtrim(getTableTxt($tables));
  348. $install=$this->getContent('install',[
  349. 'pack'=>$pack,
  350. 'type'=>$type,
  351. 'files'=>$files_txt,
  352. 'unpack'=>$unpack_txt,
  353. 'require'=>$require_txt,
  354. 'addons'=>$addons_txt,
  355. 'config'=>$config_txt,
  356. 'tables'=>$tables_txt,
  357. 'menu'=>$menu_txt,
  358. ]);
  359. mkdir($addonspath,0777,true);
  360. file_put_contents($addonspath.'Install.php',$install);
  361. //拷贝数据文件
  362. $param['install']=1;
  363. $model->save($param);
  364. }
  365. public function package(string $key)
  366. {
  367. $addon=Addons::where('key',$key)->find();
  368. if(!Addons::checkKey($addon)){
  369. //禁止修改、删除,否则后果自负
  370. throw new \Exception('不是你的扩展,无法操作');
  371. }
  372. $this->includeInstall($addon);
  373. $packfile=$this->getAddonsPack($addon['type'],$addon['pack'],$addon['version']);
  374. if(is_file($packfile)){
  375. throw new \Exception('已经打包过了');
  376. }
  377. $addonpath=$this->getAddonsPath($addon['type'],$addon['pack']);
  378. if(!is_file($addonpath.'Install.php')){
  379. throw new \Exception('安装文件不存在');
  380. }
  381. $install='\\addons\\'.$addon['type'].'\\'.$addon['pack'].'\\Install';
  382. if(!$this->checkPackFiles($install::$files,$error)){
  383. throw new \Exception($error);
  384. }
  385. //打包表格
  386. if(!empty($install::$tables)){
  387. $savesql=$addonpath.'install.sql';
  388. $prefix=config('database.connections.mysql.prefix');
  389. $sqltxt='';
  390. foreach ($install::$tables as $table){
  391. $nopretable=str_replace($prefix,'__PREFIX__',$table);
  392. $createComment=PHP_EOL.'-- 创建表结构 `'.$nopretable.'`'.PHP_EOL;
  393. $sql="SHOW CREATE TABLE `{$table}`";
  394. $createResult=Db::query($sql)[0]['Create Table'].';';
  395. $createResult=str_replace('CREATE TABLE','CREATE TABLE IF NOT EXISTS',$createResult);
  396. $createResult=str_replace($prefix,'__PREFIX__',$createResult);
  397. $sql="select * from `{$table}`";
  398. $data=Db::query($sql);
  399. $insertComment='';
  400. $insertResult='';
  401. if(count($data)>0){
  402. $insertComment=PHP_EOL.PHP_EOL.'-- 导入表数据 `'.$nopretable.'`'.PHP_EOL;
  403. $insertResult='';
  404. foreach ($data as $item){
  405. $insertResult.="INSERT INTO `{$nopretable}` VALUES (";
  406. foreach ($item as $value){
  407. if($value===null) {
  408. $insertResult .= 'null,';
  409. }else if(is_string($value)){
  410. $value=addslashes($value);
  411. $insertResult.="'{$value}',";
  412. }else{
  413. $insertResult.="'{$value}',";
  414. }
  415. }
  416. $insertResult=rtrim($insertResult,',');
  417. $insertResult.=");".PHP_EOL;
  418. }
  419. }else{
  420. $createResult.=PHP_EOL;
  421. }
  422. $sqltxt.=$createComment.$createResult.$insertComment.$insertResult;
  423. }
  424. file_put_contents($savesql,$sqltxt);
  425. }
  426. //创建打包目录
  427. $package=$addonpath.'package'.DS;
  428. if(!is_dir($package)){
  429. mkdir($package,0777,true);
  430. }
  431. //拷贝文件
  432. foreach ($install::$files as $file){
  433. $path=root_path().$file;
  434. if(is_dir($path)){
  435. $this->copy_dir($path,$package.$file,$install::$unpack);
  436. }
  437. if(is_file($path)){
  438. $this->copy_file($path,$package.$file,$install::$unpack);
  439. }
  440. }
  441. $zip=new \ZipArchive();
  442. $zip->open($packfile,\ZipArchive::CREATE);
  443. self::addFileToZip($package,$package,$zip);
  444. //追加安装文件
  445. $zip->addFile($addonpath.'Install.php','Install.php');
  446. //追加数据库文件
  447. if(is_file($addonpath.'install.sql')){
  448. $zip->addFile($addonpath.'install.sql','install.sql');
  449. }
  450. $zip->close();
  451. $addon->save();
  452. }
  453. public function getAddons(int $page,string $type,string $plain,int $limit,string $keywords='')
  454. {
  455. $data=[
  456. 'page'=>$page,
  457. 'type'=>$type,
  458. 'plain'=>$plain,
  459. 'limit'=>$limit
  460. ];
  461. if($keywords){
  462. $data['keywords']=$keywords;
  463. }
  464. $response=Http::get($this->pluginsHost.'/addons/list',$data);
  465. if($response->isSuccess()){
  466. return $response->content;
  467. }else{
  468. return [
  469. 'total'=>0,
  470. 'rows'=>[]
  471. ];
  472. }
  473. }
  474. private function parseMenu(array $menu,string $pack,int $pid=0)
  475. {
  476. $time=time();
  477. $rr=[];
  478. foreach ($menu as $item){
  479. $id=$this->menuid;
  480. $arr=[];
  481. $arr['id']=$id;
  482. $arr['pid']=isset($item['pid'])?$item['pid']:$pid;
  483. $arr['addons']=$pack;
  484. $arr['controller']=$item['controller'];
  485. $arr['action']=$item['action'];
  486. $arr['title']=$item['title'];
  487. $arr['icon']=$item['icon'];
  488. $arr['weigh']=$item['weigh'];
  489. $arr['ismenu']=$item['ismenu'];
  490. $arr['extend']=$item['extend'];
  491. if($arr['ismenu']){
  492. $arr['status']='normal';
  493. $arr['menutype']=$item['menutype'];
  494. }else{
  495. $arr['status']=null;
  496. $arr['menutype']=null;
  497. }
  498. $arr['createtime']=$time;
  499. $arr['updatetime']=$time;
  500. $rr[]=$arr;
  501. $this->menuid++;
  502. if(isset($item['childlist'])){
  503. $ir=$this->parseMenu($item['childlist'],$pack,$id);
  504. $rr=array_merge($rr,$ir);
  505. }
  506. }
  507. return $rr;
  508. }
  509. private function parseTable(string $addonspath)
  510. {
  511. $sqlpath=$addonspath.'install.sql';
  512. if(!is_file($sqlpath)){
  513. return [];
  514. }
  515. $prefix=config('database.connections.mysql.prefix');
  516. $tables=[];
  517. $fp=fopen($sqlpath,'r');
  518. while(!feof($fp)) {
  519. $line=fgets($fp);
  520. if(!$line){
  521. continue;
  522. }
  523. if(strpos($line,'CREATE TABLE')!==false){
  524. $prefixtable=substr($line,strpos($line,'`')+1);
  525. $prefixtable=substr($prefixtable,0,strpos($prefixtable,'`'));
  526. $table=str_replace('__PREFIX__',$prefix,$prefixtable);
  527. $tables[$prefixtable]=$table;
  528. }
  529. }
  530. fclose($fp);
  531. return $tables;
  532. }
  533. private function addFileToZip(string $root,string $folder,\ZipArchive $zip){
  534. $handler=opendir($folder);
  535. while (($filename=readdir($handler))!==false){
  536. if($filename!='.' && $filename!='..'){
  537. if(is_dir($folder.$filename)){
  538. $this->addFileToZip($root,$folder.$filename.DS,$zip);
  539. }else{
  540. $writefile=substr($folder,strlen($root));
  541. $zip->addFile($folder.$filename,$writefile.$filename);
  542. }
  543. }
  544. }
  545. @closedir($handler);
  546. }
  547. private function includeInstall(Addons $addon)
  548. {
  549. $install=root_path().'addons'.DS.$addon['type'].DS.$addon['pack'].DS.'Install.php';
  550. include $install;
  551. }
  552. private function checkInstallFiles(array $files,&$error)
  553. {
  554. usort($files,function ($x,$y){
  555. return strlen($x)-strlen($y);
  556. });
  557. foreach ($files as $k1=>$file)
  558. {
  559. foreach ($files as $k2=>$check){
  560. if($k1!=$k2 && $file==$check){
  561. $error='检测到安装目录或文件【'.$file.'】重复';
  562. return false;
  563. }
  564. if($k1!=$k2 && str_starts_with($file, $check)){
  565. $error='检测到安装目录或文件【'.$file.'】包含于【'.$check.'】中';
  566. return false;
  567. }
  568. }
  569. $path=root_path().$file;
  570. if(is_file($path) || is_dir($path)){
  571. $error='检测到安装目录或文件【'.$file.'】已经存在';
  572. return false;
  573. }
  574. }
  575. return true;
  576. }
  577. private function checkCreateFiles(array $files,&$error)
  578. {
  579. usort($files,function ($x,$y){
  580. return strlen($x)-strlen($y);
  581. });
  582. foreach ($files as $k1=>$file)
  583. {
  584. foreach ($files as $k2=>$check){
  585. if($k1!=$k2 && $file==$check){
  586. $error='检测到要创建目录或文件【'.$file.'】重复';
  587. return false;
  588. }
  589. if($k1!=$k2 && str_starts_with($file, $check)){
  590. $error='检测到要创建目录或文件【'.$file.'】包含于【'.$check.'】中';
  591. return false;
  592. }
  593. }
  594. $path=root_path().$file;
  595. if(!is_file($path) && !is_dir($path)){
  596. $error='检测到要创建目录或文件【'.$file.'】不存在';
  597. return false;
  598. }
  599. }
  600. return true;
  601. }
  602. private function checkPackFiles(array $files,&$error)
  603. {
  604. usort($files,function ($x,$y){
  605. return strlen($x)-strlen($y);
  606. });
  607. foreach ($files as $k1=>$file)
  608. {
  609. foreach ($files as $k2=>$check){
  610. if($k1!=$k2 && $file==$check){
  611. $error='检测到打包目录或文件【'.$file.'】重复';
  612. return false;
  613. }
  614. if($k1!=$k2 && str_starts_with($file, $check)){
  615. $error='检测到打包目录或文件【'.$file.'】包含于【'.$check.'】中';
  616. return false;
  617. }
  618. }
  619. $path=root_path().$file;
  620. if(!is_file($path) && !is_dir($path)){
  621. $error='检测到打包目录或文件【'.$file.'】不存在';
  622. return false;
  623. }
  624. }
  625. return true;
  626. }
  627. private function copy_file(string $from,string $to,array $filters=[])
  628. {
  629. if(!is_file($from)){
  630. return;
  631. }
  632. //判断文件扩展名是否在过滤列表中
  633. $ext='*.'.strtolower(substr($from,strrpos($from,'.')+1));
  634. if(in_array($ext,$filters)){
  635. return;
  636. }
  637. //获取文件$to所在的目录
  638. $folder=substr($to,0,strrpos($to,DS));
  639. if(!is_dir($folder)){
  640. mkdir($folder, 0777, true);
  641. }
  642. copy($from,$to);
  643. }
  644. private function copy_dir(string $from, string $to,array $filters=[])
  645. {
  646. if(!is_dir($from)){
  647. return;
  648. }
  649. if(!is_dir($to)){
  650. mkdir($to,0777,true);
  651. }
  652. $handle= dir($from);
  653. while($entry = $handle->read()) {
  654. if(($entry != ".") && ($entry != "..")){
  655. if(in_array($entry,$filters)){
  656. continue;
  657. }
  658. if(is_dir($from."/".$entry)){
  659. $this->copy_dir($from."/".$entry,$to."/".$entry,$filters);
  660. }
  661. if(is_file($from."/".$entry)){
  662. //判断文件扩展名是否在过滤列表中
  663. $ext='*.'.strtolower(substr($entry,strrpos($entry,'.')+1));
  664. if(in_array($ext,$filters)){
  665. continue;
  666. }
  667. copy($from."/".$entry,$to."/".$entry);
  668. }
  669. }
  670. }
  671. }
  672. private function getContent(string $file,array $replace=[]):string
  673. {
  674. $filepath=__DIR__.DS.$file.'.txt';
  675. $myfile = fopen($filepath, "r");
  676. $content='';
  677. $if=[];
  678. $lastline='';
  679. while(!feof($myfile)) {
  680. $line_str = fgets($myfile);
  681. if($line_str){
  682. $ix=false;
  683. if($lastline==='' && trim($line_str)===''){
  684. $ix=true;
  685. }
  686. //条件判断
  687. if(strpos($line_str,'<#if')!==false){
  688. $continue=false;
  689. $if_str=substr($line_str,strpos($line_str,'<#if')+4);
  690. $if_str=substr($if_str,0,strpos($if_str,'#>'));
  691. $keys=array_keys($replace);
  692. $values=array_map(function ($res){
  693. return '$replace[\''.$res.'\']';
  694. },$keys);
  695. $if_str=str_replace(array_keys($replace),$values,$if_str);
  696. $phpstr="if(!({$if_str})){\$continue=true;}";
  697. eval($phpstr);
  698. $if[]=$continue;
  699. $ix=true;
  700. }
  701. if(strpos($line_str,'<#endif#>')!==false){
  702. array_pop($if);
  703. $ix=true;
  704. }
  705. foreach ($if as $value) {
  706. if ($value) {
  707. $ix = true;
  708. break;
  709. }
  710. }
  711. if($ix){
  712. continue;
  713. }
  714. //替换内容
  715. foreach ($replace as $key=>$value){
  716. if(is_string($value)){
  717. $line_str=str_replace('<#'.$key.'#>',$value,$line_str);
  718. }
  719. }
  720. $content.=$line_str;
  721. $lastline=trim($line_str);
  722. }
  723. }
  724. fclose($myfile);
  725. return $content;
  726. }
  727. }