FastAdmin框架学习-安装
命令行下载php依赖包前置操作
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
使用命令行下载FastAdmin源码包
git clone https://gitee.com/karson/fastadmin.git
cd fastadmin
bower install #下载前端插件依赖包
composer install #下载php依赖包
其中,前端依赖包会被下载到public/assets/libs
目录下,这个目录在.bowerrc
文件中被定义。
PHP依赖包会被下载到verdor
目录下,通过自动加载机制引用依赖文件。同时,thinkphp核心目录也会被下载到根目录下。
添加虚拟主机到public目录并访问
index.php文件解析
添加完虚拟主机并访问站点后,apache会自动访问到index.php文件。
define('APP_PATH', __DIR__ . '/../application/');
// 判断是否安装FastAdmin
if (!is_file(APP_PATH . 'admin/command/Install/install.lock'))
{
header("location:./install.php");
exit;
}
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
如上为index.php的源码,跟tp框架的原index.php文件不同的地方是,fastadmin在此处加入了判断是否已经安装fastadmin的判断。所谓的安装fastadmin,就是为fastadmin程序设定数据库的地址等,以及给后端管理员设定一个基本的用户名和密码。
如果未安装,网页会跳转到fastAdmin的安装界面。
install.php文件解析
define('DS', DIRECTORY_SEPARATOR);
// 定义根目录
define('ROOT_PATH', __DIR__ . DS . '..' . DS);
// 定义应用目录
define('APP_PATH', ROOT_PATH . 'application' . DS);
// 安装包目录
define('INSTALL_PATH', APP_PATH . 'admin' . DS . 'command' . DS . 'Install' . DS);
install文件就是一个最普通的php文件,里面没有使用任何的框架或者面向对象的方法等。在文件的一开始,定义了一些基本常量。
// 判断文件或目录是否有写的权限
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 = "FastAdmin";
$link = array(
'qqun' => "https://jq.qq.com/?_wv=1027&k=487PNBb",
'gitee' => 'https://gitee.com/karson/fastadmin/attach_files',
'home' => 'https://www.fastadmin.net?ref=install',
'forum' => 'https://forum.fastadmin.net?ref=install',
'doc' => 'https://doc.fastadmin.net?ref=install',
);
// 检测目录是否存在
$checkDirs = [
'thinkphp',
'vendor',
'public' . DS . 'assets' . DS . 'libs'
];
//缓存目录
$runtimeDir = APP_PATH . 'runtime';
//错误信息
$errInfo = '';
//数据库配置文件
$dbConfigFile = APP_PATH . 'database.php';
//后台入口文件
$adminFile = ROOT_PATH . 'public' . DS . 'admin.php';
基本的变量,用于后面的网页渲染,逻辑判断。
// 锁定的文件
$lockFile = INSTALL_PATH . 'install.lock';
//如果lockFile已经存在,代表已经安装fastadmin。
if (is_file($lockFile)) {
$errInfo = "当前已经安装{$sitename},如果需要重新安装,请手动移除application/admin/command/Install/install.lock文件";
} else {
//如果php小于5.5版本,则无法安装。
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
$errInfo = "当前版本(" . PHP_VERSION . ")过低,请使用PHP5.5以上版本";
} else {
//如果没有开启PDO扩展,也无法安装。因为安装脚本后面会使用PDO扩展去执行初始化的sql语句。
if (!extension_loaded("PDO")) {
$errInfo = "当前未开启PDO,无法进行安装";
} else {
//如果数据库配置文件不可写
if (!is_really_writable($dbConfigFile)) {
//判断是不是配置了open_basedir,open_basedir规定了php程序能够访问的目录范围
$open_basedir = ini_get('open_basedir');
//如果在php.ini中注释掉这一行,那么就不会开启open_basedir
if ($open_basedir) {
//字符串转数组
$dirArr = explode(PATH_SEPARATOR, $open_basedir);
//判断当前目录是不是在open_basedir目录中,一般来说不会出现这种情况,因为这个目录不会无缘无故的被配置到open_basedir目录中。反而是open_basedir目录会没有将当前站点的目录配置进去而报错。
if ($dirArr && in_array(__DIR__, $dirArr)) {
$errInfo = '当前服务器因配置了open_basedir,导致无法读取父目录<br><a href="https://forum.fastadmin.net/thread/1145?ref=install" target="_blank">点击查看解决办法</a>';
}
}
if (!$errInfo) {
$errInfo = '当前权限不足,无法写入配置文件application/database.php<br><a href="https://forum.fastadmin.net/thread/1145?ref=install" target="_blank">点击查看解决办法</a>';
}
} else {
//如果没有composer install,就会缺失thinkphp和vendor目录。
$dirArr = [];
foreach ($checkDirs as $k => $v) {
if (!is_dir(ROOT_PATH . $v)) {
$errInfo = '当前代码仅包含核心代码,请前往官网下载完整包或资源包覆盖后再尝试安装,<a href="https://www.fastadmin.net/download.html?ref=install" target="_blank">立即前往下载</a>';
break;
}
}
}
}
}
}
判断fastadmin是否安装的核心逻辑。
//如果是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'] : 'fastadmin';
$mysqlPrefix = isset($_POST['mysqlPrefix']) ? $_POST['mysqlPrefix'] : 'fa_';
$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'] : '[email protected]';
//对数据进行判断
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 . 'fastadmin.sql');
if (!$sql) {
throw new Exception("无法读取application/admin/command/Install/fastadmin.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}"};
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("无法写入数据库信息到application/database.php文件,请检查是否有写权限");
}
//检测能否成功写入lock文件
$result = @file_put_contents($lockFile, 1);
if (!$result) {
throw new Exception("无法写入安装锁定到application/admin/command/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 = '';
//将后台管理的入口文件改名
//这里如果已经安装过一次,第二次就不会再改名,因为找不到admin.php文件了。
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;
}