feat: 删除安装文件
|
@ -1,158 +0,0 @@
|
|||
<?php
|
||||
|
||||
class YxEnv
|
||||
{
|
||||
/**
|
||||
* 环境变量数据
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
protected $filePath = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//$this->data = $_ENV;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取环境变量定义文件
|
||||
* @access public
|
||||
* @param string $file 环境变量定义文件
|
||||
* @return void
|
||||
*/
|
||||
public function load($file)
|
||||
{
|
||||
$this->filePath = $file;
|
||||
$env = parse_ini_file($file, true);
|
||||
$this->set($env);
|
||||
}
|
||||
|
||||
public function makeEnv($file){
|
||||
if(!file_exists($file)){
|
||||
try{
|
||||
touch($file);
|
||||
}catch (Exception $e){
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取环境变量值
|
||||
* @access public
|
||||
* @param string $name 环境变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name = null, $default = null, $php_prefix = true)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
if (isset($this->data[$name])) {
|
||||
return $this->data[$name];
|
||||
}
|
||||
|
||||
return $this->getEnv($name, $default, $php_prefix);
|
||||
}
|
||||
|
||||
protected function getEnv($name, $default = null, $php_prefix = true)
|
||||
{
|
||||
if ($php_prefix) {
|
||||
$name = 'PHP_' . $name;
|
||||
}
|
||||
|
||||
$result = getenv($name);
|
||||
|
||||
if (false === $result) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ('false' === $result) {
|
||||
$result = false;
|
||||
} elseif ('true' === $result) {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
if ( !isset($this->data[$name])) {
|
||||
$this->data[$name] = $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 写入Env文件
|
||||
* @author luzg(2020/8/27 18:12)
|
||||
* @param $envFilePath
|
||||
* @param array $databaseEnv
|
||||
*/
|
||||
public function putEnv($envFilePath, array $databaseEnv)
|
||||
{
|
||||
$applyDbEnv = [
|
||||
'database.hostname' => $databaseEnv['host'],
|
||||
'database.database' => $databaseEnv['name'],
|
||||
'database.username' => $databaseEnv['user'],
|
||||
'database.password' => $databaseEnv['password'],
|
||||
'database.hostport' => $databaseEnv['port'],
|
||||
'database.prefix' => $databaseEnv['prefix'],
|
||||
'project.file_domain' => $_SERVER['HTTP_HOST'],
|
||||
];
|
||||
|
||||
$envLine = array_merge($this->data, $applyDbEnv);
|
||||
ksort($envLine);
|
||||
|
||||
$content = '';
|
||||
$lastPrefix = '';
|
||||
|
||||
foreach ($envLine as $index => $value) {
|
||||
list($prefix, $key) = explode('.', $index);
|
||||
|
||||
if ($prefix != $lastPrefix && $key != null) {
|
||||
if ($lastPrefix != '')
|
||||
$content .= "\n";
|
||||
|
||||
$content .= "[$prefix]\n";
|
||||
$lastPrefix = $prefix;
|
||||
}
|
||||
|
||||
if ($prefix != $lastPrefix && $key == null) {
|
||||
$content .= "$index = \"$value\"\n";
|
||||
} else {
|
||||
$content .= "$key = \"$value\"\n";
|
||||
}
|
||||
}
|
||||
if ( !empty($content)) {
|
||||
file_put_contents($envFilePath, $content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置环境变量值
|
||||
* @access public
|
||||
* @param string|array $env 环境变量
|
||||
* @param mixed $value 值
|
||||
* @return void
|
||||
*/
|
||||
public function set($env, $value = null)
|
||||
{
|
||||
if (is_array($env)) {
|
||||
|
||||
foreach ($env as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $k => $v) {
|
||||
$this->data[$key . '.' . $k] = $v;
|
||||
}
|
||||
} else {
|
||||
$this->data[$key] = $val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$name = strtoupper(str_replace('.', '_', $env));
|
||||
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,401 +0,0 @@
|
|||
body {
|
||||
position: relative;
|
||||
background-color: #F6F6F6;
|
||||
}
|
||||
|
||||
.mounted {
|
||||
background-color: #F6F6F6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
margin-bottom: 17px;
|
||||
margin-top: 70px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #F6F6F6;
|
||||
padding: 14px 39px;
|
||||
}
|
||||
|
||||
.mounted-box {
|
||||
display: flex;
|
||||
width: 940px;
|
||||
min-height: 611px;
|
||||
background-color: white;
|
||||
padding: 15px 30px 24px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-shadow:3px 2px 20px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.mounted-title {
|
||||
font-size: 18px;
|
||||
color: #222222;
|
||||
font-weight: Bold;
|
||||
}
|
||||
|
||||
.mounted-container {
|
||||
width: 940px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mounted-nav {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.mounted-nav .active {
|
||||
color: white;
|
||||
background-color: #2C85EA;
|
||||
border: 1px solid #2C85EA !important;
|
||||
}
|
||||
|
||||
.mounted-nav li:nth-of-type(even) {
|
||||
width: 140px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
font-family: PingFang SC;
|
||||
border-top: 1px solid #E5E5E5;
|
||||
border-bottom: 1px solid #E5E5E5;
|
||||
}
|
||||
|
||||
.mounted-nav li:nth-of-type(odd) {
|
||||
width: 140px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
font-family: PingFang SC;
|
||||
border: 1px solid #E5E5E5;
|
||||
}
|
||||
|
||||
.mounted-nav li:last-child {
|
||||
border-right: 1px solid #E5E5E5;
|
||||
}
|
||||
|
||||
.mounted-content-item {
|
||||
margin-top: 15px;
|
||||
/* border:1px solid #E5E5E5; */
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content-header {
|
||||
background-color: #E5E5E5;
|
||||
padding: 8px 16px;
|
||||
font-family: PingFang SC;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
height: 392px;
|
||||
border: 1px solid #E5E5E5;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.content h2 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.content p {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.content h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.mt6 {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.mt16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.content-form {
|
||||
padding: 23px 60px;
|
||||
border: 1px solid #E5E5E5;
|
||||
}
|
||||
|
||||
.form-box-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
}
|
||||
.form-box-item:not(:nth-of-type(1)) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
|
||||
.form-desc {
|
||||
width: 60px;
|
||||
font-size: 12px;
|
||||
margin-right: 16px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.form-box-item div input {
|
||||
width:328px;
|
||||
height: 32px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
padding: 7px 28px;
|
||||
background-color: white;
|
||||
border: 1px solid #D7D7D7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.accept-btn {
|
||||
padding: 7px 28px;
|
||||
color: white;
|
||||
background-color: #2C85EA;
|
||||
border: none;
|
||||
flex: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.disabled-btn {
|
||||
padding: 7px 28px;
|
||||
color: #222222;
|
||||
background-color: #D7D7D7;
|
||||
border: none;
|
||||
flex: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border:1px solid #D7D7D7;
|
||||
}
|
||||
|
||||
.item-btn-group {
|
||||
display: none;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.form-box-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
footer {
|
||||
font-size: 12px;
|
||||
margin-bottom: 20px;
|
||||
color:#707070;
|
||||
font-weight: 400;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: #F6F6F6;
|
||||
}
|
||||
|
||||
.layui-table {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layui-table tr {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.layui-table tr td{
|
||||
font-size: 12px;
|
||||
font-family:PingFang SC;
|
||||
line-height:20px;
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.layui-table tr th {
|
||||
font-size: 14px;
|
||||
font-family:PingFang SC;
|
||||
font-weight:bold;
|
||||
line-height:20px;
|
||||
}
|
||||
|
||||
.mounted-env-container {
|
||||
height: 440px;
|
||||
padding-bottom: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mounted-tips {
|
||||
padding: 15px 24px;
|
||||
color: #2C85EA;
|
||||
background-color: #eef4ff;
|
||||
}
|
||||
|
||||
.mounting-container {
|
||||
padding: 16px;
|
||||
height: 479px;
|
||||
max-height: 479px;
|
||||
border: 1px solid #E5E5E5;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.item-cell {
|
||||
padding: 4px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.green{
|
||||
color: #11d55c;
|
||||
}
|
||||
|
||||
.wrong {
|
||||
color: #FC4D4D;
|
||||
}
|
||||
|
||||
.layui-icon {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
|
||||
.success-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 392px;
|
||||
border: 1px solid #E5E5E5;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.success-content .tips {
|
||||
width: 400px;
|
||||
height: 80px;
|
||||
padding: 9px 18px;
|
||||
background-color: #F8F8F8;
|
||||
font-size: 12px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.success-content .btn-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.success-content .result {
|
||||
font-size:20px;
|
||||
font-family:PingFang SC;
|
||||
font-weight:bold;
|
||||
line-height:28px;
|
||||
}
|
||||
|
||||
.success-content .btn-group .store-btn {
|
||||
padding: 7px 35px;
|
||||
border: 1px solid #2C85EA;
|
||||
background-color: white;
|
||||
color: #2C85EA;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.success-content .btn-group .btn {
|
||||
padding: 7px 35px;
|
||||
border: 1px solid #2C85EA;
|
||||
background-color: #2C85EA;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mounted-footer {
|
||||
width: 940px;
|
||||
background-color: white;
|
||||
padding: 16px 30px 23px;
|
||||
margin-top: 16px;
|
||||
box-shadow:3px 2px 20px rgba(0,0,0,0.08);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mounted-footer-title {
|
||||
font-size: 18px;
|
||||
line-height: 25px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mounted-recommend-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mounted-recommend-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 224px;
|
||||
height: 140px;
|
||||
border:1px solid #D7D7D7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mounted-recommend-item .icon {
|
||||
width: 128px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.mounted-recommend-item:hover {
|
||||
background-color: #F6F9FF;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
width: 224px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.mounted-recommend-item:hover .icon{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.recommend-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mounted-recommend-item:hover .recommend-content {
|
||||
display: block;
|
||||
padding: 6px 10px 10px;
|
||||
}
|
||||
|
||||
.mounted-recommend-item:hover .recommend-content .title {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mounted-recommend-item:hover .recommend-content ul {
|
||||
list-style-type: disc;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.mounted-recommend-item:hover .recommend-content li {
|
||||
list-style-type: disc;
|
||||
}
|
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 489 B |
Before Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 632 B |
Before Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 386 B |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 6.2 KiB |
|
@ -1,92 +0,0 @@
|
|||
<?php
|
||||
// error_reporting(0);
|
||||
include "model.php";
|
||||
include "YxEnv.php";
|
||||
|
||||
define('install', true);
|
||||
define('INSTALL_ROOT', __DIR__);
|
||||
define('TESTING_TABLE', 'config');
|
||||
|
||||
$step = $_GET['step'] ?? 1;
|
||||
|
||||
$installDir = "install";
|
||||
$modelInstall = new installModel();
|
||||
|
||||
// Env设置
|
||||
$yxEnv = new YxEnv();
|
||||
|
||||
// 检查是否有安装过
|
||||
$envFilePath = $modelInstall->getAppRoot() . '/.env';
|
||||
if ($modelInstall->appIsInstalled() && in_array($step, [1, 2, 3, 4])) {
|
||||
die('可能已经安装过本系统了,请删除配置目录下面的install.lock文件再尝试');
|
||||
}
|
||||
|
||||
// 加载Example文件
|
||||
$yxEnv->load($modelInstall->getAppRoot() . '/.example.env');
|
||||
|
||||
//尝试生成.env
|
||||
$yxEnv->makeEnv($modelInstall->getAppRoot() . '/.env');
|
||||
|
||||
$post = [
|
||||
'host' => $_POST['host'] ?? '127.0.0.1',
|
||||
'port' => $_POST['port'] ?? '3306',
|
||||
'user' => $_POST['user'] ?? 'root',
|
||||
'password' => $_POST['password'] ?? '',
|
||||
'name' => $_POST['name'] ?? 'likeshopb2b2c',
|
||||
'admin_user' => $_POST['admin_user'] ?? '',
|
||||
'admin_password' => $_POST['admin_password'] ?? '',
|
||||
'admin_confirm_password' => $_POST['admin_confirm_password'] ?? '',
|
||||
'prefix' => $_POST['prefix'] ?? 'ls_',
|
||||
'import_test_data' => $_POST['import_test_data'] ?? 'off',
|
||||
'clear_db' => $_POST['clear_db'] ?? 'off',
|
||||
];
|
||||
|
||||
$message = '';
|
||||
|
||||
// 检查数据库正确性
|
||||
if ($step == 4) {
|
||||
$canNext = true;
|
||||
if (empty($post['prefix'])) {
|
||||
$canNext = false;
|
||||
$message = '数据表前缀不能为空';
|
||||
} elseif ($post['admin_user'] == '') {
|
||||
$canNext = false;
|
||||
$message = '请填写管理员用户名';
|
||||
} elseif (empty(trim($post['admin_password']))) {
|
||||
$canNext = false;
|
||||
$message = '管理员密码不能为空';
|
||||
} elseif ($post['admin_password'] != $post['admin_confirm_password']) {
|
||||
$canNext = false;
|
||||
$message = '两次密码不一致';
|
||||
} else {
|
||||
// 检查 数据库信息
|
||||
$result = $modelInstall->checkConfig($post['name'], $post);
|
||||
if ($result->result == 'fail') {
|
||||
$canNext = false;
|
||||
$message = $result->error;
|
||||
}
|
||||
|
||||
// 导入测试数据
|
||||
if ($canNext == true && $post['import_test_data'] == 'on') {
|
||||
if (!$modelInstall->importDemoData()) {
|
||||
$canNext = false;
|
||||
$message = '导入测试数据错误';
|
||||
}
|
||||
}
|
||||
|
||||
// 写配置文件
|
||||
if ($canNext) {
|
||||
$yxEnv->putEnv($envFilePath, $post);
|
||||
$modelInstall->mkLockFile();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$canNext)
|
||||
$step = 3;
|
||||
}
|
||||
|
||||
// 取得安装成功的表
|
||||
$successTables = $modelInstall->getSuccessTable();
|
||||
|
||||
$nextStep = $step + 1;
|
||||
include __DIR__ . "/template/main.php";
|
|
@ -1,94 +0,0 @@
|
|||
var canClick = true;
|
||||
var installIndex = 0;
|
||||
|
||||
String.prototype.format = function(args)
|
||||
{
|
||||
if (arguments.length > 0)
|
||||
{
|
||||
var result = this;
|
||||
if (arguments.length === 1 && typeof (args) == "object")
|
||||
{
|
||||
for (var key in args)
|
||||
{
|
||||
var reg = new RegExp("({" + key + "})", "g");
|
||||
result = result.replace(reg, args[key]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
{
|
||||
if (arguments[i] === undefined)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
var reg = new RegExp("({[" + i + "]})", "g");
|
||||
result = result.replace(reg, arguments[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 将内容推送到内容里面
|
||||
*/
|
||||
function pushSuccessTableToBox(successLine) {
|
||||
var installBox = document.getElementById('install_message');
|
||||
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.className = 'item-cell';
|
||||
var lineHtml = `
|
||||
<div style="display: flex;align-items: center;">
|
||||
<div class="layui-icon green"></div>
|
||||
<div style="margin-left: 10px;">创建数据表{0}完成!</div>
|
||||
</div>
|
||||
<div>{1}</div>
|
||||
`;
|
||||
div.innerHTML = lineHtml.format(successLine[0], successLine[1]);
|
||||
|
||||
installBox.append(div);
|
||||
|
||||
}
|
||||
|
||||
function showParts(index) {
|
||||
function getRndInteger(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) ) + min;
|
||||
}
|
||||
|
||||
if (index <= successTables.length) {
|
||||
setTimeout(function () { pushSuccessTableToBox(successTables[index]); showParts(++index); }, getRndInteger(50, 150));
|
||||
}
|
||||
|
||||
if (index === successTables.length) {
|
||||
goStep(5);
|
||||
}
|
||||
}
|
||||
|
||||
function goStep(step) {
|
||||
//var form = document.getElementsByTagName('form')[0];
|
||||
if (canClick === false)
|
||||
return;
|
||||
|
||||
canClick = false;
|
||||
document.main_form.action = "?step=" + step;
|
||||
document.main_form.submit();
|
||||
// form.action = "?step=" + step;
|
||||
// window.location.href = "?step=" + step;
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
window.history.go(-1);
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
showParts(0);
|
||||
}, 100);
|
|
@ -1,760 +0,0 @@
|
|||
<?php
|
||||
/** 安装界面需要的各种模块 */
|
||||
|
||||
class installModel
|
||||
{
|
||||
private $host;
|
||||
private $name;
|
||||
private $user;
|
||||
private $encoding;
|
||||
private $password;
|
||||
private $port;
|
||||
private $prefix;
|
||||
private $successTable = [];
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $allowNext = true;
|
||||
/**
|
||||
* @var PDO|string
|
||||
*/
|
||||
private $dbh = null;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $clearDB = false;
|
||||
|
||||
|
||||
/**
|
||||
* Notes: php版本
|
||||
* @author luzg(2020/8/25 9:56)
|
||||
* @return string
|
||||
*/
|
||||
public function getPhpVersion()
|
||||
{
|
||||
return PHP_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 当前版本是否符合
|
||||
* @author luzg(2020/8/25 9:57)
|
||||
* @return string
|
||||
*/
|
||||
public function checkPHP()
|
||||
{
|
||||
return $result = version_compare(PHP_VERSION, '7.2.0') >= 0 ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否有PDO
|
||||
* @author luzg(2020/8/25 9:57)
|
||||
* @return string
|
||||
*/
|
||||
public function checkPDO()
|
||||
{
|
||||
return $result = extension_loaded('pdo') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否有PDO::MySQL
|
||||
* @author luzg(2020/8/25 9:58)
|
||||
* @return string
|
||||
*/
|
||||
public function checkPDOMySQL()
|
||||
{
|
||||
return $result = extension_loaded('pdo_mysql') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否支持JSON
|
||||
* @author luzg(2020/8/25 9:58)
|
||||
* @return string
|
||||
*/
|
||||
public function checkJSON()
|
||||
{
|
||||
return $result = extension_loaded('json') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否支持openssl
|
||||
* @author luzg(2020/8/25 9:58)
|
||||
* @return string
|
||||
*/
|
||||
public function checkOpenssl()
|
||||
{
|
||||
return $result = extension_loaded('openssl') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否支持mbstring
|
||||
* @author luzg(2020/8/25 9:58)
|
||||
* @return string
|
||||
*/
|
||||
public function checkMbstring()
|
||||
{
|
||||
return $result = extension_loaded('mbstring') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否支持zlib
|
||||
* @author luzg(2020/8/25 9:59)
|
||||
* @return string
|
||||
*/
|
||||
public function checkZlib()
|
||||
{
|
||||
return $result = extension_loaded('zlib') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否支持curl
|
||||
* @author luzg(2020/8/25 9:59)
|
||||
* @return string
|
||||
*/
|
||||
public function checkCurl()
|
||||
{
|
||||
return $result = extension_loaded('curl') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查GD2扩展
|
||||
* @author luzg(2020/8/26 9:59)
|
||||
* @return string
|
||||
*/
|
||||
public function checkGd2()
|
||||
{
|
||||
return $result = extension_loaded('gd') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查Dom扩展
|
||||
* @author luzg(2020/8/26 9:59)
|
||||
* @return string
|
||||
*/
|
||||
public function checkDom()
|
||||
{
|
||||
return $result = extension_loaded('dom') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否支持filter
|
||||
* @author luzg(2020/8/25 9:59)
|
||||
* @return string
|
||||
*/
|
||||
public function checkFilter()
|
||||
{
|
||||
return $result = extension_loaded('filter') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否支持iconv
|
||||
* @author luzg(2020/8/25 9:59)
|
||||
* @return string
|
||||
*/
|
||||
public function checkIconv()
|
||||
{
|
||||
return $result = extension_loaded('iconv') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 检查fileinfo扩展
|
||||
* @author 段誉(2021/6/28 11:03)
|
||||
* @return string
|
||||
*/
|
||||
public function checkFileInfo()
|
||||
{
|
||||
return $result = extension_loaded('fileinfo') ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 取得临时目录路径
|
||||
* @author luzg(2020/8/25 10:05)
|
||||
* @return array
|
||||
*/
|
||||
public function getTmpRoot()
|
||||
{
|
||||
$path = $this->getAppRoot() . '/runtime';
|
||||
return [
|
||||
'path' => $path,
|
||||
'exists' => is_dir($path),
|
||||
'writable' => is_writable($path),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查临时路径
|
||||
* @author luzg(2020/8/25 10:06)
|
||||
* @return string
|
||||
*/
|
||||
public function checkTmpRoot()
|
||||
{
|
||||
$tmpRoot = $this->getTmpRoot()['path'];
|
||||
return $result = (is_dir($tmpRoot) and is_writable($tmpRoot)) ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: SESSION路径是否可写
|
||||
* @author luzg(2020/8/25 10:06)
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSessionSavePath()
|
||||
{
|
||||
$sessionSavePath = preg_replace("/\d;/", '', session_save_path());
|
||||
|
||||
return [
|
||||
'path' => $sessionSavePath,
|
||||
'exists' => is_dir($sessionSavePath),
|
||||
'writable' => is_writable($sessionSavePath),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查session路径可写状态
|
||||
* @author luzg(2020/8/25 10:13)
|
||||
* @return string
|
||||
*/
|
||||
public function checkSessionSavePath()
|
||||
{
|
||||
$sessionSavePath = preg_replace("/\d;/", '', session_save_path());
|
||||
$result = (is_dir($sessionSavePath) and is_writable($sessionSavePath)) ? 'ok' : 'fail';
|
||||
if ($result == 'fail') return $result;
|
||||
|
||||
file_put_contents($sessionSavePath . '/zentaotest', 'zentao');
|
||||
$sessionContent = file_get_contents($sessionSavePath . '/zentaotest');
|
||||
if ($sessionContent == 'zentao') {
|
||||
unlink($sessionSavePath . '/zentaotest');
|
||||
return 'ok';
|
||||
}
|
||||
return 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 取得data目录是否可选
|
||||
* @author luzg(2020/8/25 10:58)
|
||||
* @return array
|
||||
*/
|
||||
public function getDataRoot()
|
||||
{
|
||||
$path = $this->getAppRoot();
|
||||
return [
|
||||
'path' => $path . 'www' . DS . 'data',
|
||||
'exists' => is_dir($path),
|
||||
'writable' => is_writable($path),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 取得root路径
|
||||
* @author luzg(2020/8/25 11:02)
|
||||
* @return string
|
||||
*/
|
||||
public function checkDataRoot()
|
||||
{
|
||||
$dataRoot = $this->getAppRoot() . 'www' . DS . 'data';
|
||||
return $result = (is_dir($dataRoot) and is_writable($dataRoot)) ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 取得php.ini信息
|
||||
* @author luzg(2020/8/25 11:03)
|
||||
* @return string
|
||||
*/
|
||||
public function getIniInfo()
|
||||
{
|
||||
$iniInfo = '';
|
||||
ob_start();
|
||||
phpinfo(1);
|
||||
$lines = explode("\n", strip_tags(ob_get_contents()));
|
||||
ob_end_clean();
|
||||
foreach ($lines as $line) if (strpos($line, 'ini') !== false) $iniInfo .= $line . "\n";
|
||||
return $iniInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 创建安装锁定文件
|
||||
* @author luzg(2020/8/28 11:32)
|
||||
* @return bool
|
||||
*/
|
||||
public function mkLockFile()
|
||||
{
|
||||
return touch($this->getAppRoot() . '/config/install.lock');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查之前是否有安装
|
||||
* @author luzg(2020/8/28 11:36)
|
||||
*/
|
||||
public function appIsInstalled()
|
||||
{
|
||||
return file_exists($this->getAppRoot() . '/config/install.lock');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 取得配置信息
|
||||
* @author luzg(2020/8/25 11:05)
|
||||
* @param string $dbName 数据库名称
|
||||
* @param array $connectionInfo 连接信息
|
||||
* @return stdclass
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkConfig($dbName, $connectionInfo)
|
||||
{
|
||||
$return = new stdclass();
|
||||
$return->result = 'ok';
|
||||
|
||||
/* Connect to database. */
|
||||
$this->setDBParam($connectionInfo);
|
||||
$this->dbh = $this->connectDB();
|
||||
if (strpos($dbName, '.') !== false) {
|
||||
$return->result = 'fail';
|
||||
$return->error = '没有发现数据库信息';
|
||||
return $return;
|
||||
}
|
||||
if ( !is_object($this->dbh)) {
|
||||
$return->result = 'fail';
|
||||
$return->error = '安装错误,请检查连接信息:'.mb_strcut($this->dbh,0,30).'...';
|
||||
echo $this->dbh;
|
||||
return $return;
|
||||
}
|
||||
|
||||
/* Get mysql version. */
|
||||
$version = $this->getMysqlVersion();
|
||||
|
||||
/* check mysql sql_model */
|
||||
if(!$this->checkSqlMode($version)) {
|
||||
$return->result = 'fail';
|
||||
$return->error = '请在mysql配置文件修改sql-mode添加NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
|
||||
return $return;
|
||||
}
|
||||
|
||||
/* If database no exits, try create it. */
|
||||
if ( !$this->dbExists()) {
|
||||
if ( !$this->createDB($version)) {
|
||||
$return->result = 'fail';
|
||||
$return->error = '创建数据库错误';
|
||||
return $return;
|
||||
}
|
||||
} elseif ($this->tableExits() and $this->clearDB == false) {
|
||||
$return->result = 'fail';
|
||||
$return->error = '数据表已经存在,您之前应该有安装过本系统,继续安装请选择清空现有数据';
|
||||
return $return;
|
||||
} elseif ($this->dbExists() and $this->clearDB == true) {
|
||||
if (!$this->dropDb($connectionInfo['name'])) {
|
||||
$return->result = 'fail';
|
||||
$return->error = '数据表已经存在,删除已存在库错误,请手动清除';
|
||||
return $return;
|
||||
} else {
|
||||
if ( !$this->createDB($version)) {
|
||||
$return->result = 'fail';
|
||||
$return->error = '创建数据库错误!';
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create tables. */
|
||||
if ( !$this->createTable($version, $connectionInfo)) {
|
||||
$return->result = 'fail';
|
||||
$return->error = '创建表格失败';
|
||||
return $return;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 设置数据库相关信息
|
||||
* @author luzg(2020/8/25 11:17)
|
||||
* @param $post
|
||||
*/
|
||||
public function setDBParam($post)
|
||||
{
|
||||
$this->host = $post['host'];
|
||||
$this->name = $post['name'];
|
||||
$this->user = $post['user'];
|
||||
$this->encoding = 'utf8mb4';
|
||||
$this->password = $post['password'];
|
||||
$this->port = $post['port'];
|
||||
$this->prefix = $post['prefix'];
|
||||
$this->clearDB = $post['clear_db'] == 'on';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 连接数据库
|
||||
* @author luzg(2020/8/25 11:56)
|
||||
* @return PDO|string
|
||||
*/
|
||||
public function connectDB()
|
||||
{
|
||||
$dsn = "mysql:host={$this->host}; port={$this->port}";
|
||||
try {
|
||||
$dbh = new PDO($dsn, $this->user, $this->password);
|
||||
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
||||
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$dbh->exec("SET NAMES {$this->encoding}");
|
||||
$dbh->exec("SET NAMES {$this->encoding}");
|
||||
try{
|
||||
$dbh->exec("SET GLOBAL sql_mode='STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';");
|
||||
}catch (Exception $e){
|
||||
|
||||
}
|
||||
return $dbh;
|
||||
} catch (PDOException $exception) {
|
||||
return $exception->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查数据库是否存在
|
||||
* @author luzg(2020/8/25 11:56)
|
||||
* @return mixed
|
||||
*/
|
||||
public function dbExists()
|
||||
{
|
||||
$sql = "SHOW DATABASES like '{$this->name}'";
|
||||
return $this->dbh->query($sql)->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查表是否存在
|
||||
* @author luzg(2020/8/25 11:56)
|
||||
* @return mixed
|
||||
*/
|
||||
public function tableExits()
|
||||
{
|
||||
$configTable = sprintf("'%s'", $this->prefix . TESTING_TABLE);
|
||||
$sql = "SHOW TABLES FROM {$this->name} like $configTable";
|
||||
return $this->dbh->query($sql)->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取mysql版本号
|
||||
* @author luzg(2020/8/25 11:56)
|
||||
* @return false|string
|
||||
*/
|
||||
public function getMysqlVersion()
|
||||
{
|
||||
$sql = "SELECT VERSION() AS version";
|
||||
$result = $this->dbh->query($sql)->fetch();
|
||||
return substr($result->version, 0, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 检测数据库sql_mode
|
||||
* @param $version
|
||||
* @return bool
|
||||
* @author 段誉
|
||||
* @date 2021/8/27 17:17
|
||||
*/
|
||||
public function checkSqlMode($version)
|
||||
{
|
||||
$sql = "SELECT @@global.sql_mode";
|
||||
$result = $this->dbh->query($sql)->fetch();
|
||||
$result = (array)$result;
|
||||
|
||||
if ($version >= 5.7) {
|
||||
if ((strpos($result['@@global.sql_mode'],'NO_AUTO_CREATE_USER') !==false)
|
||||
&& (strpos($result['@@global.sql_mode'],'NO_ENGINE_SUBSTITUTION') !==false)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 创建数据库
|
||||
* @author luzg(2020/8/25 11:57)
|
||||
* @param $version
|
||||
* @return mixed
|
||||
*/
|
||||
public function createDB($version)
|
||||
{
|
||||
$sql = "CREATE DATABASE `{$this->name}`";
|
||||
if ($version > 4.1) $sql .= " DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci";
|
||||
return $this->dbh->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 创建表
|
||||
* @author luzg(2020/8/25 11:57)
|
||||
* @param $version
|
||||
* @param $post
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createTable($version, $post)
|
||||
{
|
||||
$dbFile = $this->getInstallRoot() . '/db/like.sql';
|
||||
//file_put_contents($dbFile, $this->initAccount($post), FILE_APPEND);
|
||||
$content = str_replace(";\r\n", ";\n", file_get_contents($dbFile));
|
||||
$tables = explode(";\n", $content);
|
||||
$tables[] = $this->initAccount($post);
|
||||
$installTime = microtime(true) * 10000;
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$table = trim($table);
|
||||
if (empty($table)) continue;
|
||||
|
||||
if (strpos($table, 'CREATE') !== false and $version <= 4.1) {
|
||||
$table = str_replace('DEFAULT CHARSET=utf8', '', $table);
|
||||
}
|
||||
// elseif (strpos($table, 'DROP') !== false and $this->clearDB != false) {
|
||||
// $table = str_replace('--', '', $table);
|
||||
// }
|
||||
|
||||
/* Skip sql that is note. */
|
||||
if (strpos($table, '--') === 0) continue;
|
||||
|
||||
$table = str_replace('`ls_', $this->name . '.`ls_', $table);
|
||||
$table = str_replace('`ls_', '`' . $this->prefix, $table);
|
||||
|
||||
if (strpos($table, 'CREATE') !== false) {
|
||||
$tableName = explode('`', $table)[1];
|
||||
$installTime += random_int(3000, 7000);
|
||||
$this->successTable[] = [$tableName, date('Y-m-d H:i:s', $installTime / 10000)];
|
||||
}
|
||||
|
||||
// if (strpos($table, "INSERT INTO ") !== false) {
|
||||
// $table = str_replace('INSERT INTO ', 'INSERT INTO ' .$this->name .'.', $table);
|
||||
// }
|
||||
|
||||
try {
|
||||
if ( !$this->dbh->query($table)) return false;
|
||||
} catch (Exception $e) {
|
||||
echo 'error sql: ' . $table . "<br>";
|
||||
echo $e->getMessage() . "<br>";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 删除数据库
|
||||
* @param $db
|
||||
* @return false|PDOStatement
|
||||
*/
|
||||
public function dropDb($db)
|
||||
{
|
||||
$sql = "drop database {$db};";
|
||||
return $this->dbh->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 取得安装成功的表列表
|
||||
* @author luzg(2020/8/26 18:28)
|
||||
* @return array
|
||||
*/
|
||||
public function getSuccessTable()
|
||||
{
|
||||
return $this->successTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 创建演示数据
|
||||
* @author luzg(2020/8/25 11:58)
|
||||
* @return bool
|
||||
*/
|
||||
public function importDemoData()
|
||||
{
|
||||
$demoDataFile = 'ys.sql';
|
||||
$demoDataFile = $this->getInstallRoot() . '/db/' . $demoDataFile;
|
||||
if (!is_file($demoDataFile)) {
|
||||
echo "<br>";
|
||||
echo 'no file:' .$demoDataFile;
|
||||
return false;
|
||||
}
|
||||
$content = str_replace(";\r\n", ";\n", file_get_contents($demoDataFile));
|
||||
$insertTables = explode(";\n", $content);
|
||||
foreach ($insertTables as $table) {
|
||||
$table = trim($table);
|
||||
if (empty($table)) continue;
|
||||
|
||||
$table = str_replace('`ls_', $this->name . '.`ls_', $table);
|
||||
$table = str_replace('`ls_', '`' .$this->prefix, $table);
|
||||
if ( !$this->dbh->query($table)) return false;
|
||||
}
|
||||
|
||||
// 移动图片资源
|
||||
$this->cpFiles($this->getInstallRoot().'/uploads', $this->getAppRoot().'/public/uploads');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个文件夹下的所有文件及文件夹
|
||||
* 复制到另一个文件夹里(保持原有结构)
|
||||
*
|
||||
* @param <string> $rootFrom 源文件夹地址(最好为绝对路径)
|
||||
* @param <string> $rootTo 目的文件夹地址(最好为绝对路径)
|
||||
*/
|
||||
function cpFiles($rootFrom, $rootTo){
|
||||
|
||||
$handle = opendir($rootFrom);
|
||||
while (false !== ($file = readdir($handle))) {
|
||||
//DIRECTORY_SEPARATOR 为系统的文件夹名称的分隔符 例如:windos为'/'; linux为'/'
|
||||
$fileFrom = $rootFrom . DIRECTORY_SEPARATOR . $file;
|
||||
$fileTo = $rootTo . DIRECTORY_SEPARATOR . $file;
|
||||
if ($file == '.' || $file == '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir($fileFrom)) {
|
||||
if (!is_dir($fileTo)) { //目标目录不存在则创建
|
||||
mkdir($fileTo, 0777);
|
||||
}
|
||||
$this->cpFiles($fileFrom, $fileTo);
|
||||
} else {
|
||||
if (!file_exists($fileTo)) {
|
||||
@copy($fileFrom, $fileTo);
|
||||
if (strstr($fileTo, "access_token.txt")) {
|
||||
chmod($fileTo, 0777);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 当前应用程序的相对路径
|
||||
* @author luzg(2020/8/25 10:55)
|
||||
* @return string
|
||||
*/
|
||||
public function getAppRoot()
|
||||
{
|
||||
return realpath($this->getInstallRoot() . '/../../');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取安装目录
|
||||
* @author luzg(2020/8/26 16:15)
|
||||
* @return string
|
||||
*/
|
||||
public function getInstallRoot()
|
||||
{
|
||||
return INSTALL_ROOT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 目录的容量
|
||||
* @author luzg(2020/8/25 15:21)
|
||||
* @param $dir
|
||||
* @return string
|
||||
*/
|
||||
public function freeDiskSpace($dir)
|
||||
{
|
||||
// M
|
||||
$freeDiskSpace = disk_free_space(realpath(__DIR__)) / 1024 / 1024;
|
||||
|
||||
// G
|
||||
if ($freeDiskSpace > 1024) {
|
||||
return number_format($freeDiskSpace / 1024, 2) . 'G';
|
||||
}
|
||||
|
||||
return number_format($freeDiskSpace, 2) . 'M';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取状态标志
|
||||
* @author luzg(2020/8/25 16:10)
|
||||
* @param $statusSingle
|
||||
* @return string
|
||||
*/
|
||||
public function correctOrFail($statusSingle)
|
||||
{
|
||||
if ($statusSingle == 'ok')
|
||||
return '<td class="layui-icon green"></td>';
|
||||
|
||||
$this->allowNext = false;
|
||||
return '<td class="layui-icon wrong">ဆ</td>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否允许下一步
|
||||
* @author luzg(2020/8/25 17:29)
|
||||
* @return bool
|
||||
*/
|
||||
public function getAllowNext()
|
||||
{
|
||||
return $this->allowNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查session auto start
|
||||
* @author luzg(2020/8/25 16:55)
|
||||
* @return string
|
||||
*/
|
||||
public function checkSessionAutoStart()
|
||||
{
|
||||
return $result = ini_get('session.auto_start') == '0' ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查auto tags
|
||||
* @author luzg(2020/8/25 16:55)
|
||||
* @return string
|
||||
*/
|
||||
public function checkAutoTags()
|
||||
{
|
||||
return $result = ini_get('session.auto_start') == '0' ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查目录是否可写
|
||||
* @param $dir
|
||||
* @return string
|
||||
*/
|
||||
public function checkDirWrite($dir='')
|
||||
{
|
||||
$route = $this->getAppRoot().'/'.$dir;
|
||||
return $result = is_writable($route) ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 检查目录是否可写
|
||||
* @param $dir
|
||||
* @return string
|
||||
*/
|
||||
public function checkSuperiorDirWrite($dir='')
|
||||
{
|
||||
$route = $this->getAppRoot().'/'.$dir;
|
||||
return $result = is_writable($route) ? 'ok' : 'fail';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 初始化管理账号
|
||||
* @param $post
|
||||
* @return string
|
||||
*/
|
||||
public function initAccount($post)
|
||||
{
|
||||
$time = time();
|
||||
$salt = substr(md5($time . $post['admin_user']), 0, 4);//随机4位密码盐
|
||||
$password = $this->createPassword($post['admin_password'], $salt);
|
||||
|
||||
$sql = "INSERT INTO `ls_admin` VALUES (1, 1, '{$post['admin_user']}', NULL, '{$post['admin_user']}',
|
||||
'{$password}', '{$salt}', 0, '{$time}', '{$time}', '{$time}', '', 0, 0);";
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 生成密码密文
|
||||
* @param $pwd
|
||||
* @param $salt
|
||||
* @return string
|
||||
*/
|
||||
public function createPassword($pwd, $salt)
|
||||
{
|
||||
$salt = md5('y' . $salt . 'x');
|
||||
$salt .= '2021';
|
||||
return md5($pwd . $salt);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,479 +0,0 @@
|
|||
<?php !defined('install') && exit(); ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>likeshop多商户安装</title>
|
||||
<link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="./css/mounted.css"/>
|
||||
<link rel="shortcut icon" href="./favicon.ico"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="logo" style="width: 220px;">
|
||||
<img src="./images/slogn.png?v=1"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mounted" id="mounted">
|
||||
<div class="mounted-box">
|
||||
<form method="post" action="#" name="main_form">
|
||||
<div class="mounted-title">安装步骤</div>
|
||||
<div class="mounted-container" id="tab">
|
||||
<ul class="mounted-nav" id="nav">
|
||||
<li <?php if ($step == "1") { ?>class="active"<?php } ?>>许可协议</li>
|
||||
<li <?php if ($step == "2") { ?>class="active"<?php } ?>>环境监测</li>
|
||||
<li <?php if ($step == "3") { ?>class="active"<?php } ?>>参数配置</li>
|
||||
<li <?php if ($step == "4" or $step == '5') { ?>class="active"<?php } ?>>安装</li>
|
||||
</ul>
|
||||
|
||||
<!-- 阅读许可 -->
|
||||
<?php if ($step == '1') { ?>
|
||||
<div class="mounted-content-item show">
|
||||
<div class="content-header">
|
||||
likeshop100%开源免费商用电商系统授权协议
|
||||
</div>
|
||||
<div class="content">
|
||||
<h2>版权所有(c)2019-<?=date('Y')?>,likeshop团队保留所有权利。</h2>
|
||||
<p class="mt16">
|
||||
感谢你信任并选择likeshop100%开源免费商用电商系统,likeshop100%开源免费商用电商系统由广州好象科技有限公司(www.likeshop.cn)原创研发并取得软件著作权,100%开放源码,无加密,自主可控,方便二次开发。</p>
|
||||
<p class="mt6">为了正确并合法的使用本软件,请你在使用前务必阅读清楚下面的协议条款:</p>
|
||||
<h3 class="mt16">一、本授权协议适用且仅适用于likeshop系列开源软件产品(以下简称likeshop)任何版本,广州好象科技有限公司拥有本授权协议的最终解释权。</h3>
|
||||
<h3 class="mt16">二、协议许可的权利</h3>
|
||||
<p class="mt6">
|
||||
1.开源版本可以任意免费商用,可去除界面版权logo,不能去除代码版权。付费版本需要取得商业授权方可使用,否则会被视为盗版行为并承担相应法律责任。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
2.请尊重likeshop开源团队劳动成果,严禁使用本系统转手、转卖、倒卖或二次开发后转手、转卖、倒卖等商业行为。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
3.任何企业和个人不允许对likeshop程序代码以任何形式任何目的再发布。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
4.你可以在协议规定的约束和限制范围内修改likeshop系列开源软件产品或界面风格以适应你的网站要求。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
5.你拥有使用本软件构建的系统全部内容所有权,并独立承担与这些内容的相关法律义务。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
6.获得商业授权之后,你可以将本软件应用于商业用途,同时依据所购买的授权类型中确定的技术支持内容,自购买时刻起,在技术支持期限内拥有通过指定的方式获得指定范围内的技术支持服务。商业授权用户享有反映和提出意见的权力,相关意见将被作为首要考虑,但没有一定被采纳的承诺或保证。
|
||||
</p>
|
||||
<h3 class="mt6">三、协议规定的约束和限制</h3>
|
||||
<p class="mt6">
|
||||
1.开源版本可以任意免费商用,可去除界面版权logo,不能去除代码版权。付费版本需要取得商业授权方可使用,否则会被视为盗版行为并承担相应法律责任。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
2.未经官方许可,不得对本软件或与之关联的商业授权进行出租、出售、抵押或发放子许可证。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
3.未经官方许可,禁止在likeshop开源商城的整体或任何部分基础上以发展任何派生版本、修改版本或第三方版本用于重新分发。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
4.如果你未能遵守本协议的条款,你的授权将被终止,所被许可的权利将被收回,并承担相应法律责任。
|
||||
</p>
|
||||
<h3 class="mt6">四、有限担保和免责声明</h3>
|
||||
<p class="mt6">
|
||||
1.本软件及所附带的文件是作为不提供任何明确的或隐含的赔偿或担保的形式提供的。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
2.用户出于自愿而使用本软件,你必须了解使用本软件的风险,在尚未购买产品技术服务之前,我们不承诺对免费用户提供任何形式的技术支持、使用担保,也不承担任何因使用本软件而产生问题的相关责任。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
3.电子文本形式的授权协议如同双方书面签署的协议一样,具有完全的和等同的法律效力。你一旦开始确认本协议并安装本软件,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的权力的同时,受到相关的约束和限制。协议许可范围以外的行为,将直接违反本授权协议并构成侵权,我们有权随时终止授权,责令停止损害,并保留追究相关责任的权力。
|
||||
</p>
|
||||
<p class="mt6">
|
||||
4.如果本软件带有其它软件的整合API示范例子包,这些文件版权不属于本软件官方,并且这些文件是没经过授权发布的,请参考相关软件的使用许可合法的使用。
|
||||
</p>
|
||||
<br><br>
|
||||
<p class="mt6">
|
||||
likeshop开源地址:https://gitee.com/likeshop_gitee/likeshop
|
||||
</p>
|
||||
<p class="mt6">
|
||||
likeshop官方网站:https://www.likeshop.cn
|
||||
</p>
|
||||
<p class="mt6">
|
||||
likeshop知识社区:https://home.likeshop.cn
|
||||
</p>
|
||||
<p class="mt6">
|
||||
-----------------------------------------------------
|
||||
</p>
|
||||
<p class="mt6">
|
||||
广州好象科技有限公司
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- 检查信息 -->
|
||||
<?php if ($step == '2') { ?>
|
||||
<div class="mounted-content-item show">
|
||||
<div class="mounted-env-container">
|
||||
<div class="mounted-item">
|
||||
<div class="content-header">
|
||||
服务器信息
|
||||
</div>
|
||||
<div class="content-table">
|
||||
<table class="layui-table" lay-skin="line">
|
||||
<colgroup>
|
||||
<col width="210">
|
||||
<col width="730">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
<th>值</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>服务器操作系统</td>
|
||||
<td><?php echo PHP_OS ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>web服务器环境</td>
|
||||
<td><?php echo $_SERVER['SERVER_SOFTWARE']; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PHP版本</td>
|
||||
<td><?php echo @phpversion(); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>程序安装目录</td>
|
||||
<td><?php echo realpath(__DIR__ . '../../../'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>磁盘空间</td>
|
||||
<td><?php echo $modelInstall->freeDiskSpace(realpath(__DIR__ . '../../../')) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>上传限制</td>
|
||||
<?php if (ini_get('file_uploads')): ?>
|
||||
<td><?php echo ini_get('upload_max_filesize'); ?></td>
|
||||
<?php else: ?>
|
||||
<td>禁止上传</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mounted-tips mt16">PHP环境要求必须满足下列所有条件,否则系统或系统部分功能将无法使用。</div>
|
||||
<div class="mounted-item mt16">
|
||||
<div class="content-header">
|
||||
PHP环境要求
|
||||
</div>
|
||||
<div class="content-table">
|
||||
<table class="layui-table" lay-skin="line">
|
||||
<colgroup>
|
||||
<col width="210">
|
||||
<col width="210">
|
||||
<col width="120">
|
||||
<col width="400">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>选项</th>
|
||||
<th>要求</th>
|
||||
<th>状态</th>
|
||||
<th>说明及帮助</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>PHP版本</td>
|
||||
<td>大于7.2</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkPHP()) ?>
|
||||
<td>建议使用PHP7.2.4版本</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PDO_MYSQL</td>
|
||||
<td>支持 (强烈建议支持)</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkPDOMySQL()) ?>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>allow_url_fopen</td>
|
||||
<td>支持 (建议支持cURL)</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkCurl()) ?>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GD2</td>
|
||||
<td>支持</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkGd2()) ?>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DOM</td>
|
||||
<td>支持</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkDom()) ?>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>fileinfo</td>
|
||||
<td>支持</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkFileInfo()) ?>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>session.auto_start</td>
|
||||
<td>关闭</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkSessionAutoStart()) ?>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mounted-tips mt16">
|
||||
系统要求likeshop开源商城安装目录下的runtime和upload必须可写,才能使用likeshop开源商城的所有功能。
|
||||
</div>
|
||||
<div class="mounted-item mt16">
|
||||
<div class="content-header">
|
||||
目录权限监测
|
||||
</div>
|
||||
<div class="content-table">
|
||||
<table class="layui-table" lay-skin="line">
|
||||
<colgroup>
|
||||
<col width="210">
|
||||
<col width="210">
|
||||
<col width="120">
|
||||
<col width="400">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>目录</th>
|
||||
<th>要求</th>
|
||||
<th>状态</th>
|
||||
<th>说明及帮助</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>/server/runtime</td>
|
||||
<td>/runtime目录可写</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkDirWrite('runtime')) ?>
|
||||
<td><?php if($modelInstall->checkDirWrite('runtime') =='fail') echo'请给runtime目录权限,若目录不存在先新建';?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/server/public/uploads</td>
|
||||
<td>uploads目录可写</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkDirWrite('public/uploads')) ?>
|
||||
<td><?php if($modelInstall->checkDirWrite('public/uploads')=='fail') echo'请给public/uploads目录权限,若目录不存在先新建';?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/server/config</td>
|
||||
<td>config目录可写</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkDirWrite('config')) ?>
|
||||
<td><?php if($modelInstall->checkDirWrite('config')=='fail') echo'请给config目录权限,若目录不存在先新建';?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/server/.env</td>
|
||||
<td>.env文件可写</td>
|
||||
<?php echo $modelInstall->correctOrFail($modelInstall->checkDirWrite('.env')) ?>
|
||||
<td><?php if($modelInstall->checkDirWrite('.env')=='fail') echo'请给.env文件权限,若文件不存在,注意文件名第1字符是" . "';?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- 数据库设置 -->
|
||||
<?php if ($step == '3') { ?>
|
||||
<div class="mounted-content-item show">
|
||||
<div class="mounted-item">
|
||||
<div class="content-header">
|
||||
数据库选项
|
||||
</div>
|
||||
<div class="content-form">
|
||||
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
数据库主机
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="host" value="<?= $post['host'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
端口号
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="port" value="<?= $post['port'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
数据库用户
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="user" value="<?= $post['user'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
数据库密码
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="password" value="<?= $post['password'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
数据库名称
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="name" value="<?= $post['name'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
数据表前缀
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="prefix" value="<?= $post['prefix'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mounted-item">
|
||||
<div class="content-header mt16">
|
||||
管理选项
|
||||
</div>
|
||||
<div class="content-form">
|
||||
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
管理员账号
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="admin_user" value="<?= $post['admin_user'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
管理员密码
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" name="admin_password"
|
||||
value="<?= $post['admin_password'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-item">
|
||||
<div class="form-desc">
|
||||
确认密码
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" name="admin_confirm_password"
|
||||
value="<?= $post['admin_confirm_password'] ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-check">
|
||||
<div class="form-desc"></div>
|
||||
<div style="display: flex;align-items: center;">
|
||||
<input type="checkbox" name="import_test_data"
|
||||
<?php if ($post['import_test_data'] == 'on'): ?>checked<?php endif; ?>
|
||||
title="导入测试数据"/>
|
||||
<div style="color: #666666;"> 导入测试数据</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box-check">
|
||||
<div class="form-desc"></div>
|
||||
<div style="display: flex;align-items: center;">
|
||||
<input type="checkbox" name="clear_db"
|
||||
<?php if ($post['clear_db'] == 'on'): ?>checked<?php endif; ?>
|
||||
title="清空现有数据"/>
|
||||
<div style="color: #666666;"> 清空现有数据</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- 安装中 -->
|
||||
<?php if ($step == '4' or $step == '5') { ?>
|
||||
<div class="mounted-content-item show">
|
||||
<?php if ($step == '4') { ?>
|
||||
<div id="mounting">
|
||||
<div class="content-header">
|
||||
正在安装中
|
||||
</div>
|
||||
<div class="mounting-container " id="install_message">
|
||||
<?php if (count($successTables) > 0): ?>
|
||||
<p style="margin-bottom: 4px;">成功创建数据库:<?= $post['name'] ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($step == '5') { ?>
|
||||
<div class="show" id="mounting-success">
|
||||
<div class="content-header">
|
||||
安装成功
|
||||
</div>
|
||||
<div class="success-content">
|
||||
<div style="width: 48px;height: 48px;">
|
||||
<img src="./images/icon_mountSuccess.png"/>
|
||||
</div>
|
||||
<div class="mt16 result">安装完成,进入管理后台</div>
|
||||
<div style="margin-top: 5px;font-size:14px;">版本号:1.9.3.20220609</div>
|
||||
<div class="tips">
|
||||
为了您站点的安全,安装完成后即可将网站根目录下的“install”文件夹删除,或者config/install.lock/目录下创建install.lock文件防止重复安装。
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<a class="btn" href="/admin" style="margin-left: 20px;">进入管理平台</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</form>
|
||||
<?php if ($step == '1') { ?>
|
||||
<div class="item-btn-group show">
|
||||
<button class="accept-btn" onclick="goStep(<?php echo $nextStep ?>)">我已阅读并同意</button>
|
||||
</div>
|
||||
<?php } elseif (in_array($step, ['2', "3"])) { ?>
|
||||
<div class="item-btn-group show">
|
||||
<button class="cancel-btn" onclick="cancel()" style="padding: 7px 63px;margin-right: 16px">返回
|
||||
</button>
|
||||
<?php if ($modelInstall->getAllowNext()): ?>
|
||||
<button class="accept-btn" onclick="goStep(<?php echo $nextStep ?>)" style="padding: 7px 63px;">
|
||||
继续
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<button class="accept-btn" onclick="goStep(<?php echo $step ?>)" style="padding: 7px 63px;">重新检查
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php } elseif ($step == "4") { ?>
|
||||
<div class="item-btn-group show">
|
||||
<button class="disabled-btn" disabled="disabled">
|
||||
<div class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></div>
|
||||
<div style="font-size: 14px;margin-left: 7px;">正在安装中...</div>
|
||||
</button>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
Copyright © 2019-<?=date('Y')?> 广州好象科技有限公司 粤ICP备16101670号-2
|
||||
</footer>
|
||||
<script src="https://www.layuicdn.com/layui/layui.js"></script>
|
||||
<?php if (count($successTables) > 0): ?>
|
||||
<script>var successTables = eval(<?=json_encode($successTables) ?>); </script>
|
||||
<?php endif; ?>
|
||||
<script src="./js/mounted.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
<?php if ($message != ''): ?>
|
||||
<script>alert('<?=$message; ?>');</script>
|
||||
<?php endif; ?>
|
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 282 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 415 KiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 328 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 392 KiB |
Before Width: | Height: | Size: 188 KiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 415 KiB |
Before Width: | Height: | Size: 328 KiB |
Before Width: | Height: | Size: 563 KiB |
Before Width: | Height: | Size: 448 KiB |
Before Width: | Height: | Size: 331 KiB |
Before Width: | Height: | Size: 327 KiB |
Before Width: | Height: | Size: 368 KiB |
Before Width: | Height: | Size: 458 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 125 KiB |
Before Width: | Height: | Size: 332 KiB |
Before Width: | Height: | Size: 339 KiB |
Before Width: | Height: | Size: 344 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 274 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 138 KiB |
Before Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 296 KiB |
Before Width: | Height: | Size: 277 KiB |
Before Width: | Height: | Size: 287 KiB |
Before Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 177 KiB |