在我们做一个项目的时候,如果是自己用或者是给同行用的话往往不需要做一个安装页面的,但是如果是将项目给一些不怎么会操作服务器,不怎么会程序的人用的时候,我们就需要一个安装页面来帮助他们更好的将项目安装好。废话补多少了,我们直接开始教学吧,我这个是基于tp6.0上的,如果不是tp6.0也可以使用,稍作修改就行了,按自己的需求来。
首先,我们先从入口文件入手,先判断一下是否已经安装好项目了,我们通过文件锁来进行判断。判断是否存在install.lock文件,如果存在证明已经安装了,否则就还没有安装,就需要跳转到安装页面了,代码如下:
// [ 应用入口文件 ]
namespace think;
// 定义目录分隔符
define(‘DS‘, DIRECTORY_SEPARATOR);
// 定义根目录
define(‘ROOT_PATH‘, __DIR__ . DS . ‘..‘ . DS);
// 定义应用目录
define(‘APP_PATH‘, ROOT_PATH . ‘app‘ . DS);
// 判断是否安装了项目
if (!is_file(APP_PATH . ‘install/install.lock‘))
{
header("location:./install.php");
exit;
}
require __DIR__ . ‘/../vendor/autoload.php‘;
// 执行HTTP应用并响应
$http = (new App())->http;
$response = $http->run();
$response->send();
$http->end($response);
我们需要再public文件夹下新建一个install.php的文件。还有在app文件夹下创建一个install文件夹,并将我们项目的数据库命名为install.sql放到install文件夹下面。
我们先定义几个常量和会用到的变量,方便以后使用。
// 定义目录分隔符
define(‘DS‘, DIRECTORY_SEPARATOR);
// 定义根目录
define(‘ROOT_PATH‘, __DIR__ . DS . ‘..‘ . DS);
// 定义应用目录
define(‘APP_PATH‘, ROOT_PATH . ‘app‘ . DS);
// 安装包目录
define(‘INSTALL_PATH‘, APP_PATH . ‘install‘ . DS);
//项目名称
$sitename = "tp6";
//链接
$link = array(
‘qqun‘ => "",
‘home‘ => ‘‘,
‘doc‘ => ‘‘,
);
// 检测目录是否存在,这个可以按自己的需求进行修改
$checkDirs = [
‘vendor‘
];
//缓存目录
$runtimeDir = APP_PATH . ‘runtime‘;
//错误信息
$errInfo = ‘‘;
//数据库配置文件
$dbConfigFile = ROOT_PATH. ‘config‘. DS. ‘database.php‘;
//后台入口文件
$adminFile = ROOT_PATH . ‘public‘ . DS . ‘admin.php‘;
// 锁定的文件
$lockFile = INSTALL_PATH . ‘install.lock‘;
定义好后,我们先写个函数来判断特定文件或文件夹的读写权限,如果没有读写权限的话,我们是没法操作的,Windows系统一般不用担心这个问题,如果是Linux的话需要我们去修改一下权限为777。
// 判断文件或目录是否有写的权限
function is_really_writable($file)
{
if (DIRECTORY_SEPARATOR == ‘/‘ AND @ ini_get("safe_mode") == false) {
return is_writable($file);
}
if (!is_file($file) OR ($fp = @fopen($file, "r+")) === false) {
return false;
}
fclose($fp);
return true;
}
接下来我们就要进行一系列的判断,这个主要是为了能够正常安装项目,首先需要判断是否已经安装了项目,然后就是环境的判断,比如PHP版本是否大于或等于7.1.0,是否开启了PDO,数据库配置文件是否可读写等等。来,直接上代码:
// 当前是POST请求
if (isset($_SERVER[‘REQUEST_METHOD‘]) && $_SERVER[‘REQUEST_METHOD‘] == ‘POST‘) {
if ($errInfo) {//错误信息
echo $errInfo;
exit;
}
$err = ‘‘;
$mysqlHostname = isset($_POST[‘mysqlHost‘]) ? $_POST[‘mysqlHost‘] : ‘127.0.0.1‘;//数据库地址
$mysqlHostport = isset($_POST[‘mysqlHostport‘]) ? $_POST[‘mysqlHostport‘] : 3306;//端口号
$hostArr = explode(‘:‘, $mysqlHostname);//如果数据库地址中填写了端口号,将他们分开
if (count($hostArr) > 1) {
$mysqlHostname = $hostArr[0];
$mysqlHostport = $hostArr[1];
}
$mysqlUsername = isset($_POST[‘mysqlUsername‘]) ? $_POST[‘mysqlUsername‘] : ‘root‘;//用户名
$mysqlPassword = isset($_POST[‘mysqlPassword‘]) ? $_POST[‘mysqlPassword‘] : ‘‘;//密码
$mysqlDatabase = isset($_POST[‘mysqlDatabase‘]) ? $_POST[‘mysqlDatabase‘] : ‘tp6‘;//数据库名
$mysqlPrefix = isset($_POST[‘mysqlPrefix‘]) ? $_POST[‘mysqlPrefix‘] : ‘tp_‘;//前缀
$adminUsername = isset($_POST[‘adminUsername‘]) ? $_POST[‘adminUsername‘] : ‘admin‘;//后台管理者用户名
$adminPassword = isset($_POST[‘adminPassword‘]) ? $_POST[‘adminPassword‘] : ‘123456‘;//后台管理者密码
$adminPasswordConfirmation = isset($_POST[‘adminPasswordConfirmation‘]) ? $_POST[‘adminPasswordConfirmation‘] : ‘123456‘;//重复密码
$adminEmail = isset($_POST[‘adminEmail‘]) ? $_POST[‘adminEmail‘] : ‘admin@admin.com‘;//邮箱
if (!preg_match("/^w{3,12}$/", $adminUsername)) {
echo "用户名只能由3-12位数字、字母、下划线组合";
exit;
}
if (!preg_match("/^[S]{6,16}$/", $adminPassword)) {
echo "密码长度必须在6-16位之间,不能包含空格";
exit;
}
if ($adminPassword !== $adminPasswordConfirmation) {
echo "两次输入的密码不一致";
exit;
}
try {
//检测能否读取安装文件
$sql = @file_get_contents(INSTALL_PATH . ‘install.sql‘);
if (!$sql) {
throw new Exception("无法读取app/install/install.sql文件,请检查是否有读权限");
}
$sql = str_replace("`fa_", "`{$mysqlPrefix}", $sql);
$pdo = new PDO("mysql:host={$mysqlHostname};port={$mysqlHostport}", $mysqlUsername, $mysqlPassword, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
));
//检测是否支持innodb存储引擎
$pdoStatement = $pdo->query("SHOW VARIABLES LIKE ‘innodb_version‘");
$result = $pdoStatement->fetch();
if (!$result) {
throw new Exception("当前数据库不支持innodb存储引擎,请开启后再重新尝试安装");
}
$pdo->query("CREATE DATABASE IF NOT EXISTS `{$mysqlDatabase}` CHARACTER SET utf8 COLLATE utf8_general_ci;");
$pdo->query("USE `{$mysqlDatabase}`");
$pdo->exec($sql);
$config = @file_get_contents($dbConfigFile);
$callback = function ($matches) use ($mysqlHostname, $mysqlHostport, $mysqlUsername, $mysqlPassword, $mysqlDatabase, $mysqlPrefix) {
$field = ucfirst($matches[1]);//首字符大写
$replace = ${"mysql{$field}"};//$mysqlHostname,$mysqlHostport,$mysqlUsername,$mysqlPassword,$mysqlDatabase,$mysqlPrefix
if ($matches[1] == ‘hostport‘ && $mysqlHostport == 3306) {
$replace = ‘‘;
}
return "‘{$matches[1]}‘{$matches[2]}=>{$matches[3]}Env::get(‘database.{$matches[1]}‘, ‘{$replace}‘),";
};
$config = preg_replace_callback("/‘(hostname|database|username|password|hostport|prefix)‘(s+)=>(s+)Env::get((.*)),/", $callback, $config);
//检测能否成功写入数据库配置
$result = @file_put_contents($dbConfigFile, $config);
if (!$result) {
throw new Exception("无法写入数据库信息到config/database.php文件,请检查是否有写权限");
}
//检测能否成功写入lock文件
$result = @file_put_contents($lockFile, 1);
if (!$result) {
throw new Exception("无法写入安装锁定到app/install/install.lock文件,请检查是否有写权限");
}
$newSalt = substr(md5(uniqid(true)), 0, 6);
$newPassword = md5(md5($adminPassword) . $newSalt);
$pdo->query("UPDATE {$mysqlPrefix}admin SET username = ‘{$adminUsername}‘, email = ‘{$adminEmail}‘,password = ‘{$newPassword}‘, salt = ‘{$newSalt}‘ WHERE username = ‘admin‘");
$adminName = ‘‘;
if (is_file($adminFile)) {//修改后台入口文件名
$x = ‘0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ‘;
$adminName = substr(str_shuffle(str_repeat($x, ceil(10 / strlen($x)))), 1, 10) . ‘.php‘;
rename($adminFile, ROOT_PATH . ‘public‘ . DS . $adminName);
}
echo "success|{$adminName}";
} catch (PDOException $e) {
$err = $e->getMessage();
} catch (Exception $e) {
$err = $e->getMessage();
}
echo $err;
exit;
}
下面是完整的代码:
/**
* 安装完成后建议删除此文件
*/
// error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
// ini_set(‘display_errors‘, ‘1‘);
// 定义目录分隔符
define(‘DS‘, DIRECTORY_SEPARATOR);
// 定义根目录
define(‘ROOT_PATH‘, __DIR__ . DS . ‘..‘ . DS);
// 定义应用目录
define(‘APP_PATH‘, ROOT_PATH . ‘app‘ . DS);
// 安装包目录
define(‘INSTALL_PATH‘, APP_PATH . ‘install‘ . DS);
// 判断文件或目录是否有写的权限
function is_really_writable($file)
{
if (DIRECTORY_SEPARATOR == ‘/‘ AND @ ini_get("safe_mode") == false) {
return is_writable($file);
}
if (!is_file($file) OR ($fp = @fopen($file, "r+")) === false) {
return false;
}
fclose($fp);
return true;
}
$sitename = "tp6";
$link = array(
‘qqun‘ => "",
‘home‘ => ‘‘,
‘doc‘ => ‘‘,
);
// 检测目录是否存在
$checkDirs = [
‘vendor‘
// ‘public‘ . DS . ‘assets‘ . DS . ‘libs‘
];
//缓存目录
$runtimeDir = APP_PATH . ‘runtime‘;
//错误信息
$errInfo = ‘‘;
//数据库配置文件
$dbConfigFile = ROOT_PATH. ‘config‘. DS. ‘database.php‘;
//后台入口文件
$adminFile = ROOT_PATH . ‘public‘ . DS . ‘admin.php‘;
// 锁定的文件
$lockFile = INSTALL_PATH . ‘install.lock‘;
if (is_file($lockFile)) {
$errInfo = "当前已经安装{$sitename},如果需要重新安装,请手动移除app/install/install.lock文件";
} else {
if (version_compare(PHP_VERSION, ‘7.1.0‘, ‘
$errInfo = "当前版本(" . PHP_VERSION . ")过低,请使用PHP7.1.0以上版本";
} else {
if (!extension_loaded("PDO")) {
$errInfo = "当前未开启PDO,无法进行安装";
} else {
if (!is_really_writable($dbConfigFile)) {
$open_basedir = ini_get(‘open_basedir‘);
if ($open_basedir) {
$dirArr = explode(PATH_SEPARATOR, $open_basedir);
if ($dirArr && in_array(__DIR__, $dirArr)) {
$errInfo = ‘当前服务器因配置了open_basedir,导致无法读取父目录
‘;
}
}
if (!$errInfo) {
$errInfo = ‘当前权限不足,无法写入配置文件config/database.php
‘;
}
} else {
$dirArr = [];
foreach ($checkDirs as $k => $v) {
if (!is_dir(ROOT_PATH . $v)) {
$errInfo = ‘当前代码仅包含核心代码,请前往官网下载完整包或资源包覆盖后再尝试安装,‘;
break;
}
}
}
}
}
}
// 当前是POST请求
if (isset($_SERVER[‘REQUEST_METHOD‘]) && $_SERVER[‘REQUEST_METHOD‘] == ‘POST‘) {
if ($errInfo) {//错误信息
echo $errInfo;
exit;
}
$err = ‘‘;
$mysqlHostname = isset($_POST[‘mysqlHost‘]) ? $_POST[‘mysqlHost‘] : ‘127.0.0.1‘;//数据库地址
$mysqlHostport = isset($_POST[‘mysqlHostport‘]) ? $_POST[‘mysqlHostport‘] : 3306;//端口号
$hostArr = explode(‘:‘, $mysqlHostname);//如果数据库地址中填写了端口号,将他们分开
if (count($hostArr) > 1) {
$mysqlHostname = $hostArr[0];
$mysqlHostport = $hostArr[1];
}
$mysqlUsername = isset($_POST[‘mysqlUsername‘]) ? $_POST[‘mysqlUsername‘] : ‘root‘;//用户名
$mysqlPassword = isset($_POST[‘mysqlPassword‘]) ? $_POST[‘mysqlPassword‘] : ‘‘;//密码
$mysqlDatabase = isset($_POST[‘mysqlDatabase‘]) ? $_POST[‘mysqlDatabase‘] : ‘tp6‘;//数据库名
$mysqlPrefix = isset($_POST[‘mysqlPrefix‘]) ? $_POST[‘mysqlPrefix‘] : ‘tp_‘;//前缀
$adminUsername = isset($_POST[‘adminUsername‘]) ? $_POST[‘adminUsername‘] : ‘admin‘;//后台管理者用户名
$adminPassword = isset($_POST[‘adminPassword‘]) ? $_POST[‘adminPassword‘] : ‘123456‘;//后台管理者密码
$adminPasswordConfirmation = isset($_POST[‘adminPasswordConfirmation‘]) ? $_POST[‘adminPasswordConfirmation‘] : ‘123456‘;//重复密码
$adminEmail = isset($_POST[‘adminEmail‘]) ? $_POST[‘adminEmail‘] : ‘admin@admin.com‘;//邮箱
if (!preg_match("/^w{3,12}$/", $adminUsername)) {
echo "用户名只能由3-12位数字、字母、下划线组合";
exit;
}
if (!preg_match("/^[S]{6,16}$/", $adminPassword)) {
echo "密码长度必须在6-16位之间,不能包含空格";
exit;
}
if ($adminPassword !== $adminPasswordConfirmation) {
echo "两次输入的密码不一致";
exit;
}
try {
//检测能否读取安装文件
$sql = @file_get_contents(INSTALL_PATH . ‘install.sql‘);
if (!$sql) {
throw new Exception("无法读取app/install/install.sql文件,请检查是否有读权限");
}
$sql = str_replace("`fa_", "`{$mysqlPrefix}", $sql);
$pdo = new PDO("mysql:host={$mysqlHostname};port={$mysqlHostport}", $mysqlUsername, $mysqlPassword, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
));
//检测是否支持innodb存储引擎
$pdoStatement = $pdo->query("SHOW VARIABLES LIKE ‘innodb_version‘");
$result = $pdoStatement->fetch();
if (!$result) {
throw new Exception("当前数据库不支持innodb存储引擎,请开启后再重新尝试安装");
}
$pdo->query("CREATE DATABASE IF NOT EXISTS `{$mysqlDatabase}` CHARACTER SET utf8 COLLATE utf8_general_ci;");
$pdo->query("USE `{$mysqlDatabase}`");
$pdo->exec($sql);
$config = @file_get_contents($dbConfigFile);
$callback = function ($matches) use ($mysqlHostname, $mysqlHostport, $mysqlUsername, $mysqlPassword, $mysqlDatabase, $mysqlPrefix) {
$field = ucfirst($matches[1]);//首字符大写
$replace = ${"mysql{$field}"};//$mysqlHostname,$mysqlHostport,$mysqlUsername,$mysqlPassword,$mysqlDatabase,$mysqlPrefix
if ($matches[1] == ‘hostport‘ && $mysqlHostport == 3306) {
$replace = ‘‘;
}
return "‘{$matches[1]}‘{$matches[2]}=>{$matches[3]}Env::get(‘database.{$matches[1]}‘, ‘{$replace}‘),";
};
$config = preg_replace_callback("/‘(hostname|database|username|password|hostport|prefix)‘(s+)=>(s+)Env::get((.*)),/", $callback, $config);
//检测能否成功写入数据库配置
$result = @file_put_contents($dbConfigFile, $config);
if (!$result) {
throw new Exception("无法写入数据库信息到config/database.php文件,请检查是否有写权限");
}
//检测能否成功写入lock文件
$result = @file_put_contents($lockFile, 1);
if (!$result) {
throw new Exception("无法写入安装锁定到app/install/install.lock文件,请检查是否有写权限");
}
$newSalt = substr(md5(uniqid(true)), 0, 6);
$newPassword = md5(md5($adminPassword) . $newSalt);
$pdo->query("UPDATE {$mysqlPrefix}admin SET username = ‘{$adminUsername}‘, email = ‘{$adminEmail}‘,password = ‘{$newPassword}‘, salt = ‘{$newSalt}‘ WHERE username = ‘admin‘");
$adminName = ‘‘;
if (is_file($adminFile)) {//修改后台入口文件名
$x = ‘0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ‘;
$adminName = substr(str_shuffle(str_repeat($x, ceil(10 / strlen($x)))), 1, 10) . ‘.php‘;
rename($adminFile, ROOT_PATH . ‘public‘ . DS . $adminName);
}
echo "success|{$adminName}";
} catch (PDOException $e) {
$err = $e->getMessage();
} catch (Exception $e) {
$err = $e->getMessage();
}
echo $err;
exit;
}
?>
安装<?php echo $sitename; ?>body {
background: #fff;
margin: 0;
padding: 0;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body, input, button {
font-family: ‘Source Sans Pro‘, ‘Helvetica Neue‘, Helvetica, ‘Microsoft Yahei‘, Arial, sans-serif;
font-size: 14px;
color: #7E96B3;
}
.container {
max-width: 480px;
margin: 0 auto;
padding: 20px;
text-align: center;
}
a {
color: #18bc9c;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
h1 {
margin-top: 0;
margin-bottom: 10px;
}
h2 {
font-size: 28px;
font-weight: normal;
color: #3C5675;
margin-bottom: 0;
margin-top: 0;
}
form {
margin-top: 40px;
}
.form-group {
margin-bottom: 20px;
}
.form-group .form-field:first-child input {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.form-group .form-field:last-child input {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.form-field input {
background: #EDF2F7;
margin: 0 0 1px;
border: 2px solid transparent;
transition: background 0.2s, border-color 0.2s, color 0.2s;
width: 100%;
padding: 15px 15px 15px 180px;
box-sizing: border-box;
}
.form-field input:focus {
border-color: #18bc9c;
background: #fff;
color: #444;
outline: none;
}
.form-field label {
float: left;
width: 160px;
text-align: right;
margin-right: -160px;
position: relative;
margin-top: 18px;
font-size: 14px;
pointer-events: none;
opacity: 0.7;
}
button, .btn {
background: #3C5675;
color: #fff;
border: 0;
font-weight: bold;
border-radius: 4px;
cursor: pointer;
padding: 15px 30px;
-webkit-appearance: none;
}
button[disabled] {
opacity: 0.5;
}
.form-buttons {
height: 52px;
line-height: 52px;
}
.form-buttons .btn {
margin-right: 5px;
}
#error, .error, #success, .success, #warmtips, .warmtips {
background: #D83E3E;
color: #fff;
padding: 15px 20px;
border-radius: 4px;
margin-bottom: 20px;
}
#success {
background: #3C5675;
}
#error a, .error a {
color: white;
text-decoration: underline;
}
#warmtips {
background: #ffcdcd;
font-size: 14px;
color: #e74c3c;
}
#warmtips a {
background: #ffffff7a;
display: block;
height: 30px;
line-height: 30px;
margin-top: 10px;
color: #e21a1a;
border-radius: 3px;
}
xmlns:xlink="http://www.w3.org/1999/xlink">
id="body" fill="#18BC9C">
id="flash" fill="#FFFFFF">
安装 <?php echo $sitename; ?>
若你在安装中遇到麻烦可点击 安装文档
href="<?php echo $link[‘forum‘]; ?>" target="_blank">问答社区
href="<?php echo $link[‘qqun‘]; ?>">QQ交流群
MySQL 数据库地址
MySQL 数据库名
MySQL 用户名
MySQL 密码
MySQL 数据表前缀
MySQL 端口号
管理者用户名
管理者Email
管理者密码
重复密码
$(function () {
$(‘form :input:first‘).select();
$(‘form‘).on(‘submit‘, function (e) {
e.preventDefault();
var form = this;
var $button = $(this).find(‘button‘)
.text(‘安装中...‘)
.prop(‘disabled‘, true);
$.post(‘‘, $(this).serialize())
.done(function (ret) {
if (ret.substr(0, 7) === ‘success‘) {
var retArr = ret.split(/|/);
$(‘#error‘).hide();
$(".form-group", form).remove();
$button.remove();
$("#success").text("安装成功!开始你的<?php echo $sitename; ?>之旅吧!").show();
$buttons = $(".form-buttons", form);
$(‘访问首页‘).appendTo($buttons);
if (typeof retArr[1] !== ‘undefined‘ && retArr[1] !== ‘‘) {
var url = location.href.replace(/install.php/, retArr[1]);
$("#warmtips").html(‘温馨提示:请将以下后台登录入口添加到你的收藏夹,为了你的安全,不要泄漏或发送给他人!如有泄漏请及时修改!‘ + url + ‘‘).show();
$(‘访问后台‘).appendTo($buttons);
}
localStorage.setItem("fastep", "installed");
} else {
$(‘#error‘).show().text(ret);
$button.prop(‘disabled‘, false).text(‘点击安装‘);
$("html,body").animate({
scrollTop: 0
}, 500);
}
})
.fail(function (data) {
$(‘#error‘).show().text(‘发生错误:
‘ + data.responseText);
$button.prop(‘disabled‘, false).text(‘点击安装‘);
$("html,body").animate({
scrollTop: 0
}, 500);
});
return false;
});
});