znt/module/install/zen.php

464 lines
14 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
/**
* The zen file of install module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Yuting Wang<wangyuting@easycorp.ltd>
* @package install
* @link https://www.zentao.net
*/
class installZen extends install
{
/**
* 获取当前PHP版本。
* get php version.
*
* @access protected
* @return string
*/
protected function getPHPVersion(): string
{
return PHP_VERSION;
}
/**
* 获取tmp的目录信息。
* Get tempRoot info.
*
* @access protected
* @return array
*/
protected function getTmpRoot(): array
{
$result['path'] = $this->app->getTmpRoot();
$result['exists'] = is_dir($result['path']);
$result['writable'] = is_writable($result['path']);
return $result;
}
/**
* 获取session的存储目录信息。
* Get session save path.
*
* @access protected
* @return array
*/
protected function getSessionSavePath(): array
{
$result['path'] = preg_replace("/\d;/", '', session_save_path());
$result['exists'] = is_dir($result['path']);
$result['writable'] = is_writable($result['path']);
return $result;
}
/**
* 获取附件存储的目录信息。
* Get data root.
*
* @access protected
* @return array
*/
protected function getDataRoot(): array
{
$result['path'] = $this->app->getAppRoot() . 'www' . DS . 'data';
$result['exists'] = is_dir($result['path']);
$result['writable']= is_writable($result['path']);
return $result;
}
/**
* 检查PHP版本是否大于5.2.0。
* Check php version.
*
* @access protected
* @return string ok|fail
*/
protected function checkPHPVersion(): string
{
return version_compare(PHP_VERSION, '5.2.0') >= 0 ? 'ok' : 'fail';
}
/**
* 检查是否安装pdo扩展。
* Check PDO.
*
* @access protected
* @return string ok|fail
*/
protected function checkPDO(): string
{
return extension_loaded('pdo') ? 'ok' : 'fail';
}
/**
* 检查是否安装pdo_mysql扩展。
* Check PDO::MySQL
*
* @access protected
* @return string ok|fail
*/
protected function checkPDOMySQL(): string
{
return extension_loaded('pdo_mysql') ? 'ok' : 'fail';
}
/**
* 检查是否安装了json扩展。
* Check json extension.
*
* @access protected
* @return string ok|fail
*/
protected function checkJSON(): string
{
return extension_loaded('json') ? 'ok' : 'fail';
}
/**
* 检查是否安装了openssl扩展。
* Check openssl extension.
*
* @access protected
* @return string ok|fail
*/
protected function checkOpenssl(): string
{
return extension_loaded('openssl') ? 'ok' : 'fail';
}
/**
* 检查是否安装了mbstring扩展。
* Check mbstring extension.
*
* @access protected
* @return string ok|fail
*/
protected function checkMBstring(): string
{
return extension_loaded('mbstring') ? 'ok' : 'fail';
}
/**
* 检查是否安装了zlib扩展。
* Check zlib extension.
*
* @access protected
* @return string ok|fail
*/
protected function checkZlib(): string
{
return extension_loaded('zlib') ? 'ok' : 'fail';
}
/**
* 检查是否安装了curl扩展。
* Check curl extension.
*
* @access protected
* @return string ok|fail
*/
protected function checkCURL(): string
{
return extension_loaded('curl') ? 'ok' : 'fail';
}
/**
* 检查是否安装了filter扩展。
* Check filter extension.
*
* @access protected
* @return string ok|fail
*/
protected function checkFilter(): string
{
return extension_loaded('filter') ? 'ok' : 'fail';
}
/**
* 检查是否安装了iconv扩展。
* Check iconv extension.
*
* @access protected
* @return string ok|fail
*/
protected function checkIconv(): string
{
return extension_loaded('iconv') ? 'ok' : 'fail';
}
/**
* 检查tmp目录的完整性和可写性。
* Check tmpRoot.
*
* @access protected
* @return string ok|fail
*/
protected function checkTmpRoot(): string
{
$tmpRoot = $this->app->getTmpRoot();
return is_dir($tmpRoot) && is_writable($tmpRoot) ? 'ok' : 'fail';
}
/**
* 检查session存储目录的完整性和可写性质。
* Check session save path.
*
* @access protected
* @return string ok|fail
*/
protected function checkSessionSavePath(): string
{
$sessionSavePath = preg_replace("/\d;/", '', session_save_path());
if(!is_dir($sessionSavePath) || !is_writable($sessionSavePath)) return 'fail';
/* Test session path again. */
file_put_contents($sessionSavePath . '/zentaotest', 'zentao');
$sessionContent = file_get_contents($sessionSavePath . '/zentaotest');
if($sessionContent == 'zentao')
{
unlink($sessionSavePath . '/zentaotest');
return 'ok';
}
return 'fail';
}
/**
* 检查附件存储目录的完整性和可写性质。
* Check the data root.
*
* @access protected
* @return string ok|fail
*/
protected function checkDataRoot(): string
{
$dataRoot = $this->app->getAppRoot() . 'www' . DS . 'data';
return is_dir($dataRoot) && is_writable($dataRoot) ? 'ok' : 'fail';
}
/**
* 检查数据库配置信息的正确性。
* Check config ok or not.
*
* @param object $data
* @access protected
* @return object
*/
protected function checkConfig(object $data): object
{
$return = new stdclass();
$return->result = 'ok';
/* Connect to database. */
$this->setDBParam($data);
$this->install->dbh = $this->install->connectDB();
if(strpos($data->dbName, '.') !== false)
{
/* 如果数据库名字带有.字符的话,则提示错误信息。 */
$return->result = 'fail';
$return->error = $this->lang->install->errorDBName;
return $return;
}
if(!is_object($this->install->dbh))
{
/* 没有成功连接数据库的话,则提示错误信息。 */
$return->result = 'fail';
$return->error = $this->lang->install->errorConnectDB . $this->install->dbh;
return $return;
}
/* 检查数据库用户是否缺少权限。 */
$missingPrivs = $this->install->dbh->checkUserPriv();
if($missingPrivs)
{
$missingPrivs = $this->lang->install->errorDBUserPriv . '<code>' . $missingPrivs . '</code>';
return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.alert({icon: 'icon-exclamation-sign', size: '600', iconClass: 'text-4xl text-warning', message: {html:'" . str_replace("'", '"', $missingPrivs) . "'}})"));
}
/* Get database version. */
$version = $this->install->getDatabaseVersion();
/* If database no exits, try create it. */
if(!$this->install->dbh->dbExists())
{
if(!$this->install->dbh->createDB($version))
{
/* 如果创建数据库失败的话,则提示错误信息。 */
$return->result = 'fail';
$return->error = $this->lang->install->errorCreateDB;
return $return;
}
}
elseif($this->install->dbh->tableExist(TABLE_ACL) && empty($data->clearDB))
{
/* 如果已经存在config表并且用户没有勾选清空旧数据库选项的话则提示错误信息。 */
$return->result = 'fail';
$return->error = $this->lang->install->errorTableExists;
return $return;
}
return $return;
}
/**
* DevOps平台版将配置信息写入my.php。
* Save config file when inQuickon is true.
*
* @access protected
* @return bool
*/
protected function saveConfigFile(): bool
{
$configRoot = $this->app->getConfigRoot();
$myConfigFile = $configRoot . 'my.php';
if(file_exists($myConfigFile) && trim(file_get_contents($myConfigFile))) return false;
/* Set the session save path when the session save path is null. */
$customSession = $this->setSessionPath();
$configContent = <<<EOT
<?php
\$config->installed = getEnvData('ZT_INSTALLED', true, 'bool');
\$config->debug = getEnvData('ZT_DEBUG', 0, 'int');
\$config->requestType = getEnvData('ZT_REQUEST_TYPE');
\$config->timezone = getEnvData('ZT_TIMEZONE', 'Asia/Shanghai');
\$config->db->driver = getEnvData('ZT_DB_DRIVER', 'mysql');
\$config->db->host = getEnvData('ZT_DB_HOST');
\$config->db->port = getEnvData('ZT_DB_PORT');
\$config->db->name = getEnvData('ZT_DB_NAME');
\$config->db->user = getEnvData('ZT_DB_USER');
\$config->db->encoding = getEnvData('ZT_DB_ENCODING', 'UTF8');
\$config->db->password = getEnvData('ZT_DB_PASSWORD');
\$config->db->prefix = getEnvData('ZT_DB_PREFIX');
\$config->webRoot = getWebRoot();
\$config->default->lang = getEnvData('ZT_DEFAULT_LANG', 'zh-cn');
\$hasSlaveDB = (string)getEnvData('ENABLE_DB_SLAVE');
if(\$hasSlaveDB && \$hasSlaveDB != 'false')
{
\$slaveDB = new stdclass();
\$slaveDB->host = getEnvData('ZT_SLAVE_DB_HOST');
\$slaveDB->port = getEnvData('ZT_SLAVE_DB_PORT');
\$slaveDB->name = getEnvData('ZT_SLAVE_DB_NAME');
\$slaveDB->user = getEnvData('ZT_SLAVE_DB_USER');
\$slaveDB->password = getEnvData('ZT_SLAVE_DB_PASSWORD');
\$slaveDB->driver = getEnvData('ZT_DB_DRIVER');
\$slaveDB->encoding = getEnvData('ZT_DB_ENCODING');
\$slaveDB->prefix = getEnvData('ZT_DB_PREFIX');
\$config->slaveDBList = array(\$slaveDB);
}
EOT;
if($customSession) $configContent .= "\n\$config->customSession = true;";
if(is_writable($configRoot)) @file_put_contents($myConfigFile, $configContent);
$this->config->installed = true;
return true;
}
/**
* 写入数据库配置信息。
* Set database params.
*
* @param object $data
* @access private
* @return bool
*/
private function setDBParam(object $data): bool
{
$this->config->db->driver = $data->dbDriver;
if($this->config->inQuickon)
{
$this->config->db->host = getenv('ZT_MYSQL_HOST');
$this->config->db->user = getenv('ZT_MYSQL_USER');
$this->config->db->encoding = 'UTF8';
$this->config->db->password = getenv('ZT_MYSQL_PASSWORD');
$this->config->db->port = getenv('ZT_MYSQL_PORT');
}
else
{
$this->config->db->host = $data->dbHost;
$this->config->db->user = $data->dbUser;
$this->config->db->encoding = $data->dbEncoding;
$this->config->db->password = $data->dbPassword;
$this->config->db->port = $data->dbPort;
}
$this->config->db->name = $data->dbName;
$this->config->db->prefix = $data->dbPrefix;
file_put_contents($this->install->buildDBLogFile('config'), json_encode(array('db' => $this->config->db, 'post' => $data)));
return true;
}
/**
* DevOps平台版设置session path。
* Set session save path.
*
* @access private
* @return bool
*/
private function setSessionPath(): bool
{
$customSession = false;
$checkSession = ini_get('session.save_handler') == 'files';
if($checkSession)
{
if(!session_save_path())
{
/* Restart the session because the session save path is null when start the session last time. */
session_write_close();
$tmpRootInfo = $this->getTmpRoot();
$sessionSavePath = $tmpRootInfo['path'] . 'session';
if(!is_dir($sessionSavePath)) mkdir($sessionSavePath, 0777, true);
session_save_path($sessionSavePath);
$customSession = true;
$sessionResult = $this->checkSessionSavePath();
if($sessionResult == 'fail') chmod($sessionSavePath, 0777);
session_start();
$this->session->set('installing', true);
}
}
$_SESSION['installing'] = true;
return $customSession;
}
/**
* 处理安装应用下拉选择的数据。
* Process application options.
*
* @param object $components
* @param object $cloudSolution
* @access protected
* @return object
*/
protected function processComponents(object $components, object $cloudSolution): object
{
foreach($components->category as $key => &$item)
{
if($item->name === 'pms')
{
unset($components->category[$key]);
continue;
}
if(in_array($item->name, array('analysis', 'artifact'))) array_unshift($item->choices, (object)array('name' => $this->lang->install->solution->skipInstall, 'version' => ''));
$item->schemaChoices = array();
foreach($item->choices as $cloudApp)
{
$appInfo = zget($cloudSolution->apps, $cloudApp->name, array());
$item->schemaChoices[$cloudApp->name] = zget($appInfo, 'alias', $cloudApp->name);
}
}
return $components;
}
}