From 178efb84b0691c233d19b123a9ee7d26bb7070e7 Mon Sep 17 00:00:00 2001 From: wangyuting Date: Wed, 6 Dec 2023 13:58:21 +0800 Subject: [PATCH] * Optimize extension install function. --- module/extension/control.php | 179 ++---------------------- module/extension/zen.php | 264 +++++++++++++++++++++++++++++++++++ 2 files changed, 279 insertions(+), 164 deletions(-) create mode 100644 module/extension/zen.php diff --git a/module/extension/control.php b/module/extension/control.php index e58635e656..9453137645 100644 --- a/module/extension/control.php +++ b/module/extension/control.php @@ -102,6 +102,7 @@ class extension extends control } /** + * 安装插件流程。 * Install a extension * * @param string $extension @@ -112,143 +113,27 @@ class extension extends control * @param string $ignoreCompatible * @param string $overrideFile * @param string $agreeLicense - * @param int $upgrade + * @param string $upgrade * @access public * @return void */ - public function install($extension, $downLink = '', $md5 = '', $type = '', $overridePackage = 'no', $ignoreCompatible = 'no', $overrideFile = 'no', $agreeLicense = 'no', $upgrade = 'no') + public function install(string $extension, string $downLink = '', string $md5 = '', string $type = '', string $overridePackage = 'no', string $ignoreCompatible = 'no', string $overrideFile = 'no', string $agreeLicense = 'no', string $upgrade = 'no') { $this->checkSafe(); set_time_limit(0); - $this->view->error = ''; - $installTitle = $upgrade == 'no' ? $this->lang->extension->install : $this->lang->extension->upgrade; - $installType = $upgrade == 'no' ? $this->lang->extension->installExt : $this->lang->extension->upgradeExt; + $installTitle = $upgrade == 'no' ? $this->lang->extension->install : $this->lang->extension->upgrade; + $installType = $upgrade == 'no' ? $this->lang->extension->installExt : $this->lang->extension->upgradeExt; + $this->view->title = $installTitle . $extension; $this->view->installType = $installType; $this->view->upgrade = $upgrade; - $this->view->title = $installTitle . $extension; + $this->view->error = ''; - $statusFile = $this->loadModel('common')->checkSafeFile(); - if($statusFile) - { - $this->view->error = sprintf($this->lang->extension->noticeOkFile, $statusFile, $statusFile); - return $this->display(); - } - /* Get the package file name. */ - $packageFile = $this->extension->getPackageFile($extension); - - /* Check the package file exists or not. */ - if(!file_exists($packageFile)) - { - $this->view->error = sprintf($this->lang->extension->errorPackageNotFound, $packageFile); - return $this->display(); - } - - /* Checking the extension paths. */ - $return = $this->extension->checkExtensionPaths($extension); - if($this->session->dirs2Created == false) $this->session->set('dirs2Created', $return->dirs2Created, 'admin'); // Save the dirs to be created. - if($return->result != 'ok') - { - $this->view->error = $return->errors; - return $this->display(); - } - - /* Extract the package. */ - $return = $this->extension->extractPackage($extension); - if($return->result != 'ok') - { - $this->view->error = sprintf($this->lang->extension->errorExtracted, $packageFile, $return->error); - return $this->display(); - } - /* Get condition. e.g. zentao|depends|conflicts. */ - $condition = $this->extension->getCondition($extension); - $installedExts = $this->extension->getLocalExtensions('installed'); - - /* Check version incompatible */ - $incompatible = $condition->zentao['incompatible']; - if($this->extension->checkVersion($incompatible)) - { - $this->view->error = $this->lang->extension->errorIncompatible; - return $this->display(); - } - - /* Check conflicts. */ - $conflicts = $condition->conflicts; - if($conflicts) - { - $conflictsExt = ''; - foreach($conflicts as $code => $limit) - { - if(isset($installedExts[$code])) - { - if($this->extension->compare4Limit($installedExts[$code]->version, $limit)) $conflictsExt .= $installedExts[$code]->name . " "; - } - } - - if($conflictsExt) - { - $this->view->error = sprintf($this->lang->extension->errorConflicts, $conflictsExt); - return $this->display(); - } - } - - /* Check Depends. */ - $depends = $condition->depends; - if($depends) - { - $dependsExt = ''; - foreach($depends as $code => $limit) - { - $noDepends = false; - if(isset($installedExts[$code])) - { - if($this->extension->compare4Limit($installedExts[$code]->version, $limit, 'noBetween')) $noDepends = true; - } - else - { - $noDepends = true; - } - - $extVersion = ''; - if($limit != 'all') - { - $extVersion .= '('; - if(!empty($limit['min'])) $extVersion .= '>=v' . $limit['min']; - if(!empty($limit['max'])) $extVersion .= ' <=v' . $limit['max']; - $extVersion .=')'; - } - if($noDepends) $dependsExt .= $code . $extVersion . ' ' . html::a(inlink('obtain', 'type=bycode¶m=' . helper::safe64Encode($code)), $this->lang->extension->installExt, '_blank') . '
'; - } - - if($noDepends) - { - $this->view->error = sprintf($this->lang->extension->errorDepends, $dependsExt); - return $this->display(); - } - } - - /* Check version compatible. */ - $zentaoCompatible = $condition->zentao['compatible']; - if(!$this->extension->checkVersion($zentaoCompatible) and $ignoreCompatible == 'no') - { - $ignoreLink = inlink('install', "extension=$extension&downLink=&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=yes&overrideFile=$overrideFile&agreeLicense=$agreeLicense&upgrade=$upgrade"); - $returnLink = inlink('obtain'); - $this->view->error = sprintf($this->lang->extension->errorCheckIncompatible, $installType, $ignoreLink, $installType, $returnLink); - return $this->display(); - } - - /* Check files in the package conflicts with exists files or not. */ - if($overrideFile == 'no') - { - $return = $this->extension->checkFile($extension); - if($return->result != 'ok') - { - $overrideLink = inlink('install', "extension=$extension&downLink=&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=$ignoreCompatible&overrideFile=yes&agreeLicense=$agreeLicense&upgrade=$upgrade"); - $returnLink = inlink('obtain'); - $this->view->error = sprintf($this->lang->extension->errorFileConflicted, $return->error, $overrideLink, $returnLink); - return $this->display(); - } - } + /* 插件安装前的合规校验。 */ + $ignoreLink = inlink('install', "extension=$extension&downLink=&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=yes&overrideFile=$overrideFile&agreeLicense=$agreeLicense&upgrade=$upgrade"); + $overrideLink = inlink('install', "extension=$extension&downLink=&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=$ignoreCompatible&overrideFile=yes&agreeLicense=$agreeLicense&upgrade=$upgrade"); + $this->checkExtension($extension, $ignoreCompatible, $ignoreLink, $overrideFile, $overrideLink, $installType); + if($this->view->error) return $this->display(); if($upgrade == 'yes') { @@ -258,6 +143,7 @@ class extension extends control $this->post->installedVersion = $oldInfo ? $oldInfo->version : ''; } + /* 打印授权协议同意表单。 */ /* Print the license form. */ if($agreeLicense == 'no') { @@ -270,43 +156,8 @@ class extension extends control return $this->display(); } - /* The preInstall hook file. */ - $hook = $upgrade == 'yes' ? 'preupgrade' : 'preinstall'; - if($preHookFile = $this->extension->getHookFile($extension, $hook)) include $preHookFile; - - /* Save to database. */ - $this->extension->saveExtension($extension, $type); - - /* Copy files to target directory. */ - $this->view->files = $this->extension->copyPackageFiles($extension); - - /* Judge need execute db install or not. */ - $data = new stdclass(); - $data->status = 'installed'; - $data->dirs = $this->session->dirs2Created; - $data->files = $this->view->files; - $data->installedTime = helper::now(); - $this->session->set('dirs2Created', array(), 'admin'); // clean the session. - - /* Execute the install.sql. */ - if($upgrade == 'no' and $this->extension->needExecuteDB($extension, 'install')) - { - $return = $this->extension->executeDB($extension, 'install'); - if($return->result != 'ok') - { - $this->view->error = sprintf($this->lang->extension->errorInstallDB, $return->error); - return $this->display(); - } - } - - /* Update status, dirs, files and installed time. */ - $this->extension->updateExtension($extension, $data); - $this->view->downloadedPackage = false; - - /* The postInstall hook file. */ - $hook = $upgrade == 'yes' ? 'postupgrade' : 'postinstall'; - if($postHookFile = $this->extension->getHookFile($extension, $hook)) include $postHookFile; - + /* 安装插件。 */ + $this->installExtension($extension, $type, $upgrade); $this->display(); } diff --git a/module/extension/zen.php b/module/extension/zen.php new file mode 100644 index 0000000000..006f2351cc --- /dev/null +++ b/module/extension/zen.php @@ -0,0 +1,264 @@ + + * @package extension + * @link https://www.zentao.net + */ +class extensionZen extends extension +{ + /** + * 插件安装前的合规校验。 + * Check before installation. + * + * @param string $extension + * @param string $ignoreCompatible + * @param string $ignoreLink + * @param string $overrideFile + * @param string $overrideLink + * @param string $installType + * @access protected + * @return bool + */ + protected function checkExtension(string $extension, string $ignoreCompatible, string $ignoreLink, string $overrideFile, string $overrideLink, string $installType): bool + { + /* 安全性校验。 */ + $statusFile = $this->loadModel('common')->checkSafeFile(); + if($statusFile) + { + $this->view->error = sprintf($this->lang->extension->noticeOkFile, $statusFile, $statusFile); + return false; + } + + /* Check the package file exists or not. */ + $packageFile = $this->extension->getPackageFile($extension); + if(!file_exists($packageFile)) + { + $this->view->error = sprintf($this->lang->extension->errorPackageNotFound, $packageFile); + return false; + } + + /* Checking the extension paths. */ + $return = $this->extension->checkExtensionPaths($extension); + if($this->session->dirs2Created == false) $this->session->set('dirs2Created', $return->dirs2Created, 'admin'); // Save the dirs to be created. + if($return->result != 'ok') + { + $this->view->error = $return->errors; + return false; + } + + /* Extract the package. */ + $return = $this->extension->extractPackage($extension); + if($return->result != 'ok') + { + $this->view->error = sprintf($this->lang->extension->errorExtracted, $packageFile, $return->error); + return false; + } + + /* Get condition. e.g. zentao|depends|conflicts. */ + $condition = $this->extension->getCondition($extension); + $installedExts = $this->extension->getLocalExtensions('installed'); + + if(!$this->checkCompatible($extension, $condition, $ignoreCompatible, $ignoreLink, $installType)) return false; + if(!$this->checkConflicts($condition, $installedExts)) return false; + if(!$this->checkDepends($condition, $installedExts)) return false; + if(!$this->checkFile($extension, $overrideFile, $overrideLink)) return false; + + return true; + } + + /** + * 插件兼容性检查。 + * Extension compatibility check. + * + * @param string $extension + * @param object $condition + * @param string $ignoreCompatible + * @param string $ignoreLink + * @param string $installType + * @access private + * @return bool + */ + private function checkCompatible(string $extension, object $condition, string $ignoreCompatible, string $ignoreLink, string $installType): bool + { + /* 不兼容版本检查。 */ + /* Check version incompatible */ + $incompatible = $condition->zentao['incompatible']; + if($this->extension->checkVersion($incompatible)) + { + $this->view->error = $this->lang->extension->errorIncompatible; + return false; + } + + /* 兼容版本检查。 */ + /* Check version compatible. */ + $zentaoCompatible = $condition->zentao['compatible']; + if(!$this->extension->checkVersion($zentaoCompatible) && $ignoreCompatible == 'no') + { + $this->view->error = sprintf($this->lang->extension->errorCheckIncompatible, $installType, $ignoreLink, $installType, inlink('obtain')); + return false; + } + + return true; + } + + /** + * 插件与插件之间的冲突检查。 + * Check conflicts. + * + * @param object $condition + * @param array $installedExts + * @access private + * @return bool + */ + private function checkConflicts(object $condition, array $installedExts): bool + { + $conflicts = $condition->conflicts; + if($conflicts) + { + $conflictsExt = ''; + foreach($conflicts as $code => $limit) + { + if(isset($installedExts[$code])) + { + if($this->extension->compare4Limit($installedExts[$code]->version, $limit)) $conflictsExt .= $installedExts[$code]->name . " "; + } + } + + if($conflictsExt) + { + $this->view->error = sprintf($this->lang->extension->errorConflicts, $conflictsExt); + return false; + } + } + return true; + } + + /** + * 相关依赖插件检查。 + * Check depends. + * + * @param object $condition + * @param array $installedExts + * @access private + * @return bool + */ + private function checkDepends(object $condition, array $installedExts): bool + { + $depends = $condition->depends; + if($depends) + { + $dependsExt = ''; + foreach($depends as $code => $limit) + { + $noDepends = false; + if(isset($installedExts[$code])) + { + if($this->extension->compare4Limit($installedExts[$code]->version, $limit, 'noBetween')) $noDepends = true; + } + else + { + $noDepends = true; + } + + $extVersion = ''; + if($limit != 'all') + { + $extVersion .= '('; + if(!empty($limit['min'])) $extVersion .= '>=v' . $limit['min']; + if(!empty($limit['max'])) $extVersion .= ' <=v' . $limit['max']; + $extVersion .=')'; + } + if($noDepends) $dependsExt .= $code . $extVersion . ' ' . html::a(inlink('obtain', 'type=bycode¶m=' . helper::safe64Encode($code)), $this->lang->extension->installExt, '_blank') . '
'; + } + + if($noDepends) + { + $this->view->error = sprintf($this->lang->extension->errorDepends, $dependsExt); + return false; + } + } + return true; + } + + /** + * 插件文件和禅道已有文件的冲突检查。 + * Check files in the package conflicts with exists files or not. + * + * @param string $extension + * @param string $overrideFile + * @param string $overrideLink + * @access private + * @return bool + */ + private function checkFile(string $extension, string $overrideFile, string $overrideLink): bool + { + if($overrideFile == 'no') + { + $return = $this->extension->checkFile($extension); + if($return->result != 'ok') + { + $this->view->error = sprintf($this->lang->extension->errorFileConflicted, $return->error, $overrideLink, inlink('obtain')); + return false; + } + } + + return true; + } + + /** + * 执行插件安装程序。 + * Install extension. + * + * @param string $extension + * @param string $type + * @param string $upgrade + * @access protected + * @return void + */ + protected function installExtension(string $extension, string $type, string $upgrade): bool + { + /* The preInstall hook file. */ + $hook = $upgrade == 'yes' ? 'preupgrade' : 'preinstall'; + if($preHookFile = $this->extension->getHookFile($extension, $hook)) include $preHookFile; + + /* Save to database. */ + $this->extension->saveExtension($extension, $type); + + /* Copy files to target directory. */ + $this->view->files = $this->extension->copyPackageFiles($extension); + + /* Judge need execute db install or not. */ + $data = new stdclass(); + $data->status = 'installed'; + $data->dirs = $this->session->dirs2Created; + $data->files = $this->view->files; + $data->installedTime = helper::now(); + $this->session->set('dirs2Created', array(), 'admin'); // clean the session. + + /* Execute the install.sql. */ + if($upgrade == 'no' && $this->extension->needExecuteDB($extension, 'install')) + { + $return = $this->extension->executeDB($extension, 'install'); + if($return->result != 'ok') + { + $this->view->error = sprintf($this->lang->extension->errorInstallDB, $return->error); + return false; + } + } + + /* Update status, dirs, files and installed time. */ + $this->extension->updateExtension($extension, $data); + $this->view->downloadedPackage = false; + + /* The postInstall hook file. */ + $hook = $upgrade == 'yes' ? 'postupgrade' : 'postinstall'; + if($postHookFile = $this->extension->getHookFile($extension, $hook)) include $postHookFile; + + return true; + } +}