上传兰空图床第一个版本

master
notte 2018-07-08 17:19:22 +08:00
parent 736503a219
commit 8822f941ce
557 changed files with 71823 additions and 4 deletions

View File

@ -4,10 +4,10 @@
## 原程序(已停止维护)
项目:兰空图床
作者WispX
作者博客https://www.wispx.cn/
源项目https://gitee.com/wispx/lsky
- 项目:兰空图床
- 作者WispX
- 作者博客https://www.wispx.cn/
- 源项目https://gitee.com/wispx/lsky
## 新特性

1
app/.htaccess Normal file
View File

@ -0,0 +1 @@
deny from all

10
app/admin/config.php Normal file
View File

@ -0,0 +1,10 @@
<?php
/**
* admin模块配置
* User: WispX
* Date: 2017/9/15
* Time: 15:30
*/
return [
];

View File

@ -0,0 +1,81 @@
<?php
/**
* admin模块共用控制器
* User: WispX
* Date: 2017/9/15
* Time: 15:32
*/
namespace app\admin\controller;
use think\Controller;
use think\Config;
use think\Db;
use think\Exception;
use think\exception\ErrorException;
use think\Request;
class Common extends Controller
{
protected $admin;
protected $web;
protected $conf;
protected $scheme;
public function _initialize()
{
// 检测域名授权
// 不收费了。。
//$auth = json_decode(curl('https://service.lskys.cc/server.php', ['action' => 'auth', 'domain' => $_SERVER['HTTP_HOST']]), true);
//if(!$auth['code']) die('程序未授权请联系QQ<a href="http://wpa.qq.com/msgrd?v=3&uin=1591788658&site=qq&menu=yes">1591788658</a> 授权!');
if(empty(session('admin')) || empty(cookie('admin'))) return $this->redirect('login/');
$this->admin = Db::name('user')->where('username', session('admin'))->find();
if(count($this->admin) > 0) {
$this->web = Config::get('web');
$this->conf = getSystemConf();
$this->conf['file_path'] = Config::get('file_path');
$this->conf['theme_path'] = Config::get('theme_path');
$this->scheme = getSchemeList();
$this->assign('admin', $this->admin);
$this->assign('web', $this->web);
$this->assign('conf', $this->conf);
} else {
session('admin', null);
cookie('admin', null);
return $this->redirect('login/');
}
}
public function index()
{
return $this->fetch();
}
/**
* 自定义加密方式
* @param $str
* @return string
*/
protected function md6($str)
{
return md5("LK{$str}");
}
/**
* 直接返回json
* @param int $code 状态码
* @param string $msg 状态信息
* @param string $data 返回数据(可选)
* @return \think\response\Json
*/
protected function json($code, $msg, $data = '', $url = '', $count = '')
{
$result = ['code' => $code, 'msg' => $msg];
if(!empty($data)) $result['data'] = $data;
if(!empty($url)) $result['url'] = $url;
if(!empty($count)) $result['count'] = $count;
return json($result);
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace app\admin\controller;
use think\Db;
class Console extends Common
{
public function index()
{
$file_db = Db::name('file');
$user_db = Db::name('user');
// 图片数量
$data['img_num'] = $file_db->count();
// 今日新增图片
$data['add_img_num'] = $file_db->where(['upload_time' => ['gt', strtotime(date('Y-m-d', time()))]])->count();
// 用户总数
$data['user_num'] = $user_db->count();
// 今日新增用户
$data['add_user_num'] = $user_db->where(['reg_time' => ['gt', strtotime(date('Y-m-d', time()))]])->count();
// 总占用内存
$data['occupy'] = round($file_db->sum('size') / 1024 / 1024, 2);
// 上传文件限制
$data['upload_max_filesize'] = ini_get('upload_max_filesize');
// 执行时间限制
$data['max_execution_time'] = ini_get('max_execution_time');
// 剩余空间
$data['disk_free_space'] = round((disk_free_space(".") / (1024 * 1024)), 2);
// 获取公告
$data['notice'] = json_decode(curl('https://service.lskys.cc/server.php', ['action' => 'getNoticeAll']), true);
$this->assign('data', $data);
return $this->fetch();
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace app\admin\controller;
class Index extends Common
{
public function index()
{
return $this->fetch();
}
public function logout()
{
session('admin', null);
cookie('admin', null);
return $this->redirect('/');
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace app\admin\controller;
use think\Db;
use think\Request;
class Login extends Common
{
public function _initialize()
{
}
public function index()
{
if(Request::instance()->isAjax()) {
$input = trimArray(Request::instance()->post());
$user_db = Db::name('user');
if(filter_var($input['user'], FILTER_VALIDATE_EMAIL)) {
// 验证邮箱
$where = ['email' => $input['user'], 'id' => 1];
$is_user = $user_db->where($where)->count() > 0 ? true : false;
$user = '邮箱';
} else {
// 验证用户名
$where = ['username' => $input['user'], 'id' => 1];
$is_user = $user_db->where($where)->count() > 0 ? true : false;
$user = '用户名';
}
if(!$is_user) return parent::json(0, "{$user}不存在!");
$where['password'] = $this->md6($input['password']);
$user = $user_db->where($where)->find();
if($user) {
session('admin', $user['username']);
cookie('admin', $user['username']);
return parent::json(1, '登录成功');
}
return parent::json(0, "{$user}或密码错误!");
}
return $this->fetch();
}
}

View File

@ -0,0 +1,158 @@
<?php
/**
* 图片管理
* User: WispX
* Date: 2017/9/22
* Time: 15:26
* Link: http://gitee.com/wispx
*/
namespace app\admin\controller;
use think\Db;
use think\Request;
use Qiniu\Auth;
use Upyun\Upyun;
class Picture extends Common
{
public function index()
{
return $this->fetch();
}
public function getFileList($page = 0, $limit = 0, array $key = [])
{
$map['id'] = ['gt', 0];
if(count($key) > 0) $map = $key;
$file_db = Db::name('file');
$file_list = $file_db->where($map)->order('upload_time desc')->page($page, $limit)->select();
// 上传方案
$scheme = getSchemeList();
foreach ($file_list as &$val) {
$val['upload_time'] = formatTime($val['upload_time']);
$val['size'] = round(($val['size'] / 1024 / 1024), 2) . 'Mb';
$val['user_id'] = $this->getUserName($val['user_id']);
switch ($val['scheme_id']) {
case 1:
$url = "{$this->web['domain']}/pic/{$val['path']}"; break;
case 2:
$url = "{$scheme['qiniu']['domain']}/{$val['path']}"; break;
case 3:
$url = "{$scheme['upyun']['domain']}/{$val['path']}"; break;
// TODO case 4
}
$val['name'] = "<a target=\"_blank\" href=\"{$url}\">{$val['name']}</a>";
}
return parent::json(0, '', $file_list, '', $file_db->count());
}
/**
* 删除文件及记录
* @param $id
* @return \think\response\Json
*/
public function del($id)
{
if(Request::instance()->isAjax()) {
Db::startTrans();
try {
$file_db = Db::name('file');
$map = ['id' => $id];
$file_info = $file_db->where($map)->find();
switch ((int)$file_info['scheme_id']) {
case 1: // 删除本地文件
// 删除文件记录
if($file_db->where($map)->delete()) {
// 删除文件
@unlink("{$this->conf['file_path']}/{$file_info['path']}");
}
break;
case 2: // 删除七牛云文件
$auth = new Auth($this->scheme['qiniu']['access_key'], $this->scheme['qiniu']['secret_key']);
$config = new \Qiniu\Config();
$bucketManager = new \Qiniu\Storage\BucketManager($auth, $config);
$bucketManager->delete($this->scheme['qiniu']['bucket_name'], $file_info['path']);
$file_db->where($map)->delete();
break;
case 3: // 删除又拍云文件
if($file_db->where($map)->delete()) {
// 创建实例
$bucketConfig = new \Upyun\Config($this->scheme['upyun']['bucket_name'], $this->scheme['upyun']['access_key'], $this->scheme['upyun']['secret_key']);
$client = new Upyun($bucketConfig);
// 删除文件
$client->delete($file_info['path']);
// 删除目录
//$client->deleteDir(substr('/' . $file_info['path'], 0, strrpos($file_info['path'], '/')));
}
break;
case 4: // 删除阿里OSS文件
break;
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return parent::json(0, "删除失败,{$e->getMessage()}");
}
return parent::json(1, "删除成功");
}
}
/**
* 批量删除
* @param $array
* @return \think\response\Json
*/
public function batchDel($array)
{
if(Request::instance()->isAjax()) {
Db::startTrans();
try {
$file_db = Db::name('file');
foreach ($array as $val) {
$file_info = $file_db->where(['id' => $val])->find();
switch ((int)$file_info['scheme_id']) {
case 1: // 删除本地文件
@unlink("{$this->conf['file_path']}/{$file_info['path']}");
$file_db->where('id', $val)->delete();
break;
case 2: // 删除七牛云文件
$auth = new Auth($this->scheme['qiniu']['access_key'], $this->scheme['qiniu']['secret_key']);
$config = new \Qiniu\Config();
$bucketManager = new \Qiniu\Storage\BucketManager($auth, $config);
$bucketManager->delete($this->scheme['qiniu']['bucket_name'], $file_info['path']);
$file_db->where('id', $val)->delete();
break;
case 3: // 删除又拍云文件
$file_db->where('id', $val)->delete();
// 创建实例
$bucketConfig = new \Upyun\Config($this->scheme['upyun']['bucket_name'], $this->scheme['upyun']['access_key'], $this->scheme['upyun']['secret_key']);
$client = new Upyun($bucketConfig);
$client->delete($file_info['path']);
// 删除目录
//$client->deleteDir(substr('/' . $file_info['path'], 0, strrpos($file_info['path'], '/')));
break;
case 4: // 删除阿里OSS文件
//$file_db->where('id', $val)->delete();
break;
}
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return parent::json(0, "删除失败,{$e->getMessage()}");
}
return parent::json(1, '删除成功');
}
}
/**
* 根据ID获取用户用户名
* @param $id
* @return array|false|\PDOStatement|string|\think\Model
*/
public function getUserName($id)
{
return Db::name('user')->where('id', $id)->value('username');
}
}

View File

@ -0,0 +1,83 @@
<?php
/**
* 系统管理
* User: WispX
* Date: 2017/9/22
* Time: 15:27
* Link: http://gitee.com/wispx
*/
namespace app\admin\controller;
use think\Db;
use think\Request;
use mail\Smtp;
class System extends Common
{
public function index()
{
if(Request::instance()->isAjax()) {
$data = Request::instance()->post();
Db::startTrans();
try {
foreach ($data as $key => $val) {
Db::name('config')->where('key', $key)->update(['value' => $val, 'edit_time' => time()]);
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return parent::json(0, '修改失败');
}
return parent::json(1, '修改成功');
}
$this->assign('scheme', getSchemeList());
return $this->fetch();
}
/**
* 修改上传方案配置
* @return \think\response\Json
*/
public function setScheme()
{
if(Request::instance()->isAjax()) {
Db::startTrans();
try {
$input = Request::instance()->param();
$input['edit_time'] = time();
Db::name('config')->where('key', 'upload_scheme_id')->setField('value', $input['id']);
Db::name('scheme')->where('id', $input['id'])->update($input);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return parent::json(0, "Code: {$e->getCode()} Msg: {$e->getMessage()}");
}
return parent::json(1, '修改成功');
}
}
/**
* 发送测试Email
* @param $email
* @return \think\response\Json\
*/
public function sendTestEmail($email)
{
if(Request::instance()->isAjax()) {
$smtp = new Smtp(
$this->conf['smtp_host'],
$this->conf['smtp_port'],
$this->conf['smtp_auth'],
$this->conf['smtp_user'],
$this->conf['smtp_pass'],
$this->conf['smtp_ssl']
);
$send = $smtp->send($email, $this->conf['smtp_user'], "{$this->conf['web_title']}", '这是一封测试邮件');
if($send) {
return parent::json(1, '发送成功');
} else {
return parent::json(0, '发送失败');
}
}
}
}

View File

@ -0,0 +1,56 @@
<?php
/**
* 主题管理
* User: WispX
* Date: 2017/9/22
* Time: 15:28
* Link: http://gitee.com/wispx
*/
namespace app\admin\controller;
use think\Db;
use think\Request;
use think\Config;
class Theme extends Common
{
public function index($theme = '')
{
if(Request::instance()->isAjax()) {
if(!empty($theme)) {
if(Db::name('config')->where('key', 'now_theme')->update(['value' => $theme, 'edit_time' => time()])) {
return parent::json(1, '成功');
}
return parent::json(0, '失败');
}
}
$theme = $this->getTheme($this->conf['theme_path']);
foreach ($theme as $key => $val) {
$data[$val] = Config::load("{$this->conf['theme_path']}/{$val}/config.php", '', 'Theme');
}
$this->assign('theme', $data);
return $this->fetch();
}
/**
* 获取所有主题文件夹
* @param $dir 父目录路径
* @return array
*/
function getTheme($dir)
{
$subdirs = array();
if(!$dh = opendir($dir))
return $subdirs;
$i = 0;
while ($f = readdir($dh))
{
if($f =='.' || $f =='..')
continue;
$path = $f;
$subdirs[$i] = $path;
$i++;
}
return $subdirs;
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* 用户管理
* User: WispX
* Date: 2017/9/22
* Time: 15:21
* Link: http://gitee.com/wispx
*/
namespace app\admin\controller;
use think\Db;
use think\Request;
class Users extends Common
{
public function index()
{
return $this->fetch();
}
/**
* 分页获取会员
* @param int $page 页码
* @param int $limit 每页显示数量
* @param array $key 条件
* @return \think\response\Json
*/
public function getUserList($page = 0, $limit = 0, array $key = [])
{
$map['id'] = ['neq', 1];
if(count($key) > 0) $map = $key;
$user_db = Db::name('user');
$user_list = $user_db->where($map)->order('reg_time desc')->page($page, $limit)->select();
foreach ($user_list as $key => &$val) {
$val['login_time'] = formatTime($val['login_time']);
$val['reg_time'] = date('Y-m-d h:i:s', $val['reg_time']);
unset($val['password']);
unset($val['edit_time']);
}
return parent::json(0, '', $user_list, '', $user_db->count());
}
/**
* 删除 And 批量删除会员
* @param $id
* @return \think\response\Json
* @throws \think\Exception
*/
public function del($id)
{
if(Request::instance()->isAjax()) {
if(Db::name('user')->delete($id)) {
return parent::json(1, '删除成功');
}
return parent::json(0, '删除失败');
}
}
}

View File

@ -0,0 +1,2 @@
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子窗口</title>
{css href="_layui_css/layui.css"}
{css href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css"}
{css href="//cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css"}
{css href="_css_style.css"}
{js href="_layui_layui.js"}
{js href="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"}
{js href="//cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"}
{js href="_js_main.js"}
</head>
<body>

View File

@ -0,0 +1,144 @@
{include file="/common/header"}
<div class="">
<div class="col-sm-3 col-md-3 col-lg-3">
<div class="wp-panel">
<i class="fa fa-picture-o" style="background-color: #00c0ef !important;"></i>
<div class="wp-word">
<span>{$data.img_num}</span>
<cite>图片数量</cite>
</div>
</div>
</div>
<div class="col-sm-3 col-md-3 col-lg-3">
<div class="wp-panel">
<i class="fa fa-picture-o" style="background-color: #dd4b39 !important;"></i>
<div class="wp-word">
<span>{$data.add_img_num}</span>
<cite>今日新增图片</cite>
</div>
</div>
</div>
<div class="col-sm-3 col-md-3 col-lg-3">
<div class="wp-panel">
<i class="fa fa-users" style="background-color: #00a65a !important;"></i>
<div class="wp-word">
<span>{$data.user_num}</span>
<cite>用户总数</cite>
</div>
</div>
</div>
<div class="col-sm-3 col-md-3 col-lg-3">
<div class="wp-panel">
<i class="fa fa-user-plus" style="background-color: #f39c12 !important;"></i>
<div class="wp-word">
<span>{$data.add_user_num}</span>
<cite>今日新增用户</cite>
</div>
</div>
</div>
<div class="col-sm-3 col-md-3 col-lg-3">
<div class="wp-panel">
<i class="fa fa-tasks" style="background-color: #009688 !important;"></i>
<div class="wp-word">
<span>{$data.occupy} mb</span>
<cite>占用储存</cite>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="col-sm-6 col-md-6 col-lg-6">
<div class="system sysNotice">
<blockquote class="layui-elem-quote title">最新公告<i class="iconfont icon-new1"></i></blockquote>
<table class="layui-table" lay-skin="line">
<colgroup>
<col>
<col width="150">
</colgroup>
<tbody class="hot_news">
{if condition="count($data.notice) gt 0"}
{foreach $data.notice.data as $k => $v}
<tr>
<td align="left"><a class="notice" data-id="{$k}">{$v.title}</a><span class="none noticeDetails notice-{$k}">{$v.content}<cite>{$v.date}</cite></span></td>
<td class="notice-date">{$v.date}</td>
</tr>
{/foreach}
{else /}
<tr>
<td align="left">公告获取失败或暂时没有公告</td>
<!--<td></td>-->
</tr>
{/if}
</tbody>
</table>
</div>
</div>
<div class="col-sm-6 col-md-6 col-lg-6">
<div class="notice sysNotice">
<blockquote class="layui-elem-quote title">系统基本参数</blockquote>
<table class="layui-table">
<colgroup>
<col width="150">
<col>
</colgroup>
<tbody>
<tr>
<td>操作系统</td>
<td class="">{$Think.PHP_OS}</td>
</tr>
<tr>
<td>运行环境</td>
<td class="">{$Think.server.server_software}</td>
</tr>
<tr>
<td>请求端口</td>
<td class="">{$Think.server.server_port}</td>
</tr>
<tr>
<td>通信协议</td>
<td class="">{$Think.server.server_protocol}</td>
</tr>
<tr>
<td>当前版本</td>
<td class="">v{$conf.version}</td>
</tr>
<tr>
<td>网站域名</td>
<td class="">{$Think.server.server_name}</td>
</tr>
<tr>
<td>服务器IP</td>
<td class="">{$Think.server.http_host|gethostbyname}</td>
</tr>
<tr>
<td>剩余空间</td>
<td class="">{$data.disk_free_space} Mb</td>
</tr>
<tr>
<td>上传文件限制</td>
<td class="">{$data.upload_max_filesize}</td>
</tr>
<tr>
<td>执行时间限制</td>
<td class="">{$data.max_execution_time} 秒</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<script type="text/javascript">
$('.notice').click(function() {
layer.closeAll();
var t = $(this);
layer.open({
title: t.text(),
type: 1,
anim: 4,
shade: 0,
area: ['420px', '240px'], //宽高
content: $('.notice-' + $(this).attr('data-id'))
});
});
</script>
{include file="/common/footer"}

View File

@ -0,0 +1,107 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>兰空 - 后台管理系统</title>
{css href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css"}
{css href="//cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css"}
</head>
<body>
<style type="text/css">
body { width: 100%; height: 100%; padding: 65px 0 0; }
/*body { margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; overflow: hidden; }*/
.navbar-brand { color: #fff!important; }
a { color: #333; transition: all .3s; -webkit-transition: all .3s; text-decoration: none; }
.lk-this > a { color: #fff!important; }
.lk-this:after {
position: absolute;
left: 0;
top: 0;
width: 0;
height: 3px;
background-color: #5FB878;
transition: all .2s;
-webkit-transition: all .2s;
}
.lk-this:after {
content: '';
top: auto;
bottom: 0;
width: 100%;
}
.navbar-inverse { border: 0px; }
#main {
width: 100%;
height: 100%;
border: none;
}
.main { }
@media screen and (max-width: 768px) {
.lk-this:after { display: none; }
.main {
padding-right: 0px;
padding-left: 0px;
}
}
</style>
<nav class="navbar navbar-default navbar-fixed-top navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#menu">
<span class="sr-only">Navbar</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="javascript:void(0)"><i class="fa fa-leaf fa-fw"></i> 兰空</a>
</div>
<div class="collapse navbar-collapse" id="menu">
<ul class="nav navbar-nav menu">
<li class="lk-this"><a href="{:url('/console')}" target="main"><i class="fa fa-home fa-fw"></i> 控制台</a></li>
<li><a href="{:url('/users')}" target="main"><i class="fa fa-users fa-fw"></i> 用户管理</a></li>
<li><a href="{:url('/picture')}" target="main"><i class="fa fa-picture-o fa-fw"></i> 图片管理</a></li>
<li><a href="{:url('/theme')}" target="main"><i class="fa fa-puzzle-piece fa-fw"></i> 主题管理</a></li>
<li><a href="{:url('/system')}" target="main"><i class="fa fa-cog fa-fw"></i> 系统设置</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-user fa-fw"></i> {$admin.username} <b class="caret"></b></a>
<ul class="dropdown-menu">
<!--<li><a href="javascript:void(0)">修改资料</a></li>
<li class="divider"></li>-->
<li><a href="{:url('index/logout')}">退出</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="container main">
<iframe id="main" name="main" src="{:url('/console')}"></iframe>
</div>
</body>
{js href="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"}
{js href="//cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"}
{js href="_layui_layui.js"}
<script type="text/javascript">
var menu = $('.menu li');
menu.click(function() {
layer.load(2);
menu.each(function() {
$(this).removeClass('lk-this');
})
$(this).addClass('lk-this');
var a = $(this).children('a');
$('title').html(a.text() + ' - {$conf.web_title} - 后台管理系统');
a.attr('data-url');
});
layui.use('layer', function() {
var layer = layui.layer;
$('#main').on('load', function() {
layer.closeAll('loading');
});
});
</script>
</html>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>兰空- 后台管理</title>
{css href="_layui_css/layui.css" /}
</head>
<style type="text/css">
html {
width:100%;height:100%;
background-image: -webkit-radial-gradient(-20% 140%, ellipse , rgba(255,144,187,.6) 30%,rgba(255,255,227,0) 50%), -webkit-linear-gradient(top, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -webkit-radial-gradient(60% 40%,ellipse, #d9e3e5 10%,rgba(44,70,76,.0) 60%), -webkit-linear-gradient(-45deg, rgba(18,101,101,.8) -10%,#d9e3e5 80% );
}
body{margin:0;width:100%;height:100%;}
.btn-block{width:100%}
.shadow{background-color:rgba(0,0,0,.42);-webkit-box-shadow:0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12);box-shadow:0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12)}
.login{position:absolute;top:50%;left:50%;z-index:99;margin:-150px 0 0 -170px;padding:20px;width:300px;border-radius:4px;background-color:rgba(0,0,0,.5);color:#fff}
.text-center{text-align:center}
h1{margin:20px auto;font-weight:700;font-size:30px;font-family:Georgia}
</style>
<body>
<div class="login shadow">
<h1 class="text-center">兰 空</h1>
<form class="layui-form" action="" method="post">
<div class="layui-form-item">
<input type="text" name="user" required lay-verify="required" placeholder="请输入账号" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<input type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<button id="embed-submit" class="layui-btn btn-block" lay-submit lay-filter="sign-in">登录</button>
</div>
</form>
</div>
</body>
{js href="_layui_layui.js" /}
<script type="text/javascript">
layui.use('form', function() {
var form = layui.form,$ = layui.$;
form.on('submit(sign-in)', function(data) {
$.post('', data.field, function(res) {
if(res.code) return window.location.href = '/admin.php';
layer.alert(res.msg);
return false;
});
return false;
});
});
</script>
</html>

View File

@ -0,0 +1,109 @@
{include file="/common/header"}
<div class="container-fluid">
<div class="layui-form list-per" action="" method="post">
<div class="layui-inline">
<div class="layui-input-inline">
<select name="key" lay-verify="required" lay-filter="key">
<option value="1">文件名</option>
<option value="2">用户名</option>
<option value="3">ID</option>
</select>
</div>
</div>
<div class="layui-inline">
<div class="layui-input-inline">
<input type="text" name="name" id="reload" value="" placeholder="搜索..." class="layui-input">
</div>
<button class="layui-btn layui-btn-small layui-btn-primary" lay-submit data-type="reload">查询</button>
<button class="layui-btn layui-btn-small layui-btn-danger" data-type="getCheckData" style="margin-left: 0;">批量删除</button>
</div>
</div>
<table class="table layui-hide" id="file_list" lay-filter="file_list"></table>
<script type="text/html" id="per">
<a class="layui-btn layui-btn-mini" lay-event="del">删除</a>
</script>
</div>
<div class="seeImg"><img src="" width="100%" /></div>
<script type="text/javascript">
layui.use(['table', 'form'], function() {
var table = layui.table, form = layui.form;
table.render({
elem: '#file_list',
url: '{:url("getFileList")}',
cols: [[
{checkbox: true, fixed: true},
{field:'id', title: 'ID', width: 80, sort: true},
{field:'user_id', title: '所属用户', width: 150},
{field:'name', title: '文件名', width: 150},
{field:'type', title: '文件类型', width: 150},
{field:'size', title: '文件大小', width: 100, sort: true},
{field:'hash', title: '散列值', width: 172},
{field:'upload_time', title: '上传时间', width: 150, sort: true},
{field:'right', width: 100, title: '操作', align:'center', toolbar: '#per'}
]],
id: 'reload',
page: true,
size: 'sm',
limits: [10, 20, 30, 40, 50],
limit: 10,
loading: true,
});
var active = {
// 搜索
reload: function() {
var reload = $('#reload'), where = {email: reload.val()};
switch (parseInt($('[name=key]').val())) {
case 1: where = {name: reload.val()}; break;
case 2: where = {username: reload.val()}; break;
case 3: where = {id: reload.val()}; break;
}
table.reload('reload', {
where: {
key: where
}
});
},
// 获取选中数据
getCheckData: function() {
var checkStatus = table.checkStatus('reload') ,data = checkStatus.data, arr = [];
for (var i = 0; i < data.length; i++) {
arr.push(data[i].id);
}
if(arr.length > 0) {
layer.confirm('真的删除选中的' + arr.length + '张图片吗?', function(index) {
layer.close(index);
$.post("{:url('picture/batchDel')}", {array: arr}, function(res) {
table.reload('reload'); // 全局重载
return layer.msg(res.msg, {icon: res.code ? 1 : 2});
});
});
} else {
return layer.msg('没有选中项');
}
}
};
$('.list-per .layui-btn').on('click', function() {
var type = $(this).data('type');
active[type] ? active[type].call(this) : '';
return false;
});
table.on('tool(file_list)', function(obj) {
var data = obj.data, layEvent = obj.event;
//var tr = obj.tr;
if(layEvent === 'del'){
layer.confirm('真的删除么?', function(index) {
layer.close(index);
$.post("{:url('picture/del')}", {id: data.id}, function(res) {
if(res.code) obj.del();
return layer.msg(res.msg, {icon: res.code ? 1 : 2});
});
});
}
});
});
</script>
{include file="/common/footer"}

View File

@ -0,0 +1,309 @@
{include file="/common/header"}
<div class="container-fluid">
<div class="layui-tab layui-tab-brief" lay-filter="">
<ul class="layui-tab-title">
<li class="layui-this">网站设置</li>
<li>邮件配置</li>
<li>储存方案</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="row">
<div class="col-sm-6 col-md-6 col-1g-6">
<form class="form-horizontal setConf" role="form" action="" method="post">
<div class="form-group">
<label for="web_title" class="col-sm-3 control-label">网站名称</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="web_title" name="web_title" value="{$conf.web_title}" placeholder="网站名称">
</div>
</div>
<div class="form-group">
<label for="keywords" class="col-sm-3 control-label">关键字</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="keywords" name="keywords" value="{$conf.keywords}" placeholder="网站关键字">
</div>
</div>
<div class="form-group">
<label for="description" class="col-sm-3 control-label">描述</label>
<div class="col-sm-9">
<textarea id="description" name="description" class="form-control" rows="3" placeholder="网站描述">{$conf.description}</textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">关闭注册</label>
<div class="col-sm-9">
<label class="radio-inline">
<input type="radio" name="reg_close" value="0" {if condition="$conf.reg_close eq 0"}checked{/if}> 关闭
</label>
<label class="radio-inline">
<input type="radio" name="reg_close" value="1" {if condition="$conf.reg_close eq 1"}checked{/if}> 开启
</label>
</div>
</div>
<div class="form-group">
<label for="upload_max_filesize" class="col-sm-3 control-label">上传限制</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="upload_max_filesize" name="upload_max_filesize" value="{$conf.upload_max_filesize}" placeholder="最大上传限制(Kb)">
</div>
</div>
<div class="form-group">
<label for="upload_max_file_count" class="col-sm-3 control-label">最大上传数</label>
<div class="col-sm-9">
<input type="number" class="form-control" id="upload_max_file_count" name="upload_max_file_count" value="{$conf.upload_max_file_count}" placeholder="最大上传图片数量">
</div>
</div>
<div class="form-group">
<label for="upload_images_ext" class="col-sm-3 control-label">上传拓展名</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="upload_images_ext" name="upload_images_ext" value="{$conf.upload_images_ext}" placeholder="允许的文件拓展名,逗号隔开(开头和结尾不需要逗号)">
</div>
</div>
<div class="form-group">
<label for="flow_load_mode" class="col-sm-3 control-label">流加载方式</label>
<div class="col-sm-9">
<select name="flow_load_mode" id="flow_load_mode" class="form-control">
<option value="0" {if condition="$conf.flow_load_mode eq 0"}selected{/if}>手动加载</option>
<option value="1" {if condition="$conf.flow_load_mode eq 1"}selected{/if}>下拉加载</option>
</select>
</div>
</div>
<div class="form-group">
<label for="img_rows" class="col-sm-3 control-label">每页显示数量</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="img_rows" name="img_rows" value="{$conf.img_rows}" placeholder="每页显示数量">
</div>
</div>
<div class="form-group">
<label for="captcha_id" class="col-sm-3 control-label">极检验证ID</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="captcha_id" name="captcha_id" value="{$conf.captcha_id}" placeholder="极检验证ID">
</div>
</div>
<div class="form-group">
<label for="private_key" class="col-sm-3 control-label">极检验证KEY</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="private_key" name="private_key" value="{$conf.private_key}" placeholder="极检验证KEY">
</div>
</div>
<div class="form-group">
<label for="custom_style" class="col-sm-3 control-label">自定义Style</label>
<div class="col-sm-9">
<textarea id="custom_style" name="custom_style" class="form-control" rows="3" placeholder="自定义Css样式">{$conf.custom_style}</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" id="setConf" class="btn btn-primary">修改</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="layui-tab-item">
<div class="row">
<div class="col-sm-6 col-md-6 col-1g-6">
<form class="form-horizontal setSmtp" role="form" action="" method="post">
<div class="form-group">
<label for="smtp_host" class="col-sm-3 control-label">SMTP连接地址</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="smtp_host" name="smtp_host" value="{$conf.smtp_host}" placeholder="SMTP连接地址不需要加http://">
</div>
</div>
<div class="form-group">
<label for="smtp_port" class="col-sm-3 control-label">SMTP端口</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="smtp_port" name="keywords" value="{$conf.smtp_port}" placeholder="SMTP端口默认25">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">SMTP认证</label>
<div class="col-sm-9">
<label class="radio-inline">
<input type="radio" name="smtp_auth" value="0" {if condition="$conf.smtp_auth eq 0"}checked{/if}> 关闭
</label>
<label class="radio-inline">
<input type="radio" name="smtp_auth" value="1" {if condition="$conf.smtp_auth eq 1"}checked{/if}> 开启
</label>
</div>
</div>
<div class="form-group">
<label for="smtp_user" class="col-sm-3 control-label">SMTP用户</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="smtp_user" name="smtp_user" value="{$conf.smtp_user}" placeholder="SMTP登录账户">
</div>
</div>
<div class="form-group">
<label for="smtp_pass" class="col-sm-3 control-label">SMTP密码</label>
<div class="col-sm-9">
<input type="password" class="form-control" id="smtp_pass" name="smtp_pass" value="{$conf.smtp_pass}" placeholder="SMTP密码">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">开启SSL</label>
<div class="col-sm-9">
<label class="radio-inline">
<input type="radio" name="smtp_ssl" value="0" {if condition="$conf.smtp_ssl eq 0"}checked{/if}> 关闭
</label>
<label class="radio-inline">
<input type="radio" name="smtp_ssl" value="1" {if condition="$conf.smtp_ssl eq 1"}checked{/if}> 开启
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" id="setSmtp" class="btn btn-primary">修改</button>
<button type="button" id="sendTestEmail" class="btn btn-default">发送测试邮件</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="layui-tab-item">
<div class="row">
<div class="col-sm-6 col-md-6 col-1g-6">
<label class="radio-inline">
<input type="radio" name="select-id" value="1"{if condition="$conf.upload_scheme_id eq 1"} checked{/if}> 本地
</label>
<label class="radio-inline">
<input type="radio" name="select-id" value="2"{if condition="$conf.upload_scheme_id eq 2"} checked{/if}> 七牛云
</label>
<label class="radio-inline">
<input type="radio" name="select-id" value="3"{if condition="$conf.upload_scheme_id eq 3"} checked{/if}> 又拍云
</label>
<form class="form-horizontal setScheme" role="form" action="" method="post">
<div class="scheme scheme-1{if condition="$conf.upload_scheme_id neq 1"} none{/if}">
<blockquote class="layui-elem-quote">本地</blockquote>
<p class="text-danger">本地默认无需配置,文件路径所在目录 /public/pic</p>
<div class="form-group">
<div class="col-sm-9">
<input type="hidden" name="id" value="1">
<button type="submit" class="btn btn-primary set-scheme">修改</button>
</div>
</div>
</div>
</form>
<form class="form-horizontal setScheme" role="form" action="" method="post">
<div class="scheme scheme-2{if condition="$conf.upload_scheme_id neq 2"} none{/if}">
<blockquote class="layui-elem-quote">七牛云</blockquote>
<div class="form-group">
<label class="col-sm-3 control-label">AccessKey</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="access_key" value="{$scheme.qiniu.access_key}" placeholder="AccessKey">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">SecretKey</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="secret_key" value="{$scheme.qiniu.secret_key}" placeholder="SecretKey">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">储存空间名</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="bucket_name" value="{$scheme.qiniu.bucket_name}" placeholder="储存空间名">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">外链默认域名</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="domain" value="{$scheme.qiniu.domain}" placeholder="外链默认域名开头加“http://”结尾不需要加“/”">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="hidden" name="id" value="2">
<button type="submit" class="btn btn-primary set-scheme">修改</button>
</div>
</div>
</div>
</form>
<form class="form-horizontal setScheme" role="form" action="" method="post">
<div class="scheme scheme-3{if condition="$conf.upload_scheme_id neq 3"} none{/if}">
<blockquote class="layui-elem-quote">又拍云</blockquote>
<div class="form-group">
<label class="col-sm-3 control-label">管理员操作名</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="access_key" value="{$scheme.upyun.access_key}" placeholder="管理员操作员名称">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">管理员操作密码</label>
<div class="col-sm-9">
<input type="password" class="form-control" name="secret_key" value="{$scheme.upyun.secret_key}" placeholder="操作员密码">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">服务名称</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="bucket_name" value="{$scheme.upyun.bucket_name}" placeholder="储存空间名">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">加速域名</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="domain" value="{$scheme.upyun.domain}" placeholder="加速域名开头加“http://”结尾不需要加“/”">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="hidden" name="id" value="3">
<button type="submit" class="btn btn-primary set-scheme">修改</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
layui.use(['form', 'element'], function() {
var form = layui.form, element = layui.element;
});
$('.setConf').submit(function() {
var data = $(this).serialize();
btnLoad('#setConf');
$.post('', data, function(res) {
layer.msg(res.msg, {icon: res.code ? 1 : 2});
closeBtnLoad('#setConf', '修改');
});
return false;
});
$('.setSmtp').submit(function() {
var data = $(this).serialize();
btnLoad('#setSmtp');
$.post('', data, function(res) {
layer.msg(res.msg, {icon: res.code ? 1 : 2});
closeBtnLoad('#setSmtp', '修改');
});
return false;
});
$('#sendTestEmail').click(function() {
layer.prompt({title: '请输入邮箱'}, function(email, index) {
layer.close(index);
$.post('system/sendTestEmail', {'email': email}, function(res) {
return layer.msg(res.msg, {icon: res.code ? 1 : 2});
});
});
});
$('[name=select-id]').click(function() {
$('form .scheme').each(function() {
$(this).addClass('none');
});
var val = $(this).val();
$('form .scheme-' + val).removeClass('none');
});
$('.setScheme').submit(function() {
btnLoad('.set-scheme');
$.post('system/setScheme', $(this).serialize(), function(res) {
closeBtnLoad('.set-scheme', '修改');
return layer.msg(res.msg, {icon: res.code ? 1 : 2});
});
return false;
});
</script>
{include file="/common/footer"}

View File

@ -0,0 +1,34 @@
{include file="/common/header"}
<div class="container-fluid">
<div class="row">
{foreach $theme as $v}
<div class="col-sm-3 col-md-3 col-1g-3">
<div class="thumbnail">
<img src="{$v.images}" width="100%" alt="{$v.name}">
<div class="caption">
<h3>{$v.name} <small><a target="_blank" href="{$v.link}">{$v.author}</a></small></h3>
<p>{$v.explain}</p>
<p>
<a class="btn btn-primary btn-block use" role="button"{if condition="$conf.now_theme eq $v.key"}disabled>当前使用{else /} href="javascript:use('{$v.key}')">使用{/if}</a>
</p>
</div>
</div>
</div>
{/foreach}
</div>
</div>
<script type="text/javascript">
function use(key) {
btnLoad('.use', 'Loading...');
$.post('', {'theme': key}, function(res) {
if(res.code) {
layer.msg(res.msg, {icon: 1}, function() {
return history.go(0);
});
}
return layer.alert(res.msg, {icon: res.code ? 1 : 2});
});
closeBtnLoad('.use', '使用');
}
</script>
{include file="/common/footer"}

View File

@ -0,0 +1,109 @@
{include file="/common/header"}
<div class="container-fluid">
<div class="layui-form list-per" action="" method="post">
<div class="layui-inline">
<div class="layui-input-inline">
<select name="key" lay-verify="required" lay-filter="key">
<option value="1">Email</option>
<option value="2">昵称</option>
<option value="3">ID</option>
</select>
</div>
</div>
<div class="layui-inline">
<div class="layui-input-inline">
<input type="text" name="email" id="reload" value="" placeholder="搜索..." class="layui-input">
</div>
<button class="layui-btn layui-btn-small layui-btn-primary" lay-submit data-type="reload">查询</button>
<button class="layui-btn layui-btn-small layui-btn-danger" data-type="getCheckData" style="margin-left: 0;">批量删除</button>
</div>
</div>
<table class="table layui-hide" id="user_list" lay-filter="user_list"></table>
<script type="text/html" id="per">
<a class="layui-btn layui-btn-mini" lay-event="del">删除</a>
</script>
</div>
<script type="text/javascript">
layui.use(['table', 'form'], function() {
var table = layui.table, form = layui.form;
table.render({
elem: '#user_list',
url: '{:url("getUserList")}',
cols: [[
{checkbox: true, fixed: true},
{field:'id', title: 'ID', width: 80, sort: true},
{field:'email', title: 'Email', width: 150},
{field:'username', title: '用户名', width: 150},
{field:'login_time', title: '最后登录时间', width: 150, sort: true},
{field:'login_ip', title: '最后登录IP', width: 100},
{field:'reg_ip', title: '注册IP', width: 100},
{field:'reg_time', title: '注册时间', width: 150, sort: true},
{field:'right', width: 100, title: '操作', align:'center', toolbar: '#per'}
]],
id: 'reload',
page: true,
size: 'sm',
limits: [10, 20, 30, 40, 50],
limit: 10,
loading: true,
});
var active = {
// 搜索
reload: function() {
var reload = $('#reload'), where = {email: reload.val()};
switch (parseInt($('[name=key]').val())) {
case 1: where = {email: reload.val()}; break;
case 2: where = {username: reload.val()}; break;
case 3: where = {id: reload.val()}; break;
}
table.reload('reload', {
where: {
key: where
}
});
},
// 获取选中数据
getCheckData: function() {
var checkStatus = table.checkStatus('reload') ,data = checkStatus.data, arr = [];
for (var i = 0; i < data.length; i++) {
arr.push(data[i].id);
}
if(arr.length > 0) {
layer.confirm('真的删除选中的' + arr.length + '个会员吗?', function(index) {
layer.close(index);
$.post("{:url('users/del')}", {id: arr}, function(res) {
table.reload('reload'); // 全局重载
return layer.msg(res.msg, {icon: res.code ? 1 : 2});
});
});
} else {
return layer.msg('没有选中项');
}
}
};
$('.list-per .layui-btn').on('click', function() {
var type = $(this).data('type');
active[type] ? active[type].call(this) : '';
return false;
});
table.on('tool(user_list)', function(obj) {
var data = obj.data, layEvent = obj.event;
//var tr = obj.tr;
if(layEvent === 'del'){
layer.confirm('真的删除么?', function(index) {
layer.close(index);
$.post("{:url('users/del')}", {id: data.id}, function(res) {
if(res.code) obj.del();
return layer.msg(res.msg, {icon: res.code ? 1 : 2});
});
});
}
});
});
</script>
{include file="/common/footer"}

12
app/command.php Normal file
View File

@ -0,0 +1,12 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
return [];

156
app/common.php Normal file
View File

@ -0,0 +1,156 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 应用公共文件
/**
* 判断是否是https
* @return boolean
*/
function is_https()
{
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') {
return true;
} elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
return true;
} elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
return true;
}
return false;
}
/**
* 二维数组去空格
* @author WispX
* @date 2017-09-04 9:44
* @param array $array
* @return string|boolean
*/
function trimArray($array)
{
if(count($array) > 0) {
foreach ($array as $key => &$val) {
$array[$key] = trim($val);
}
return $array;
}
return false;
}
/**
* 格式化时间
* @param [type] $unixTime [description]
* @return [type] [description]
*/
function formatTime($unixTime)
{
$showTime = date('Y', $unixTime) . "" . date('n', $unixTime) . "" . date('j', $unixTime) . "";
if (date('Y', $unixTime) == date('Y')) {
$showTime = date('n', $unixTime) . "" . date('j', $unixTime) . "" . date('H:i', $unixTime);
if (date('n.j', $unixTime) == date('n.j')) {
$timeDifference = time() - $unixTime + 1;
if ($timeDifference < 30) {
return "刚刚";
}
if ($timeDifference >= 30 && $timeDifference < 60) {
return $timeDifference . "秒前";
}
if ($timeDifference >= 60 && $timeDifference < 3600) {
return floor($timeDifference / 60) . "分钟前";
}
return date('H:i', $unixTime);
}
if (date('n.j', ($unixTime + 86400)) == date('n.j')) {
return "昨天 " . date('H:i', $unixTime);
}
}
return $showTime;
}
/**
* 获取系统配置
* @return bool
*/
function getSystemConf($key = '')
{
if(!empty($key)) {
return \think\Db::name('config')->where('key', $key)->value('value');
} else {
$conf = \think\Db::name('config')->select();
if($conf) {
foreach ($conf as $val) {
$_conf[$val['key']] = $val['value'];
}
return $_conf;
}
return false;
}
}
/**
* 生成验证码
* @param number $length
* @return string
*/
function getCode($length = 7)
{
return substr(str_shuffle("012345678901234567890123456789"), 0, $length);
}
/**
* curl
* @param $url 请求地址
* @param array $data 请求数据
* @param array $header 请求header头
* @param int $timeout 超时时间
* @return mixed
*/
function curl($url, array $data = [], array $header = [], $timeout = 30)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
//curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
$response = curl_exec($ch);
if($error = curl_error($ch)) {
return $error;
}
curl_close($ch);
return $response;
}
/**
* 获取所有上传方案
*/
function getSchemeList()
{
$scheme_list = \think\Db::name('scheme')->select();
foreach ($scheme_list as $key => $val) {
switch ($val['id']) {
// 七牛云
case 2:
$scheme['qiniu'] = $val; break;
// 又拍云
case 3:
$scheme['upyun'] = $val; break;
// 阿里云OSS
case 4:
$scheme['alioss'] = $val; break;
}
}
return $scheme;
}

253
app/config.php Normal file
View File

@ -0,0 +1,253 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
// 应用命名空间
'app_namespace' => 'app',
// 应用调试模式
'app_debug' => false,
// 应用Trace
'app_trace' => false,
// 应用模式状态
'app_status' => '',
// 是否支持多模块
'app_multi_module' => true,
// 入口自动绑定模块
'auto_bind_module' => false,
// 注册的根命名空间
'root_namespace' => [],
// 扩展函数文件
'extra_file_list' => [THINK_PATH . 'helper' . EXT],
// 默认输出类型
'default_return_type' => 'html',
// 默认AJAX 数据返回格式,可选json xml ...
'default_ajax_return' => 'json',
// 默认JSONP格式返回的处理方法
'default_jsonp_handler' => 'jsonpReturn',
// 默认JSONP处理方法
'var_jsonp_handler' => 'callback',
// 默认时区
'default_timezone' => 'PRC',
// 是否开启多语言
'lang_switch_on' => false,
// 默认全局过滤方法 用逗号分隔多个
'default_filter' => '',
// 默认语言
'default_lang' => 'zh-cn',
// 应用类库后缀
'class_suffix' => false,
// 控制器类后缀
'controller_suffix' => false,
// +----------------------------------------------------------------------
// | 模块设置
// +----------------------------------------------------------------------
// 默认模块名
'default_module' => 'index',
// 禁止访问模块
'deny_module_list' => ['common'],
// 默认控制器名
'default_controller' => 'Index',
// 默认操作名
'default_action' => 'index',
// 默认验证器
'default_validate' => '',
// 默认的空控制器名
'empty_controller' => 'Error',
// 操作方法后缀
'action_suffix' => '',
// 自动搜索控制器
'controller_auto_search' => false,
// +----------------------------------------------------------------------
// | URL设置
// +----------------------------------------------------------------------
// PATHINFO变量名 用于兼容模式
'var_pathinfo' => 's',
// 兼容PATH_INFO获取
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
// pathinfo分隔符
'pathinfo_depr' => '/',
// URL伪静态后缀
'url_html_suffix' => '',
// URL普通方式参数 用于自动生成
'url_common_param' => false,
// URL参数方式 0 按名称成对解析 1 按顺序解析
'url_param_type' => 0,
// 是否开启路由
'url_route_on' => true,
// 路由使用完整匹配
'route_complete_match' => false,
// 路由配置文件(支持配置多个)
'route_config_file' => ['route'],
// 是否强制使用路由
'url_route_must' => false,
// 域名部署
'url_domain_deploy' => false,
// 域名根如thinkphp.cn
'url_domain_root' => '',
// 是否自动转换URL中的控制器和操作名
'url_convert' => true,
// 默认的访问控制器层
'url_controller_layer' => 'controller',
// 表单请求类型伪装变量
'var_method' => '_method',
// 表单ajax伪装变量
'var_ajax' => '_ajax',
// 表单pjax伪装变量
'var_pjax' => '_pjax',
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
'request_cache' => false,
// 请求缓存有效期
'request_cache_expire' => null,
// 全局请求缓存排除规则
'request_cache_except' => [],
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
'template' => [
// 模板引擎类型 支持 php think 支持扩展
'type' => 'Think',
// 模板路径
'view_path' => '',
// 模板后缀
'view_suffix' => 'html',
// 模板文件名分隔符
'view_depr' => DS,
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '{',
// 标签库标签结束标记
'taglib_end' => '}',
],
// 视图输出字符串内容替换
'view_replace_str' => [
'_css_' => '/static/css/',
'_js_' => '/static/js/',
'_img_' => '/static/images/',
'_layui_' => '/static/layui/',
'_pic_' => '/pic/',
],
// 默认跳转页面对应的模板文件
'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
'dispatch_error_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
// +----------------------------------------------------------------------
// | 异常及错误设置
// +----------------------------------------------------------------------
// 异常页面的模板文件
'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',
// 显示错误信息
'show_error_msg' => false,
// 异常处理handle类 留空使用 \think\exception\Handle
'exception_handle' => '',
// +----------------------------------------------------------------------
// | 日志设置
// +----------------------------------------------------------------------
'log' => [
// 日志记录方式,内置 file socket 支持扩展
'type' => 'File',
// 日志保存目录
'path' => LOG_PATH,
// 日志记录级别
'level' => [],
],
// +----------------------------------------------------------------------
// | Trace设置 开启 app_trace 后 有效
// +----------------------------------------------------------------------
'trace' => [
// 内置Html Console 支持扩展
'type' => 'Html',
],
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
'cache' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => CACHE_PATH,
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
],
// +----------------------------------------------------------------------
// | 会话设置
// +----------------------------------------------------------------------
'session' => [
'id' => '',
// SESSION_ID的提交变量,解决flash上传跨域
'var_session_id' => '',
// SESSION 前缀
'prefix' => 'think',
// 驱动方式 支持redis memcache memcached
'type' => '',
// 是否自动开启 SESSION
'auto_start' => true,
],
// +----------------------------------------------------------------------
// | Cookie设置
// +----------------------------------------------------------------------
'cookie' => [
// cookie 名称前缀
'prefix' => '',
// cookie 保存时间
'expire' => 0,
// cookie 保存路径
'path' => '/',
// cookie 有效域名
'domain' => '',
// cookie 启用安全传输
'secure' => false,
// httponly设置
'httponly' => '',
// 是否使用 setcookie
'setcookie' => true,
],
//分页配置
'paginate' => [
'type' => 'bootstrap',
'var_page' => 'page',
'list_rows' => 15,
],
//主题路径
'theme_path' => str_replace("\\", "/", APP_PATH . "index/view/theme"),
//文件上传路径
'file_path' => str_replace("\\", "/", ROOT_PATH . "public/pic"),
];

47
app/database.php Normal file
View File

@ -0,0 +1,47 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
require_once 'db.php';
$database = [
// 数据库类型
'type' => 'mysql',
// 连接dsn
'dsn' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'lk_',
// 数据库调试模式
'debug' => true,
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 数据集返回类型
'resultset_type' => 'array',
// 自动写入时间戳字段
'auto_timestamp' => false,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 是否需要进行SQL性能分析
'sql_explain' => false,
];
return array_merge($db, $database);

0
app/db.php Normal file
View File

15
app/index/config.php Normal file
View File

@ -0,0 +1,15 @@
<?php
/**
* index模块配置
* User: WispX
* Date: 2017/9/15
* Time: 15:30
*/
return [
'web' => [
'domain' => \think\Request::instance()->domain()
],
'template' => [
'view_path' => '../app/index/view/theme/' . getSystemConf('now_theme') . '/'
],
];

View File

@ -0,0 +1,88 @@
<?php
/**
* index模块共用控制器
* User: WispX
* Date: 2017/9/15
* Time: 15:32
*/
namespace app\index\controller;
use think\Config;
use think\Db;
use think\Controller;
class Common extends Controller
{
protected $user = false;
protected $conf;
protected $web;
protected $scheme;
/**
* 前置操作
*/
public function _initialize()
{
// 检测域名授权
//$auth = json_decode(curl('https://service.lskys.cc/server.php', ['action' => 'auth', 'domain' => $_SERVER['HTTP_HOST']]), true);
//if(!$auth['code']) die('程序未授权请联系QQ<a href="http://wpa.qq.com/msgrd?v=3&uin=1591788658&site=qq&menu=yes">1591788658</a> 授权!');
$this->web = Config::get('web');
$this->conf = getSystemConf();
$this->conf['file_path'] = Config::get('file_path');
$this->conf['theme_path'] = Config::get('theme_path');
$this->user = $this->getUser();
$this->scheme = getSchemeList();
$this->assign('web', $this->web);
$this->assign('conf', $this->conf);
$this->assign('user', $this->user);
}
/**
* 未登录重定向
* @return bool|void
*/
protected function isLoginRedirect()
{
return $this->user ? true : $this->redirect('/login');
}
/**
* 获取已登录会员信息
* @return array|bool|false|\PDOStatement|string|\think\Model
*/
public function getUser()
{
if(!$this->user) {
$login_status = session('login_status');
$user = Db::name('user')->where('login_status', $login_status)->find();
return $user ? $user : false;
}
return false;
}
/**
* 直接返回json
* @param int $code 状态码
* @param string $msg 状态信息
* @param string $data 返回数据(可选)
* @return \think\response\Json
*/
protected function json($code, $msg, $data = '', $url = '')
{
$result = ['code' => $code, 'msg' => $msg];
if(!empty($data)) $result['data'] = $data;
if(!empty($url)) $result['url'] = $url;
return json($result);
}
/**
* 自定义加密方式
* @param $str
* @return string
*/
protected function md6($str)
{
return md5("LK{$str}");
}
}

View File

@ -0,0 +1,218 @@
<?php
namespace app\index\controller;
use think\Config;
use think\Db;
use think\Request;
use Qiniu\Auth;
use Qiniu\Storage\UploadManager;
use Upyun\Upyun;
class Index extends Common
{
public function index()
{
if(Request::instance()->isAjax()) {
if(!$this->user) return $this->response(0, '你没有登录,无法上传图片');
$file = Request::instance()->file('img');
switch ((int)$this->conf['upload_scheme_id']) {
// 本地
case 1:
return $this->localUpload($file);
break;
// 七牛云
case 2:
return $this->qiniuUpload($file);
break;
// 又拍云
case 3:
return $this->upyunUpload($file);
break;
// TODO 阿里OSS
case 4:
break;
default:
return $this->localUpload($file);
break;
}
}
$this->conf['web_title'] = "{$this->conf['web_title']} - 免费的图片托管平台";
$this->assign('conf', $this->conf);
return $this->fetch();
}
/**
* 本地上传
* @param $file TP上传文件资源
* @return string
*/
private function localUpload($file)
{
if($file) {
$date = date('Ymd', time());
$info = $file->validate(['size'=> $this->conf['upload_max_filesize'] * 1024, 'ext'=> $this->conf['upload_images_ext']])->rule('uniqid')->move("{$this->conf['file_path']}/{$this->user['id']}/" . $date);
if($info) {
$file_path = str_replace("\\", "/", Config::get('web.domain') . "/pic/{$this->user['id']}/{$date}/{$info->getSaveName()}");
return $this->saveImg(
1,
$info->getFilename(),
$file->getInfo('type'),
$info->getSize(),
$info->hash('sha1'),
str_replace("\\", "/", "{$this->user['id']}/{$date}/{$info->getSaveName()}"),
$file_path
);
} else {
return $this->response(0, $file->getError());
}
}
}
/**
* 七牛云上传
* @param $file TP文件资源
*/
private function qiniuUpload($file)
{
// TODO 图片合法性验证
Db::startTrans();
try {
// 初始化签权对象
$auth = new Auth($this->scheme['qiniu']['access_key'], $this->scheme['qiniu']['secret_key']);
// 生成上传Token
$token = $auth->uploadToken($this->scheme['qiniu']['bucket_name']);
// 构建 UploadManager 对象
$uploadMgr = new UploadManager();
// 文件名
$file_name = uniqid() . ".{$this->getFileExt($file->getInfo('name'))}";
// 文件夹名
$file_dir = "{$this->user['id']}/" . date('Y-m-d', time()) . "/";
// 文件路径
$file_path = $file_dir . $file_name;
// 上传文件
$upload = $uploadMgr->putFile($token, $file_path, $file->getInfo('tmp_name'));
if($upload) {
// 获取文件信息
$config = new \Qiniu\Config();
$bucketManager = new \Qiniu\Storage\BucketManager($auth, $config);
list($file_info, $err) = $bucketManager->stat($this->scheme['qiniu']['bucket_name'], $file_path);
if ($err) {
//print_r($err);
} else {
$this->saveImg(
$this->scheme['qiniu']['id'],
$file_name,
$file_info['mimeType'],
$file_info['fsize'],
$file_info['hash'],
$file_path,
"{$this->scheme['qiniu']['domain']}/{$file_path}"
);
}
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
die("Code {$e->getCode()} Msg: {$e->getMessage()}");
}
}
private function upyunUpload($file)
{
// TODO 图片合法性验证
Db::startTrans();
try {
// 创建实例
$bucketConfig = new \Upyun\Config($this->scheme['upyun']['bucket_name'], $this->scheme['upyun']['access_key'], $this->scheme['upyun']['secret_key']);
$client = new Upyun($bucketConfig);
// 文件名
$file_name = uniqid() . ".{$this->getFileExt($file->getInfo('name'))}";
// 文件夹名
$file_dir = "{$this->user['id']}/" . date('Y-m-d', time()) . "/";
// 文件路径
$file_path = $file_dir . $file_name;
// 读文件
$file_names = fopen($file->getInfo('tmp_name'), 'r');
$res = $client->write($file_path, $file_names);
if(count($res) > 0) {
$this->saveImg(
$this->scheme['upyun']['id'],
$file_name,
$file->getInfo('type'),
$file->getInfo('size'),
$file->hash('sha1'),
$file_path,
"{$this->scheme['upyun']['domain']}/{$file_path}"
);
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
die("Code {$e->getCode()} Msg: {$e->getMessage()}");
}
}
/**
* 保存图片数据
* @param $scheme_id 文件储存方式1本地2七牛3又拍4阿里OSS
* @param $name 文件名
* @param $type 文件类型
* @param $size 文件大小(kb)
* @param $hash 文件hash值
* @param $path 文件相对路径
* @param $paths 文件绝对路径
* @param $url 文件访问url
* @return string
*/
private function saveImg($scheme_id, $name, $type, $size, $hash, $path, $paths)
{
$ins = Db::name('file')->insert([
'user_id' => $this->user['id'],
'scheme_id' => $scheme_id,
'name' => $name,
'type' => $type,
'size' => $size,
'hash' => $hash,
'path' => $path,
'upload_time' => time()
]);
if($ins) {
return $this->response(true, 'success', [
'ip' => Request::instance()->ip(),
'size' => $size,
'url' => $paths
]);
} else {
unlink($path);
return $this->response(0, '文件信息保存失败');
}
}
/**
* 获取文件后缀
* @param $file 文件名
* @return mixed
*/
private function getFileExt($file)
{
return pathinfo($file, PATHINFO_EXTENSION);
}
/**
* 返回上传数据
* @param $code bool 状态
* @param $data array 数据
* @return string
*/
private function response($code, $msg = '', array $data = [])
{
$response = [
'code' => is_numeric($code) ? $code : ($code ? 'success' : 'error'),
];
if(!empty($msg)) $response['msg'] = $msg;
if(count($data) > 0) $response['data'] = $data;
echo(json_encode($response));
}
}

View File

@ -0,0 +1,110 @@
<?php
namespace app\index\controller;
use think\Db;
use think\Request;
use mail\Smtp;
class Login extends Common
{
public function index()
{
if(Request::instance()->isAjax()) {
$input = trimArray(Request::instance()->param());
$user_db = Db::name('user');
if(filter_var($input['user'], FILTER_VALIDATE_EMAIL)) {
// 验证邮箱
$where = ['email' => $input['user']];
$is_user = $user_db->where($where)->count() > 0 ? true : false;
$user = '邮箱';
} else {
// 验证用户名
$where = ['username' => $input['user']];
$is_user = $user_db->where($where)->count() > 0 ? true : false;
$user = '用户名';
}
if(!$is_user) return parent::json(0, "{$user}不存在!");
$where['password'] = $this->md6($input['password']);
if($user_db->where($where)->count() > 0 ? true : false) {
$login_status = base64_encode(uniqid() . time());
if($user_db->where($where)->update(['login_status' => $login_status, 'login_time' => time(), 'login_ip' => Request::instance()->ip()])) {
session('login_status', $login_status);
return parent::json(1, '登录成功');
}
return parent::json(0, '登录失败');
}
return parent::json(0, "{$user}或密码错误!");
}
$this->conf['web_title'] = "登录 - {$this->conf['web_title']}";
$this->assign('conf', $this->conf);
return $this->fetch();
}
/**
* 获取邮箱验证码
* @param $email
* @return \think\response\Json
*/
public function getEmailCode($email)
{
if(Request::instance()->isAjax()) {
if(Db::name('user')->where('email', $email)->count() > 0 ? true : false) {
$code = getCode();
$smtp = new Smtp(
$this->conf['smtp_host'],
$this->conf['smtp_port'],
$this->conf['smtp_auth'],
$this->conf['smtp_user'],
$this->conf['smtp_pass'],
$this->conf['smtp_ssl']
);
$html = "<h2>重置密码</h2><hr><p>你本次的验证码是 <b>{$code}</b></p><p>(如果不是您本人发起的,请忽略此邮件。)</p><br><hr><p>「{$this->conf['web_title']}」</p>";
$send = $smtp->send($email, $this->conf['smtp_user'], "{$this->conf['web_title']}」重置密码", $html);
if($send) {
session('reset_pass', ['reset_email' => $email, 'email_code' => $code]);
} else {
return parent::json(0, '验证码发送失败');
}
return parent::json(1, '验证码发送成功');
}
return parent::json(0, '邮箱不存在');
}
}
/**
* 校检邮件验证码
* @param $code
* @return \think\response\Json
*/
public function isEmailCode($code)
{
if(Request::instance()->isAjax()) {
$reset_pass = session('reset_pass');
if($code == $reset_pass['email_code']) {
// 用户输入的验证码
session('user_code', $code);
return parent::json(1, '验证成功');
}
return parent::json(0, '验证码错误');
}
}
/**
* 重置密码
* @param $password
* @return \think\response\Json
*/
public function resetPassWord($password) {
if(Request::instance()->isAjax()) {
$reset_pass = session('reset_pass');
if(session('user_code') == $reset_pass['email_code']) {
if(Db::name('user')->where('email', $reset_pass['reset_email'])->setField('password', parent::md6($password))) {
session('reset_pass', null);
session('user_code', null);
return parent::json(1, '重置成功');
}
return parent::json(0, '重置失败');
}
}
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace app\index\controller;
use gt\gtCaptcha;
use think\Db;
use think\Request;
use think\Loader;
class Reg extends Common
{
public function _initialize()
{
$this->conf = getSystemConf();
$this->assign('conf', $this->conf);
$this->assign('user', false);
}
public function index()
{
if(Request::instance()->isAjax()) {
if($this->conf['reg_close']) return $this->error('注册功能已关闭');
if($this->gtVerifyServlet()) {
$input = trimArray(Request::instance()->param());
$validate = Loader::validate('Reg');
if(!$validate->check($input)) {
return parent::json(0, $validate->getError());
} elseif ($input['password'] != $input['passwords']) {
return parent::json(0, '两次输入的密码不一致');
}
$data = [
'email' => $input['email'],
'username' => $input['username'],
'password' => parent::md6($input['password']),
'reg_ip' => Request::instance()->ip(),
'reg_time' => time(),
];
if(Db::name('user')->insert($data)) {
return parent::json(1, '注册成功');
}
return parent::json(0, '注册失败');
}
return parent::json(0, '人类验证失败,请刷新重试');
}
$this->conf['web_title'] = "注册 - {$this->conf['web_title']}";
$this->assign('conf', $this->conf);
return $this->fetch();
}
public function gtStartCaptchaServlet()
{
$GtSdk = new gtCaptcha($this->conf['captcha_id'], $this->conf['private_key']);
$data = array(
"uid" => uniqid(), # 网站用户id
"client_type" => "web", #web:电脑上的浏览器h5:手机上的浏览器包括移动应用内完全内置的web_viewnative通过原生SDK植入APP应用的方式
"ip_address" => Request::instance()->ip() # 请在此处传输用户请求验证时所携带的IP
);
$status = $GtSdk->pre_process($data, 1);
session('gtserver', $status);
session('uid', $data['uid']);
echo $GtSdk->get_response_str();
}
public function gtVerifyServlet()
{
$GtSdk = new gtCaptcha($this->conf['captcha_id'], $this->conf['private_key']);
$data = array(
"uid" => session('uid'), # 网站用户id
"client_type" => "web", #web:电脑上的浏览器h5:手机上的浏览器包括移动应用内完全内置的web_viewnative通过原生SDK植入APP应用的方式
"ip_address" => Request::instance()->ip() # 请在此处传输用户请求验证时所携带的IP
);
if (session('gtserver') == 1) { //服务器正常
$result = $GtSdk->success_validate(
Request::instance()->param('geetest_challenge'),
Request::instance()->param('geetest_validate'),
Request::instance()->param('geetest_seccode'),
$data);
if ($result) {
session(null);
return $this->verifyStatus(true);
} else {
return $this->verifyStatus();
}
} else { //服务器宕机,走failback模式
if ($GtSdk->fail_validate(
Request::instance()->param('geetest_challenge'),
Request::instance()->param('geetest_validate'),
Request::instance()->param('geetest_seccode')
)) {
session(null);
return $this->verifyStatus(true);
} else {
return $this->verifyStatus();
}
}
}
private function verifyStatus($status = false)
{
return $status;
//echo json_encode(['status' => $status ? 'success' : 'fail']);
}
}

View File

@ -0,0 +1,205 @@
<?php
namespace app\index\controller;
use think\Request;
use think\File;
use think\Db;
use think\Loader;
use Qiniu\Auth;
use Upyun\Upyun;
class User extends Common
{
public function _initialize()
{
parent::_initialize();
parent::isLoginRedirect();
}
public function index()
{
$this->conf['web_title'] = "用户中心 - {$this->conf['web_title']}";
$this->assign('conf', $this->conf);
return $this->fetch();
}
/**
* 分页获取图片数据
* @param $page 页码
* @param $limit 每页显示条数
* @param array $so 搜索条件
* @param string $sort 排序条件
* @return \think\response\Json
*/
function getImgList($page, $limit, array $so = [], $sort = '')
{
if(Request::instance()->isAjax()) {
$where = ['id' => ['gt', 0]];
$map = count($so) > 0 ? trimArray($so) : false;
if($map) {
if(!empty($map['date'])) {
$date = explode(' - ', $map['date']);
foreach ($date as $key => $val) {
switch ($key) {
case 0: $where['upload_time'] = ['gt', strtotime($val)];
case 1: $where['upload_time'] = ['lt', strtotime($val)];
}
}
}
if(!empty($map['search_val'])) $where['name'] = ['like', "%{$map['search_val']}%"];
}
// 上传方案
$scheme = getSchemeList();
$data = Db::name('file')->where('user_id', $this->user['id'])->where($where)->order(!empty($sort) ? $sort : 'upload_time desc')->page($page, $limit)->select();
foreach ($data as &$val) {
switch ($val['scheme_id']) {
case 1:
$val['url'] = "{$this->web['domain']}/pic/{$val['path']}"; break;
case 2:
$val['url'] = "{$scheme['qiniu']['domain']}/{$val['path']}"; break;
case 3:
$val['url'] = "{$scheme['upyun']['domain']}/{$val['path']}"; break;
// TODO case 4
}
}
return parent::json(1, 'success', $data);
}
}
/**
* 编辑资料
* @return \think\response\Json
*/
public function edit()
{
if(Request::instance()->isAjax()) {
$input = trimArray(Request::instance()->param());
$validate = Loader::validate('Edit');
if(!$validate->check($input)) return parent::json(0, $validate->getError());
if(!empty($input['password'])) {
if($input['password'] != $input['passwords']) {
return parent::json(0, '两次输入的密码不一致');
}
$input['password'] = parent::md6($input['password']);
} else {
unset($input['password']);
}
unset($input['passwords']);
$input['edit_time'] = time();
if(Db::name('user')->where('id', $this->user['id'])->update($input)) {
return parent::json(1, '修改成功');
}
return parent::json(0, '修改失败');
}
}
/**
* 退出账号
*/
public function logout()
{
if(Request::instance()->isAjax()) {
session('login_status', null);
}
}
/**
* 删除文件及记录
* @param $id
* @return \think\response\Json
*/
public function picDel($id)
{
if(Request::instance()->isAjax()) {
Db::startTrans();
try {
$file_db = Db::name('file');
$map = ['id' => $id, 'user_id' => $this->user['id']];
$file_info = $file_db->where($map)->find();
switch ($file_info['scheme_id']) {
case 1: // 删除本地文件
// 删除文件记录
if($file_db->where($map)->delete()) {
// 删除文件
@unlink("{$this->conf['file_path']}/{$file_info['path']}");
}
break;
case 2: // 删除七牛云文件
$auth = new Auth($this->scheme['qiniu']['access_key'], $this->scheme['qiniu']['secret_key']);
$config = new \Qiniu\Config();
$bucketManager = new \Qiniu\Storage\BucketManager($auth, $config);
$bucketManager->delete($this->scheme['qiniu']['bucket_name'], $file_info['path']);
$file_db->where($map)->delete();
break;
case 3: // 删除又拍云文件
if($file_db->where($map)->delete()) {
// 创建实例
$bucketConfig = new \Upyun\Config($this->scheme['upyun']['bucket_name'], $this->scheme['upyun']['access_key'], $this->scheme['upyun']['secret_key']);
$client = new Upyun($bucketConfig);
// 删除文件
$client->delete($file_info['path']);
// 删除目录
//$client->deleteDir(substr('/' . $file_info['path'], 0, strrpos($file_info['path'], '/')));
}
break;
case 4: // 删除阿里OSS文件
break;
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return parent::json(0, "删除失败,{$e->getMessage()}");
}
return parent::json(1, "删除成功");
}
}
/**
* 批量删除
* @param $array
* @return \think\response\Json
*/
public function picBatchDel($array)
{
if(Request::instance()->isAjax()) {
Db::startTrans();
try {
$file_db = Db::name('file');
foreach ($array as $val) {
$file_info = $file_db->where(['id' => $val, 'user_id' => $this->user['id']])->find();
switch ($file_info['scheme_id']) {
case 1: // 删除本地文件
@unlink("{$this->conf['file_path']}/{$file_info['path']}");
$file_db->where('id', $val)->delete();
break;
case 2: // 删除七牛云文件
$auth = new Auth($this->scheme['qiniu']['access_key'], $this->scheme['qiniu']['secret_key']);
$config = new \Qiniu\Config();
$bucketManager = new \Qiniu\Storage\BucketManager($auth, $config);
$bucketManager->delete($this->scheme['qiniu']['bucket_name'], $file_info['path']);
$file_db->where('id', $val)->delete();
break;
case 3: // 删除又拍云文件
$file_db->where('id', $val)->delete();
// 创建实例
$bucketConfig = new \Upyun\Config($this->scheme['upyun']['bucket_name'], $this->scheme['upyun']['access_key'], $this->scheme['upyun']['secret_key']);
$client = new Upyun($bucketConfig);
$client->delete($file_info['path']);
// 删除目录
//$client->deleteDir(substr('/' . $file_info['path'], 0, strrpos($file_info['path'], '/')));
break;
case 4: // 删除阿里OSS文件
//$file_db->where('id', $val)->delete();
break;
}
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return parent::json(0, "删除失败,{$e->getMessage()}");
}
return parent::json(1, '删除成功');
}
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* 注册会员验证器
* @author WispX
* @copyright WispX
* @link http://gitee.com/wispx
*/
namespace app\index\validate;
use think\Validate;
class Edit extends Validate
{
protected $rule = [
'username' => 'require|chsAlphaNum|length:2, 25',
'password' => 'length:4, 25',
];
protected $message = [
'username.require' => '用户名不能为空',
'username.chsAlphaNum' => '用户名名只能是汉字、字母和数字',
'username.length' => '用户名长度必须在2-25之间',
'password.length' => '密码必须在4-25个字符之间',
];
}

View File

@ -0,0 +1,33 @@
<?php
/**
* 注册会员验证器
* @author WispX
* @copyright WispX
* @link http://gitee.com/wispx
*/
namespace app\index\validate;
use think\Validate;
class Reg extends Validate
{
protected $rule = [
'email' => 'require|regex:/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/',
'username' => 'require|chsAlphaNum|length:2, 25',
'password' => 'require|length:4, 25',
'passwords' => 'require',
];
protected $message = [
'email.require' => 'email不能为空',
'email.regex' => 'email格式不正确',
'username.require' => '用户名不能为空',
'username.chsAlphaNum' => '用户名名只能是汉字、字母和数字',
'username.length' => '用户名长度必须在2-25之间',
'password.require' => '请输入密码',
'password.length' => '密码必须在4-25个字符之间',
'passwords.require' => '请输入确认密码'
];
}

View File

@ -0,0 +1,7 @@
<footer>
<div class="container">
<p class="text-muted">Copyright &copy; 2017 <a href="http://www.lskys.cc">兰空</a> Powered by <a href="http://www.xlogs.cn">WispX</a>. All rights reserved. 请勿上传违反中国大陆和香港法律的图片,违者后果自负。</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{$conf.web_title}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="keywords" content="{$conf.keywords}" />
<meta name="description" content="{$conf.description}" />
{css href="_layui_css/layui.css"}
{css href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css"}
{css href="//cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css"}
{css href="//cdn.bootcss.com/bootstrap-fileinput/4.4.3/css/fileinput.min.css"}
{css href="_css_main.css"}
{js href="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"}
{js href="//cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"}
{js href="//cdn.bootcss.com/bootstrap-fileinput/4.4.3/js/fileinput.min.js"}
{js href="//cdn.bootcss.com/bootstrap-fileinput/4.4.3/js/locales/zh.min.js"}
{js href="_layui_layui.js"}
{js href="_js_main.js"}
</head>
<!-- 自定义style -->
<style type="text/css">
{$conf.custom_style}
</style>
<body>
<nav class="header navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#menu">
<span class="sr-only">navbar</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/"><i class="fa fa-leaf fa-fw"></i> 兰空</a>
</div>
<div class="collapse navbar-collapse" id="menu">
<ul class="nav navbar-nav navbar-left">
<!--<li><a href="/">首页</a></li>-->
</ul>
<ul class="nav navbar-nav navbar-right">
{if condition="$user"}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{$user.email} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{:url('/user')}">管理</a></li>
{if condition="$user.id eq 1"}
<li><a href="{:url('/admin.php')}">后台</a></li>
{/if}
<li role="separator" class="divider"></li>
<li><a href="javascript:logout()">退出</a></li>
</ul>
</li>
{else /}
<li><a href="{:url('/reg')}">注册</a></li>
<li><a href="{:url('/login')}">登录</a></li>
{/if}
</ul>
</div>
</div>
</nav>

View File

@ -0,0 +1,16 @@
<?php
/**
* 主题配置文件
* User: WispX
* Date: 2017/9/23
* Time: 8:53
* Link: http://gitee.com/wispx
*/
return [
'name' => '默认',
'key' => 'default',
'author' => 'WispX',
'explain' => '官方默认主题',
'images' => '/static/images/preview.jpg', // 除官方外,这里必须是绝对路径
'link' => 'http://www.xlogs.cn',
];

View File

@ -0,0 +1,77 @@
{include file="/common/header"}
<div class="container">
<div class="fileinput lk-panel">
<h1>请选择图片上传 <small>最大限制 {$conf.upload_max_filesize / 1024|round=###, 2}M</small></h1>
<form enctype="multipart/form-data">
<div class="form-group">
<input id="img" type="file" multiple class="file" data-overwrite-initial="false" data-min-file-count="1" data-max-file-count="10" name="img" accept="image/*">
</div>
</form>
</div>
<div id="link" class="lk-panel none">
<ul id="navTab" class="nav nav-tabs">
<li class="active"><a href="#urlcodes" data-toggle="tab">URL</a></li>
<li><a href="#htmlcodes" data-toggle="tab">HTML</a></li>
<li><a href="#bbcodes" data-toggle="tab">BBCode</a></li>
<li><a href="#markdowncodes" data-toggle="tab">Markdown</a></li>
<li><a href="#markdowncodes2" data-toggle="tab">Markdown with Link</a></li>
</ul>
<div id="navTabContent" class="tab-content">
<div class="tab-pane fade in active" id="urlcodes">
<pre style="margin-top: 5px;"><code id="urlcode"></code></pre>
</div>
<div class="tab-pane fade" id="htmlcodes">
<pre style="margin-top: 5px;"><code id="htmlcode"></code></pre>
</div>
<div class="tab-pane fade" id="bbcodes">
<pre style="margin-top: 5px;"><code id="bbcode"></code></pre>
</div>
<div class="tab-pane fade" id="markdowncodes">
<pre style="margin-top: 5px;"><code id="markdown"></code></pre>
</div>
<div class="tab-pane fade" id="markdowncodes2">
<pre style="margin-top: 5px;"><code id="markdownlinks"></code></pre>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$("#img").fileinput({
uploadUrl: './',
language: 'zh',
allowedFileExtensions : ['{$conf.upload_images_ext|str_replace=",", "','", ###}'],
overwriteInitial: false,
//browseClass: "btn btn-info",
maxFileSize: {$conf.upload_max_filesize},
maxFileCount: {$conf.upload_max_file_count},
browseIcon: "<i class=\"glyphicon glyphicon-picture\"></i>"
});
$('#img').on('fileuploaded', function(event, data, previewId, index) {
var form = data.form, files = data.files, extra = data.extra, response = data.response, reader = data.reader;
if(response.code == 'success') {
if ($("#link").css("display") != 'none') {
$('#urlcode').append(response.data.url + "\n");
$('#htmlcode').append("&lt;img src=\""+ response.data.url +"\" alt=\""+ files[index].name +"\" title=\""+ files[index].name +"\" /&gt;" + "\n");
$('#bbcode').append("[img]"+ response.data.url +"[/img]" + "\n");
$('#markdown').append("!["+ files[index].name +"](" + response.data.url + ")" + "\n");
$('#markdownlinks').append("[!["+ files[index].name +"](" + response.data.url + ")]" +"(" + response.data.url + ")" + "\n");
$('#deletecode').append(response.data.delete + "\n");
} else if (response.data.url) {
$("#link").show();
$('#urlcode').append(response.data.url + "\n");
$('#htmlcode').append("&lt;img src=\""+ response.data.url +"\" alt=\""+ files[index].name +"\" title=\""+ files[index].name +"\" /&gt;" + "\n");
$('#bbcode').append("[img]"+ response.data.url +"[/img]" + "\n");
$('#markdown').append("!["+ files[index].name +"](" + response.data.url + ")" + "\n");
$('#markdownlinks').append("[!["+ files[index].name +"](" + response.data.url + ")]" +"(" + response.data.url + ")" + "\n");
$('#deletecode').append(response.data.delete + "\n");
}
} else if (response.code == 0) {
return layer.msg(response.msg, {icon: 2});
}
});
/*$('#img').on('fileerror', function(event, data, msg) {
console.log(msg);
});*/
</script>
{include file="/common/footer"}

View File

@ -0,0 +1,47 @@
{include file="/common/header"}
<div class="container">
<div class="row">
<div class="col-md-6 col-sm-6 col-1g-6 login">
<div class="lk-panel">
<h1 class="text-center">登录</h1>
<form class="layui-form" action="" method="post">
<div class="layui-form-item">
<input type="text" name="user" required="" lay-verify="required" placeholder="请输入邮箱/用户名" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<input type="password" name="password" required="" lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<div class="pull-right">
<a href="javascript:forgot()">忘记密码?</a>
</div>
</div>
<div class="layui-form-item">
<button class="layui-btn btn-block" id="sign-in" lay-submit="" lay-filter="sign-in">登录</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
layui.use('form', function() {
var form = layui.form;
form.on('submit(sign-in)', function(data) {
btnLoad('#sign-in', '登录中...');
$.post('', data.field, function(result) {
closeBtnLoad('#sign-in', '登录');
if(result.code) {
layer.msg(result.msg, {icon: 1}, function(index) {
layer.close(index);
location.href = '/';
});
} else {
layer.msg(result.msg, {icon: 2});
}
});
return false;
});
});
</script>
{include file="/common/footer"}

View File

@ -0,0 +1,93 @@
{include file="/common/header"}
<style type="text/css">
.geetest_holder.geetest_wind { width: 100%!important; }
</style>
<div class="container">
<div class="row">
<div class="col-md-6 col-sm-6 col-1g-6 reg">
<div class="lk-panel">
<h1 class="text-center">注册</h1>
<form class="layui-form" action="" method="post">
<div class="layui-form-item">
<input type="email" name="email" required lay-verify="required" placeholder="请输入邮箱" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<input type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<input type="password" name="passwords" required lay-verify="required" placeholder="请输入确认密码" autocomplete="off" class="layui-input">
</div>
{if condition="!$conf.reg_close"}
<div class="layui-form-item">
<div id="embed-captcha"></div>
<p id="wait">正在加载验证码......</p>
</div>
{/if}
<div class="layui-form-item">
<button class="layui-btn btn-block" id="sign-up" lay-submit="" lay-filter="sign-up"{if condition="$conf.reg_close"} disabled>已关闭注册{else /}>注册{/if}</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="_js_gt.js"></script>
<script type="text/javascript">
layui.use('form', function() {
var form = layui.form;
$.ajax({
// 获取idchallengesuccess是否启用failback
url: "/reg/gtStartCaptchaServlet",
type: "post",
data: {'t': (new Date()).getTime()},
dataType: "json",
success: function (data) {
// 使用initGeetest接口
// 参数1配置参数
// 参数2回调回调的第一个参数验证码对象之后可以使用它做appendTo之类的事件
initGeetest({
gt: data.gt,
challenge: data.challenge,
new_captcha: data.new_captcha,
protocol: 'https://',
product: "popup", // 产品形式包括floatembedpopup。注意只对PC版验证码有效
offline: !data.success // 表示用户后台检测极验服务器是否宕机,一般不需要关注
}, handlerEmbed);
}
});
//监听提交
var handlerEmbed = function (captchaObj) {
form.on('submit(sign-up)', function(data) {
var validate = captchaObj.getValidate();
if (!validate) {
layer.msg('请完成验证', function() {});
return false;
} else {
btnLoad('#sign-up', '注册中...');
$.post('', data.field, function(res) {
closeBtnLoad('#sign-up', '注册');
if(res.code) {
return layer.alert('注册成功', {icon: 1}, function (index) {
layer.close(index);
window.location.href = '/login';
});
}
return layer.alert(res.msg, {icon: 2});
});
}
return false;
});
// 将验证码加到id为captcha的元素里同时会有三个input的值geetest_challenge, geetest_validate, geetest_seccode
captchaObj.appendTo("#embed-captcha");
// 验证码加载完成
captchaObj.onReady(function () {
$("#wait").hide();
});
};
});
</script>
{include file="/common/footer"}

View File

@ -0,0 +1,216 @@
{include file="/common/header"}
<style type="text/css">
.layui-form-label { width: 100px; text-align: center; }
</style>
<div class="container">
<div class="user">
<div class="layui-tab layui-tab-brief" lay-filter="menu">
<ul class="layui-tab-title">
<li class="layui-this">图片管理</li>
<li>修改资料</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show fadeInDown animated">
<div class="list-per">
<form class="layui-form" action="" method="post">
<div class="layui-inline">
<div class="layui-input-inline">
<select name="sort" lay-verify="required" lay-filter="sort">
<option value="1">最新的</option>
<option value="2">最旧的</option>
<option value="3">最大的</option>
<option value="4">最小的</option>
</select>
</div>
</div>
<div class="layui-inline">
<div class="layui-input-inline">
<input type="text" name="date" class="layui-input" id="date" placeholder=" - ">
</div>
</div>
<div class="layui-inline">
<div class="layui-input-inline">
<input type="text" name="search_val" value="" placeholder="请输入文件名" class="layui-input">
</div>
<button class="layui-btn search_btn layui-btn-small layui-btn-primary" lay-submit lay-filter="search_btn">查询</button>
</div>
<div class="layui-inline pull-right layui-btn-group">
<button type="button" class="layui-btn batchDel layui-btn-small checkBoxAll" onclick="checkBoxAll()">全选</button>
<button type="button" class="layui-btn layui-btn-danger batchDel layui-btn-small" onclick="picBatchDel()">批量删除</button>
</div>
</form>
</div>
<div class="row list">
</div>
</div>
<div class="layui-tab-item fadeInDown animated">
<div class="row">
<div class="col-md-6 col-1g-6">
<form class="form-horizontal layui-form" role="form">
<div class="form-group">
<label for="email" class="col-sm-2 control-label">Email</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="email" placeholder="请输入Email" value="{$user.email}" disabled>
</div>
</div>
<div class="form-group">
<label for="username" class="col-sm-2 control-label">昵称</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="username" name="username" placeholder="请输入昵称" value="{$user.username}">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">密码</label>
<div class="col-sm-10">
<input type="password" class="form-control" id="password" name="password" placeholder="不修改请留空">
</div>
</div>
<div class="form-group">
<label for="passwords" class="col-sm-2 control-label">确认</label>
<div class="col-sm-10">
<input type="password" class="form-control" id="passwords" name="passwords" placeholder="请输入确认密码">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default" id="edit" lay-submit lay-filter="edit">修改</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{js href="//cdn.bootcss.com/clipboard.js/1.7.1/clipboard.min.js"}
<script type="text/javascript">
layui.use(['flow', 'layer', 'laydate', 'form'], function() {
var flow = layui.flow, layer = layui.layer, laydate = layui.laydate, form = layui.form;
var rows = {$conf.img_rows}; // 每页显示数量
laydate.render({
elem: '#date',
range: true
});
getImgList([], $('[name=search_val]').val());
function getImgList(so, sort) {
flow.load({
elem: '.list',
isAuto: {$conf.flow_load_mode ? 'true' : 'false'},
isLazyimg: true,
done: function(page, next) {
var lis = [];
$.ajax({
url: 'user/getImgList',
type: 'POST',
timeout: 8000,
data: {'page': page, 'limit': rows, 'so': so, 'sort': sort},
dataType: 'JSON',
success: function(res) {
if(res.code) {
var data = res.data;
var append = '';
layui.each(data, function(k, v) {
append += "<div class=\"picture pic-"+ v.id +" col-md-3 col-sm-3 col-1g-3\"><i title=\"选中\" data-id="+ v.id + " class=\"pic-del fa fa-circle-thin\"></i>";
append += " <div class=\"img\">";
append += " <img lay-src=\""+ v.url +"\">";
append += " <div class=\"img-per\">";
append += " <div class=\"input-group\">";
append += " <input class=\"form-control input-sm\" id=\"copy-"+ v.id +"\" value=\""+ v.url +"\">";
append += " <div class=\"input-group-btn\">";
append += " <button class=\"btn btn-default btn-sm copy\" data-clipboard-action=\"copy\" data-clipboard-target=\"#copy-"+ v.id +"\" title=\"复制\"><i class=\"fa fa-copy\"></i></button>";
append += " <button class=\"btn btn-default btn-sm\" onclick=\"picDel(" + v.id + ")\" title=\"删除\"><i class=\"fa fa-trash-o\"></i></button>";
append += " <a href=\""+ v.url +"\" target=\"_blank\" title=\"新窗口打开\" class=\"btn btn-default btn-sm\"><i class=\"fa fa-rocket\"></i></a>";
append += " </div>";
append += " </div>";
append += " </div>";
append += " </div>";
append += "</div>";
});
lis.push(append)
next(lis.join(''), rows == (data ? data.length : '没有更多啦'));
/*layer.msg('加载中', {
icon: 16,
shade: 0.1,
time: 2000
}, function() {
// 大图预览
layer.photos({
photos: '.img',
anim: 0
});
});*/
layer.photos({
photos: '.img',
anim: 0
});
$('.pic-del').click(function() {
var t = $(this);
// 判断是否选中
if(t.hasClass('fa-check-circle-o')) {
t.removeClass('fa-check-circle-o');
t.addClass('fa-circle-thin');
} else {
t.removeClass('fa-circle-thin');
t.addClass('fa-check-circle-o');
}
});
}
},
error: function(err) {
layer.msg(err);
}
});
}
});
}
form.on('submit(search_btn)', function(data) {
//layer.load(2);
$('.list').html('');
getImgList(data.field);
//layer.closeAll('loading');
return false;
});
form.on('select(sort)', function(data) {
var sort = '';
switch (parseInt(data.value)) {
case 1: sort = 'upload_time desc'; break;
case 2: sort = 'upload_time asc'; break;
case 3: sort = 'size desc'; break;
case 4: sort = 'size asc'; break;
default: sort = 'upload_time desc';
}
$('.list').html('');
return getImgList([], sort);
});
//监听提交
form.on('submit(edit)', function(data) {
btnLoad('#edit');
//layer.msg(JSON.stringify(data.field));
$.post('/user/edit', data.field, function(res) {
closeBtnLoad('#edit', '修改');
return layer.msg(res.msg, {icon: res.code ? 1 : 2});
});
return false;
});
});
var clipboard = new Clipboard('.copy');
clipboard.on('success', function(e) {
/*console.info('Action:', e.action);
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);*/
layer.msg("复制成功", {icon: 1});
e.clearSelection();
});
clipboard.on('error', function(e) {
console.error('Action:', e.action);
console.error('Trigger:', e.trigger);
});
</script>
{include file="/common/footer"}

14
app/route.php Normal file
View File

@ -0,0 +1,14 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
];

28
app/tags.php Normal file
View File

@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 应用行为扩展定义文件
return [
// 应用初始化
'app_init' => [],
// 应用开始
'app_begin' => [],
// 模块初始化
'module_init' => [],
// 操作开始执行
'action_begin' => [],
// 视图内容过滤
'view_filter' => [],
// 日志写入
'log_write' => [],
// 应用结束
'app_end' => [],
];

36
composer.json Normal file
View File

@ -0,0 +1,36 @@
{
"name": "topthink/think",
"description": "the new thinkphp framework",
"type": "project",
"keywords": [
"framework",
"thinkphp",
"ORM"
],
"homepage": "http://thinkphp.cn/",
"license": "Apache-2.0",
"authors": [
{
"name": "liu21st",
"email": "liu21st@gmail.com"
}
],
"require": {
"php": ">=5.4.0",
"topthink/framework": "~5.0.0",
"qiniu/php-sdk": "^7.2",
"upyun/sdk": "^3.1"
},
"extra": {
"think-path": "thinkphp"
},
"config": {
"preferred-install": "dist"
},
"repositories": {
"packagist": {
"type": "composer",
"url": "https://packagist.phpcomposer.com"
}
}
}

454
composer.lock generated Normal file
View File

@ -0,0 +1,454 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "0de8498e2f3317e3601d435dc6d7a29f",
"packages": [
{
"name": "guzzlehttp/guzzle",
"version": "6.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/guzzle/guzzle/f4db5a78a5ea468d4831de7f0bf9d9415e348699.zip",
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.4",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.0 || ^5.0",
"psr/log": "^1.0"
},
"suggest": {
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.2-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2017-06-22T18:50:49+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/guzzle/promises/a59da6cf61d80060647ff4d3eb2c03a2bc694646.zip",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"time": "2016-12-20T10:07:11+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/guzzle/psr7/f5b8a8512e2b58b0071a7280e39f14f72e05d87c.zip",
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Schultze",
"homepage": "https://github.com/Tobion"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"request",
"response",
"stream",
"uri",
"url"
],
"time": "2017-03-20T17:10:46+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/php-fig/http-message/f6561bf28d520154e4b0ec72be95418abe6d9363.zip",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "qiniu/php-sdk",
"version": "v7.2.1",
"source": {
"type": "git",
"url": "https://github.com/qiniu/php-sdk.git",
"reference": "8c7ba738bd4443ee3569a07441913b07c4b2c4a2"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/qiniu/php-sdk/8c7ba738bd4443ee3569a07441913b07c4b2c4a2.zip",
"reference": "8c7ba738bd4443ee3569a07441913b07c4b2c4a2",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "~2.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Qiniu\\": "src/Qiniu"
},
"files": [
"src/Qiniu/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Qiniu",
"email": "sdk@qiniu.com",
"homepage": "http://www.qiniu.com"
}
],
"description": "Qiniu Resource (Cloud) Storage SDK for PHP",
"homepage": "http://developer.qiniu.com/",
"keywords": [
"cloud",
"qiniu",
"sdk",
"storage"
],
"time": "2017-08-26T00:46:11+00:00"
},
{
"name": "topthink/framework",
"version": "v5.0.11",
"source": {
"type": "git",
"url": "https://github.com/top-think/framework.git",
"reference": "45268eeba3da7eedaead09a524e2bc20a0132e29"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/top-think/framework/45268eeba3da7eedaead09a524e2bc20a0132e29.zip",
"reference": "45268eeba3da7eedaead09a524e2bc20a0132e29",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"topthink/think-installer": "~1.0"
},
"require-dev": {
"johnkary/phpunit-speedtrap": "^1.0",
"mikey179/vfsstream": "~1.6",
"phpdocumentor/reflection-docblock": "^2.0",
"phploc/phploc": "2.*",
"phpunit/phpunit": "4.8.*",
"sebastian/phpcpd": "2.*"
},
"type": "think-framework",
"autoload": {
"psr-4": {
"think\\": "library/think"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "liu21st",
"email": "liu21st@gmail.com"
}
],
"description": "the new thinkphp framework",
"homepage": "http://thinkphp.cn/",
"keywords": [
"framework",
"orm",
"thinkphp"
],
"time": "2017-09-07T10:37:47+00:00"
},
{
"name": "topthink/think-installer",
"version": "v1.0.12",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-installer.git",
"reference": "1be326e68f63de4e95977ed50f46ae75f017556d"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/top-think/think-installer/1be326e68f63de4e95977ed50f46ae75f017556d.zip",
"reference": "1be326e68f63de4e95977ed50f46ae75f017556d",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0"
},
"require-dev": {
"composer/composer": "1.0.*@dev"
},
"type": "composer-plugin",
"extra": {
"class": "think\\composer\\Plugin"
},
"autoload": {
"psr-4": {
"think\\composer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "yunwuxin",
"email": "448901948@qq.com"
}
],
"time": "2017-05-27T06:58:09+00:00"
},
{
"name": "upyun/sdk",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/upyun/php-sdk.git",
"reference": "bfccb98293b0a00165284bd1dc20c56e914d55a8"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/upyun/php-sdk/bfccb98293b0a00165284bd1dc20c56e914d55a8.zip",
"reference": "bfccb98293b0a00165284bd1dc20c56e914d55a8",
"shasum": ""
},
"require": {
"ext-curl": "*",
"guzzlehttp/guzzle": "~6.0",
"php": ">=5.5.0"
},
"require-dev": {
"consolidation/robo": "^1.0",
"phpdocumentor/phpdocumentor": "^2.9",
"phpunit/phpunit": "~4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Upyun\\": "src/Upyun/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "totoleo",
"email": "totoleo@163.com"
},
{
"name": "lfeng",
"email": "bonevv@gmail.com"
},
{
"name": "lvtongda",
"email": "riyao.lyu@gmail.com"
},
{
"name": "sabakugaara",
"email": "senellise@gmail.com"
}
],
"description": "UPYUN sdk for php",
"homepage": "https://github.com/upyun/php-sdk/",
"keywords": [
"sdk",
"upyun"
],
"time": "2017-08-15T02:41:45+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.4.0"
},
"platform-dev": []
}

258
extend/gt/gtCaptcha.php Normal file
View File

@ -0,0 +1,258 @@
<?php
/**
* 极验行为式验证安全平台php 网站主后台包含的库文件
*
* @author Tanxu
*/
namespace gt;
class gtCaptcha
{
const GT_SDK_VERSION = 'php_3.0.0';
public static $connectTimeout = 1;
public static $socketTimeout = 1;
private $response;
public function __construct($captcha_id, $private_key) {
$this->captcha_id = $captcha_id;
$this->private_key = $private_key;
}
/**
* 判断极验服务器是否down机
*
* @param array $data
* @return int
*/
public function pre_process($param, $new_captcha=1) {
$data = array('gt'=>$this->captcha_id,
'new_captcha'=>$new_captcha
);
$data = array_merge($data,$param);
$query = http_build_query($data);
$url = "http://api.geetest.com/register.php?" . $query;
$challenge = $this->send_request($url);
if (strlen($challenge) != 32) {
$this->failback_process();
return 0;
}
$this->success_process($challenge);
return 1;
}
/**
* @param $challenge
*/
private function success_process($challenge) {
$challenge = md5($challenge . $this->private_key);
$result = array(
'success' => 1,
'gt' => $this->captcha_id,
'challenge' => $challenge,
'new_captcha'=>1
);
$this->response = $result;
}
/**
*
*/
private function failback_process() {
$rnd1 = md5(rand(0, 100));
$rnd2 = md5(rand(0, 100));
$challenge = $rnd1 . substr($rnd2, 0, 2);
$result = array(
'success' => 0,
'gt' => $this->captcha_id,
'challenge' => $challenge,
'new_captcha'=>1
);
$this->response = $result;
}
/**
* @return mixed
*/
public function get_response_str() {
return json_encode($this->response);
}
/**
* 返回数组方便扩展
*
* @return mixed
*/
public function get_response() {
return $this->response;
}
/**
* 正常模式获取验证结果
*
* @param string $challenge
* @param string $validate
* @param string $seccode
* @param array $param
* @return int
*/
public function success_validate($challenge, $validate, $seccode,$param, $json_format=1) {
if (!$this->check_validate($challenge, $validate)) {
return 0;
}
$query = array(
"seccode" => $seccode,
"timestamp"=>time(),
"challenge"=>$challenge,
"captchaid"=>$this->captcha_id,
"json_format"=>$json_format,
"sdk" => self::GT_SDK_VERSION
);
$query = array_merge($query,$param);
$url = "http://api.geetest.com/validate.php";
$codevalidate = $this->post_request($url, $query);
$obj = json_decode($codevalidate,true);
if ($obj === false){
return 0;
}
if ($obj['seccode'] == md5($seccode)) {
return 1;
} else {
return 0;
}
}
/**
* 宕机模式获取验证结果
*
* @param $challenge
* @param $validate
* @param $seccode
* @return int
*/
public function fail_validate($challenge, $validate, $seccode) {
if(md5($challenge) == $validate){
return 1;
}else{
return 0;
}
}
/**
* @param $challenge
* @param $validate
* @return bool
*/
private function check_validate($challenge, $validate) {
if (strlen($validate) != 32) {
return false;
}
if (md5($this->private_key . 'geetest' . $challenge) != $validate) {
return false;
}
return true;
}
/**
* GET 请求
*
* @param $url
* @return mixed|string
*/
private function send_request($url) {
if (function_exists('curl_exec')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::$connectTimeout);
curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$curl_errno = curl_errno($ch);
$data = curl_exec($ch);
curl_close($ch);
if ($curl_errno >0) {
return 0;
}else{
return $data;
}
} else {
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => self::$connectTimeout + self::$socketTimeout,
)
);
$context = stream_context_create($opts);
$data = @file_get_contents($url, false, $context);
if($data){
return $data;
}else{
return 0;
}
}
}
/**
*
* @param $url
* @param array $postdata
* @return mixed|string
*/
private function post_request($url, $postdata = '') {
if (!$postdata) {
return false;
}
$data = http_build_query($postdata);
if (function_exists('curl_exec')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::$connectTimeout);
curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout);
//不可能执行到的代码
if (!$postdata) {
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
} else {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
$data = curl_exec($ch);
if (curl_errno($ch)) {
$err = sprintf("curl[%s] error[%s]", $url, curl_errno($ch) . ':' . curl_error($ch));
$this->triggerError($err);
}
curl_close($ch);
} else {
if ($postdata) {
$opts = array(
'http' => array(
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded\r\n" . "Content-Length: " . strlen($data) . "\r\n",
'content' => $data,
'timeout' => self::$connectTimeout + self::$socketTimeout
)
);
$context = stream_context_create($opts);
$data = file_get_contents($url, false, $context);
}
}
return $data;
}
/**
* @param $err
*/
private function triggerError($err) {
trigger_error($err);
}
}

253
extend/mail/Smtp.php Normal file
View File

@ -0,0 +1,253 @@
<?php
/**
* SMTP 发送邮件工具类
* Example:
* $x = new Smtp('smtp.qq.com',25,true,'wispx@xlogs.cn','*************');
* $x->send('收件人邮箱','发件人邮箱','标题','内容');
* 此类需要开启PHP OpenSSL拓展
*/
namespace mail;
class Smtp {
public $smtp_port;
public $time_out;
public $host_name;
public $log_file;
public $part_boundary = '--PART-BOUNDARY-ID-WRG11-Y4RD1-5AS1D-RE4D1-AF1EG---';
public $relay_host;
public $debug;
public $auth;
public $user;
public $pass;
public $sock;
public $log;
public $error;
public $att = array(); //附件内容
public $ssl = false;
public function __construct($relay_host = '', $smtp_port = 25, $auth = false, $user, $pass , $ssl = false) {
$this ->debug = false;
$this ->smtp_port = $smtp_port;
if ($ssl == true) {
$this->ssl = true;
$relay_host = 'ssl://' . $relay_host;
}
$this ->relay_host = $relay_host;
$this ->time_out = 30;
$this ->auth = $auth;
$this ->user = $user;
$this ->pass = $pass;
$this ->host_name = "localhost";
$this ->log_file = "";
}
/**
* 添加一个附件
* @param string $name 文件名
* @param string $value 文件内容
*/
public function addatt($name , $value = '') {
$this->att[$name] = $value;
}
/**
* 发送邮件
* @param unknown $to 收件人
* @param unknown $from 发件人
* @param string $subject 邮件标题
* @param string $body 邮件内容
* @param string $fromname 发件人名称
* @param string $reply
* @param string $cc
* @param string $bcc
* @param string $additional_headers
* @return boolean
*/
public function send($to, $from, $subject = "", $body = "", $fromname = "", $reply = '', $cc = "", $bcc = "", $additional_headers = "") {
if (empty($reply)) {
$reply = $from;
}
$header = "";
$mail_from = $this ->get_address($this ->strip_comment($from));
$from = "=?UTF-8?B?".base64_encode($fromname)."?= " . "<$from>";
$body = mb_ereg_replace("(^|(\r\n))(\\.)", "\\1.\\3", $body);
$header .= "MIME-Version:1.0\r\n";
$header .= 'Content-Type: multipart/mixed; boundary="'.$this->part_boundary.'"' . "\r\n";
$header .= "To: " . $to . "\r\n";
if ($cc!="") $header .= "Cc: " . $cc . "\r\n";
$header .= "From: " . $from . "\r\n";
$header .= "Subject: " . $subject . "\r\n";
$header .= $additional_headers;
$header .= "Date: " . date("r") . "\r\n";
$header .= 'Reply-To: ' . $reply . "\r\n";
$header .= "Content-Transfer-Encoding: base64\r\n";
list($msec, $sec) = explode(" ", microtime());
$header .= "Message-ID: <" . date("YmdHis", $sec) . "." . ($msec*1000000) . "." . $mail_from . ">\r\n";
$TO = explode(",", $this ->strip_comment($to));
if ($cc!="") $TO = array_merge($TO, explode(",", $this ->strip_comment($cc)));
if ($bcc!="") $TO = array_merge($TO, explode(",", $this ->strip_comment($bcc)));
$sent = true;
foreach ($TO as $rcpt_to) {
$rcpt_to = $this ->get_address($rcpt_to);
if (!$this ->smtp_sockopen($rcpt_to)) {
$this ->log_write("Error: Cannot send email to [ " . $rcpt_to . " ] (Step 1)<br/>" . $this->error);
$sent = false;
continue;
}
if ($this ->smtp_send($this ->host_name, $mail_from, $rcpt_to, $header, $body)) {
$this ->log_write("邮件已成功发送到 [" . $rcpt_to . "]\n");
} else {
$this ->log_write("Error: Cannot send email to [ " . $rcpt_to . " ] (Step 2)<br/>" . $this->error);
$sent = false;
}
fclose($this ->sock);
}
return $sent;
}
private function smtp_send($helo, $from, $to, $header, $body = "") {
if (!$this ->smtp_putcmd("HELO", $helo)) return $this ->smtp_error("sending HELO command");
if ($this ->auth) {
if (!$this ->smtp_putcmd("AUTH LOGIN", base64_encode($this ->user))) return $this ->smtp_error("sending HELO command");
if (!$this ->smtp_putcmd("", base64_encode($this ->pass))) return $this ->smtp_error("sending HELO command");
}
if (!$this ->smtp_putcmd("MAIL", "FROM:<" . $from . ">")) return $this ->smtp_error("sending MAIL FROM command");
if (!$this ->smtp_putcmd("RCPT", "TO:<" . $to . ">")) return $this ->smtp_error("sending RCPT TO command");
if (!$this ->smtp_putcmd("DATA")) return $this ->smtp_error("sending DATA command");
if (!$this ->smtp_message($header)) return $this ->smtp_error("sending head message");
if (!$this ->smtp_sendbody($body)) return $this ->smtp_error("sending body message");
if (!$this ->smtp_sendatt()) return $this ->smtp_error("sending attachments message");
if (!$this ->smtp_sendend()) return $this ->smtp_error("sending end message");
if (!$this ->smtp_eom()) return $this ->smtp_error("sending <CR><LF>.<CR><LF> [EOM]");
if (!$this ->smtp_putcmd("QUIT")) return $this ->smtp_error("sending QUIT command");
return true;
}
private function smtp_sockopen($address) {
if ($this ->relay_host=="") return $this ->smtp_sockopen_mx($address); else return $this ->smtp_sockopen_relay();
}
private function smtp_sockopen_relay() {
$this ->log_write("Trying to " . $this ->relay_host . ":" . $this ->smtp_port . "\n");
$this ->sock = @fsockopen($this ->relay_host, $this ->smtp_port, $errno, $errstr, $this ->time_out);
if (!($this ->sock && $this ->smtp_ok())) {
$this ->log_write("Error: Cannot connenct to relay host " . $this ->relay_host . "\n");
$this ->log_write("Error: " . $errstr . " (" . $errno . ")\n");
return false;
}
$this ->log_write("Connected to relay host " . $this ->relay_host . "\n");
return true;;
}
private function smtp_sockopen_mx($address) {
$domain = ereg_replace("^.+@([^@]+)$", "\\1", $address);
if (!@getmxrr($domain, $MXHOSTS)) {
$this ->log_write("Error: Cannot resolve MX \"" . $domain . "\"\n");
return false;
}
foreach ($MXHOSTS as $host) {
$this ->log_write("Trying to " . $host . ":" . $this ->smtp_port . "\n");
$this ->sock = @fsockopen($host, $this ->smtp_port, $errno, $errstr, $this ->time_out);
if (!($this ->sock && $this ->smtp_ok())) {
$this ->log_write("Warning: Cannot connect to mx host " . $host . "\n");
$this ->log_write("Error: " . $errstr . " (" . $errno . ")\n");
continue;
}
$this ->log_write("Connected to mx host " . $host . "\n");
return true;
}
$this ->log_write("Error: Cannot connect to any mx hosts (" . implode(", ", $MXHOSTS) . ")\n");
return false;
}
private function smtp_message($header) {
fputs($this ->sock, $header . "\r\n");
$this ->smtp_debug("> " . str_replace("\r\n", "\n" . "> ", $header . "\n>"));
return true;
}
private function smtp_sendbody($body) {
$head = "\r\n\r\n" . '--' . $this->part_boundary;
$head .= "\r\n" . 'Content-Type: text/html; charset="utf-8"';
$head .= "\r\n" . 'Content-Transfer-Encoding: base64';
$head .= "\r\n\r\n" . base64_encode($body);
return fputs($this ->sock, $head . "\r\n");
}
private function smtp_sendatt() {
$head = '';
foreach ($this->att as $n => $v) {
$head .= "\r\n\r\n" . '--' . $this->part_boundary;
$head .= "\r\n" . 'Content-Type: ' . get_mime(get_extname($n)) . '; charset="utf-8"; name="'.$n.'"';
$head .= "\r\n" . 'Content-Disposition: attachment; filename="'.$n.'"';
$head .= "\r\n" . 'Content-Transfer-Encoding: base64';
$head .= "\r\n\r\n" . base64_encode($v);
}
return fputs($this ->sock, $head . "\r\n");
}
private function smtp_sendend() {
return fputs($this ->sock, "\r\n\r\n" . '--' . $this->part_boundary . '--');
}
private function smtp_eom() {
fputs($this ->sock, "\r\n.\r\n");
$this ->smtp_debug(". [EOM]\n");
return $this ->smtp_ok();
}
private function smtp_ok() {
$response = str_replace("\r\n", "", fgets($this ->sock, 512));
$this ->smtp_debug($response . "\n");
if (!mb_ereg("^[23]", $response)) {
fputs($this ->sock, "QUIT\r\n");
fgets($this ->sock, 512);
$this ->log_write("Error: Remote host returned \"" . $response . "\"\n");
return false;
}
return true;
}
private function smtp_putcmd($cmd, $arg = "") {
if ($arg!="") {
if ($cmd=="") $cmd = $arg; else
$cmd = $cmd . " " . $arg;
}
fputs($this ->sock, $cmd . "\r\n");
$this ->smtp_debug("> " . $cmd . "\n");
return $this ->smtp_ok();
}
private function smtp_error($string) {
$this ->error .= "<br/>Error: Error occurred while " . $string . ".<br/>";
return false;
}
private function log_write($message) {
//$this->log .= '<br/>'.$message.'<br/>';
return true;
}
private function strip_comment($address) {
$comment = "\\([^()]*\\)";
while (mb_ereg($comment, $address)) {
$address = mb_ereg_replace($comment, "", $address);
}
return $address;
}
private function get_address($address) {
$address = mb_ereg_replace("([ \t\r\n])+", "", $address);
$address = mb_ereg_replace("^.*<(.+)>.*$", "\\1", $address);
return $address;
}
public function smtp_debug($message) {
if ($this ->debug) {
return $message . "<br>";
}
}
}

8
public/.htaccess Normal file
View File

@ -0,0 +1,8 @@
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?s=$1 [QSA,PT,L]
</IfModule>

21
public/admin.php Normal file
View File

@ -0,0 +1,21 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// [ 应用入口文件 ]
if (!file_exists("../app/db.php") || (file_exists("../app/db.php") && file_get_contents("../app/db.php") == "")) exit(header("location: install.php"));
// 定义应用目录
define('APP_PATH', __DIR__ . '/../app/');
// 绑定到admin模块
define('BIND_MODULE', 'admin');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

21
public/index.php Normal file
View File

@ -0,0 +1,21 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// [ 应用入口文件 ]
if (!file_exists("../app/db.php") || (file_exists("../app/db.php") && file_get_contents("../app/db.php") == "")) exit(header("location: install.php"));
// 定义应用目录
define('APP_PATH', __DIR__ . '/../app/');
// 绑定到index模块
define('BIND_MODULE', 'index');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';

218
public/install.php Normal file
View File

@ -0,0 +1,218 @@
<?php
/**
* 安装
* User: WispX
* Date: 2017/9/23
* Time: 16:46
* Link: http://gitee.com/wispx
*/
$config_file = '../app/db.php';
$stop = isset($_GET['stop']) ? $_GET['stop'] : 1;
$action = isset($_GET['action']) ? $_GET['action'] : false;
if(file_exists($config_file) && !empty(file_get_contents($config_file)) && $stop != 3) {
die('你已安装成功重新安装请清空db.php');
} elseif (!file_exists($config_file)) {
die('缺失db.php文件请上传重写安装请直接上传空文件');
}
switch ($stop) {
case 1:
$is['curl'] = function_exists('curl_init');
$is['mysqli'] = class_exists('mysqli');
//$is['zipArchive'] = class_exists('ZipArchive');
$is['config_writable'] = is_writable($config_file);
$is['pic_writable'] = is_writable('./pic');
$php_version = explode('-', phpversion());
$php_version = $php_version[0];
$is['php_version_gt530'] = strnatcasecmp($php_version, '5.3.0') >= 0 ? true : false;
break;
case 2:
if($action == 'conn') {
$email = isset($_POST['admin_email']) ? $_POST['admin_email'] : false;
$user = isset($_POST['admin_user']) ? $_POST['admin_user'] : false;
$pass = isset($_POST['admin_pass']) ? $_POST['admin_pass'] : false;
$db_host = isset($_POST['db_host']) ? $_POST['db_host'] : false;
$db_user = isset($_POST['db_user']) ? $_POST['db_user'] : false;
$db_pass = isset($_POST['db_pass']) ? $_POST['db_pass'] : false;
$db_base = isset($_POST['db_base']) ? $_POST['db_base'] : false;
$db_port = isset($_POST['db_port']) ? $_POST['db_port'] : false;
@$mysqli = new mysqli($db_host, $db_user, $db_pass, $db_base, $db_port);
@$mysqli->set_charset("utf8");
if (mysqli_connect_errno()) {
$msg = "数据库连接出错,请检查数据库配置是否正确";
break;
}
$db_config_content = "<?php\r\n/**\r\n * 数据库连接配置\r\n */\r\n\$db = [\r\n // 服务器地址\r\n 'hostname' => '{$db_host}',\r\n // 数据库名\r\n 'database' => '{$db_base}',\r\n // 用户名\r\n 'username' => '{$db_user}',\r\n // 密码\r\n 'password' => '{$db_pass}',\r\n // 端口\r\n 'hostport' => '{$db_port}',\r\n];";
if (!@file_put_contents($config_file, $db_config_content)) {
$msg = "数据库配置写入db.php文件失败!";
break;
}
if (!file_exists("install.sql")) die("缺少程序安装文件install.sql");
$sql = file_get_contents("install.sql");
$mysqli->multi_query($sql . " INSERT INTO `lk_user` VALUES (1,'{$email}','{$user}','" . md5("LK{$pass}") . "','','','127.0.0.1','127.0.0.1'," . time() . ",'');");
header('location: ?stop=3');
}
break;
case 3:
break;
default:
break;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>安装兰空</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<style type="text/css">
body { background-color: #e2e2e2; }
.container { margin-top: 70px; margin-bottom: 70px; }
.main { background-color: #fff; border-radius: 2px; padding: 10px; }
@media screen and (max-width: 768px) {
.container { margin-top: 10px; }
}
</style>
<body>
<div class="container">
<div class="row">
<div class="col-sm-6 col-md-6 col-1g-6 col-sm-offset-3 col-md-offset-3 col-1g-offset-3">
<div class="main">
<?php if($stop == 2) { ?>
<h2>安装兰空 - 连接数据库</h2><hr>
<?php if(!empty($msg)) { ?>
<div class="alert alert-danger" role="alert"><?php echo $msg; ?></div>
<?php } ?>
<form method="post" action="?stop=2&action=conn">
<input type="hidden" name="t" value="true">
<div class="form-group">
<label for="db_host">数据库连接地址</label>
<input type="text" class="form-control" required id="db_host" name="db_host" value="127.0.0.1" placeholder="数据库连接地址">
</div>
<div class="form-group">
<label for="db_base">数据库名</label>
<input type="text" class="form-control" required id="db_base" name="db_base" value="lsky" placeholder="数据库名">
</div>
<div class="form-group">
<label for="db_user">用户名</label>
<input type="text" class="form-control" required id="db_user" name="db_user" value="lsky" placeholder="数据库用户名">
</div>
<div class="form-group">
<label for="db_pass">数据库密码</label>
<input type="password" class="form-control" required id="db_pass" name="db_pass" value="" placeholder="数据库密码">
</div>
<div class="form-group">
<label for="db_port">数据库连接端口</label>
<input type="text" class="form-control" required id="db_port" name="db_port" value="3306" placeholder="数据库连接端口">
</div>
<div class="form-group">
<label for="admin_email">后台管理邮箱</label>
<input type="text" class="form-control" required id="admin_email" name="admin_email" value="" placeholder="管理员邮箱">
</div>
<div class="form-group">
<label for="admin_user">后台管理账号</label>
<input type="text" class="form-control" required id="admin_user" name="admin_user" value="admin" placeholder="管理员账号">
</div>
<div class="form-group">
<label for="admin_pass">管理员密码</label>
<input type="text" class="form-control" required id="admin_pass" name="admin_pass" value="" placeholder="管理员密码">
</div>
<button type="submit" class="btn btn-default btn-block">下一步</button>
</form>
<?php } elseif ($stop == 3) { ?>
<h2>安装成功</h2><hr>
<?php if(!empty($msg)) { ?>
<div class="alert alert-danger" role="alert"><?php echo $msg; ?></div>
<?php } ?>
<div class="row">
<div class="col-md-4">
<div class="">
<img width="100%" src="./static/images/preview.jpg">
</div>
</div>
<div class="col-md-6">
<div class="">
<h3>安装成功</h3>
<p class="text-danger">请手动删除public/install.php文件</p>
<a href="/" class="btn btn-default">访问前台</a>
<a href="/admin.php" class="btn btn-default">访问后台</a>
</div>
</div>
</div>
<?php } else { ?>
<h2>安装兰空 - 检测</h2><hr>
<?php if(!empty($msg)) { ?>
<div class="alert alert-danger" role="alert"><?php echo $msg; ?></div>
<?php } ?>
<table class="table table-bordered text-center">
<thead>
<tr>
<th class="text-center">函数</th>
<th class="text-center">状态</th>
</tr>
</thead>
<tbody>
<tr>
<td>PHP版本 &gt; 5.3</td>
<td>
<?php if($is['php_version_gt530']) { ?>
<span class="text-success glyphicon glyphicon-ok-sign" aria-hidden="true"></span> 支持
<?php } else { ?>
<span class="text-danger glyphicon glyphicon-remove-sign" aria-hidden="true"></span> 不支持
<?php } ?>
</td>
</tr>
<tr>
<td>Curl</td>
<td>
<?php if($is['curl']) { ?>
<span class="text-success glyphicon glyphicon-ok-sign" aria-hidden="true"></span> 支持
<?php } else { ?>
<span class="text-danger glyphicon glyphicon-remove-sign" aria-hidden="true"></span> 不支持
<?php } ?>
</td>
</tr>
<tr>
<td>Mysqli</td>
<td>
<?php if($is['mysqli']) { ?>
<span class="text-success glyphicon glyphicon-ok-sign" aria-hidden="true"></span> 支持
<?php } else { ?>
<span class="text-danger glyphicon glyphicon-remove-sign" aria-hidden="true"></span> 不支持
<?php } ?>
</td>
</tr>
<tr>
<td>图片存放目录</td>
<td>
<?php if($is['pic_writable']) { ?>
<span class="text-success glyphicon glyphicon-ok-sign" aria-hidden="true"></span> 可写
<?php } else { ?>
<span class="text-danger glyphicon glyphicon-remove-sign" aria-hidden="true"></span> 不可写
<?php } ?>
</td>
</tr>
<tr>
<td>配置文件</td>
<td>
<?php if($is['config_writable']) { ?>
<span class="text-success glyphicon glyphicon-ok-sign" aria-hidden="true"></span> 可写
<?php } else { ?>
<span class="text-danger glyphicon glyphicon-remove-sign" aria-hidden="true"></span> 不可写
<?php } ?>
</td>
</tr>
</tbody>
</table>
<a class="btn btn-default btn-block" <?php if(!$is['php_version_gt530'] || !$is['curl'] || !$is['mysqli'] || !$is['pic_writable'] || !$is['config_writable']) { ?>disabled<?php } else { ?>href="?stop=2"<?php } ?>>下一步</a>
<?php } ?>
</div>
</div>
</div>
</div>
</body>
<script type="text/javascript" src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</html>

85
public/install.sql Normal file
View File

@ -0,0 +1,85 @@
--
-- Table structure for table `lk_config`
--
DROP TABLE IF EXISTS `lk_config`;
CREATE TABLE `lk_config` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`key` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT '配置项',
`value` text COLLATE utf8_unicode_ci NOT NULL COMMENT '配置值',
`text` text COLLATE utf8_unicode_ci NOT NULL COMMENT '可选',
`notes` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT '注释',
`edit_time` int(11) NOT NULL COMMENT '编辑时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='系统配置';
--
-- Dumping data for table `lk_config`
--
LOCK TABLES `lk_config` WRITE;
INSERT INTO `lk_config` VALUES (1,'web_title','兰空','','网站名称',1506570042),(2,'keywords','兰空,兰空图床,图片储存,免费图床,免费相册,免费图床程序,兰空IMG,www.lskys.cc,lskys','','网站首页关键字',1506570042),(3,'description','免费、快速、稳定、高效、全球CDN加速支持外链、不限流量支持粘贴上传、拖放上传一键复制 markdown 链接的图床','','网站首页描述',1506570042),(4,'captcha_id','','','极检验证ID',1506570043),(5,'private_key','','','极检验证key',1506570043),(6,'upload_max_filesize','5120','','最大上传限制(kb)',1506570042),(7,'upload_max_file_count','10','','单次上传文件个数限制(最低10)',1506570042),(8,'upload_images_ext','jpeg,jpg,png,gif,bmp','','允许上传的图片拓展名',1506570042),(9,'flow_load_mode','1','','流加载方式0:手动加载,1:下拉加载',1506570042),(10,'img_rows','20','','图片每页显示数量',1506570043),(11,'smtp_host','','','SMTP地址',0),(12,'smtp_port','465','','SMTP端口',0),(13,'smtp_auth','1','','SMTP认证',0),(14,'smtp_user','','','SMTP用户',0),(15,'smtp_pass','','','SMTP密码',0),(16,'smtp_ssl','1','','开启SMTP SSL',0),(17,'now_theme','default','','当前使用主题',0),(18,'custom_style','','','自定义style',1506570043),(19,'version','1.1','','当前版本',0),(20,'reg_close','0','','关闭注册',1506570042),(21,'upload_scheme_id','1','','上传方案',0);
UNLOCK TABLES;
--
-- Table structure for table `lk_file`
--
DROP TABLE IF EXISTS `lk_file`;
CREATE TABLE `lk_file` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`user_id` mediumint(8) NOT NULL COMMENT '用户ID',
`scheme_id` tinyint(1) NOT NULL COMMENT '储存方式ID',
`name` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件名',
`type` char(32) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件类型',
`size` bigint(20) NOT NULL COMMENT '大小(KB)',
`hash` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT '散列值',
`path` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件路径',
`upload_time` int(11) NOT NULL COMMENT '上传时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='文件表';
--
-- Dumping data for table `lk_file`
--
LOCK TABLES `lk_file` WRITE;
UNLOCK TABLES;
--
-- Table structure for table `lk_scheme`
--
DROP TABLE IF EXISTS `lk_scheme`;
CREATE TABLE `lk_scheme` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`access_key` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT 'AK',
`secret_key` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT 'SK',
`bucket_name` char(32) COLLATE utf8_unicode_ci NOT NULL COMMENT '空间名',
`domain` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT '加速域名',
`edit_time` int(11) NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='储存方案';
--
-- Dumping data for table `lk_scheme`
--
LOCK TABLES `lk_scheme` WRITE;
INSERT INTO `lk_scheme` VALUES (2,'','','','',0),(3,'','','','',0);
UNLOCK TABLES;
--
-- Table structure for table `lk_user`
--
DROP TABLE IF EXISTS `lk_user`;
CREATE TABLE `lk_user` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`email` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT 'email',
`username` char(32) COLLATE utf8_unicode_ci NOT NULL COMMENT '用户名',
`password` char(32) COLLATE utf8_unicode_ci NOT NULL COMMENT '密码',
`login_status` varchar(225) COLLATE utf8_unicode_ci NOT NULL COMMENT '登录状态',
`login_time` int(11) NOT NULL COMMENT '最后登录时间',
`login_ip` char(32) COLLATE utf8_unicode_ci NOT NULL COMMENT '最后登录IP',
`reg_ip` char(32) COLLATE utf8_unicode_ci NOT NULL COMMENT '注册IP',
`reg_time` int(11) NOT NULL COMMENT '注册时间',
`edit_time` int(11) NOT NULL COMMENT '最后修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='用户表';
-- Dump completed on 2017-10-12 17:33:50

2
public/pic/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
public/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Disallow:

20
public/router.php Normal file
View File

@ -0,0 +1,20 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id$
if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["REQUEST_URI"])) {
return false;
} else {
if (!isset($_SERVER['PATH_INFO'])) {
$_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'];
}
require __DIR__ . "/index.php";
}

154
public/static/css/main.css Normal file
View File

@ -0,0 +1,154 @@
body { font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; background-color: #eee; padding-top: 100px; word-wrap:break-word; }
a { bblr:expression(this.onFocus=this.blur()); outline-style:none; text-decoration: none; }
a:hover, a:focus, a:active, a:visited { text-decoration: none; }
a { -webkit-transition: all 0.2s; -moz-transition: all 0.2s; -ms-transition: all 0.2s; -o-transition: all 0.2s; transition: all 0.2s; }
.navbar-brand { color: #fff!important; }
.none { display: none; }
.login, .reg { margin:0 auto; float: none; }
.login h1, .reg h1 { margin-bottom: 20px; }
#link { margin-top: 20px; }
.lk-panel {
background-color: #fff;
padding: 15px;
-webkit-box-shadow: 0 8px 7px 0 rgba(0,0,0,.2), 0 0px 10px 0 rgba(0,0,0,.19);
box-shadow: 0 8px 7px 0 rgba(0,0,0,.2), 0 0px 10px 0 rgba(0,0,0,.19);
border-radius: 2px;
}
.user {
padding: 10px;background-color: #fff;
-webkit-box-shadow: 0px 0px 1px 0 rgba(0,0,0,.2), 0 0px 8px 0 rgba(0,0,0,.19);
box-shadow: 0px 0px 1px 0 rgba(0,0,0,.2), 0 0px 8px 0 rgba(0,0,0,.19);
}
.list {
margin-top: 20px;
}
.img {
position: relative;
cursor: pointer;
padding: 10px;
background-color: #f4f4f4;
border-radius: 2px;
overflow: hidden;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}
.img img {
width: 100%;
height: 140px;
}
.img-per {
margin-top: 8px;
}
.list-per {
border-bottom: 1px solid #f4f4f4;
padding-bottom: 10px;
}
.picture {
margin-bottom: 10px;
}
.layui-flow-more { clear: both; padding-top: 30px; }
.list-per .layui-input, .list-per .layui-select, .list-per .layui-textarea { height: 30px; width: 150px; }
.pic-del {
position: relative;
top: 50px;
left: 20px;
font-size: 30px;
cursor: pointer;
z-index: 9;
}
.forgot .input-group {
margin-bottom: 10px;
}
.m-b-10 {
margin-bottom: 10px;
}
/* ------- BootStarp ------- */
.form-control { border-radius: 2px; }
/* ------- FileInput ------- */
.fileinput h1 {
padding: 20px 0;
font-weight: 400;
font-size: 30px;
margin-bottom: 20px;
border-bottom: 1px solid lavender;
text-shadow: -5px 5px 0 rgba(0,0,0,.1);
}
.file-input .btn {
padding: 10px 18px;
}
.file-input .form-control {
height: 42px;
padding: 10px 12px;
}
.file-input .btn-file {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.file-input .file-caption {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/**
.file-input .file-preview {
border-radius: 0px;
}
**/
footer {
margin-top: 50px;
width: 100%;
}
footer .container .text-muted { margin: 20px 0; }
.text-muted { color: #999999; }
@media screen and (max-width: 768px) {
.layui-layer-iframe { width: 100%!important; height: 100%!important; }
.batchDel { display: none; }
.list-per .layui-input-inline, .list-per .layui-inline, .list-per .search_btn { display: grid; margin-top: 5px; }
.list-per .layui-input, .list-per .layui-select, .list-per .layui-textarea { width: 100%; }
.pic-del { display: none; }
}
.animated {
-webkit-animation-fill-mode: both;
-moz-animation-fill-mode: both;
-ms-animation-fill-mode: both;
-o-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-duration: 1s;
-moz-animation-duration: 1s;
-ms-animation-duration: 1s;
-o-animation-duration: 1s;
animation-duration: 1s;
}
.fadeInDown {
-webkit-animation-name: fadeInDown;
-moz-animation-name: fadeInDown;
-o-animation-name: fadeInDown;
animation-name: fadeInDown;
}
@-webkit-keyframes fadeIn{50%{opacity:.6}
100%{opacity:1}
}
@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translateY(-20px)}
100%{opacity:1;-webkit-transform:translateY(0)}
}
@-moz-keyframes fadeInDown{0%{opacity:0;-moz-transform:translateY(-20px)}
100%{opacity:1;-moz-transform:translateY(0)}
}
@-o-keyframes fadeInDown{0%{opacity:0;-o-transform:translateY(-20px)}
100%{opacity:1;-o-transform:translateY(0)}
}
@keyframes fadeInDown{0%{opacity:0;transform:translateY(-20px)}
100%{opacity:1;transform:translateY(0)}
}
::selection{color:#fff;background:#207cc7}
::-moz-selection{color:#fff;background:#207cc7;}
:window-inactive {display: none;}
::-webkit-scrollbar{width:5px;height:5px;}
::-webkit-scrollbar-track{background:#ccc;}
::-webkit-scrollbar-track:hover{background:#ff0;}
::-webkit-scrollbar-track:window-inactive{background:#f6f6f6;}
::-webkit-scrollbar-thumb{background:#888;}
::-webkit-scrollbar-thumb:window-inactive{background:#f6f6f6;}
::-webkit-scrollbar-thumb:hover{background:#666;}
::-webkit-scrollbar-button {background:#333;}
::-webkit-scrollbar-button:window-inactive {background:#f6f6f6;}

View File

@ -0,0 +1,62 @@
a, a:hover, a:active, a:focus { text-decoration:none; }
.m-r-10 { margin-right: 10px; }
.none { display: none; }
/* ----- BootStarp ----- */
.form-control { border-radius: 2px; }
/* ----- Layui ----- */
.layui-elem-quote.title {
padding: 10px 15px;
margin-bottom: 0;
}
.sysNotice .layui-elem-quote {
line-height: 26px;
position: relative;
}
.sysNotice .layui-table { border-left: 5px solid #e2e2e2; }
.notice { cursor: pointer; }
.noticeDetails { margin: 20px; }
.noticeDetails cite { position: absolute; right: 1px; bottom: 1px; }
.system .layui-table, .notice .layui-table { margin-top: 0; }
.scheme { margin-top: 10px; }
.wp-panel {
height: 85px;
background-color: white;
background-color: #ecf0f5;
margin-bottom: 10px;
}
.wp-panel > i {
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px;
display: block;
float: left;
height: 85px;
width: 85px;
text-align: center;
font-size: 45px;
line-height: 85px;
background: rgba(0, 0, 0, 0.2);
color: white;
}
.wp-word {
text-align: center;
padding: 20px 10px;
margin-left: 85px;
}
.wp-word > span {
display: block;
font-weight: bold;
font-size: 18px;
}
.list-per .layui-input, .list-per .layui-select, .list-per .layui-textarea {
height: 30px;
width: 200px;
}
@media screen and (max-width: 768px) {
.list-per .layui-input, .list-per .layui-select, .list-per .layui-textarea { width: 100px; }
.notice-date { display: none; }
}
@media screen and (max-width: 360px) {
.list-per .layui-form-select input { width: 100%; margin-bottom: 10px; }
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

277
public/static/js/gt.js Normal file
View File

@ -0,0 +1,277 @@
/* initGeetest 1.0.0
* 用于加载id对应的验证码库并支持宕机模式
* 暴露 initGeetest 进行验证码的初始化
* 一般不需要用户进行修改
*/
(function (global, factory) {
"use strict";
if (typeof module === "object" && typeof module.exports === "object") {
// CommonJS
module.exports = global.document ?
factory(global, true) :
function (w) {
if (!w.document) {
throw new Error("Geetest requires a window with a document");
}
return factory(w);
};
} else {
factory(global);
}
})(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
"use strict";
if (typeof window === 'undefined') {
throw new Error('Geetest requires browser environment');
}
var document = window.document;
var Math = window.Math;
var head = document.getElementsByTagName("head")[0];
function _Object(obj) {
this._obj = obj;
}
_Object.prototype = {
_each: function (process) {
var _obj = this._obj;
for (var k in _obj) {
if (_obj.hasOwnProperty(k)) {
process(k, _obj[k]);
}
}
return this;
}
};
function Config(config) {
var self = this;
new _Object(config)._each(function (key, value) {
self[key] = value;
});
}
Config.prototype = {
api_server: 'api.geetest.com',
protocol: 'http://',
type_path: '/gettype.php',
fallback_config: {
slide: {
static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
type: 'slide',
slide: '/static/js/geetest.0.0.0.js'
},
fullpage: {
static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
type: 'fullpage',
fullpage: '/static/js/fullpage.0.0.0.js'
}
},
_get_fallback_config: function () {
var self = this;
if (isString(self.type)) {
return self.fallback_config[self.type];
} else if (self.new_captcha) {
return self.fallback_config.fullpage;
} else {
return self.fallback_config.slide;
}
},
_extend: function (obj) {
var self = this;
new _Object(obj)._each(function (key, value) {
self[key] = value;
})
}
};
var isNumber = function (value) {
return (typeof value === 'number');
};
var isString = function (value) {
return (typeof value === 'string');
};
var isBoolean = function (value) {
return (typeof value === 'boolean');
};
var isObject = function (value) {
return (typeof value === 'object' && value !== null);
};
var isFunction = function (value) {
return (typeof value === 'function');
};
var callbacks = {};
var status = {};
var random = function () {
return parseInt(Math.random() * 10000) + (new Date()).valueOf();
};
var loadScript = function (url, cb) {
var script = document.createElement("script");
script.charset = "UTF-8";
script.async = true;
script.onerror = function () {
cb(true);
};
var loaded = false;
script.onload = script.onreadystatechange = function () {
if (!loaded &&
(!script.readyState ||
"loaded" === script.readyState ||
"complete" === script.readyState)) {
loaded = true;
setTimeout(function () {
cb(false);
}, 0);
}
};
script.src = url;
head.appendChild(script);
};
var normalizeDomain = function (domain) {
return domain.replace(/^https?:\/\/|\/$/g, '');
};
var normalizePath = function (path) {
path = path.replace(/\/+/g, '/');
if (path.indexOf('/') !== 0) {
path = '/' + path;
}
return path;
};
var normalizeQuery = function (query) {
if (!query) {
return '';
}
var q = '?';
new _Object(query)._each(function (key, value) {
if (isString(value) || isNumber(value) || isBoolean(value)) {
q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
}
});
if (q === '?') {
q = '';
}
return q.replace(/&$/, '');
};
var makeURL = function (protocol, domain, path, query) {
domain = normalizeDomain(domain);
var url = normalizePath(path) + normalizeQuery(query);
if (domain) {
url = protocol + domain + url;
}
return url;
};
var load = function (protocol, domains, path, query, cb) {
var tryRequest = function (at) {
var url = makeURL(protocol, domains[at], path, query);
loadScript(url, function (err) {
if (err) {
if (at >= domains.length - 1) {
cb(true);
} else {
tryRequest(at + 1);
}
} else {
cb(false);
}
});
};
tryRequest(0);
};
var jsonp = function (domains, path, config, callback) {
if (isObject(config.getLib)) {
config._extend(config.getLib);
callback(config);
return;
}
if (config.offline) {
callback(config._get_fallback_config());
return;
}
var cb = "geetest_" + random();
window[cb] = function (data) {
if (data.status === 'success') {
callback(data.data);
} else if (!data.status) {
callback(data);
} else {
callback(config._get_fallback_config());
}
window[cb] = undefined;
try {
delete window[cb];
} catch (e) {
}
};
load(config.protocol, domains, path, {
gt: config.gt,
callback: cb
}, function (err) {
if (err) {
callback(config._get_fallback_config());
}
});
};
var throwError = function (errorType, config) {
var errors = {
networkError: '网络错误'
};
if (typeof config.onError === 'function') {
config.onError(errors[errorType]);
} else {
throw new Error(errors[errorType]);
}
};
var detect = function () {
return !!window.Geetest;
};
if (detect()) {
status.slide = "loaded";
}
var initGeetest = function (userConfig, callback) {
var config = new Config(userConfig);
if (userConfig.https) {
config.protocol = 'https://';
} else if (!userConfig.protocol) {
config.protocol = window.location.protocol + '//';
}
jsonp([config.api_server || config.apiserver], config.type_path, config, function (newConfig) {
var type = newConfig.type;
var init = function () {
config._extend(newConfig);
callback(new window.Geetest(config));
};
callbacks[type] = callbacks[type] || [];
var s = status[type] || 'init';
if (s === 'init') {
status[type] = 'loading';
callbacks[type].push(init);
load(config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) {
if (err) {
status[type] = 'fail';
throwError('networkError', config);
} else {
status[type] = 'loaded';
var cbs = callbacks[type];
for (var i = 0, len = cbs.length; i < len; i = i + 1) {
var cb = cbs[i];
if (isFunction(cb)) {
cb();
}
}
callbacks[type] = [];
}
});
} else if (s === "loaded") {
init();
} else if (s === "fail") {
throwError('networkError', config);
} else if (s === "loading") {
callbacks[type].push(init);
}
});
};
window.initGeetest = initGeetest;
return initGeetest;
});

154
public/static/js/main.js Normal file
View File

@ -0,0 +1,154 @@
layui.use(['layer', 'element'], function() {
var layer = layui.layer, element = layui.element;
});
function logout() {
$.post('/user/logout', {'exit': true}, function() {
return location.href = '/';
});
}
var btnLoad = function(a, b) {
var element = $(a), V = element.html();
try {
element.html('<i class="fa fa-cog fa-spin"></i> ' + (b ? b : '保存中...'));
element.attr('disabled', true);
element.css('cursor', 'not-allowed');
} catch (e) {
element.html(V);
element.attr('disabled', false);
element.css('cursor', 'pointer');
}
}
var closeBtnLoad = function(a, b) {
var element = $(a);
element.html(b);
element.attr('disabled', false);
element.css('cursor', 'pointer');
}
function picDel(id) {
layer.confirm('您真的要删除这张图片吗?', {
title: '删除图片',
btn: ['删除', '取消'] //按钮
}, function() {
layer.load(2);
$.post('/user/picDel', {'id': id}, function(res) {
layer.msg(res.msg, {icon: res.code ? 1 : 2});
if(res.code) {
fadeRemove('.pic-' + id);
}
layer.closeAll('loading');
});
});
}
function fadeRemove(a) {
$(a).fadeTo("slow", 0.01, function() {
$(this).slideUp("slow", function() {
$(this).remove();
});
});
}
function picBatchDel() {
var array = [];
$('.fa-check-circle-o').each(function() {
array.push($(this).attr('data-id'));
});
if(array.length > 0) {
return layer.confirm('您真的要删除这 '+ array.length +' 张图片吗?', {
title: '删除图片',
btn: ['删除', '取消'] //按钮
}, function() {
layer.load(2);
$.post('/user/picBatchDel', {'array': array}, function(res) {
if(res.code) {
for (var i = 0; i < array.length; i++) {
fadeRemove('.pic-' + array[i]);
}
}
layer.msg(res.msg, {icon: res.code ? 1 : 2});
layer.closeAll('loading');
});
});
}
return layer.msg('没有选中项');
}
function checkBoxAll() {
var t = $('.pic-del');
if(t.hasClass('fa-check-circle-o')) {
t.removeClass('fa-check-circle-o');
t.addClass('fa-circle-thin');
$('.checkBoxAll').html('全选');
} else {
t.removeClass('fa-circle-thin');
t.addClass('fa-check-circle-o');
$('.checkBoxAll').html('反选');
}
}
function forgot() {
layer.open({
type: 1,
//area: ['500px', '300px'],
title: '找回密码',
shade: 0.6,
content: '<div class="forgot" style="padding: 15px;"><div class="input-group"><input type="email" id="get-email" class="form-control" placeholder="请输入邮箱" required><span class="input-group-btn"><button class="btn btn-default" id="getEmail" onclick="getEmail()" type="button">发送验证码</button></span> </div></div>'
});
}
function getEmail() {
var email = $('.forgot #get-email');
if(email.val() != '') {
layer.load(2);
$.post('/login/getEmailCode', {'email': $.trim(email.val())}, function(res) {
layer.closeAll('loading');
layer.msg(res.msg, {icon: res.code ? 1 : 2});
if(res.code) {
email.attr('disabled', true);
$('#getEmail').attr('disabled', true);
$('.forgot').append('<div class="input-group isEmailCode"><input type="text" id="email_code" class="form-control" placeholder="请输入验证码" required><span class="input-group-btn"><button class="btn btn-default" onclick="isEmailCode()" type="button">验证</button></span> </div>');
}
});
} else {
return layer.msg('请输入邮箱');
}
}
function isEmailCode() {
var email_code = $.trim($('#email_code').val());
if(email_code == "") {
return layer.msg('请输入验证码');
} else {
layer.load(2);
$.post('/login/isEmailCode', {'code': email_code}, function(res) {
layer.closeAll('loading');
if(res.code) {
$('.isEmailCode').remove();
var html = '';
html += '<input type="password" id="reset-password" class="form-control m-b-10" placeholder="密码">';
html += '<input type="password" id="reset-passwords" class="form-control m-b-10" placeholder="确认密码">';
html += '<button type="button" onclick="resetPassWord()" class="btn btn-primary btn-sm btn-block">重置密码</button>';
$('.forgot').append(html);
}
return layer.msg(res.msg, {icon: res.code ? 1 : 2});
});
}
}
function resetPassWord() {
var password = $.trim($('#reset-password').val()), passwords = $.trim($('#reset-passwords').val());
if(password != passwords) {
return layer.msg('两次输入的密码不一致');
} else {
layer.load(2);
$.post('/login/resetPassWord', {'password': password}, function(res) {
layer.closeAll('loading');
if(res.code) {
layer.alert(res.msg, {icon: 1}, function(index) {
layer.close(index);
history.go(0);
});
} else {
return layer.alert(res.msg, {icon: res.code ? 1 : 0});
}
});
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
/** layui-v2.1.5 MIT License By http://www.layui.com */
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Some files were not shown because too many files have changed in this diff Show More