作者 Karson

新增短信发送单IP总数限制

新增$selectpageFields字段用于控制selectpage的字段
修复指定语言不起作用的Bug
修复Selectpage过滤字段不起作用的Bug
优化跳转页面,允许页面停留显示
优化弹窗内部显示,去除min-height限制
优化Citypicker城市数据,使用最新数据源
优化install.php错误提醒
优化部分多语言显示
... ... @@ -38,6 +38,14 @@ return [
'Wipe template cache' => '清除模板缓存',
'Wipe addons cache' => '清除插件缓存',
'Check for updates' => '检测更新',
'Discover new version' => '发现新版本',
'Go to download' => '去下载更新',
'Currently is the latest version' => '当前已经是最新版本',
'Ignore this version' => '忽略此次更新',
'Do not remind again' => '不再提示',
'Your current version' => '你的版本是',
'New version' => '新版本',
'Release notes' => '更新说明',
'Latest news' => '最新消息',
'View more' => '查看更多',
'Links' => '相关链接',
... ...
... ... @@ -377,6 +377,7 @@ class Auth extends \fast\Auth
continue;
}
$select_id = $v['name'] == $fixedPage ? $v['id'] : $select_id;
$v['icon'] = $v['icon'] . ' fa-fw';
$v['url'] = '/' . $module . '/' . $v['name'];
$v['badge'] = isset($badgeList[$v['name']]) ? $badgeList[$v['name']] : '';
$v['py'] = $pinyin->abbr($v['title'], '');
... ...
... ... @@ -12,24 +12,22 @@ trait Backend
{
//设置过滤方法
$this->request->filter(['strip_tags']);
if ($this->request->isAjax())
{
if ($this->request->isAjax()) {
//如果发送的来源是Selectpage,则转发到Selectpage
if ($this->request->request('keyField'))
{
if ($this->request->request('keyField')) {
return $this->selectpage();
}
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$list = collection($list)->toArray();
$result = array("total" => $total, "rows" => $list);
... ... @@ -46,21 +44,20 @@ trait Backend
{
//设置过滤方法
$this->request->filter(['strip_tags']);
if ($this->request->isAjax())
{
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->onlyTrashed()
->where($where)
->order($sort, $order)
->count();
->onlyTrashed()
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->onlyTrashed()
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
->onlyTrashed()
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
... ... @@ -74,36 +71,26 @@ trait Backend
*/
public function add()
{
if ($this->request->isPost())
{
if ($this->request->isPost()) {
$params = $this->request->post("row/a");
if ($params)
{
if ($this->dataLimit && $this->dataLimitFieldAutoFill)
{
if ($params) {
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$params[$this->dataLimitField] = $this->auth->id;
}
try
{
try {
//是否采用模型验证
if ($this->modelValidate)
{
if ($this->modelValidate) {
$name = basename(str_replace('\\', '/', get_class($this->model)));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : true) : $this->modelValidate;
$this->model->validate($validate);
}
$result = $this->model->allowField(true)->save($params);
if ($result !== false)
{
if ($result !== false) {
$this->success();
}
else
{
} else {
$this->error($this->model->getError());
}
}
catch (\think\exception\PDOException $e)
{
} catch (\think\exception\PDOException $e) {
$this->error($e->getMessage());
}
}
... ... @@ -121,39 +108,28 @@ trait Backend
if (!$row)
$this->error(__('No Results were found'));
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds))
{
if (!in_array($row[$this->dataLimitField], $adminIds))
{
if (is_array($adminIds)) {
if (!in_array($row[$this->dataLimitField], $adminIds)) {
$this->error(__('You have no permission'));
}
}
if ($this->request->isPost())
{
if ($this->request->isPost()) {
$params = $this->request->post("row/a");
if ($params)
{
try
{
if ($params) {
try {
//是否采用模型验证
if ($this->modelValidate)
{
if ($this->modelValidate) {
$name = basename(str_replace('\\', '/', get_class($this->model)));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : true) : $this->modelValidate;
$row->validate($validate);
}
$result = $row->allowField(true)->save($params);
if ($result !== false)
{
if ($result !== false) {
$this->success();
}
else
{
} else {
$this->error($row->getError());
}
}
catch (\think\exception\PDOException $e)
{
} catch (\think\exception\PDOException $e) {
$this->error($e->getMessage());
}
}
... ... @@ -168,26 +144,20 @@ trait Backend
*/
public function del($ids = "")
{
if ($ids)
{
if ($ids) {
$pk = $this->model->getPk();
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds))
{
if (is_array($adminIds)) {
$count = $this->model->where($this->dataLimitField, 'in', $adminIds);
}
$list = $this->model->where($pk, 'in', $ids)->select();
$count = 0;
foreach ($list as $k => $v)
{
foreach ($list as $k => $v) {
$count += $v->delete();
}
if ($count)
{
if ($count) {
$this->success();
}
else
{
} else {
$this->error(__('No rows were deleted'));
}
}
... ... @@ -201,26 +171,20 @@ trait Backend
{
$pk = $this->model->getPk();
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds))
{
if (is_array($adminIds)) {
$count = $this->model->where($this->dataLimitField, 'in', $adminIds);
}
if ($ids)
{
if ($ids) {
$this->model->where($pk, 'in', $ids);
}
$count = 0;
$list = $this->model->onlyTrashed()->select();
foreach ($list as $k => $v)
{
foreach ($list as $k => $v) {
$count += $v->delete(true);
}
if ($count)
{
if ($count) {
$this->success();
}
else
{
} else {
$this->error(__('No rows were deleted'));
}
$this->error(__('Parameter %s can not be empty', 'ids'));
... ... @@ -233,17 +197,18 @@ trait Backend
{
$pk = $this->model->getPk();
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds))
{
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
if ($ids)
{
if ($ids) {
$this->model->where($pk, 'in', $ids);
}
$count = $this->model->restore('1=1');
if ($count)
{
$count = 0;
$list = $this->model->onlyTrashed()->select();
foreach ($list as $index => $item) {
$count += $item->restore();
}
if ($count) {
$this->success();
}
$this->error(__('No rows were updated'));
... ... @@ -255,32 +220,26 @@ trait Backend
public function multi($ids = "")
{
$ids = $ids ? $ids : $this->request->param("ids");
if ($ids)
{
if ($this->request->has('params'))
{
if ($ids) {
if ($this->request->has('params')) {
parse_str($this->request->post("params"), $values);
$values = array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));
if ($values)
{
if ($values) {
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds))
{
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$this->model->where($this->model->getPk(), 'in', $ids);
$count = $this->model->allowField(true)->isUpdate(true)->save($values);
if ($count)
{
$this->success();
$count = 0;
$list = $this->model->where($this->model->getPk(), 'in', $ids)->select();
foreach ($list as $index => $item) {
$count += $item->allowField(true)->isUpdate(true)->save($values);
}
else
{
if ($count) {
$this->success();
} else {
$this->error(__('No rows were updated'));
}
}
else
{
} else {
$this->error(__('You have no permission'));
}
}
... ... @@ -294,24 +253,19 @@ trait Backend
protected function import()
{
$file = $this->request->request('file');
if (!$file)
{
if (!$file) {
$this->error(__('Parameter %s can not be empty', 'file'));
}
$filePath = ROOT_PATH . DS . 'public' . DS . $file;
if (!is_file($filePath))
{
if (!is_file($filePath)) {
$this->error(__('No results were found'));
}
$PHPReader = new \PHPExcel_Reader_Excel2007();
if (!$PHPReader->canRead($filePath))
{
if (!$PHPReader->canRead($filePath)) {
$PHPReader = new \PHPExcel_Reader_Excel5();
if (!$PHPReader->canRead($filePath))
{
if (!$PHPReader->canRead($filePath)) {
$PHPReader = new \PHPExcel_Reader_CSV();
if (!$PHPReader->canRead($filePath))
{
if (!$PHPReader->canRead($filePath)) {
$this->error(__('Unknown data format'));
}
}
... ... @@ -324,14 +278,10 @@ trait Backend
$database = \think\Config::get('database.database');
$fieldArr = [];
$list = db()->query("SELECT COLUMN_NAME,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?", [$table, $database]);
foreach ($list as $k => $v)
{
if ($importHeadType == 'comment')
{
foreach ($list as $k => $v) {
if ($importHeadType == 'comment') {
$fieldArr[$v['COLUMN_COMMENT']] = $v['COLUMN_NAME'];
}
else
{
} else {
$fieldArr[$v['COLUMN_NAME']] = $v['COLUMN_NAME'];
}
}
... ... @@ -341,47 +291,36 @@ trait Backend
$allColumn = $currentSheet->getHighestDataColumn(); //取得最大的列号
$allRow = $currentSheet->getHighestRow(); //取得一共有多少行
$maxColumnNumber = \PHPExcel_Cell::columnIndexFromString($allColumn);
for ($currentRow = 1; $currentRow <= 1; $currentRow++)
{
for ($currentColumn = 0; $currentColumn < $maxColumnNumber; $currentColumn++)
{
for ($currentRow = 1; $currentRow <= 1; $currentRow++) {
for ($currentColumn = 0; $currentColumn < $maxColumnNumber; $currentColumn++) {
$val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
$fields[] = $val;
}
}
$insert = [];
for ($currentRow = 2; $currentRow <= $allRow; $currentRow++)
{
for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) {
$values = [];
for ($currentColumn = 0; $currentColumn < $maxColumnNumber; $currentColumn++)
{
for ($currentColumn = 0; $currentColumn < $maxColumnNumber; $currentColumn++) {
$val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
$values[] = is_null($val) ? '' : $val;
}
$row = [];
$temp = array_combine($fields, $values);
foreach ($temp as $k => $v)
{
if (isset($fieldArr[$k]) && $k !== '')
{
foreach ($temp as $k => $v) {
if (isset($fieldArr[$k]) && $k !== '') {
$row[$fieldArr[$k]] = $v;
}
}
if ($row)
{
if ($row) {
$insert[] = $row;
}
}
if (!$insert)
{
if (!$insert) {
$this->error(__('No rows were updated'));
}
try
{
try {
$this->model->saveAll($insert);
}
catch (\think\exception\PDOException $exception)
{
} catch (\think\exception\PDOException $exception) {
$this->error($exception->getMessage());
}
... ...
... ... @@ -24,7 +24,7 @@
<div>
<form onsubmit="return false;">
<div class="input-group input-groupp-md">
<div class="input-group-addon">搜索图标</div>
<div class="input-group-addon">{:__('Search icon')}</div>
<input class="js-icon-search form-control" type="text" placeholder="">
</div>
</form>
... ...
... ... @@ -23,8 +23,8 @@ class Sms extends Api
/**
* 发送验证码
*
* @param string $mobile 手机号
* @param string $event 事件名称
* @param string $mobile 手机号
* @param string $event 事件名称
*/
public function send()
{
... ... @@ -32,37 +32,34 @@ class Sms extends Api
$event = $this->request->request("event");
$event = $event ? $event : 'register';
if (!$mobile || !\think\Validate::regex($mobile, "^1\d{10}$")) {
$this->error(__('手机号不正确'));
}
$last = Smslib::get($mobile, $event);
if ($last && time() - $last['createtime'] < 60)
{
if ($last && time() - $last['createtime'] < 60) {
$this->error(__('发送频繁'));
}
$ipSendTotal = \app\common\model\Sms::where(['ip' => $this->request->ip()])->whereTime('createtime', '-1 hours')->count();
if ($ipSendTotal >= 5) {
$this->error(__('发送频繁'));
}
if ($event)
{
if ($event) {
$userinfo = User::getByMobile($mobile);
if ($event == 'register' && $userinfo)
{
if ($event == 'register' && $userinfo) {
//已被注册
$this->error(__('已被注册'));
}
else if (in_array($event, ['changemobile']) && $userinfo)
{
} else if (in_array($event, ['changemobile']) && $userinfo) {
//被占用
$this->error(__('已被占用'));
}
else if (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo)
{
} else if (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo) {
//未注册
$this->error(__('未注册'));
}
}
$ret = Smslib::send($mobile, NULL, $event);
if ($ret)
{
if ($ret) {
$this->success(__('发送成功'));
}
else
{
} else {
$this->error(__('发送失败'));
}
}
... ... @@ -70,9 +67,9 @@ class Sms extends Api
/**
* 检测验证码
*
* @param string $mobile 手机号
* @param string $event 事件名称
* @param string $captcha 验证码
* @param string $mobile 手机号
* @param string $event 事件名称
* @param string $captcha 验证码
*/
public function check()
{
... ... @@ -81,32 +78,26 @@ class Sms extends Api
$event = $event ? $event : 'register';
$captcha = $this->request->request("captcha");
if ($event)
{
if (!$mobile || !\think\Validate::regex($mobile, "^1\d{10}$")) {
$this->error(__('手机号不正确'));
}
if ($event) {
$userinfo = User::getByMobile($mobile);
if ($event == 'register' && $userinfo)
{
if ($event == 'register' && $userinfo) {
//已被注册
$this->error(__('已被注册'));
}
else if (in_array($event, ['changemobile']) && $userinfo)
{
} else if (in_array($event, ['changemobile']) && $userinfo) {
//被占用
$this->error(__('已被占用'));
}
else if (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo)
{
} else if (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo) {
//未注册
$this->error(__('未注册'));
}
}
$ret = Smslib::check($mobile, $captcha, $event);
if ($ret)
{
if ($ret) {
$this->success(__('成功'));
}
else
{
} else {
$this->error(__('验证码不正确'));
}
}
... ...
... ... @@ -153,7 +153,7 @@ class Api
*/
protected function loadlang($name)
{
Lang::load(APP_PATH . $this->request->module() . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $name) . '.php');
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
}
/**
... ...
... ... @@ -89,6 +89,11 @@ class Backend extends Controller
protected $multiFields = 'status';
/**
* Selectpage可显示的字段
*/
protected $selectpageFields = '*';
/**
* 导入文件首行类型
* 支持comment/name
* 表示注释或字段名
... ... @@ -166,7 +171,7 @@ class Backend extends Controller
}
// 语言检测
$lang = strip_tags(Lang::detect());
$lang = strip_tags($this->request->langset());
$site = Config::get("site");
... ... @@ -212,7 +217,7 @@ class Backend extends Controller
*/
protected function loadlang($name)
{
Lang::load(APP_PATH . $this->request->module() . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $name) . '.php');
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
}
/**
... ... @@ -402,7 +407,7 @@ class Backend extends Controller
//分页大小
$pagesize = $this->request->request("pageSize");
//搜索条件
$andor = $this->request->request("andOr");
$andor = $this->request->request("andOr", "and", "strtoupper");
//排序方式
$orderby = (array)$this->request->request("orderBy/a");
//显示的字段
... ... @@ -426,10 +431,10 @@ class Backend extends Controller
$where = [$primarykey => ['in', $primaryvalue]];
} else {
$where = function ($query) use ($word, $andor, $field, $searchfield, $custom) {
$logic = $andor == 'AND' ? '&' : '|';
$searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield;
foreach ($word as $k => $v) {
foreach ($searchfield as $m => $n) {
$query->where($n, "like", "%{$v}%", $andor);
}
$query->where(str_replace(',', $logic, $searchfield), "like", "%{$v}%");
}
if ($custom && is_array($custom)) {
foreach ($custom as $k => $v) {
... ... @@ -448,12 +453,18 @@ class Backend extends Controller
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$list = $this->model->where($where)
$datalist = $this->model->where($where)
->order($order)
->page($page, $pagesize)
->field("{$primarykey},{$field}")
->field("password,salt", true)
->field($this->selectpageFields)
->select();
foreach ($datalist as $index => $item) {
unset($item['password'], $item['salt']);
$list[] = [
$primarykey => isset($item[$primarykey]) ? $item[$primarykey] : '',
$field => isset($item[$field]) ? $item[$field] : ''
];
}
}
//这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
return json(['list' => $list, 'total' => $total]);
... ...
... ... @@ -34,7 +34,7 @@ class Frontend extends Controller
/**
* 权限Auth
* @var Auth
* @var Auth
*/
protected $auth = null;
... ... @@ -47,8 +47,7 @@ class Frontend extends Controller
$actionname = strtolower($this->request->action());
// 如果有使用模板布局
if ($this->layout)
{
if ($this->layout) {
$this->view->engine->layout('layout/' . $this->layout);
}
$this->auth = Auth::instance();
... ... @@ -60,30 +59,23 @@ class Frontend extends Controller
// 设置当前请求的URI
$this->auth->setRequestUri($path);
// 检测是否需要验证登录
if (!$this->auth->match($this->noNeedLogin))
{
if (!$this->auth->match($this->noNeedLogin)) {
//初始化
$this->auth->init($token);
//检测是否登录
if (!$this->auth->isLogin())
{
if (!$this->auth->isLogin()) {
$this->error(__('Please login first'), 'user/login');
}
// 判断是否需要验证权限
if (!$this->auth->match($this->noNeedRight))
{
if (!$this->auth->match($this->noNeedRight)) {
// 判断控制器和方法判断是否有对应权限
if (!$this->auth->check($path))
{
if (!$this->auth->check($path)) {
$this->error(__('You have no permission'));
}
}
}
else
{
} else {
// 如果有传递token才验证是否登录状态
if ($token)
{
if ($token) {
$this->auth->init($token);
}
}
... ... @@ -91,7 +83,7 @@ class Frontend extends Controller
$this->view->assign('user', $this->auth->getUser());
// 语言检测
$lang = strip_tags(Lang::detect());
$lang = strip_tags($this->request->langset());
$site = Config::get("site");
... ... @@ -129,13 +121,13 @@ class Frontend extends Controller
*/
protected function loadlang($name)
{
Lang::load(APP_PATH . $this->request->module() . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $name) . '.php');
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
}
/**
* 渲染配置信息
* @param mixed $name 键名或数组
* @param mixed $value 值
* @param mixed $value 值
*/
protected function assignconfig($name, $value = '')
{
... ...
{__NOLAYOUT__}<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{:__('Warning')}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
<style type="text/css">
*{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased}
body{padding:70px 0;background:#edf1f4;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333}
a{outline:0;color:#3498db;text-decoration:none;cursor:pointer}
.system-message{margin:20px 5%;padding:40px 20px;background:#fff;box-shadow:1px 1px 1px hsla(0,0%,39%,.1);text-align:center}
.system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:40px}
.system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400}
.system-message .jump{font-size:14px}
.system-message .jump a{color:#333}
.system-message p{font-size:9pt;line-height:20px}
.system-message .btn{display:inline-block;margin-right:10px;width:138px;height:2pc;border:1px solid #44a0e8;border-radius:30px;color:#44a0e8;text-align:center;font-size:1pc;line-height:2pc;margin-bottom:5px;}
.success .btn{border-color:#69bf4e;color:#69bf4e}
.error .btn{border-color:#ff8992;color:#ff8992}
.info .btn{border-color:#3498db;color:#3498db}
.copyright p{width:100%;color:#919191;text-align:center;font-size:10px}
.system-message .btn-grey{border-color:#bbb;color:#bbb}
.clearfix:after{clear:both;display:block;visibility:hidden;height:0;content:"."}
@media (max-width:768px){body {padding:20px 0;}}
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{:__('Warning')}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
<style type="text/css">
*{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased}
body{padding:70px 0;background:#edf1f4;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333}
a{outline:0;color:#3498db;text-decoration:none;cursor:pointer}
.system-message{margin:20px 5%;padding:40px 20px;background:#fff;box-shadow:1px 1px 1px hsla(0,0%,39%,.1);text-align:center}
.system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:40px}
.system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400}
.system-message .jump{font-size:14px}
.system-message .jump a{color:#333}
.system-message p{font-size:9pt;line-height:20px}
.system-message .btn{display:inline-block;margin-right:10px;width:138px;height:2pc;border:1px solid #44a0e8;border-radius:30px;color:#44a0e8;text-align:center;font-size:1pc;line-height:2pc;margin-bottom:5px;}
.success .btn{border-color:#69bf4e;color:#69bf4e}
.error .btn{border-color:#ff8992;color:#ff8992}
.info .btn{border-color:#3498db;color:#3498db}
.copyright p{width:100%;color:#919191;text-align:center;font-size:10px}
.system-message .btn-grey{border-color:#bbb;color:#bbb}
.clearfix:after{clear:both;display:block;visibility:hidden;height:0;content:"."}
@media (max-width:768px){body {padding:20px 0;}}
@media (max-width:480px){.system-message h1{font-size:30px;}}
</style>
</head>
<body>
{php}$codeText=$code == 1 ? 'success' : ($code == 0 ? 'error' : 'info');{/php}
<div class="system-message {$codeText}">
<div class="image">
<img src="__CDN__/assets/img/{$codeText}.svg" alt="" width="150" />
</div>
<h1>{$msg}</h1>
<p class="jump">
{:__('This page will be re-directed in %s seconds', '<span id="wait">' . $wait . '</span>')}
</p>
<p class="clearfix">
<a href="javascript:history.go(-1);" class="btn btn-grey">{:__('Go back')}</a>
<a href="{$url}" class="btn btn-primary">{:__('Jump now')}</a>
</p>
</div>
<div class="copyright">
<p>Powered by <a href="https://www.fastadmin.net/?ref=jump">FastAdmin</a></p>
</div>
<script type="text/javascript">
(function () {
var wait = document.getElementById('wait');
var interval = setInterval(function () {
var time = --wait.innerHTML;
if (time <= 0) {
location.href = "{$url}";
clearInterval(interval);
}
}, 1000);
})();
</script>
</body>
</html>
</style>
</head>
<body>
{php}$codeText=$code == 1 ? 'success' : ($code == 0 ? 'error' : 'info');{/php}
<div class="system-message {$codeText}">
<div class="image">
<img src="__CDN__/assets/img/{$codeText}.svg" alt="" width="150" />
</div>
<h1>{$msg}</h1>
{if $url}
<p class="jump">
{:__('This page will be re-directed in %s seconds', '<span id="wait">' . $wait . '</span>')}
</p>
{/if}
<p class="clearfix">
<a href="__PUBLIC__" class="btn btn-grey">{:__('Go back')}</a>
{if $url}
<a href="{$url}" class="btn btn-primary">{:__('Jump now')}</a>
{/if}
</p>
</div>
<div class="copyright">
<p>Powered by <a href="https://www.fastadmin.net/?ref=jump">FastAdmin</a></p>
</div>
{if $url}
<script type="text/javascript">
(function () {
var wait = document.getElementById('wait');
var interval = setInterval(function () {
var time = --wait.innerHTML;
if (time <= 0) {
location.href = "{$url}";
clearInterval(interval);
}
}, 1000);
})();
</script>
{/if}
</body>
</html>
\ No newline at end of file
... ...
... ... @@ -272,7 +272,7 @@ return [
//自动检测更新
'checkupdate' => false,
//版本号
'version' => '1.0.0.20180513_beta',
'version' => '1.0.0.20180618_beta',
//API接口地址
'api_url' => 'https://api.fastadmin.net',
],
... ...
<div class="sidenav">
<ul class="list-group">
<li class="list-group-heading">{:__('User center')}</li>
<li class="list-group-item {:$config['actionname']=='index'?'active':''}"> <a href="{:url('user/index')}"><i class="fa fa-user-circle"></i> {:__('User center')}</a> </li>
<li class="list-group-item {:$config['actionname']=='profile'?'active':''}"> <a href="{:url('user/profile')}"><i class="fa fa-user-o"></i> {:__('Profile')}</a> </li>
<li class="list-group-item {:$config['actionname']=='changepwd'?'active':''}"> <a href="{:url('user/changepwd')}"><i class="fa fa-key"></i> {:__('Change password')}</a> </li>
<li class="list-group-item {:$config['actionname']=='logout'?'active':''}"> <a href="{:url('user/logout')}"><i class="fa fa-sign-out"></i> {:__('Sign out')}</a> </li>
<li class="list-group-item {:$config['actionname']=='index'?'active':''}"> <a href="{:url('user/index')}"><i class="fa fa-user-circle fa-fw"></i> {:__('User center')}</a> </li>
<li class="list-group-item {:$config['actionname']=='profile'?'active':''}"> <a href="{:url('user/profile')}"><i class="fa fa-user-o fa-fw"></i> {:__('Profile')}</a> </li>
<li class="list-group-item {:$config['actionname']=='changepwd'?'active':''}"> <a href="{:url('user/changepwd')}"><i class="fa fa-key fa-fw"></i> {:__('Change password')}</a> </li>
<li class="list-group-item {:$config['actionname']=='logout'?'active':''}"> <a href="{:url('user/logout')}"><i class="fa fa-sign-out fa-fw"></i> {:__('Sign out')}</a> </li>
</ul>
</div>
\ No newline at end of file
... ...
... ... @@ -38,13 +38,13 @@
{/if}
<ul class="dropdown-menu">
{if $user}
<li><a href="{:url('user/index')}"><i class="fa fa-user-circle"></i>{:__('User center')}</a></li>
<li><a href="{:url('user/profile')}"><i class="fa fa-user-o"></i>{:__('Profile')}</a></li>
<li><a href="{:url('user/changepwd')}"><i class="fa fa-key"></i>{:__('Change password')}</a></li>
<li><a href="{:url('user/logout')}"><i class="fa fa-sign-out"></i>{:__('Sign out')}</a></li>
<li><a href="{:url('user/index')}"><i class="fa fa-user-circle fa-fw"></i>{:__('User center')}</a></li>
<li><a href="{:url('user/profile')}"><i class="fa fa-user-o fa-fw"></i>{:__('Profile')}</a></li>
<li><a href="{:url('user/changepwd')}"><i class="fa fa-key fa-fw"></i>{:__('Change password')}</a></li>
<li><a href="{:url('user/logout')}"><i class="fa fa-sign-out fa-fw"></i>{:__('Sign out')}</a></li>
{else /}
<li><a href="{:url('user/login')}"><i class="fa fa-sign-in"></i> {:__('Sign in')}</a></li>
<li><a href="{:url('user/register')}"><i class="fa fa-user-o"></i> {:__('Sign up')}</a></li>
<li><a href="{:url('user/login')}"><i class="fa fa-sign-in fa-fw"></i> {:__('Sign in')}</a></li>
<li><a href="{:url('user/register')}"><i class="fa fa-user-o fa-fw"></i> {:__('Sign up')}</a></li>
{/if}
</ul>
... ...
<style>
.basicinfo {
margin: 15px 0;
}
.basicinfo .row > .col-xs-4 {
padding-right: 0;
}
.basicinfo .row > div {
margin: 5px 0;
}
</style>
<div id="content-container" class="container">
<div class="row">
<div class="col-md-3">
... ... @@ -6,48 +19,53 @@
<div class="col-md-9">
<div class="panel panel-default ">
<div class="panel-body">
<h2 class="page-header">{:__('User center')}</h2>
<h2 class="page-header">
{:__('User center')}
<a href="{:url('user/profile')}" class="btn btn-success pull-right"><i class="fa fa-pencil"></i>
{:__('Profile')}</a>
</h2>
<div class="row user-baseinfo">
<div class="col-md-3 col-sm-3 col-xs-2 text-center user-center">
<a href="{:url('user/profile')}" title="{:__('Click to edit')}">
<span class="avatar-img"><img src="{$user.avatar}" alt=""></span>
</a>
</div>
<div class="col-md-7 col-sm-7 col-xs-10">
<div class="col-md-9 col-sm-9 col-xs-10">
<!-- Content -->
<div class="ui-content">
<!-- Heading -->
<h4><a href="{:url('user/profile')}">{$user.username}</a></h4>
<h4><a href="{:url('user/profile')}">{$user.nickname}</a></h4>
<!-- Paragraph -->
<p><a href="{:url('user/profile')}">{$user.bio|default=__("This guy hasn't written anything yet")}</a></p>
<p>
<a href="{:url('user/profile')}">
{$user.bio|default=__("This guy hasn't written anything yet")}
</a>
</p>
<!-- Success -->
<div style="margin-top:15px;">
<table class="table">
<tbody><tr>
<th>{:__('Lv')}</th>
<td><a href="javascript:;" class="viewlv">{$user.level}</a></td>
<th>{:__('Score')}</th>
<td><a href="javascript:;" class="viewscore">{$user.score}</a></td>
</tr>
<tr>
<th>{:__('Successions')}</th>
<td>{$user.successions} {:__('Day')}</td>
<th>{:__('Maxsuccessions')}</th>
<td>{$user.maxsuccessions} {:__('Day')}</td>
</tr>
<tr>
<th>{:__('Logintime')}</th>
<td>{$user.logintime|date="Y-m-d H:i:s",###}</td>
<th>{:__('Prevtime')}</th>
<td>{$user.prevtime|date="Y-m-d H:i:s",###}</td>
</tr>
</tbody></table>
<div class="basicinfo">
<div class="row">
<div class="col-xs-4 col-md-2">{:__('Lv')}</div>
<div class="col-xs-8 col-md-4"><a href="javascript:;" class="viewlv">{$user.level}</a>
</div>
<div class="col-xs-4 col-md-2">{:__('Score')}</div>
<div class="col-xs-8 col-md-4"><a href="javascript:;" class="viewscore">{$user.score}</a>
</div>
</div>
<div class="row">
<div class="col-xs-4 col-md-2">{:__('Successions')}</div>
<div class="col-xs-8 col-md-4">{$user.successions} {:__('Day')}</div>
<div class="col-xs-4 col-md-2">{:__('Maxsuccessions')}</div>
<div class="col-xs-8 col-md-4">{$user.maxsuccessions} {:__('Day')}</div>
</div>
<div class="row">
<div class="col-xs-4 col-md-2">{:__('Logintime')}</div>
<div class="col-xs-8 col-md-4">{$user.logintime|date="Y-m-d H:i:s",###}</div>
<div class="col-xs-4 col-md-2">{:__('Prevtime')}</div>
<div class="col-xs-8 col-md-4">{$user.prevtime|date="Y-m-d H:i:s",###}</div>
</div>
</div>
</div>
</div>
<div class="col-md-2 col-sm-2 col-xs-0 col-pad">
<a href="{:url('user/profile')}" class="btn btn-success hidden-xs"><i class="fa fa-pencil"></i> {:__('Profile')}</a>
</div>
</div>
</div>
</div>
... ...
... ... @@ -28,7 +28,7 @@
"art-template": "^3.1.3",
"requirejs-plugins": "~1.0.3",
"bootstrap-daterangepicker": "~2.1.25",
"city-picker": "~1.1.0",
"fastadmin-citypicker": "~1.3.0",
"fastadmin-cxselect": "~1.4.0",
"fastadmin-dragsort": "~1.0.0",
"fastadmin-addtabs": "~1.0.0",
... ...
... ... @@ -44,9 +44,6 @@ html.ios-fix body {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.content {
min-height: 500px;
}
#header {
background: #fff;
}
... ... @@ -293,9 +290,6 @@ form.form-horizontal .control-label {
color: #2c3e50;
border-right: 1px solid rgba(0, 0, 0, 0.05);
}
.nav-addtabs > li > a i {
margin-right: 3px;
}
.nav-addtabs > li.active > a {
height: 50px;
line-height: 50px;
... ... @@ -419,9 +413,6 @@ form.form-horizontal .control-label {
background: none;
border: none;
}
#secondnav .nav-addtabs > li > a i {
margin-right: 3px;
}
#secondnav .nav-addtabs > li.active {
border-color: #bdbebd;
background-color: #f7f7f7;
... ... @@ -493,6 +484,9 @@ form.form-horizontal .control-label {
.sidebar-menu > li .badge {
margin-top: 0;
}
.sidebar-menu .treeview-menu > li > a {
font-size: inherit;
}
.sidebar-collapse .user-panel > .image img {
width: 25px;
height: 25px;
... ...
... ... @@ -125,10 +125,10 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
success: function (ret) {
if (ret.data && ignoreversion !== ret.data.newversion) {
Layer.open({
title: '发现新版本',
title: __('Discover new version'),
maxHeight: 400,
content: '<h5 style="background-color:#f7f7f7; font-size:14px; padding: 10px;">你的版本是:' + ret.data.version + ',新版本:' + ret.data.newversion + '</h5><span class="label label-danger">更新说明</span><br/>' + ret.data.upgradetext,
btn: ['去下载更新', '忽略此次更新', '不再提示'],
content: '<h5 style="background-color:#f7f7f7; font-size:14px; padding: 10px;">' + __('Your current version') + ':' + ret.data.version + ',' + __('New version') + ':' + ret.data.newversion + '</h5><span class="label label-danger">'+__('Release notes')+'</span><br/>' + ret.data.upgradetext,
btn: [__('Go to download'), __('Ignore this version'), __('Do not remind again')],
btn2: function (index, layero) {
localStorage.setItem("ignoreversion", ret.data.newversion);
},
... ... @@ -141,12 +141,12 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
});
} else {
if (tips) {
Toastr.success("当前已经是最新版本");
Toastr.success(__('Currently is the latest version'));
}
}
}, error: function (e) {
if (tips) {
Toastr.error("发生未知错误:" + e.message);
Toastr.error(__('Unknown data format') + ":" + e.message);
}
}
});
... ... @@ -257,11 +257,15 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
if ($(this).attr("url") == "javascript:;") {
var sonlist = $(".sidebar-menu > li[pid='" + $(this).attr("addtabs") + "']");
sonlist.removeClass("hidden");
var sidenav;
var last_id = $(this).attr("last-id");
if (last_id) {
$(".sidebar-menu > li[pid='" + $(this).attr("addtabs") + "'] a[addtabs='" + last_id + "']").trigger('click');
sidenav = $(".sidebar-menu > li[pid='" + $(this).attr("addtabs") + "'] a[addtabs='" + last_id + "']");
} else {
$(".sidebar-menu > li[pid='" + $(this).attr("addtabs") + "']:first > a").trigger('click');
sidenav = $(".sidebar-menu > li[pid='" + $(this).attr("addtabs") + "']:first > a");
}
if (sidenav) {
sidenav.attr("href") != "javascript:;" && sidenav.trigger('click');
}
} else {
... ... @@ -286,7 +290,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
});
var mobilenav = $(".mobilenav");
$("#firstnav .nav-addtabs li a").each(function(){
$("#firstnav .nav-addtabs li a").each(function () {
mobilenav.append($(this).clone().addClass("btn btn-app"));
});
... ...
define(['fast', 'template'], function (Fast, Template) {
define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
var Frontend = {
api: Fast.api,
init: function () {
... ... @@ -59,6 +59,8 @@ define(['fast', 'template'], function (Fast, Template) {
Frontend.api = $.extend(Fast.api, Frontend.api);
//将Template渲染至全局,以便于在子框架中调用
window.Template = Template;
//将Moment渲染至全局,以便于在子框架中调用
window.Moment = Moment;
//将Frontend渲染至全局,以便于在子框架中调用
window.Frontend = Frontend;
... ...
... ... @@ -48,8 +48,8 @@ require.config({
'cxselect': '../libs/fastadmin-cxselect/js/jquery.cxselect',
'template': '../libs/art-template/dist/template-native',
'selectpage': '../libs/fastadmin-selectpage/selectpage',
'citypicker': '../libs/city-picker/dist/js/city-picker.min',
'citypicker-data': '../libs/city-picker/dist/js/city-picker.data',
'citypicker': '../libs/fastadmin-citypicker/dist/js/city-picker.min',
'citypicker-data': '../libs/fastadmin-citypicker/dist/js/city-picker.data',
},
// shim依赖配置
shim: {
... ... @@ -114,7 +114,7 @@ require.config({
// 'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'],
'validator-lang': ['validator-core'],
// 'selectpage': ['css!../libs/fastadmin-selectpage/selectpage.css'],
'citypicker': ['citypicker-data', 'css!../libs/city-picker/dist/css/city-picker.css']
'citypicker': ['citypicker-data', 'css!../libs/fastadmin-citypicker/dist/css/city-picker.css']
},
baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径
map: {
... ...
... ... @@ -62,8 +62,8 @@ require.config({
'cxselect': '../libs/fastadmin-cxselect/js/jquery.cxselect',
'template': '../libs/art-template/dist/template-native',
'selectpage': '../libs/fastadmin-selectpage/selectpage',
'citypicker': '../libs/city-picker/dist/js/city-picker.min',
'citypicker-data': '../libs/city-picker/dist/js/city-picker.data',
'citypicker': '../libs/fastadmin-citypicker/dist/js/city-picker.min',
'citypicker-data': '../libs/fastadmin-citypicker/dist/js/city-picker.data',
},
// shim依赖配置
shim: {
... ... @@ -128,7 +128,7 @@ require.config({
// 'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'],
'validator-lang': ['validator-core'],
// 'selectpage': ['css!../libs/fastadmin-selectpage/selectpage.css'],
'citypicker': ['citypicker-data', 'css!../libs/city-picker/dist/css/city-picker.css']
'citypicker': ['citypicker-data', 'css!../libs/fastadmin-citypicker/dist/css/city-picker.css']
},
baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径
map: {
... ...
... ... @@ -48,8 +48,8 @@ require.config({
'cxselect': '../libs/fastadmin-cxselect/js/jquery.cxselect',
'template': '../libs/art-template/dist/template-native',
'selectpage': '../libs/fastadmin-selectpage/selectpage',
'citypicker': '../libs/city-picker/dist/js/city-picker.min',
'citypicker-data': '../libs/city-picker/dist/js/city-picker.data'
'citypicker': '../libs/fastadmin-citypicker/dist/js/city-picker.min',
'citypicker-data': '../libs/fastadmin-citypicker/dist/js/city-picker.data'
},
// shim依赖配置
shim: {
... ... @@ -114,7 +114,7 @@ require.config({
// 'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'],
'validator-lang': ['validator-core'],
// 'selectpage': ['css!../libs/fastadmin-selectpage/selectpage.css'],
'citypicker': ['citypicker-data', 'css!../libs/city-picker/dist/css/city-picker.css']
'citypicker': ['citypicker-data', 'css!../libs/fastadmin-citypicker/dist/css/city-picker.css']
},
baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径
map: {
... ...
... ... @@ -57,10 +57,6 @@ html.ios-fix, html.ios-fix body {
-webkit-overflow-scrolling: touch;
}
.content {
min-height: 500px;
}
#header {
background: #fff;
//box-shadow: 0 2px 2px rgba(0,0,0,.05),0 1px 0 rgba(0,0,0,.05);
... ... @@ -346,9 +342,6 @@ form.form-horizontal .control-label {
color: #2c3e50;
border-right: 1px solid rgba(0, 0, 0, 0.05);
}
i {
margin-right: 3px;
}
}
&.active > a {
height: 50px;
... ... @@ -479,9 +472,6 @@ form.form-horizontal .control-label {
overflow: hidden;
background: none;
border: none;
i {
margin-right: 3px;
}
}
&.active {
border-color: #bdbebd;
... ... @@ -565,6 +555,9 @@ form.form-horizontal .control-label {
> li .badge {
margin-top: 0;
}
.treeview-menu > li > a {
font-size:inherit;
}
}
.sidebar-collapse {
... ...
<?php
/**
* FastAdmin安装程序
*
*
* 安装完成后建议删除此文件
* @author Karson
* @website https://www.fastadmin.net
... ... @@ -23,12 +23,10 @@ define('INSTALL_PATH', APP_PATH . 'admin' . DS . 'command' . DS . 'Install' . DS
// 判断文件或目录是否有写的权限
function is_really_writable($file)
{
if (DIRECTORY_SEPARATOR == '/' AND @ ini_get("safe_mode") == FALSE)
{
if (DIRECTORY_SEPARATOR == '/' AND @ ini_get("safe_mode") == FALSE) {
return is_writable($file);
}
if (!is_file($file) OR ( $fp = @fopen($file, "r+")) === FALSE)
{
if (!is_file($file) OR ($fp = @fopen($file, "r+")) === FALSE) {
return FALSE;
}
... ... @@ -63,43 +61,43 @@ $dbConfigFile = APP_PATH . 'database.php';
// 锁定的文件
$lockFile = INSTALL_PATH . 'install.lock';
if (is_file($lockFile))
{
if (is_file($lockFile)) {
$errInfo = "当前已经安装{$sitename},如果需要重新安装,请手动移除application/admin/command/Install/install.lock文件";
}
else if (version_compare(PHP_VERSION, '5.5.0', '<'))
{
} else if (version_compare(PHP_VERSION, '5.5.0', '<')) {
$errInfo = "当前版本(" . PHP_VERSION . ")过低,请使用PHP5.5以上版本";
}
else if (!extension_loaded("PDO"))
{
} else if (!extension_loaded("PDO")) {
$errInfo = "当前未开启PDO,无法进行安装";
}
else if (!is_really_writable($dbConfigFile))
{
$errInfo = '当前权限不足,无法写入配置文件application/database.php<br><a href="https://forum.fastadmin.net/?q=%E6%9D%83%E9%99%90%E4%B8%8D%E8%B6%B3" target="_blank">点击查看解决办法</a>';
}
else
{
} 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,导致无法读取父目录<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 {
$dirArr = [];
foreach ($checkDirs as $k => $v)
{
if (!is_dir(ROOT_PATH . $v))
{
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;
}
}
}
// 当前是POST请求
if (!$errInfo && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == '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 = 3306;
$hostArr = explode(':', $mysqlHostname);
if (count($hostArr) > 1)
{
if (count($hostArr) > 1) {
$mysqlHostname = $hostArr[0];
$mysqlHostport = $hostArr[1];
}
... ... @@ -112,38 +110,26 @@ if (!$errInfo && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD']
$adminPasswordConfirmation = isset($_POST['adminPasswordConfirmation']) ? $_POST['adminPasswordConfirmation'] : '123456';
$adminEmail = isset($_POST['adminEmail']) ? $_POST['adminEmail'] : 'admin@admin.com';
if ($adminPassword !== $adminPasswordConfirmation)
{
if ($adminPassword !== $adminPasswordConfirmation) {
echo "两次输入的密码不一致";
exit;
}
else if (!preg_match("/^\w+$/", $adminUsername))
{
} else if (!preg_match("/^\w+$/", $adminUsername)) {
echo "用户名只能输入字母、数字、下划线";
exit;
}
else if (!preg_match("/^[\S]+$/", $adminPassword))
{
} else if (!preg_match("/^[\S]+$/", $adminPassword)) {
echo "密码不能包含空格";
exit;
}
else if (strlen($adminUsername) < 3 || strlen($adminUsername) > 12)
{
} else if (strlen($adminUsername) < 3 || strlen($adminUsername) > 12) {
echo "用户名请输入3~12位字符";
exit;
}
else if (strlen($adminPassword) < 6 || strlen($adminPassword) > 16)
{
} else if (strlen($adminPassword) < 6 || strlen($adminPassword) > 16) {
echo "密码请输入6~16位字符";
exit;
}
try
{
try {
//检测能否读取安装文件
$sql = @file_get_contents(INSTALL_PATH . 'fastadmin.sql');
if (!$sql)
{
if (!$sql) {
throw new Exception("无法读取application/admin/command/Install/fastadmin.sql文件,请检查是否有读权限");
}
$sql = str_replace("`fa_", "`{$mysqlPrefix}", $sql);
... ... @@ -152,6 +138,13 @@ if (!$errInfo && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD']
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}`");
... ... @@ -159,40 +152,35 @@ if (!$errInfo && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD']
$pdo->exec($sql);
$config = @file_get_contents($dbConfigFile);
$callback = function($matches) use($mysqlHostname, $mysqlHostport, $mysqlUsername, $mysqlPassword, $mysqlDatabase, $mysqlPrefix) {
$callback = function ($matches) use ($mysqlHostname, $mysqlHostport, $mysqlUsername, $mysqlPassword, $mysqlDatabase, $mysqlPrefix) {
$field = ucfirst($matches[1]);
$replace = ${"mysql{$field}"};
if ($matches[1] == 'hostport' && $mysqlHostport == 3306)
{
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)
{
if (!$result) {
throw new Exception("无法写入数据库信息到application/database.php文件,请检查是否有写权限");
}
//检测能否成功写入lock文件
$result = @file_put_contents($lockFile, 1);
if (!$result)
{
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'");
echo "success";
}
catch (Exception $e)
{
} catch (PDOException $e) {
$err = $e->getMessage();
}
catch (PDOException $e)
{
} catch (Exception $e) {
$err = $e->getMessage();
}
echo $err;
... ... @@ -201,242 +189,261 @@ if (!$errInfo && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD']
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>安装<?php echo $sitename; ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
<meta name="renderer" content="webkit">
<style>
body {
background: #fff;
margin: 0;
padding: 0;
line-height: 1.5;
}
body, input, button {
font-family: 'Open Sans', sans-serif;
font-size: 16px;
color: #7E96B3;
}
.container {
max-width: 515px;
margin: 0 auto;
padding: 20px;
text-align: center;
}
a {
color: #18bc9c;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>安装<?php echo $sitename; ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
<meta name="renderer" content="webkit">
<style>
body {
background: #fff;
margin: 0;
padding: 0;
line-height: 1.5;
}
h1 {
margin-top:0;
margin-bottom: 10px;
}
h2 {
font-size: 28px;
font-weight: normal;
color: #3C5675;
margin-bottom: 0;
}
body, input, button {
font-family: 'Open Sans', sans-serif;
font-size: 16px;
color: #7E96B3;
}
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;
}
.container {
max-width: 515px;
margin: 0 auto;
padding: 20px;
text-align: center;
}
#error,.error,#success,.success {
background: #D83E3E;
color: #fff;
padding: 15px 20px;
border-radius: 4px;
margin-bottom: 20px;
}
#success {
background:#3C5675;
}
a {
color: #18bc9c;
text-decoration: none;
}
#error a, .error a {
color:white;
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>
<svg width="100px" height="120px" viewBox="0 0 768 830" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M64.433651,605.899968 C20.067302,536.265612 0,469.698785 0,389.731348 C0,174.488668 171.922656,0 384,0 C596.077344,0 768,174.488668 768,389.731348 C768,469.698785 747.932698,536.265612 703.566349,605.899968 C614.4,753.480595 441.6,870.4 384,870.4 C326.4,870.4 153.6,753.480595 64.433651,605.899968 L64.433651,605.899968 Z" id="body" fill="#18BC9C"></path>
<path d="M429.648991,190.816 L430.160991,190.816 L429.648991,190.816 L429.648991,190.816 Z M429.648991,156 L427.088991,156 C419.408991,157.024 411.728991,160.608 404.560991,168.8 L403.024991,170.848 L206.928991,429.92 C198.736991,441.184 197.712991,453.984 204.368991,466.784 C210.512991,478.048 222.288991,485.728 235.600991,485.728 L336.464991,486.24 L304.208991,673.632 C301.648991,689.504 310.352991,705.376 325.200991,712.032 C329.808991,714.08 334.416991,714.592 339.536991,714.592 C349.776991,714.592 358.992991,709.472 366.160991,700.256 L561.744991,419.168 C569.936991,407.904 570.960991,395.104 564.304991,382.304 C557.648991,369.504 547.408991,363.36 533.072991,363.36 L432.208991,363.36 L463.952991,199.008 C464.464991,196.448 464.976991,193.376 464.976991,190.816 C464.976991,171.872 449.104991,156 431.184991,156 L429.648991,156 L429.648991,156 Z" id="flash" fill="#FFFFFF"></path>
</g>
</svg>
</h1>
<h2>安装 <?php echo $sitename; ?></h2>
<div>
<p>若你在安装中遇到麻烦可点击 <a href="<?php echo $link['doc']; ?>" target="_blank">安装文档</a> <a href="<?php echo $link['forum']; ?>" target="_blank">交流社区</a> <a href="<?php echo $link['qqun']; ?>">QQ交流群</a></p>
<!--<p><?php echo $sitename; ?>还支持在命令行php think install一键安装</p>-->
<form method="post">
<?php if ($errInfo): ?>
<div class="error">
<?php echo $errInfo; ?>
</div>
<?php endif; ?>
<div id="error" style="display:none"></div>
<div id="success" style="display:none"></div>
<div class="form-group">
<div class="form-field">
<label>MySQL 数据库地址</label>
<input type="text" name="mysqlHost" value="127.0.0.1" required="">
</div>
<div class="form-field">
<label>MySQL 数据库名</label>
<input type="text" name="mysqlDatabase" value="fastadmin" required="">
</div>
<div class="form-field">
<label>MySQL 用户名</label>
<input type="text" name="mysqlUsername" value="root" required="">
</div>
<div class="form-field">
<label>MySQL 密码</label>
<input type="password" name="mysqlPassword">
</div>
<div class="form-field">
<label>MySQL 数据表前缀</label>
<input type="text" name="mysqlPrefix" value="fa_">
</div>
</div>
<div class="form-group">
<div class="form-field">
<label>管理者用户名</label>
<input name="adminUsername" value="admin" required="" />
</div>
<div class="form-field">
<label>管理者Email</label>
<input name="adminEmail" value="admin@admin.com" required="">
</div>
<div class="form-field">
<label>管理者密码</label>
<input type="password" name="adminPassword" required="">
</div>
<div class="form-field">
<label>重复密码</label>
<input type="password" name="adminPasswordConfirmation" required="">
</div>
</div>
<div class="form-buttons">
<button type="submit" <?php echo $errInfo ? 'disabled' : '' ?>>点击安装</button>
</div>
</form>
<script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
<script>
$(function () {
$('form :input:first').select();
$('form').on('submit', function (e) {
e.preventDefault();
var $button = $(this).find('button')
.text('安装中...')
.prop('disabled', true);
$.post('', $(this).serialize())
.done(function (ret) {
if (ret === 'success') {
$('#error').hide();
$("#success").text("安装成功!开始你的<?php echo $sitename; ?>之旅吧!").show();
$('<a class="btn" href="./">访问首页</a> <a class="btn" href="./index.php/admin/index/login" style="background:#18bc9c">访问后台</a>').insertAfter($button);
$button.remove();
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('发生错误:\n\n' + data.responseText);
$button.prop('disabled', false).text('点击安装');
$("html,body").animate({
scrollTop: 0
}, 500);
});
return false;
});
});
</script>
a:hover {
text-decoration: underline;
}
h1 {
margin-top: 0;
margin-bottom: 10px;
}
h2 {
font-size: 28px;
font-weight: normal;
color: #3C5675;
margin-bottom: 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;
}
#error, .error, #success, .success {
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;
}
</style>
</head>
<body>
<div class="container">
<h1>
<svg width="100px" height="120px" viewBox="0 0 768 830" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M64.433651,605.899968 C20.067302,536.265612 0,469.698785 0,389.731348 C0,174.488668 171.922656,0 384,0 C596.077344,0 768,174.488668 768,389.731348 C768,469.698785 747.932698,536.265612 703.566349,605.899968 C614.4,753.480595 441.6,870.4 384,870.4 C326.4,870.4 153.6,753.480595 64.433651,605.899968 L64.433651,605.899968 Z"
id="body" fill="#18BC9C"></path>
<path d="M429.648991,190.816 L430.160991,190.816 L429.648991,190.816 L429.648991,190.816 Z M429.648991,156 L427.088991,156 C419.408991,157.024 411.728991,160.608 404.560991,168.8 L403.024991,170.848 L206.928991,429.92 C198.736991,441.184 197.712991,453.984 204.368991,466.784 C210.512991,478.048 222.288991,485.728 235.600991,485.728 L336.464991,486.24 L304.208991,673.632 C301.648991,689.504 310.352991,705.376 325.200991,712.032 C329.808991,714.08 334.416991,714.592 339.536991,714.592 C349.776991,714.592 358.992991,709.472 366.160991,700.256 L561.744991,419.168 C569.936991,407.904 570.960991,395.104 564.304991,382.304 C557.648991,369.504 547.408991,363.36 533.072991,363.36 L432.208991,363.36 L463.952991,199.008 C464.464991,196.448 464.976991,193.376 464.976991,190.816 C464.976991,171.872 449.104991,156 431.184991,156 L429.648991,156 L429.648991,156 Z"
id="flash" fill="#FFFFFF"></path>
</g>
</svg>
</h1>
<h2>安装 <?php echo $sitename; ?></h2>
<div>
<p>若你在安装中遇到麻烦可点击 <a href="<?php echo $link['doc']; ?>" target="_blank">安装文档</a> <a
href="<?php echo $link['forum']; ?>" target="_blank">交流社区</a> <a
href="<?php echo $link['qqun']; ?>">QQ交流群</a></p>
<!--<p><?php echo $sitename; ?>还支持在命令行php think install一键安装</p>-->
<form method="post">
<?php if ($errInfo): ?>
<div class="error">
<?php echo $errInfo; ?>
</div>
<?php endif; ?>
<div id="error" style="display:none"></div>
<div id="success" style="display:none"></div>
<div class="form-group">
<div class="form-field">
<label>MySQL 数据库地址</label>
<input type="text" name="mysqlHost" value="127.0.0.1" required="">
</div>
<div class="form-field">
<label>MySQL 数据库名</label>
<input type="text" name="mysqlDatabase" value="fastadmin" required="">
</div>
<div class="form-field">
<label>MySQL 用户名</label>
<input type="text" name="mysqlUsername" value="root" required="">
</div>
<div class="form-field">
<label>MySQL 密码</label>
<input type="password" name="mysqlPassword">
</div>
<div class="form-field">
<label>MySQL 数据表前缀</label>
<input type="text" name="mysqlPrefix" value="fa_">
</div>
</div>
<div class="form-group">
<div class="form-field">
<label>管理者用户名</label>
<input name="adminUsername" value="admin" required=""/>
</div>
<div class="form-field">
<label>管理者Email</label>
<input name="adminEmail" value="admin@admin.com" required="">
</div>
<div class="form-field">
<label>管理者密码</label>
<input type="password" name="adminPassword" required="">
</div>
<div class="form-field">
<label>重复密码</label>
<input type="password" name="adminPasswordConfirmation" required="">
</div>
</div>
<div class="form-buttons">
<button type="submit" <?php echo $errInfo ? 'disabled' : '' ?>>点击安装</button>
</div>
</div>
</body>
</form>
<script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
<script>
$(function () {
$('form :input:first').select();
$('form').on('submit', function (e) {
e.preventDefault();
var $button = $(this).find('button')
.text('安装中...')
.prop('disabled', true);
$.post('', $(this).serialize())
.done(function (ret) {
if (ret === 'success') {
$('#error').hide();
$("#success").text("安装成功!开始你的<?php echo $sitename; ?>之旅吧!").show();
$('<a class="btn" href="./">访问首页</a> <a class="btn" href="./index.php/admin/index/login" style="background:#18bc9c">访问后台</a>').insertAfter($button);
$button.remove();
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('发生错误:\n\n' + data.responseText);
$button.prop('disabled', false).text('点击安装');
$("html,body").animate({
scrollTop: 0
}, 500);
});
return false;
});
});
</script>
</div>
</div>
</body>
</html>
\ No newline at end of file
... ...