This commit is contained in:
tao 2022-08-02 21:13:36 +08:00
parent f17b24122f
commit 608211d178
908 changed files with 118285 additions and 2879 deletions

View File

@ -1,10 +1,13 @@
# TaoLer
> TaoLer是一个简单迅捷的轻论坛系统适用于个人或组织区域型信息交流发布平台。
> TaoLer是一个简单迅捷的管理系统支持插件化开发适用于企业、个人或组织建站需求。
支持多模板、多单页自由切换,网站风格可定制性强,支持插件化开发,方便二开。可做为企业门户网站,生活服务,学习问答笔记,文章分享等。
默认内置一套完整的**问答+博客+论坛+新闻+轻社区化**的模板系统,还可持续增加模块,一个系统拥有多个版式的网站风格。
* 官网https://www.aieok.com
webman版新架构已适配90%
* 文档http://wiki.aieok.com
* 演示后台https://www.aieok.com/adminff
#### 项目地址
@ -24,15 +27,14 @@
6. 双升级系统,可支持自动和手动升级。可在线检测并升级系统,保持网站的更新和安全。
7. 代码开源,不设暗门操作,更安全。
8. 项目会长期维护,优化更新。
9. 预增加插件管理机制1.02.0版本正式上线)
9. 预增加插件管理机制1.x2.x版本正式上线)
![alt taoler官网](https://www.aieok.com/storage/1/article_pic/20220802/6ea6bb3e40d9a3bc7c9ec28f3e0d7b90.png "TaoLerCMS")
#### 构架组成
- 1.x版本构架
- 构架Tinkphp6 + layui2.6
- 环境php7/php8.0 + mysql
- 前端Fly template V3.0
- 构架Tinkphp6 + layui2.7
- 环境php7/8.1 + mysql5.7/8.0
#### 构架介绍
thinkphp:
@ -43,12 +45,17 @@
一款至简的社区模板。
![alt taoler官网](https://www.aieok.com/storage/1/article_pic/20220802/edd9bfc2ca1d1ec52a551b2233b5ab62.png "TaoLerCMS")
####重点
* 长期维护,对抗消亡
* 迭代及时,查漏补缺
* 多模板多模块,一站顶多站
#### 安装教程
1. 首选确保满目使用环境要求php > 7.2, mysql > 5.7.3
2. git下载https://gitee.com/toogee/TaoLer
github https://www.github.com/taoser/TaoLer
2. https://github.com/taoser/TaoLer/archive/refs/heads/master.zip
git下载https://gitee.com/toogee/TaoLer
官网下载https://www.aieok.com
#### 引导安装
@ -92,14 +99,18 @@
}
```
>如果是宝塔集成环境,网站目录部署如下示例:
> 如果是宝塔集成环境,网站目录部署如下示例:
网站目录D:/www/TaoLer
运行目录:/public
运行目录:/public
![alt install](http://wiki.aieok.com/_images/BT.png "install")
3. 首次安装访问域名http://www.youdomain.com可自动跳转到/install/index进行引导安装重新安装需删除public目录下install.lock。
4. 安装前需要先创建mysql数据库(准备:数据库连接地址,数据库用户名,密码,端口)
5. 如果手动导入数据库管理员用户名和密码默认admin/123456前后台的管理员密码一致。前后端管理员账户是独立的前端主要对文章内容的审查管理等操作。
![alt taoler官网](https://www.aieok.com/storage/1/article_pic/20220802/54c8364fffd9ca1d15856efd90b689bc.png "TaoLerAdmin")
#### 前后台独立域名的绑定

View File

@ -12,6 +12,7 @@ use think\facade\Db;
use think\facade\Request;
use think\facade\Lang;
use think\facade\View;
use think\facade\Route;
/**
* 控制器基础类
@ -244,10 +245,16 @@ abstract class BaseController
* @param integer $aid
* @return string
*/
protected function getRouteUrl(int $aid) : string
protected function getRouteUrl(int $aid,string $ename = '') : string
{
$indexUrl = $this->getIndexUrl();
$artUrl = (string) url('detail_id', ['id' => $aid]);
if(config('taoler.url_rewrite.article_as') == '<ename>/'){
// 分类可变路由
$artUrl = (string) Route::buildUrl('article_detail', ['id' => $aid, 'ename'=> $ename]);
} else {
$artUrl = (string) url('article_detail', ['id' => $aid]);
}
// 判断是否开启绑定
//$domain_bind = array_key_exists('domain_bind',config('app'));

View File

@ -1,4 +1,13 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-28 11:44:38
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \github\TaoLer\app\Request.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app;
// 应用请求对象类
@ -8,6 +17,7 @@ class Request extends \think\Request
//protected $filter = ['trim','htmlspecialchars','strip_tags'];
//protected $filter = ['trim','htmlspecialchars'];
//protected $filter = ['trim','strip_tags'];
protected $filter = ['trim'];
//protected $filter = ['htmlspecialchars'];
//protected $filter = ['trim'];
}

View File

@ -22,7 +22,6 @@ class Addons extends AdminController
//$conf = new \addons\social\model\Conf;
//$arr = $conf->getConf();
//dump($arr);
//dump($arr[0]['value']['app_key']);
return View::fetch();
}
@ -159,7 +158,7 @@ class Addons extends AdminController
validate(['file'=>'filesize:2048|fileExt:zip,rar,7z'])
->check(array($file));
$savename = \think\facade\Filesystem::disk('public')->putFile('addons',$file);
} catch (think\exception\ValidateException $e) {
} catch (\think\exception\ValidateException $e) {
echo $e->getMessage();
}
$upload = Config::get('filesystem.disks.public.url');
@ -189,6 +188,7 @@ class Addons extends AdminController
if(!$verRes){
return json(['code'=>-1,'msg'=>'不能降级,请选择正确版本']);
}
//$tpl_ver_res = version_compare($addInstalledVersion['template_version'], config('taoler.template_version'),'<');
}
$file_url = $addons->addons_src;

View File

@ -60,7 +60,8 @@ class Forum extends AdminController
$forumList = Db::name('article')
->alias('a')
->join('user u','a.user_id = u.id')
->field('a.id as aid,name,user_img,title,content,a.update_time as update_time,is_top,is_hot,is_reply,a.status as status')
->join('cate c','a.cate_id = c.id')
->field('a.id as aid,ename,name,user_img,title,content,a.update_time as update_time,is_top,a.is_hot as is_hot,is_reply,a.status as status')
->where('a.delete_time',0)
->where($map)
->where($where)
@ -73,7 +74,7 @@ class Forum extends AdminController
$res['msg'] = '';
$res['count'] = $count;
foreach($forumList as $k=>$v){
$url = $this->getRouteUrl($v['aid']);
$url = $this->getRouteUrl($v['aid'],$v['ename']);
$res['data'][]= ['id'=>$v['aid'],'poster'=>$v['name'],'avatar'=>$v['user_img'],'title'=>htmlspecialchars($v['title']),'url'=>$url,'content'=>htmlspecialchars($v['content']),'posttime'=>date("Y-m-d",$v['update_time']),'top'=>$v['is_top'],'hot'=>$v['is_hot'],'reply'=>$v['is_reply'],'check'=>$v['status']];
}
} else {
@ -236,7 +237,8 @@ class Forum extends AdminController
->alias('a')
->join('user u','a.user_id = u.id')
->join('article c','a.article_id = c.id')
->field('a.id as aid,name,title,user_img,a.content as content,a.create_time as create_time,a.status as astatus,c.id as cid')
->join('cate ca','c.cate_id = ca.id')
->field('a.id as aid,name,ename,title,user_img,a.content as content,a.create_time as create_time,a.status as astatus,c.id as cid')
->where('a.delete_time',0)
->where($map)
->where($where)
@ -248,7 +250,7 @@ class Forum extends AdminController
if ($count) {
$res = ['code'=>0,'msg'=>'','count'=>$count];
foreach($replys as $k => $v){
$url = $this->getRouteUrl($v['cid']);
$url = $this->getRouteUrl($v['cid'],$v['ename']);
//$res['data'][] = ['id'=>$v['id'],'replyer'=>$v->user->name,'cardid'=>$v->article->title,'avatar'=>$v->user->user_img,'content'=>$v['content'],'replytime'=>$v['create_time']];
$res['data'][] = ['id'=>$v['aid'],'replyer'=>$v['name'],'title'=>htmlspecialchars($v['title']),'avatar'=>$v['user_img'],'content'=>htmlspecialchars($v['content']),'replytime'=>date("Y-m-d",$v['create_time']),'check'=>$v['astatus'],'url'=>$url];
}

View File

@ -13,6 +13,7 @@ use app\admin\model\Article;
use app\admin\model\Cunsult;
use think\facade\Config;
use taoler\com\Api;
use taoser\SetArr;
class Index extends AdminController
{
@ -111,7 +112,7 @@ class Index extends AdminController
->alias('a')
->join('user u','a.user_id = u.id')
->join('cate c','a.cate_id = c.id')
->field('a.id as aid,title,name,catename,pv')
->field('a.id as aid,title,name,ename,catename,pv')
->where('a.delete_time',0)
->whereWeek('a.create_time')
->order('a.create_time', 'desc')
@ -124,7 +125,7 @@ class Index extends AdminController
$res['count'] = $count;
foreach($forumList as $k=>$v){
//$url = (string) str_replace("admin","index",$this->domain.url('article/detail',['id'=>$v['aid']]));
$url = $this->getRouteUrl($v['aid']);
$url = $this->getRouteUrl($v['aid'],$v['ename']);
$res['data'][]= ['id'=>$url,'title'=>htmlspecialchars($v['title']),'name'=>$v['name'],'catename'=>$v['catename'],'pv'=>$v['pv']];
}
} else {
@ -142,7 +143,8 @@ class Index extends AdminController
->alias('a')
->join('user u','a.user_id = u.id')
->join('article c','a.article_id = c.id')
->field('a.content as content,title,c.id as cid,name')
->join('cate ca','c.cate_id = ca.id')
->field('a.content as content,title,c.id as cid,name,ename')
->where('c.delete_time',0)
->whereWeek('a.create_time')
->order('a.create_time', 'desc')
@ -153,7 +155,7 @@ class Index extends AdminController
if ($count) {
$res = ['code'=>0,'msg'=>'','count'=>$count];
foreach($replys as $k => $v){
$res['data'][] = ['content'=>htmlspecialchars($v['content']),'title'=>htmlspecialchars($v['title']),'cid'=>$this->getRouteUrl($v['cid']),'name'=>$v['name']];
$res['data'][] = ['content'=>htmlspecialchars($v['content']),'title'=>htmlspecialchars($v['title']),'cid'=>$this->getRouteUrl($v['cid'],$v['ename']),'name'=>$v['name']];
}
} else {
$res = ['code'=>-1,'msg'=>'本周还没评论'];
@ -242,7 +244,40 @@ class Index extends AdminController
}
}
// 系统调试
public function sysSys()
{
$status = input('status');
//打开调试
$env = root_path().'.env';
$app = config_path().'app.php';
if(file_exists($env)){
$str = file_get_contents($env);
$appStr = file_get_contents($app);
$patk = '/APP_DEBUG[^\r?\n]*/';
$appPatk = '/'.'exception_tmpl'.'[^\r?\n]*/';
if($status == 'true'){
$reps = 'APP_DEBUG = true';
$appArr = "exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',";
} else {
$reps = 'APP_DEBUG = false';
$appArr = "exception_tmpl' => app()->getAppPath() . '404.html',";
}
$str = preg_replace($patk, $reps, $str);
file_put_contents($env, $str);
$appStr = preg_replace($appPatk, $appArr, $appStr);
$res = file_put_contents($app, $appStr) ? true : false;
if($res == true){
return json(['code'=>0,'msg'=>'设置成功']);
} else {
return json(['code'=>-1,'msg'=>'开启失败']);
}
}
}
public function layout(){
return view();

View File

@ -2,11 +2,11 @@
/*
* @Author: TaoLer <alipey_tao@qq.com>
* @Date: 2022-04-13 09:54:31
* @LastEditTime: 2022-05-12 16:21:33
* @LastEditTime: 2022-07-15 18:28:57
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\admin\controller\Seo.php
* Copyright (c) 2020~2022 http://www.aieok.com All rights reserved.
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
declare(strict_types=1);
namespace app\admin\controller;
@ -20,6 +20,8 @@ use app\admin\model\PushJscode;
class Seo extends AdminController
{
// 写ID
protected $w_id = 0;
public function index()
{
@ -43,25 +45,63 @@ class Seo extends AdminController
return View::fetch();
}
/**
* 百度推送
*
* @return void
*/
public function push()
{
$data = Request::only(['start_id','end_id','time']);
// 动态路由配置
$article_as = config('taoler.url_rewrite.article_as');
$api = config('taoler.baidu.push_api');
if(empty(config('taoler.baidu.push_api'))) return json(['code'=>-1,'msg'=>'请先配置接口push_api']);
if(empty($api)) return json(['code'=>-1,'msg'=>'请先配置接口push_api']);
$urls = [];
if(empty($data['start_id']) || empty($data['end_id'])) {
$artAllId = Db::name('article')->where(['delete_time'=>0,'status'=>1])->whereTime('create_time', $data['time'])->column('id');
if($article_as == '<ename>/'){ //变量路由
$artAllId = Db::name('article')
->alias('a')
->join('cate c','a.cate_id = c.id')
->field('a.id as aid,ename')
->where(['a.delete_time'=>0,'a.status'=>1])
->whereTime('a.create_time', $data['time'])
->select()->toArray();
} else { //常量路由
$artAllId = Db::name('article')->where(['delete_time'=>0,'status'=>1])->whereTime('create_time', $data['time'])->column('id');
}
} else {
$artAllId = Db::name('article')->where(['delete_time'=>0,'status'=>1])->where('id','between',[$data['start_id'],$data['end_id']])->whereTime('create_time', $data['time'])->column('id');
if($article_as == '<ename>/') {
$artAllId = Db::name('article')
->alias('a')
->join('cate c','a.cate_id = c.id')
->field('a.id as aid,ename')
->where(['a.delete_time'=>0,'a.status'=>1])
->where('a.id','between',[$data['start_id'],$data['end_id']])
->whereTime('a.create_time', $data['time'])
->select()->toArray();
} else {
$artAllId = Db::name('article')->where(['delete_time'=>0,'status'=>1])->where('id','between',[$data['start_id'],$data['end_id']])->whereTime('create_time', $data['time'])->column('id');
}
}
if(empty($artAllId)) return json(['code'=>-1,'msg'=>'没有查询到结果,无需推送']);
// 组装链接数组
foreach($artAllId as $aid) {
$urls[] = $this->getRouteUrl($aid);
if($article_as == '<ename>/') {
foreach($artAllId as $art) {
$urls[] = $this->getRouteUrl($art['aid'], $art['ename']);
}
} else {
foreach($artAllId as $aid) {
$urls[] = $this->getRouteUrl($aid);
}
}
// 百度接口单次最大提交200进行分组
$urls = array_chunk($urls,2000);
$api = config('taoler.baidu.push_api');
$urls = array_chunk($urls,2000);
$ch = curl_init();
foreach($urls as $url) {
$options = array(
@ -125,7 +165,7 @@ class Seo extends AdminController
$data = Request::only(['map_num','map_time','map_level']);
// 写文件字符串
$str = '';
// 标记第一次调用写ID
// 标记每次调用首次调用写ID
$flag= true;
// 写ID
$w_id = '';
@ -133,6 +173,8 @@ class Seo extends AdminController
$i = 1;
// 获取public下所有xml文件
$newFile = $this->getXmlFile(public_path());
// 路由配置
$article_as = config('taoler.url_rewrite.article_as');
// 没有xml文件时不存在重写
if(empty($newFile)) {
$rewrite = false;
@ -143,7 +185,7 @@ class Seo extends AdminController
// 是否有需要追加在文件,判断最新文件是否未写满
$rewrite = $num < $data['map_num'] ? true : false;
}
if($rewrite){
// 需要追加的数量
$limit = (int) $data['map_num'] - $num;
@ -157,37 +199,73 @@ class Seo extends AdminController
} else {
$limit = (int) $data['map_num'];
}
// 最新ID
$maxId = Db::name('article')->where(['delete_time'=>0,'status'=>1])->max('id');
do
{
$wr_id = $flag ? config('taoler.sitemap.write_id') : $w_id;
$artAllId = Db::name('article')
$this->wr_id = $flag ? config('taoler.sitemap.write_id') : $this->w_id;
if($article_as == '<ename>/') {
// 分类名
$artAllId = Db::name('article')
->alias('a')
->join('cate c','a.cate_id = c.id')
->field('a.id as aid,a.update_time as uptime,ename')
->where(['a.delete_time'=>0,'a.status'=>1])
->where('a.id', '>', (int) $this->wr_id)
->order('a.id','asc')->limit($limit)
->select()->toArray();
} else {
$artAllId = Db::name('article')
->where(['delete_time'=>0,'status'=>1])
->where('id', '>', (int) $wr_id)
->where('id', '>', (int) $this->wr_id)
->order('id','asc')->limit($limit)->column('update_time','id');
}
if(empty($artAllId)) {
return json(['code'=>-1,'msg'=>'本次无需生成']);
} else {
// 本次最新文件ID
$last_id = array_key_last($artAllId);
// 循环拼接文件字符串
foreach($artAllId as $aid => $uptime) {
// url生成
$url = $this->getRouteUrl($aid);
$time = date('Y-m-d', $uptime);
// 组装字符串
$str .= <<<STR
<url>
<loc>$url</loc>
<lastmod>$time</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>\n
STR;
if($article_as == '<ename>/') {
// 循环拼接文件字符串
foreach($artAllId as $art) {
//url生成
$url = $this->getRouteUrl($art['aid'], $art['ename']);
$time = date('Y-m-d', $art['uptime']);
// 组装字符串
$str .= <<<STR
<url>
<loc>$url</loc>
<lastmod>$time</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>\n
STR;
}
$last_arr = end($artAllId);
$last_id = $last_arr['aid'];
} else {
// 循环拼接文件字符串
foreach($artAllId as $aid => $uptime) {
// url生成
$url = $this->getRouteUrl($aid);
$time = date('Y-m-d', $uptime);
// 组装字符串
$str .= <<<STR
<url>
<loc>$url</loc>
<lastmod>$time</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>\n
STR;
}
$last_id = array_key_last($artAllId);
}
// 写文件
if($rewrite){
// 写入旧xml文件
@ -213,7 +291,7 @@ class Seo extends AdminController
// 重置标记内容
$str = '';
$i++;
$w_id = $last_id;
$this->w_id = $last_id;
$flag = false;
}
}
@ -228,8 +306,7 @@ class Seo extends AdminController
if($res == false){
return json(['code'=>-1,'msg'=>'写xml配置失败']);
}
return json(['code'=>0,'msg'=>'本次成功生成'.count($artAllId).'条xml']);
return json(['code'=>0,'msg'=>'本次成功生成' . count($artAllId) . '条xml']);
}
/**
@ -314,6 +391,11 @@ class Seo extends AdminController
return json(['code'=>0,'msg'=>'删除成功']);
}
/**
* 搜索引擎日志分析
*
* @return void
*/
public function searchLog()
{
$time = input('search_time');

View File

@ -2,7 +2,7 @@
/*
* @Author: TaoLer <alipey_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-05-10 15:00:49
* @LastEditTime: 2022-07-24 11:06:14
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\admin\controller\Set.php
@ -161,7 +161,7 @@ class Set extends AdminController
return json($res);
}
/**置设
/**基础服务配置
* parem $id
*/
public function config()
@ -173,7 +173,6 @@ class Set extends AdminController
if(!isset($data['posts_check'])) $data['posts_check'] =1;
if(!isset($data['commnets_check'])) $data['commnets_check'] =1;
foreach($conf as $c=>$f){
if(array_key_exists($c,$data)){
$conf[$c] = (int) $data[$c];
}else{
@ -356,18 +355,27 @@ class Set extends AdminController
//上传logo
public function upload()
{
$param = Request::param('field');
$uploads = new \app\common\lib\Uploads();
$upRes = $uploads->put('file','logo',2000,'image','uniqid');
$upRes = $uploads->put('file','SYS_logo',2000,'image');
$logoJson = $upRes->getData();
if($logoJson['status'] == 0){
$result = Db::name('system')->where('id', 1)->cache('system')->update(['logo'=>$logoJson['url']]);
if($result){
$res = ['code'=>0,'msg'=>'上传logo成功'];
if($param == 'logo'){
$result = Db::name('system')->where('id', 1)->cache('system')->update(['logo'=>$logoJson['url']]);
} else {
$res = ['code'=>1,'msg'=>'上传错误'];
//移动端logo
$result = Db::name('system')->where('id', 1)->cache('system')->update(['m_logo'=>$logoJson['url']]);
}
}
return json($res);
if($result){
$res = ['code'=>0,'msg'=>'更新logo成功'];
} else {
$res = ['code'=>-1,'msg'=>'上传成功,数据无须更新'];
}
} else {
$res = ['code'=>-1, 'msg'=>$logoJson['msg']];
}
return json($res);
}
}

View File

@ -32,7 +32,7 @@ class Slider extends AdminController
$limit = input('limit');
$page = input('page');
if($type) {
$datas = SliderModel::where('slid_type',$type)->where('')->paginate([
$datas = SliderModel::where('slid_type',$type)->paginate([
'list_rows'=> $limit,
'page'=>$page
]);
@ -126,7 +126,7 @@ class Slider extends AdminController
public function uploadImg()
{
$uploads = new \app\common\lib\Uploads();
$upRes = $uploads->put('file','slider',1024,'image');
$upRes = $uploads->put('file','SYS_slider',1024,'image');
$slires = $upRes->getData();
if($slires['status'] == 0){
@ -135,7 +135,7 @@ class Slider extends AdminController
} else {
$res = ['code'=>1,'msg'=>'上传错误'];
}
return json($res);
return json($res);
}
/**

View File

@ -6,8 +6,8 @@
* |————runtime
* | |
* | |___update.sql(更新脚本) //create table test(id init(11)); create table test2(id init(11));
*
* | |___rockback.sql回滚脚本 //drop table test; //drop table test2;
* | |___remove.txt // clear清除目录和文件
* |
* |____php
*

View File

@ -31,7 +31,7 @@ class User extends AdminController
if($count){
$res = ['code'=>0,'msg'=>'','count'=>$count];
foreach($user as $k => $v){
$data = ['id'=>$v['id'],'username'=>$v['name'],'avatar'=>$v['user_img'],'phone'=>$v['phone'],'email'=>$v['email'],'sex'=>$v['sex'],'ip'=>$v['last_login_ip'],'city'=>$v['city'],'logintime'=>date("Y-m-d H:i",$v['last_login_time']),'jointime'=>date("Y-m-d",$v['create_time']),'check'=>$v['status'],'auth'=>$v['auth']];
$data = ['id'=>$v['id'],'username'=>$v['name'],'nick'=>$v['nickname'],'avatar'=>$v['user_img'],'phone'=>$v['phone'],'email'=>$v['email'],'sex'=>$v['sex'],'ip'=>$v['last_login_ip'],'city'=>$v['city'],'logintime'=>date("Y-m-d H:i",$v['last_login_time']),'jointime'=>date("Y-m-d",$v['create_time']),'check'=>$v['status'],'auth'=>$v['auth']];
$res['data'][] = $data;
}
} else {

View File

@ -0,0 +1,25 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2022-07-02 10:39:43
* @LastEditTime: 2022-07-02 10:42:19
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \TaoLer\app\admin\model\Addons.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\admin\model;
use think\Model;
use think\model\concern\SoftDelete;
class Addons extends Model
{
//软删除
use SoftDelete;
protected $deleteTime = 'delete_time';
protected $defaultSoftDelete = 0;
protected $createTime = 'false';
}

View File

@ -2,7 +2,7 @@
/*
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-05-07 18:33:23
* @LastEditTime: 2022-06-29 15:29:13
* @LastEditors: TaoLer
* @Description: admin路由配置
* @FilePath: \TaoLer\app\admin\route\route.php
@ -14,4 +14,9 @@ use think\facade\Route;
$detail_as = config('taoler.url_rewrite.article_as');
Route::get('captcha/[:config]','\\think\\captcha\\CaptchaController@index');
Route::get("$detail_as<id>$", '\app\index\controller\Article@detail')->name('detail_id');
Route::get("$detail_as<id>$", '\app\index\controller\Article@detail')
->pattern([
//'name' => '\w+',
'id' => '\d+',
])
->name('article_detail');

View File

@ -46,23 +46,23 @@
{{# } }}
</script>
-->
<script type="text/html" id="buttonTpl">
{{# if(d.id == '1'){ }}
<input type="checkbox" name="check" lay-skin="switch" disabled lay-text="通过|禁用" value="1" checked id="{{d.id}}">
{{# } else { }}
{if condition="checkRuleButton('admin/check')"}<input type="checkbox" name="check" lay-skin="switch" lay-filter="admincheck" lay-text="通过|禁用" {{# if(d.check == 1){ }} checked {{# } }} id="{{d.id}}" >{else}<button class="layui-btn layui-btn-xs layui-btn-radius layui-btn-disabled">无权限</button>{/if}
{{# } }}
<script type="text/html" id="buttonTpl">
{{# if(d.id == '1'){ }}
<input type="checkbox" name="check" lay-skin="switch" disabled lay-text="通过|禁用" value="1" checked id="{{d.id}}">
{{# } else { }}
{if condition="checkRuleButton('admin/check')"}<input type="checkbox" name="check" lay-skin="switch" lay-filter="admincheck" lay-text="通过|禁用" {{# if(d.check == 1){ }} checked {{# } }} id="{{d.id}}" >{else}<button class="layui-btn layui-btn-xs layui-btn-radius layui-btn-disabled">无权限</button>{/if}
{{# } }}
</script>
<script type="text/html" id="table-useradmin-admin">
{if condition="checkRuleButton('admin/edit')"}
{if condition="checkRuleButton('admin/edit')"}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
{else /}<a class="layui-btn layui-btn-normal layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-edit"></i>编辑</a>{/if}
{else /}<a class="layui-btn layui-btn-normal layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-edit"></i>编辑</a>{/if}
{{# if(d.id == '1'){ }}
<a class="layui-btn layui-btn-disabled layui-btn-xs"><i class="layui-icon layui-icon-delete"></i>删除</a>
{{# } else { }}
{if condition="checkRuleButton('admin/delete')"}
{if condition="checkRuleButton('admin/delete')"}
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
{else /}<a class="layui-btn layui-btn-danger layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-delete"></i>删除</a>{/if}
{else /}<a class="layui-btn layui-btn-danger layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-delete"></i>删除</a>{/if}
{{# } }}
</script>
</div>
@ -99,23 +99,7 @@
//监听搜索
form.on('submit(LAY-user-back-search)', function(data){
var field = data.field;
$.ajax({
type:"post",
url:"{:url('admin/index')}",
data:{"id":field.id,"username":field.username,"mobile":field.mobile,"email":field.email},
daType:"json",
success:function (data){
if (data.code == 0) {
} else {
layer.open({
content:data.msg,
icon:5,
anim:6
});
}
}
});
$.post("{:url('admin/index')}",field);
//执行重载
table.reload('LAY-user-back-manage', {
where: field
@ -125,37 +109,17 @@
//监听管理员审核
form.on('switch(admincheck)', function(data){
var data= data.elem;
//console.log(data);
if(data.checked == true){
data.value = 1;
}else{
data.value = 0;
}
//执行管理员审核
$.ajax({
type:'post',
url:"{:url('admin/check')}",
data:{"id":data.id,"status":data.value,},
dataType:'json',
success:function(res){
//执行管理员审核
var status = data.checked ? 1 : 0;
$.post("{:url('admin/check')}",{"id":data.id,"status":status},function(res){
if(res.code == 0){
layer.msg(res.msg,{
icon:res.icon,
time:2000
}
//,function(){location.reload();}
);
layer.msg(res.msg,{icon:res.icon,time:2000})
} else {
layer.open({
title:'审核失败',
content:res.msg,
icon:5,
adim:6
})
layer.open({title:'审核失败',content:res.msg,icon:5,adim:6})
}
}
});
});
return false;
});
@ -206,28 +170,14 @@
var field = data.field; //获取提交的字段
//提交 Ajax 成功后,静态更新表格中的数据
$.ajax({
type:"post",
url:"{:url('admin/add')}",
data:{"username":field.username,"password":field.password,"mobile":field.mobile,"email":field.email,"auth_group_id":field.auth_group_id,"status":field.status},
daType:"json",
success:function (data){
if (data.code == 0) {
layer.msg(data.msg,{
icon:6,
time:2000
});
} else {
layer.open({
title:'添加失败',
content:data.msg,
icon:5,
anim:6
});
}
}
});
$.post("{:url('admin/add')}",field,function(res){
if(res.code == 0){
layer.msg(res.msg,{icon:res.icon,time:2000})
} else {
layer.open({title:'添加失败',content:res.msg,icon:5,adim:6})
}
});
table.reload('LAY-user-back-manage'); //数据刷新
layer.close(index); //关闭弹层
});
@ -236,7 +186,8 @@
}
});
}
}
}
$('.layui-btn.layuiadmin-btn-admin').on('click', function(){
var type = $(this).data('type');
active[type] ? active[type].call(this) : '';

View File

@ -17,14 +17,14 @@
<input type="text" name="content" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<select name="status" lay-filter="fourm-check">
<option value="">全部</option>
<option value="0">待审</option>
<option value="">全部</option>
<option value="0">待审</option>
<option value="-1">禁止</option>
<option value="1">通过</option>
<option value="1">通过</option>
</select>
</div>
</div>
@ -41,20 +41,17 @@
</div>
<table id="LAY-app-forumreply-list" lay-filter="LAY-app-forumreply-list"></table>
<script type="text/html" id="imgTpl">
<img style="display: inline-block; width: 50%; height: 100%;" src= {{ d.avatar }}>
<img style="width: 25px; height: 25px;" src= {{ d.avatar }}>
</script>
<script type="text/html" id="title">
<a href="{{d.url}}.html" target="_blank">{{d.title}}</a>
</script>
<script type="text/html" id="buttonCheck">
{if condition="checkRuleButton('forum/recheck')"}<input type="checkbox" name="check" lay-skin="switch" lay-filter="recheck" lay-text="通过|{{# if(d.check == -1){ }}禁止{{# } }} {{# if(d.check == 0){ }}待审{{# } }}" {{# if(d.check == 1){ }} checked {{# } }} id="{{d.id}}" >
{else /}<button class="layui-btn layui-btn-xs layui-btn-radius layui-btn-disabled">无权限</button>{/if}
<script type="text/html" id="buttonCheck">
{if condition="checkRuleButton('forum/recheck')"}<input type="checkbox" name="check" lay-skin="switch" lay-filter="recheck" lay-text="通过|{{ d.check == 0 ? '待审' : '禁止' }}" {{ d.check == 1 ? 'checked' : '' }} id="{{d.id}}" >
{else /}<button class="layui-btn layui-btn-xs layui-btn-radius layui-btn-disabled">无权限</button>{/if}
</script>
<script type="text/html" id="table-forum-replys">
{if condition="checkRuleButton('forum/redel')"}
{if condition="checkRuleButton('forum/redel')"}
<!--a class="layui-btn layui-btn-disabled layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a-->
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
{else / }<a class="layui-btn layui-btn-danger layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-delete"></i>删除</a>{/if}
{else / }<a class="layui-btn layui-btn-danger layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-delete"></i>删除</a>{/if}
</script>
</div>
</div>

View File

@ -5,12 +5,11 @@
<div class="layui-row layui-col-space15">
<div class="layui-col-md8">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-header"><i class="layui-icon layui-icon-voice"></i><a id="up_version" lay-href="{:url('Upgrade/index')}"></a></div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">快捷方式</div>
@ -127,7 +126,6 @@
<div class="layui-card">
<div class="layui-card-header">数据概览</div>
<div class="layui-card-body">
<div class="layui-carousel layadmin-carousel layadmin-dataview" data-anim="fade" lay-filter="LAY-index-dataview">
<div carousel-item id="LAY-index-dataview">
<div><i class="layui-icon layui-icon-loading1 layadmin-loading"></i></div>
@ -135,7 +133,6 @@
<div></div>
</div>
</div>
</div>
</div>
<div class="layui-card">
@ -207,6 +204,14 @@
<div class="layui-card">
<div class="layui-card-header">版本信息</div>
<div class="layui-card-body layui-text">
<div class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label">系统调试:</label>
<div class="layui-input-inline" style="width: 60px;">
<input type="checkbox" name="sys-sys" lay-skin="switch" lay-text="开启|关闭" lay-filter="sys-sys" {if env('APP_DEBUG') == true} checked {/if}>
</div>
</div>
</div>
<table class="layui-table">
<colgroup>
<col width="100">
@ -226,7 +231,7 @@
<td>
<script type="text/html" template>
TaoLer_{:config('taoler.version')}
<a href="https://www.aieok.com/bbs/doc/timeline.html" target="_blank" style="padding-left: 15px;">更新日志</a>
<a href="https://www.aieok.com/article/doc/timeline.html" target="_blank">更新日志</a>
</script>
</td>
</tr>
@ -324,7 +329,7 @@
<div class="layui-card-body layui-text layadmin-text">
<p>TaoLer采用Thinkphp6.0最新版本为开发框架代码简洁运行高效更新及时。layui是国内比较流行的前端框架两者完美结合您会拥有一个非常让人舒适的网站。</p>
<p>专注专一,大简其道!--本系统的特点,力争做到简洁,不臃肿,功能专一。不管是学习还是商用,都可以良好的运行。</p>
<p>作者尽最大可能,长期进行项目的维护,做到长期可用。</p>
<p>作者尽最大可能,长期进行项目的维护,做到长期可用。</p>
</div>
</div>
</div>
@ -368,6 +373,30 @@
return layedit.sync(index);
}
});
// 系统调试
form.on('switch(sys-sys)',function(data){
var status = data.elem.checked;
console.log(status);
$.post("{:url('index/sysSys')}",{status:status},function(res){
if (res.code == 0) {
layer.msg(res.msg,{
icon:6,
time:2000
}, function(){
location.reload();
});
} else {
layer.open({
content:res.msg,
icon:5,
anim:6
});
}
})
});
form.on('submit(cunsult-add)',function(data){
var field = data.field;
@ -427,7 +456,7 @@
}
});
//obj.del();
table.reload('LAY-index-topreply');
table.reload('LAY-index-topreply');
layer.close(index);
});
}
@ -438,21 +467,20 @@
$.get("{:url('Index/getVersion')}",function(data){
$('#up_version').html(data);
})
})();
$('.layui-btn.layuiadmin-btn-oiltank').on('click', function(){
var type = $(this).data('type');
active[type] ? active[type].call(this) : '';
});
});
});
var indexForums = "{:url('Index/forums')}", //帖子
indexReplys = "{:url('Index/replys')}"; //回复
var indexNews = "{:url('Index/news')}", //动态
indexReply = "{:url('Index/reply')}"; //反馈
var monthTime = "{$monthTime}",
monthUserCount = "{$monthUserCount}";
indexReplys = "{:url('Index/replys')}", //回复
indexNews = "{:url('Index/news')}", //动态
indexReply = "{:url('Index/reply')}", //反馈
monthTime = "{$monthTime}",
monthUserCount = "{$monthUserCount}";
</script>
{/block}

View File

@ -1,7 +1,7 @@
<!--
* @Author: TaoLer <alipey_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-04-21 11:05:47
* @LastEditTime: 2022-06-28 10:02:16
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\admin\view\public\base.html
@ -19,9 +19,8 @@
<link rel="stylesheet" href="/static/admin/style/admin.css" media="all">
{block name="css"}{/block}
</head>
<body {if($Request.url==url('index/index'))}class="layui-layout-body"{/if}>
<body {if($Request.url == url('index/index'))}class="layui-layout-body"{/if}>
{block name="body"}内容{/block}
<script src="/static/layui/jquery.min.js" charset="utf-8"></script>
<script src="/static/layui/layui.js"></script>
<script type="text/javascript" charset="utf-8">
var AdminLogin = "{:url('Login/index')}",

View File

@ -1,14 +1,13 @@
<!--
* @Author: TaoLer <alipey_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-04-21 11:06:13
* @LastEditTime: 2022-06-28 10:01:43
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @Description: 后台页脚结构
* @FilePath: \TaoLer\app\admin\view\public\footer.html
* Copyright (c) 2020~2022 http://www.aieok.com All rights reserved.
-->
<div class="layui-footer">
<!-- 底部固定区域 -->
© <a href="https://www.aieok.com">aieok.com</a> - 联系QQ317927823
© <a href="https://www.aieok.com">aieok.com</a> - 联系QQ317927823
</div>

View File

@ -1,72 +1,79 @@
<!--
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-06-28 10:00:54
* @LastEditors: TaoLer
* @Description: 后台头部结构
* @FilePath: \TaoLer\app\admin\view\public\header.html
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
-->
<div class="layui-header">
<!-- 头部区域 -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item layadmin-flexible" lay-unselect>
<a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
<i class="layui-icon layui-icon-shrink-right" id="LAY_app_flexible"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="{$domain}" target="_blank" title="前台">
<i class="layui-icon layui-icon-website"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;" layadmin-event="refresh" title="刷新">
<i class="layui-icon layui-icon-refresh-3"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<input type="text" placeholder="搜索..." autocomplete="off" class="layui-input layui-input-search" layadmin-event="serach" lay-action="template/search.html?keywords=">
</li>
</ul>
<ul class="layui-nav layui-layout-right" lay-filter="layadmin-layout-right">
<li class="layui-nav-item" lay-unselect>
<a lay-href="app/message/index.html" layadmin-event="message" lay-text="消息中心">
<i class="layui-icon layui-icon-notice"></i>
<!-- 如果有新消息,则显示小圆点 -->
<span class="layui-badge-dot"></span>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="theme">
<i class="layui-icon layui-icon-theme"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="note">
<i class="layui-icon layui-icon-note"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="fullscreen">
<i class="layui-icon layui-icon-screen-full"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="clearcache">
<i class="layui-icon layui-icon-fonts-clear"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;">
<cite>{:session('admin_name')}</cite>
</a>
<dl class="layui-nav-child">
<dd><a lay-href="{:url('Admin/info')}">基本资料</a></dd>
<dd><a lay-href="{:url('Admin/repass')}">修改密码</a></dd>
<hr>
<dd layadmin-event="logout" style="text-align: center;"><a>退出</a></dd>
</dl>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event=""><i class="layui-icon layui-icon-more-vertical"></i></a>
</li>
<li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-unselect>
<a href="javascript:;" layadmin-event=""><i class="layui-icon layui-icon-more-vertical"></i></a>
</li>
</ul>
</div>
<!-- 头部区域 -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item layadmin-flexible" lay-unselect>
<a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
<i class="layui-icon layui-icon-shrink-right" id="LAY_app_flexible"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="{$domain}" target="_blank" title="前台">
<i class="layui-icon layui-icon-website"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;" layadmin-event="refresh" title="刷新">
<i class="layui-icon layui-icon-refresh-3"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<input type="text" placeholder="搜索..." autocomplete="off" class="layui-input layui-input-search" layadmin-event="serach" lay-action="template/search.html?keywords=">
</li>
</ul>
<ul class="layui-nav layui-layout-right" lay-filter="layadmin-layout-right">
<li class="layui-nav-item" lay-unselect>
<a lay-href="app/message/index.html" layadmin-event="message" lay-text="消息中心">
<i class="layui-icon layui-icon-notice"></i>
<!-- 如果有新消息,则显示小圆点 -->
<span class="layui-badge-dot"></span>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="theme">
<i class="layui-icon layui-icon-theme"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="note">
<i class="layui-icon layui-icon-note"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="fullscreen">
<i class="layui-icon layui-icon-screen-full"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="clearcache">
<i class="layui-icon layui-icon-fonts-clear"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;">
<cite>{:session('admin_name')}</cite>
</a>
<dl class="layui-nav-child">
<dd><a lay-href="{:url('Admin/info')}">基本资料</a></dd>
<dd><a lay-href="{:url('Admin/repass')}">修改密码</a></dd>
<hr>
<dd layadmin-event="logout" style="text-align: center;"><a>退出</a></dd>
</dl>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event=""><i class="layui-icon layui-icon-more-vertical"></i></a>
</li>
<li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-unselect>
<a href="javascript:;" layadmin-event=""><i class="layui-icon layui-icon-more-vertical"></i></a>
</li>
</ul>
</div>

View File

@ -1,80 +1,89 @@
<!--
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-06-28 10:01:33
* @LastEditors: TaoLer
* @Description: 后台菜单结构
* @FilePath: \TaoLer\app\admin\view\public\side_menu.html
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
-->
<!-- 侧边菜单 -->
<div class="layui-side layui-side-menu">
<div class="layui-side-scroll">
<div class="layui-logo" lay-href="home/console.html">
<span>TaoLer_Admin</span>
</div>
<ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
<li data-name="home" class="layui-nav-item layui-nav-itemed">
<a href="javascript:;" lay-tips="主页" lay-direction="2">
<i class="layui-icon layui-icon-home"></i>
<cite>主页</cite>
</a>
<dl class="layui-nav-child">
<dd data-name="console" class="layui-this">
<a lay-href="{:url('index/home')}">控制台</a>
</dd>
</dl>
</li>
<!--li data-name="user" class="layui-nav-item">
<a href="javascript:;" lay-tips="用户" lay-direction="2">
<i class="layui-icon layui-icon-user"></i>
<cite>管理</cite>
</a>
<dl class="layui-nav-child">
<dd>
<a lay-href="{:url('User/list')}">网站用户1</a>
</dd>
<dd>
<a lay-href="{:url('adminList')}">后台管理员</a>
</dd>
<dd>
<a lay-href="{:url('authgroup/role')}">角色管理</a>
</dd>
<dd>
<a lay-href="{:url('authrule/index')}">权限管理</a>
</dd>
</dl>
</li-->
{volist name="menu" id="vo1"}
{if condition="isset($vo1['children'])"}
<li data-name="set" class="layui-nav-item">
<a href="javascript:;" lay-tips="{$vo1.title}" lay-direction="2">
<i class="layui-icon {$vo1.icon}"></i>
<cite>{$vo1.title}</cite>
</a>
<dl class="layui-nav-child">
{volist name="vo1['children']" id="vo2"}
{if condition="isset($vo2['children'])"}
<dd class="layui-nav-itemed">
<a href="javascript:;">{$vo2.title}</a>
<dl class="layui-nav-child">
{volist name="vo2['children']" id="vo3"}
<dd><a lay-href="{:url($vo3.name)}">{$vo3.title}</a></dd>
{/volist}
</dl>
</dd>
{else /}
<dd><a lay-href="{:url($vo2.name)}">{$vo2.title}</a></dd>
{/if}
{/volist}
</dl>
</li>
{else /}
<li data-name="get" class="layui-nav-item">
<a href="javascript:;" lay-href="{:url($vo1.name)}" lay-tips="{$vo1.title}" lay-direction="2">
<i class="layui-icon {$vo1.icon}"></i>
<cite>{$vo1.title}</cite>
</a>
</li>
{/if}
{/volist}
</ul>
</div>
</div>
<div class="layui-side layui-side-menu">
<div class="layui-side-scroll">
<div class="layui-logo" lay-href="home/console.html">
<span>TaoLer_Admin</span>
</div>
<ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
<li data-name="home" class="layui-nav-item layui-nav-itemed">
<a href="javascript:;" lay-tips="主页" lay-direction="2">
<i class="layui-icon layui-icon-home"></i>
<cite>主页</cite>
</a>
<dl class="layui-nav-child">
<dd data-name="console" class="layui-this">
<a lay-href="{:url('index/home')}">控制台</a>
</dd>
</dl>
</li>
<!--li data-name="user" class="layui-nav-item">
<a href="javascript:;" lay-tips="用户" lay-direction="2">
<i class="layui-icon layui-icon-user"></i>
<cite>管理</cite>
</a>
<dl class="layui-nav-child">
<dd>
<a lay-href="{:url('User/list')}">网站用户1</a>
</dd>
<dd>
<a lay-href="{:url('adminList')}">后台管理员</a>
</dd>
<dd>
<a lay-href="{:url('authgroup/role')}">角色管理</a>
</dd>
<dd>
<a lay-href="{:url('authrule/index')}">权限管理</a>
</dd>
</dl>
</li-->
{volist name="menu" id="vo1"}
{if condition="isset($vo1['children'])"}
<li data-name="set" class="layui-nav-item">
<a href="javascript:;" lay-tips="{$vo1.title}" lay-direction="2">
<i class="layui-icon {$vo1.icon}"></i>
<cite>{$vo1.title}</cite>
</a>
<dl class="layui-nav-child">
{volist name="vo1['children']" id="vo2"}
{if condition="isset($vo2['children'])"}
<dd class="layui-nav-itemed">
<a href="javascript:;">{$vo2.title}</a>
<dl class="layui-nav-child">
{volist name="vo2['children']" id="vo3"}
<dd><a lay-href="{:url($vo3.name)}">{$vo3.title}</a></dd>
{/volist}
</dl>
</dd>
{else /}
<dd><a lay-href="{:url($vo2.name)}">{$vo2.title}</a></dd>
{/if}
{/volist}
</dl>
</li>
{else /}
<li data-name="get" class="layui-nav-item">
<a href="javascript:;" lay-href="{:url($vo1.name)}" lay-tips="{$vo1.title}" lay-direction="2">
<i class="layui-icon {$vo1.icon}"></i>
<cite>{$vo1.title}</cite>
</a>
</li>
{/if}
{/volist}
</ul>
</div>
</div>

View File

@ -43,13 +43,23 @@
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">LOGO</label>
<label class="layui-form-label">Logo</label>
<div class="layui-input-block">
<span><img src="{$sysInfo.logo}" hight="40" width="50" ></span>
{if condition="checkRuleButton('set/upload')"}
<button type="button" class="layui-btn layui-btn-normal" id="logo-img">选择文件</button>
<button type="button" class="layui-btn" id="logo-upload-button">开始上传</button>
{else /}<button type="button" class="layui-btn layui-btn-normal layui-btn-disabled">选择文件</button>{/if}
<button type="button" class="layui-btn layui-btn-sm" id="logo-img">选择文件</button>
<button type="button" class="layui-btn layui-btn-sm" id="logo-upload-button">开始上传</button>
{else /}<button type="button" class="layui-btn layui-btn-sm layui-btn-disabled">选择文件</button>{/if}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">M-logo</label>
<div class="layui-input-block">
<span><img src="{$sysInfo.m_logo}" hight="40" width="50" ></span>
{if condition="checkRuleButton('set/upload')"}
<button type="button" class="layui-btn layui-btn-sm" id="m-logo-img">选择文件</button>
<button type="button" class="layui-btn layui-btn-sm" id="m-logo-upload-button">开始上传</button>
{else /}<button type="button" class="layui-btn layui-btn-sm layui-btn-disabled">选择文件</button>{/if}
</div>
</div>
<div class="layui-form-item">
@ -202,6 +212,103 @@
</div>
<div class="layui-tab-item">
<div class="layui-form" wid100 lay-filter="config">
<div class="layui-form-item">
<label class="layui-form-label">注册开关:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="is_regist" lay-skin="primary" value=1 {if config('taoler.config.is_regist') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选可注册</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">登录开关:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="is_login" lay-skin="primary" value=1 {if config('taoler.config.is_login') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选可登录</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">发帖开关:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="is_post" lay-skin="primary" value=1 {if config('taoler.config.is_post') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选可发贴</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">评论开关:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="is_reply" lay-skin="primary" value=1 {if config('taoler.config.is_reply') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选可评论</div>
</div>
<hr>
<div class="layui-form-item">
<label class="layui-form-label">注册审核:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="regist_check" lay-skin="primary" value=0 {if config('taoler.config.regist_check') == 0} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选需审核</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">发帖审核:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="posts_check" lay-skin="primary" value=0 {if config('taoler.config.posts_check') == 0} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选需审核</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">评论审核:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="commnets_check" lay-skin="primary" value=0 {if config('taoler.config.commnets_check') == 0} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选需审核</div>
</div>
<hr>
<div class="layui-form-item">
<label class="layui-form-label">注册验证:</label>
<div class="layui-input-block">
<input type="radio" name="regist_type" value=1 title="验证码" {if config('taoler.config.regist_type') == 1} checked {/if}>
<input type="radio" name="regist_type" value=2 title="邮箱验证" {if config('taoler.config.regist_type') == 2} checked {/if}>
<input type="radio" name="regist_type" value=3 title="手机短信" {if config('taoler.config.regist_type') == 3} checked {/if}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">登录验证码:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="login_captcha" lay-skin="primary" value=1 {if config('taoler.config.login_captcha') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选需验证</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">发帖验证码:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="post_captcha" lay-skin="primary" value=1 {if config('taoler.config.post_captcha') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选需验证</div>
</div>
<hr>
<div class="layui-form-item">
<label class="layui-form-label">分类显示:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="cate_show" lay-skin="primary" value=1 {if config('taoler.config.cate_show') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选显示文章所属类别</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">区域简称:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="area_show" lay-skin="primary" value=1 {if config('taoler.config.area_show') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选显示归属地简称</div>
</div>
<hr>
<div class="layui-form-item">
<label class="layui-form-label">百度词条:</label>
<div class="layui-input-inline" style="width: 60px;">
<input type="checkbox" name="baidu_title_switch" lay-skin="switch" lay-text="开启|关闭" value=1 {if config('taoler.config.baidu_title_switch') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">发文章标题引用百度词条</div>
</div>
<hr>
{if($mailserver.active == 1)}
<div class="layui-form-item">
<label class="layui-form-label">邮件通知:</label>
@ -212,61 +319,10 @@
</div>
{/if}
<div class="layui-form-item">
<label class="layui-form-label">注册审核:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="regist_check" lay-skin="primary" value=0 {if config('taoler.config.regist_check') == 0} checked {/if}>
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="set_system_config">确认保存</button>
</div>
<div class="layui-form-mid layui-word-aux">注册是否需要审核</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">发帖审核:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="posts_check" lay-skin="primary" value=0 {if config('taoler.config.posts_check') == 0} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">发帖是否需要审核</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">评论审核:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="commnets_check" lay-skin="primary" value=0 {if config('taoler.config.commnets_check') == 0} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">评论是否需要审核</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类显示:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="cate_show" lay-skin="primary" value=1 {if config('taoler.config.cate_show') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">是否显示列表及详情所属分类</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">区域简称:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="area_show" lay-skin="primary" value=1 {if config('taoler.config.area_show') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">是否显示发件人所在地区简称</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">登录验证码:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="login_captcha" lay-skin="primary" value=1 {if config('taoler.config.login_captcha') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选则验证</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">发帖验证码:</label>
<div class="layui-input-inline" style="width: 30px;">
<input type="checkbox" name="post_captcha" lay-skin="primary" value=1 {if config('taoler.config.post_captcha') == 1} checked {/if}>
</div>
<div class="layui-form-mid layui-word-aux">勾选则验证</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="set_system_config">确认保存</button>
</div>
</div>
</div>
</div>
@ -380,7 +436,7 @@
upload.render({
elem: '#logo-img'
,url: "{:url('set/upload')}"
,data: {type:'image'}
,data: {type:'image',field:'logo'}
,auto: false
,exts: 'jpg|png|gif|bmp|jpeg'
,size: 1000
@ -397,6 +453,27 @@
}
});
//移动端logo
upload.render({
elem: '#m-logo-img'
,url: "{:url('set/upload')}"
,data: {type:'image',field:'mlogo'}
,auto: false
,exts: 'jpg|png|gif|bmp|jpeg'
,size: 1000
//,multiple: true
,bindAction: '#m-logo-upload-button'
,done: function(res){
if(res.code == 0){
layer.msg(res.msg,{icon:6,tiye:2000},function(){
location.reload();
});
} else {
layer.open({title:"上传失败",content:res.msg,icon:5,anim:6});
}
}
});
//网站配置
form.on('submit(set_system_config)', function(data){
var field = data.field;

View File

@ -20,6 +20,8 @@
<option value="9">9友情链接</option>
<option value="10">10头部菜单</option>
<option value="11">11页脚链接</option>
<option value="12">12移动首页幻灯-360x172</option>
<option value="13">13首页右栏广告</option>
</select>
</div>
</div>
@ -75,21 +77,21 @@
base: '/static/admin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form', 'upload','laydate','colorpicker', 'imgcom'], function(){
}).use(['index','imgcom'], function(){
var $ = layui.$
,form = layui.form
,laydate = layui.laydate
,laydate = layui.laydate
,upload = layui.upload
,imgcom = layui.imgcom;
var colorpicker = layui.colorpicker;
,imgcom = layui.imgcom;
var colorpicker = layui.colorpicker;
//颜色表单赋值
colorpicker.render({
elem: '#coloer-form'
,color: '#1c97f5'
,done: function(color){
$('#color-select').val(color);
}
elem: '#coloer-form'
,color: '#1c97f5'
,done: function(color){
$('#color-select').val(color);
}
});
//开始时间
@ -98,13 +100,13 @@
,btns: ['clear', 'now']
,trigger: 'click'
});
//结束时间
//结束时间
laydate.render({
elem: '#over-time'
,btns: ['clear', 'now']
,trigger: 'click'
});
//上传图片
upload.render({
elem: '#layuiadmin-upload-slid-img'
@ -112,26 +114,17 @@
,data:{type:'image'}
,accept: 'images'
,acceptMime: 'image/*'
,auto: false
,choose: function (obj) { //选择文件后的回调
imgcom.uploads(obj);
}
,auto: false
,choose: function (obj) { //选择文件后的回调
imgcom.uploads(obj);
}
,done: function(res){
//console.log(res)
$(this.item).prev("div").children("input").val(res.src)
if(res.code == 0){
layer.msg(res.msg,{
icon:6,
tiye:2000
});
} else {
layer.open({
title:"上传失败",
content:res.msg,
icon:5,
anim:6
});
}
$(this.item).prev("div").children("input").val(res.src)
if(res.code == 0){
layer.msg(res.msg,{icon:6,tiye:2000});
} else {
layer.open({title:"上传失败",content:res.msg,icon:5,anim:6});
}
}
});
})

View File

@ -18,6 +18,8 @@
<option {if condition="$slider.slid_type eq 9"} selected {/if} value="9">9友情链接</option>
<option {if condition="$slider.slid_type eq 10"} selected {/if} value="10">10头部菜单</option>
<option {if condition="$slider.slid_type eq 11"} selected {/if} value="11">11页脚链接</option>
<option {if condition="$slider.slid_type eq 12"} selected {/if} value="12">12移动首页幻灯</option>
<option {if condition="$slider.slid_type eq 13"} selected {/if} value="13">13移动首页幻灯</option>
</select>
</div>
</div>

View File

@ -25,6 +25,8 @@
<option value="9">9友情链接</option>
<option value="10">10头部菜单</option>
<option value="11">11页脚链接</option>
<option value="12">12移动首页幻灯</option>
<option value="13">13首页右栏广告</option>
</select>
</div>
</div>
@ -67,13 +69,13 @@
,cols: [[ //表头
{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left'}
,{field: 'slid_type', title: '位置', width:120}
,{field: 'slid_img', title: '图片/icon', width:150, templet: '#imgTpl'}
,{field: 'slid_img', title: '图片/icon', width:120, templet: '#imgTpl'}
,{field: 'slid_name', title: '名称', width:180}
,{field: 'slid_href', title: 'URL', minWidth: 250}
,{field: 'slid_color', title: '颜色', width: 80}
,{field: 'slid_start', title: '开始', width: 150, sort: true}
,{field: 'slid_over', title: '结束', width: 150, sort: true}
,{field: 'slid_status', title: '状态', width: 135}
,{field: 'slid_status', title: '状态', width: 80}
,{fixed: 'right', title:'操作', toolbar: '#barDemo', width:150}
]]
,limit: 15

View File

@ -61,36 +61,32 @@
<table id="LAY-user-manage" lay-filter="LAY-user-manage"></table>
<script type="text/html" id="imgTpl">
<img style="display: inline-block; width: 50%; height: 100%;" src= {{ d.avatar }}>
<img style="width: 25px; height: 25px;" src= {{ d.avatar }}>
</script>
<script type="text/html" id="sex">
{{# if(d.sex == 0){ }}
<button class="layui-btn layui-btn-normal layui-btn-xs" ></button>
{{# } else { }}
<button class="layui-btn layui-btn-danger layui-btn-xs"></button>
{{# } }}
<span class="layui-btn {{ d.sex == 0 ? 'layui-btn-normal' : 'layui-btn-danger' }} layui-btn-xs" >{{ d.sex == 0 ? '男' : '女' }}</span>
</script>
<script type="text/html" id="buttonCheck">
{{# if(d.id == '1'){ }}
<input type="checkbox" name="check" lay-skin="switch" disabled lay-text="通过|禁用" value="1" checked id="{{d.id}}">
{{# } else { }}
{if condition="checkRuleButton('user/check')"}<input type="checkbox" name="check" lay-skin="switch" lay-filter="usercheck" lay-text="通过|{{# if(d.check == -1){ }}禁止{{# } }} {{# if(d.check == 0){ }}待审{{# } }}" {{# if(d.check == 1){ }} checked {{# } }} id="{{d.id}}" >{else}<button class="layui-btn layui-btn-xs layui-btn-radius layui-btn-disabled">无权限</button>{/if}
{{# } }}
<script type="text/html" id="buttonCheck">
{{# if(d.id == '1'){ }}
<input type="checkbox" name="check" lay-skin="switch" disabled lay-text="通过|禁用" value="1" checked id="{{d.id}}">
{{# } else { }}
{if condition="checkRuleButton('user/check')"}<input type="checkbox" name="check" lay-skin="switch" lay-filter="usercheck" lay-text="通过|{{# if(d.check == -1){ }}禁止{{# } }} {{# if(d.check == 0){ }}待审{{# } }}" {{# if(d.check == 1){ }} checked {{# } }} id="{{d.id}}" >{else}<button class="layui-btn layui-btn-xs layui-btn-radius layui-btn-disabled">无权限</button>{/if}
{{# } }}
</script>
<script type="text/html" id="buttonAuth">
{{# if(d.id == '1'){ }}
<input type="checkbox" name="auth" lay-skin="primary" checked disabled >
{{# } else { }}
{if condition="checkRuleButton('user/auth')"}<input type="checkbox" name="auth" lay-skin="primary" lay-filter="auth" {{# if(d.auth ==1){ }}checked value="0"{{# } else { }}value="1"{{# } }} id="{{d.id}}" >{else}<button class="layui-btn layui-btn-xs layui-btn-disabled">无权限</button>{/if}
{{# } }}
<script type="text/html" id="buttonAuth">
{{# if(d.id == '1'){ }}
<input type="checkbox" name="auth" lay-skin="primary" checked disabled >
{{# } else { }}
{if condition="checkRuleButton('user/auth')"}<input type="checkbox" name="auth" lay-skin="primary" lay-filter="auth" {{# if(d.auth ==1){ }}checked value="0"{{# } else { }}value="1"{{# } }} id="{{d.id}}" >{else}<button class="layui-btn layui-btn-xs layui-btn-disabled">无权限</button>{/if}
{{# } }}
</script>
<script type="text/html" id="table-useradmin-webuser">
{if condition="checkRuleButton('user/useredit')"}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit" id={{ d.id }}><i class="layui-icon layui-icon-edit"></i>编辑</a>
{else /}<a class="layui-btn layui-btn-normal layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-edit"></i>编辑</a>{/if}
{if condition="checkRuleButton('user/delete')"}
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del" id={{ d.id }}><i class="layui-icon layui-icon-delete"></i>删除</a>
{else /}<a class="layui-btn layui-btn-danger layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-delete"></i>删除</a>{/if}
{if condition="checkRuleButton('user/useredit')"}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit" id={{ d.id }}><i class="layui-icon layui-icon-edit"></i></a>
{else /}<a class="layui-btn layui-btn-normal layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-edit"></i></a>{/if}
{if condition="checkRuleButton('user/delete')"}
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del" id={{ d.id }}><i class="layui-icon layui-icon-delete"></i></a>
{else /}<a class="layui-btn layui-btn-danger layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-delete"></i></a>{/if}
</script>
</div>
</div>

View File

@ -1,7 +1,6 @@
{extend name="public/base" /}
{block name="body"}
<div class="layui-form" lay-filter="layuiadmin-form-useradmin" id="layuiadmin-form-useradmin" style="padding: 20px 0 0 0;">
<div class="layui-form-item layui-hide">
<input type="text" name="id" class="layui-input" value="{$user.id}">
@ -50,9 +49,8 @@
base: '/static/admin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form', 'upload'], function(){
}).use(['index', 'upload'], function(){
var $ = layui.$
,form = layui.form
,upload = layui.upload ;
//上传头像
upload.render({
@ -64,19 +62,19 @@
,acceptMime: 'image/*'
,done: function(res){
$(this.item).prev("div").children("input").val(res.src);
if(res.code == 0){
layer.msg(res.msg,{
icon:6,
tiye:2000
});
} else {
layer.open({
title:"上传失败",
content:res.msg,
icon:5,
anim:6
});
}
if(res.code == 0){
layer.msg(res.msg,{
icon:6,
tiye:2000
});
} else {
layer.open({
title:"上传失败",
content:res.msg,
icon:5,
anim:6
});
}
}
});
})

View File

@ -1,7 +1,6 @@
{extend name="public/base" /}
{block name="body"}
<div class="layui-form" lay-filter="layuiadmin-form-useradmin" id="layuiadmin-form-useradmin" style="padding: 20px 30px 0 0;">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
@ -47,9 +46,8 @@
base: '/static/admin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form', 'upload'], function(){
}).use(['index', 'upload'], function(){
var $ = layui.$
,form = layui.form
,upload = layui.upload ;
//上传头像
upload.render({
@ -61,19 +59,19 @@
,acceptMime: 'image/*'
,done: function(res){
$(this.item).prev("div").children("input").val(res.src);
if(res.code == 0){
layer.msg(res.msg,{
icon:6,
tiye:2000
});
} else {
layer.open({
title:"上传失败",
content:res.msg,
icon:5,
anim:6
});
}
if(res.code == 0){
layer.msg(res.msg,{
icon:6,
tiye:2000
});
} else {
layer.open({
title:"上传失败",
content:res.msg,
icon:5,
anim:6
});
}
}
});
})

View File

@ -4,7 +4,6 @@ use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use think\facade\Request;
use think\facade\Db;
use think\facade\Cache;
use think\facade\Session;
use taoser\think\Auth;
@ -46,11 +45,13 @@ try {
$mail->send();
//echo 'Message has been sent';
return true;
//return true;
} catch (Exception $e) {
//echo 'Message could not be sent. Mailer Error: ', $mail->ErrorInfo;
return false;
//return false;
return $mail->ErrorInfo;
}
return 1;
}
//根据user area_id查询区域简称
@ -79,19 +80,28 @@ if(!function_exists('getUserImg'))
//根据文章分类ID查询分类名
function getCateName($ename)
{
return Db::name('cate')->where('ename',$ename)->cache(3600)->value('catename');
if($ename == 'all') {
return '全部分类';
} else {
return Db::name('cate')->where('ename',$ename)->cache(3600)->value('catename');
}
}
//根据文章分类ID查询分类描述
function getCateDesc($ename)
{
return Db::name('cate')->where('ename',$ename)->cache(3600)->value('desc');
if($ename == 'all') {
return '全部分类,为您展示全部分类信息';
} else {
return Db::name('cate')->where('ename',$ename)->cache(3600)->value('desc');
}
}
//过滤文章摘要
function getArtContent($content)
{
//过滤html标签
$content = strip_tags($content);
// 过滤音视频图片
$content = preg_replace('/(?:img|audio|video)(\(\S+\))?\[\S+\]/','',$content);
$content = preg_replace('/\s*/','',$content);
@ -257,3 +267,39 @@ function getSpaceNmu($level)
{
return str_repeat('---',$level);
}
//链接投放开关,有设置则打开
function showSlider($type)
{
$sliders = new \app\common\model\Slider();
$sliderArr = $sliders->getSliderList($type);
if(!empty($sliderArr)) {
return true;
} else {
return false;
}
}
//提取内容第一张图片
function getOnepic($str)
{
// <img src="http://img.com" />
/* $pattern = "/<[img|IMG].*?src=[\'|\"](.*?(?:[\.gif|\.jpg|\.png]))[\'|\"].*?[\/]?>/";
preg_match_all($pattern,$str,$matchContent);
if(isset($matchContent[1][0])){
$img = $matchContent[1][0];
}else{
$temp="./images/no-image.jpg";//在相应位置放置一张命名为no-image的jpg图片
}
*/
// img[/storage/1/article_pic/20220428/6c2647d24d5ca2c179e4a5b76990c00c.jpg]
$pattern = "/(?<=img\[)[^\]]*(?=\])/";
preg_match($pattern,$str,$matchContent);
if(isset($matchContent[0])){
$img = $matchContent[0];
}else{
return false;
}
return $img;
}

View File

@ -2,9 +2,9 @@
/*
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-05-12 16:02:40
* @LastEditTime: 2022-05-17 11:15:46
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @Description: 后台控制器设置
* @FilePath: \TaoLer\app\common\controller\AdminController.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
@ -15,10 +15,8 @@ namespace app\common\controller;
use think\facade\Session;
use think\facade\View;
use think\facade\Db;
use think\facade\Request;
use taoser\think\Auth;
use taoler\com\Files;
use think\facade\Lang;
/**
* 控制器基础类
@ -76,7 +74,7 @@ class AdminController extends \app\BaseController
protected function getMenus($type)
{
$menu = [];
$auth_rule_list = Db::name('auth_rule')->where('delete_time',0)->where(['status'=> 1])->where('type',$type)->order(['sort' => 'ASC', 'id' => 'ASC'])->select();
$auth_rule_list = Db::name('auth_rule')->where(['delete_time'=> 0, 'status'=> 1,'type'=> $type])->order(['sort' => 'ASC', 'id' => 'ASC'])->select();
//var_export($auth_rule_list);
foreach ($auth_rule_list as $value) {

View File

@ -1,13 +1,23 @@
<?php
/*
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-26 15:17:08
* @LastEditors: TaoLer
* @Description: 前端基础控制器设置
* @FilePath: \github\TaoLer\app\common\controller\BaseController.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
declare (strict_types = 1);
namespace app\common\controller;
use think\App;
use think\facade\Request;
use think\facade\View;
use think\facade\Db;
use think\facade\Session;
use think\facade\Cache;
use app\facade\Article;
use app\BaseController as BaseCtrl;
/**
@ -45,14 +55,6 @@ class BaseController extends BaseCtrl
$this->error('请登录','/index/user/login');
}
}
/* //判断密码找回是否已进行了邮件发送?
protected function isMailed()
{
if(Cache::get('repass') != 1){
$this->error('错误请求,请正确操作!','/index/user/forget');
}
}*/
// 显示导航
protected function showNav()
@ -80,25 +82,43 @@ class BaseController extends BaseCtrl
View::assign('user',$user);
return $user;
}
//热门标签
protected function getHotTag()
{
//热门标签
return Article::getHotTags();
//转换为字符串
// $tagStr = implode(",",$tags);
//转换为数组并去重
// return array_unique(explode(",",$tagStr));
}
//显示网站设置
//显示网站设置
protected function showSystem()
{
//1.查询分类表获取所有分类
$sysInfo = Db::name('system')->cache('system',3600)->find(1);
$sysInfo = $this->getSystem();
$slider = new \app\common\model\Slider();
//头部链接
$head_links = Cache::get('headlinks');
if(!$head_links){
$head_links = Db::name('slider')->where(['slid_status'=>1,'delete_time'=>0,'slid_type'=>10])->whereTime('slid_over','>=',time())->field('slid_name,slid_img,slid_href')->select();
Cache::set('headlinks',$head_links,3600);
}
$head_links = $slider->getSliderList(10);
//页脚链接
$foot_links = Cache::get('footlinks');
if(!$foot_links){
$foot_links = Db::name('slider')->where(['slid_status'=>1,'delete_time'=>0,'slid_type'=>11])->whereTime('slid_over','>=',time())->field('slid_name,slid_href')->select();
Cache::set('footlinks',$foot_links,3600);
}
View::assign(['sysInfo'=>$sysInfo,'headlinks'=>$head_links,'footlinks'=>$foot_links]);
$foot_links = $slider->getSliderList(11);
//友情链接
$friend_links = $slider->getSliderList(9);
//获取热门标签
$hotTag = $this->getHotTag();
$assign = [
'sysInfo' => $sysInfo,
'headlinks' => $head_links,
'footlinks' => $foot_links,
'flinks' => $friend_links,
'hotTag' => $hotTag,
'host' => Request::domain() . '/'
];
View::assign($assign);
return $sysInfo;
}

72
app/common/lib/QrCode.php Normal file
View File

@ -0,0 +1,72 @@
<?php
/*
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2022-05-27 20:57:43
* @LastEditTime: 2022-05-28 09:33:43
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\common\lib\QrCode.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
declare (strict_types = 1);
namespace app\common\lib;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh;
use Endroid\QrCode\Label\Alignment\LabelAlignmentCenter;
use Endroid\QrCode\Label\Font\NotoSans;
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin;
use Endroid\QrCode\Writer\PngWriter;
class QrCode
{
/**
* 生成二维码
*
* @param string $data
* @param string $labText
* @param string $logoPath
* @return string 返回图片src
*/
public function getQrcode(string $data, $labText = '', $logoPath = ''): string
{
//
if(empty($logoPath)) {
$result = Builder::create()
->writer(new PngWriter())
->writerOptions([])
->data($data)
->encoding(new Encoding('UTF-8'))
->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
->size(300)
->margin(10)
->roundBlockSizeMode(new RoundBlockSizeModeMargin())
->labelText($labText)
->labelFont(new NotoSans(20))
->labelAlignment(new LabelAlignmentCenter())
->build();
} else {
$result = Builder::create()
->writer(new PngWriter())
->writerOptions([])
->data($data)
->encoding(new Encoding('UTF-8'))
->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
->size(300)
->margin(10)
->roundBlockSizeMode(new RoundBlockSizeModeMargin())
->logoPath($logoPath)
->labelText($labText)
->labelFont(new NotoSans(20))
->labelAlignment(new LabelAlignmentCenter())
->build();
}
header('Content-Type: ' . $result->getMimeType());
//$result->getString();
$imgsrc = $result->getDataUri();
return $imgsrc;
}
}

View File

@ -15,7 +15,7 @@ class Uploads
/**
* 获取上传文件的mime和后缀
* 根据后台设置的文件类型,获取允许上传文件的mime和后缀
* @param string $fileType 上传文件的类型只能为视频video文件application图片image,文本text
* @param string $type 获取文件的mime还是文件后缀ext
* @return array
@ -57,28 +57,23 @@ class Uploads
return $arr;
}
//上传文件
/**
* 上传文件
* 1.可以指定目录若目录前有SYS_前缀会上传到public/sys系统目录不指定前缀会上传到public/storage/用户ID
* 2.命名规则 可定义文件名类型a.jpg,b.php或使用sha1,uniqid,md5函数
*
* @param string $fileName 文件名,form表单中的name
* @param string $dirName
* @param int $fileSize
* @param string $fileType
* @return \think\response\Json
*/
/**
* @param string $fileName 文件名,form表单中的name
* @param string $dirName 文件夹名,上传路径中的文件夹名称
* @param string $dirName 文件夹名,上传路径中的文件夹名称,sys_前缀存放在/public/sys系统目录
* @param int $fileSize 文件大小,上传限制大小
* @param string $fileType 文件类型只能为视频video文件application图片image,文本text
* @param string $rule 文件命名规则默认md5,uniqid,date,sha1
* @param string $rule 文件命名规则默认md5,uniqid,date,sha1为空则取文件上传名称或者自定义如a.jpg文件名
* @return \think\response\Json
*/
public function put(string $fileName, string $dirName, int $fileSize, string $fileType, string $rule = null)
{
$file = request()->file($fileName);
//halt($file->getOriginalName());
//$type = $file->getMime();
$fileExt = $this->getFileInfo($fileType,'ext');
$fileMime = $this->getFileInfo($fileType,'mime');
@ -90,22 +85,40 @@ class Uploads
} catch (ValidateException $e) {
return json(['status'=>-1,'msg'=>$e->getMessage()]);
}
$savename = \think\facade\Filesystem::disk('public')->putFile(session('user_id'). '/' .$dirName, $file, $rule);
$upload = Config::get('filesystem.disks.public.url');
// 解析存储位置
$isSys = stripos($dirName, 'SYS_');
if($isSys !== false) {
$disk = 'sys';
$dirName = substr($dirName,4);
$uploadDir = Config::get('filesystem.disks.sys.url');
} else {
$disk = 'public';
$dirName = session('user_id'). '/' .$dirName;
$uploadDir = Config::get('filesystem.disks.public.url');
}
$rules = ['md5','date','sha1','uniqid'];
// 解析是否自定义文件名
if(!in_array($rule, $rules) && !is_null($rule)) {
if(stripos($rule, '.') == false) {
$rule = $file->getOriginalName();
}
$savename = \think\facade\Filesystem::disk($disk)->putFileAs($dirName, $file, $rule);
} else {
$savename = \think\facade\Filesystem::disk($disk)->putFile($dirName, $file, $rule);
}
if($savename){
//$name = $file->hashName();
$name_path =str_replace('\\',"/",$upload.'/'.$savename);
//halt($name_path);
$name_path =str_replace('\\',"/", $uploadDir . '/' . $savename);
//$image = \think\Image::open("uploads/$name_path");
//$image->thumb(168, 168)->save("uploads/$name_path");
$res = ['status'=>0,'msg'=>'上传成功','url'=> $name_path];
$res = ['status'=>0,'msg'=>'上传成功','url'=> $name_path, 'location'=>$name_path];
}else{
$res = ['status'=>-1,'msg'=>'上传错误'];
}
return json($res);
return json($res);
}
}

View File

@ -7,7 +7,7 @@ use think\Model;
use think\model\concern\SoftDelete;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Db;
use Overtrue\Pinyin\Pinyin;
class Article extends Model
{
@ -44,6 +44,12 @@ class Article extends Model
{
return $this->hasMany(Collection::class);
}
//文章关联用户点赞
public function userzan()
{
return $this->hasMany(UserZan::class);
}
//文章关联用户
public function user()
@ -58,12 +64,13 @@ class Article extends Model
*/
public function add(array $data)
{
$superAdmin = Db::name('user')->where('id',$data['user_id'])->value('auth');
$superAdmin = User::where('id',$data['user_id'])->value('auth');
// 超级管理员无需审核
$data['status'] = $superAdmin ? 1 : Config::get('taoler.config.posts_check');
$msg = $data['status'] ? '发布成功' : '发布成功,请等待审核';
$result = $this->save($data);
if($result) {
return ['code'=>1,'msg'=>$msg];
return ['code' => 1, 'msg' => $msg, 'data' => ['status' => $data['status']]];
} else {
return 'add_error';
}
@ -79,7 +86,7 @@ class Article extends Model
*/
public function edit(array $data)
{
$article = $this->find($data['id']);
$article = $this::find($data['id']);
$result = $article->save($data);
if($result) {
return 1;
@ -107,7 +114,12 @@ class Article extends Model
'user' => function ($query) {
$query->field('id,name,nickname,user_img,area_id,vip');
}
])->withCount(['comments'])->order('create_time', 'desc')->limit($num)->select()->toArray();
])->withCount(['comments'])
->order('create_time', 'desc')
->limit($num)
->append(['url'])
->select()
->toArray();
Cache::tag('tagArtDetail')->set('arttop', $artTop, 60);
}
@ -134,7 +146,14 @@ class Article extends Model
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
} ])
->withCount(['comments'])->where(['status'=>1,'is_top'=>0])->order('create_time','desc')->limit($num)->select()->toArray();
->withCount(['comments'])
->where(['status'=>1,'is_top'=>0])
->order('create_time','desc')
->limit($num)
->append(['url'])
->select()
->toArray();
Cache::tag('tagArt')->set('artlist',$artList,60);
}
return $artList;
@ -150,13 +169,19 @@ class Article extends Model
*/
public function getArtHot(int $num)
{
$artHot = $this::field('id,title')
$artHot = $this::field('id,cate_id,title,create_time')
->with([ 'cate' => function($query){
$query->where('delete_time',0)->field('id,ename');
}])
->withCount('comments')
->where(['status'=>1,'delete_time'=>0])
->whereTime('create_time', 'year')
->order('comments_count','desc')
->limit($num)
->withCache(60)->select();
->withCache(120)
->append(['url'])
->select();
return $artHot;
}
@ -168,19 +193,23 @@ class Article extends Model
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getArtDetail(int $id, int $page)
public function getArtDetail(int $id)
{
$article = Cache::get('article_'.$id);
if(!$article){
//查询文章
$article = $this::field('id,title,content,status,cate_id,user_id,is_top,is_hot,is_reply,pv,jie,upzip,downloads,tags,description,title_color,create_time')->where('status',1)->with([
$article = $this::field('id,title,content,status,cate_id,user_id,goods_detail_id,is_top,is_hot,is_reply,pv,jie,upzip,downloads,tags,description,title_color,create_time,update_time')->where('status',1)->with([
'cate' => function($query){
$query->where('delete_time',0)->field('id,catename,ename');
},
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
$query->field('id,name,nickname,user_img,area_id,vip,city')->withCount(['article','comments']);
}
])->withCount(['comments'])->find($id)->toArray();
])
->withCount(['comments'])
->append(['url'])
->find($id)
->toArray();
Cache::tag('tagArtDetail')->set('article_'.$id, $article, 3600);
}
return $article;
@ -212,84 +241,143 @@ class Article extends Model
switch ($type) {
//查询文章,15个分1页
case 'jie':
$artList = $this::field('id,title,content,title_color,cate_id,user_id,create_time,is_top,is_hot,pv,jie,upzip,has_img,has_video,has_audio')->with([
'cate' => function($query){
$query->where('delete_time',0)->field('id,catename,ename');
},
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
}
])->withCount(['comments'])->where(['status'=>1,'jie'=>1])->where($where)->order(['is_top'=>'desc','create_time'=>'desc'])
->paginate([
'list_rows' => 15,
'page' => $page
])->toArray();
$where['jie'] = 1;
break;
case 'hot':
$artList = $this::field('id,title,content,title_color,cate_id,user_id,create_time,is_top,is_hot,pv,jie,upzip,has_img,has_video,has_audio')->with([
'cate' => function($query){
$query->where('delete_time',0)->field('id,catename,ename');
},
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
}
])->withCount(['comments'])->where('status',1)->where($where)->where('is_hot',1)->order(['is_top'=>'desc','create_time'=>'desc'])
->paginate([
'list_rows' => 15,
'page' => $page
])->toArray();
$where['is_hot'] = 1;
break;
case 'top':
$artList = $this::field('id,title,content,title_color,cate_id,user_id,create_time,is_top,is_hot,pv,jie,upzip,has_img,has_video,has_audio')->with([
'cate' => function($query){
$query->where('delete_time',0)->field('id,catename,ename');
},
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
}
])->withCount(['comments'])->where('status',1)->where($where)->where('is_top',1)->order(['is_top'=>'desc','create_time'=>'desc'])
->paginate([
'list_rows' => 15,
'page' => $page
])->toArray();
$where['is_top'] = 1;
break;
case 'wait':
$artList = $this::field('id,title,content,title_color,cate_id,user_id,create_time,is_top,is_hot,pv,jie,upzip,has_img,has_video,has_audio')->with([
'cate' => function($query){
$query->where('delete_time',0)->field('id,catename,ename');
},
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
}
])->withCount(['comments'])->where('status',1)->where($where)->where('jie',0)->order(['is_top'=>'desc','create_time'=>'desc'])
->paginate([
'list_rows' => 15,
'page' => $page
])->toArray();
$where['jie'] = 0;
break;
default:
$artList = $this::field('id,title,content,title_color,cate_id,user_id,create_time,is_top,is_hot,pv,jie,upzip,has_img,has_video,has_audio')->with([
'cate' => function($query){
$query->where('delete_time',0)->field('id,catename,ename');
},
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
}
])->withCount(['comments'])->where('status',1)->where($where)->order(['is_top'=>'desc','create_time'=>'desc'])
->paginate([
'list_rows' => 15,
'page' => $page
])->toArray();
$where = $where;
break;
}
$artList = $this::field('id,title,content,title_color,cate_id,user_id,create_time,is_top,is_hot,pv,jie,upzip,has_img,has_video,has_audio')
->with([
'cate' => function($query){
$query->where('delete_time',0)->field('id,catename,ename');
},
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
}
])->withCount(['comments'])
->where('status',1)
->where($where)
->order(['is_top'=>'desc','create_time'=>'desc'])
->paginate([
'list_rows' => 15,
'page' => $page
])->append(['url'])->toArray();
Cache::tag('tagArtDetail')->set('arts'.$ename.$type.$page,$artList,600);
}
return $artList;
}
// 获取用户发帖列表
public function getUserArtList(int $id) {
$userArtList = $this::field('id,cate_id,title,create_time,pv,is_hot')
->with(['cate' => function($query){
$query->where(['delete_time'=>0,'status'=>1])->field('id,ename');
}])
->where(['user_id' => $id,'status' => 1])
->order(['create_time'=>'desc'])
->append(['url'])
->cache(3600)
->select()
->toArray();
return $userArtList;
}
// 获取搜索文章
public function getSearchKeyWord(string $keywords)
{
//全局查询条件
$map = []; //所有的查询条件封装到数组中
//条件1
$map[] = ['status','=',1]; //这里等号不能省略
if(!empty($keywords)){
//条件2
$map[] = ['title','like','%'.$keywords.'%'];
$res = Article::where($map)
->withCount('comments')
->order('create_time','desc')
->append(['url'])
->paginate(10);
return $res;
}
}
// 热门标签
public function getHotTags()
{
$pinyin = new Pinyin();
$tags = $this->where(['status'=>1])->where('tags','<>','')->order('pv desc')->limit(100)->column('tags');
//转换为字符串
$tagStr = implode(",",$tags);
//转换为数组并去重
$tagArr = array_unique(explode(",",$tagStr));
$tagHot = [];
foreach($tagArr as $v) {
$tagHot[] = ['tag'=>$v,'url'=> (string) url('tag_list',['tag'=>$pinyin->permalink($v,'')])];
}
return $tagHot;
}
// 查询包含tag标签的文章
public function getAllTags($tag)
{
$pinyin = new Pinyin();
$allTags = $this->field('id,title,is_hot,tags,cate_id,user_id,create_time,pv')->where(['status'=>1])->where('tags','<>','')
->with([
'cate' => function($query){
$query->where('delete_time',0)->field('id,catename,ename');
},
'user' => function($query){
$query->field('id,name,nickname,user_img,area_id,vip');
}
])->withCount(['comments'])
->order('pv desc')->limit(100)->append(['url'])->select()->toArray();
//halt($tags);
$artTag = [];
foreach($allTags as $v) {
if(stripos($v['tags'],',') !== false){
$tagArr = explode(",",$v['tags']);
foreach($tagArr as $s) {
$tagPinyin = $pinyin->permalink($s,'');
if(stripos($tagPinyin, $tag) !== false) {
$artTag[] = $v;
}
}
} else {
$tagPinyin = $pinyin->permalink($v['tags'],'');
if(stripos($tagPinyin, $tag) !== false) {
$artTag[] = $v;
}
}
}
return $artTag;
}
// 获取url
public function getUrlAttr($value,$data)
{
if(config('taoler.url_rewrite.article_as') == '<ename>/') {
$cate = Cate::field('id,ename')->find($data['cate_id']);
return (string) url('article_detail',['id' => $data['id'],'ename' => $cate->ename]);
} else {
return (string) url('article_detail',['id' => $data['id']]);
}
}
}

View File

@ -1,4 +1,13 @@
<?php
/*
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-27 21:42:34
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \github\TaoLer\app\common\model\Comment.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\common\model;
use think\Model;
@ -31,37 +40,82 @@ class Comment extends Model
//获取评论
public function getComment($id, $page)
{
$comments = $this::with(['user'])->where(['article_id'=>$id,'status'=>1])->order(['cai'=>'asc','create_time'=>'asc'])->paginate(['list_rows'=>10, 'page'=>$page]);
$comments = $this::with(['user'])->where(['article_id'=>(int)$id,'status'=>1])->order(['cai'=>'asc','create_time'=>'asc'])->paginate(['list_rows'=>10, 'page'=>$page]);
return $comments;
}
//回帖榜
public function reply($num)
{
$res = Cache::get('reply');
if(!$res){
$user = User::withCount('comments')->order(['comments_count'=>'desc','last_login_time'=>'desc'])->limit($num)->select()->toArray();
if($user)
{
$res['status'] = 0;
$res['data'] = array();
foreach ($user as $key=>$v) {
$u['uid'] = (string) url('user/home',['id'=>$v['id']]);
$u['count(*)'] = $v['comments_count'];
if($v['nickname'])
{
$u['user'] = ['username'=>$v['nickname'],'avatar'=>$v['user_img']];
} else {
$u['user'] = ['username'=>$v['name'],'avatar'=>$v['user_img']];
}
$res['data'][] = $u;
}
// $user = Cache::get('user_reply');
// if(empty($user)){
try {
$user = User::field('id,user_img,name,nickname')
->withCount(['comments'=> function($query) {
$query->where(['status'=>1]);
}])
->order(['comments_count'=>'desc','last_login_time'=>'desc'])
->limit($num)
->select()
->toArray();
} catch(\Exception $e) {
return json(['status'=>-1,'msg'=>$e->getMessage()]);
}
Cache::set('reply',$res,3600);
}
// Cache::set('user_reply',$user,180);
// }
if(count($user)) {
$res['status'] = 0;
$res['data'] = array();
foreach ($user as $key=>$v) {
//$u['uid'] = (string) url('user/home',['id'=>$v['id']]);
$u['uid'] = (string) \think\facade\Route::buildUrl('user_home', ['id' => $v['id']]);
$u['count'] = $v['comments_count'];
if($v['nickname'])
{
$u['user'] = ['username'=>$v['nickname'],'avatar'=>$v['user_img']];
} else {
$u['user'] = ['username'=>$v['name'],'avatar'=>$v['user_img']];
}
$res['data'][] = $u;
}
} else {
$res = ['status' => 0, 'msg' =>'no reply'];
}
return json($res);
}
/**
* 获取用户评论列表
*
* @param integer $id
* @return void
*/
public function getUserCommentList(int $id) {
$userCommList = $this::field('id,user_id,create_time,delete_time,article_id,content')
->with(['article' => function(\think\model\Relation $query){
$query->withField('id,title,cate_id,delete_time')->where(['status' => 1,'delete_time' => 0]);
}])
->where(['user_id' => $id,'status' => 1,'delete_time'=>0])
//->append(['url'])
->order(['create_time' => 'desc'])
//->cache(3600)
->select()
->toArray();
return $userCommList;
}
// 获取url
public function getUrlAttr($value,$data)
{
if(config('taoler.url_rewrite.article_as') == '<ename>/') {
$cate = Cate::field('id,ename')->find($data['article']['cate_id']);
return (string) url('detail',['id' => $data['id'],'ename'=>$cate->ename]);
} else {
return (string) url('detail',['id' => $data['id']]);
}
}
}

View File

@ -1,4 +1,13 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-27 21:25:14
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \github\TaoLer\app\common\model\MessageTo.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\common\model;
use think\Model;
@ -22,5 +31,14 @@ class MessageTo extends Model
return $this->belongsTo('Message','message_id','id');
}
//得到消息数
public function getMsgNum($id)
{
$msg = $this::field('id')->where(['receve_id'=>$id,'is_read'=>0])->column('id');
if(!is_null($msg)) {
return count($msg);
}
}
}

View File

@ -1,10 +1,10 @@
<?php
/*
* @Author: TaoLer <alipey_tao@qq.com>
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-05-01 17:10:55
* @LastEditTime: 2022-06-28 13:54:55
* @LastEditors: TaoLer
* @Description: 链接投放优化设置
* @Description: 链接设置
* @FilePath: \TaoLer\app\common\model\Slider.php
* Copyright (c) 2020~2022 http://www.aieok.com All rights reserved.
*/
@ -44,41 +44,41 @@ class Slider extends Model
$sliders = Cache::get('slider'.$type);
if(!$sliders){
$sliders = $this::where(['slid_status'=>1,'delete_time'=>0,'slid_type'=>$type])->whereTime('slid_over','>=',time())->select()->toArray();
Cache::tag('tagSlider')->set('slider'.$type,$sliders,3600);
Cache::tag('tagSlider'.$type)->set('slider'.$type,$sliders,3600);
}
return $sliders;
}
//添加
// 添加
public function add($data)
{
$result = $this::save($data);
$result = $this::create($data);
if($result) {
Cache::tag('tagSlider')->clear();
Cache::tag('tagSlider'.$data['slid_type'])->clear();
return 1;
} else {
return 'add_error';
}
}
//文章编辑
// 文章编辑
public function edit($data)
{
$slider = $this::find($data['id']);
$result = $slider->save($data);
if($result) {
Cache::tag('tagSlider')->clear();
Cache::tag('tagSlider'.$data['slid_type'])->clear();
return 1;
} else {
return 'edit_error';
}
}
//获取器
// 获取器
public function getSlidTypeAttr($value)
{
$slid_type = [1=>'首页幻灯',2=>'首页图片',3=>'分类图片',4=>'详情图片',5=>'首页赞助',6=>'分类赞助',7=>'详情赞助',8=>'温馨通道',9=>'友情链接',10=>'头部菜单',11=>'页脚链接'];
$slid_type = [1=>'首页幻灯',2=>'首页图片',3=>'分类图片',4=>'详情图片',5=>'首页赞助',6=>'分类赞助',7=>'详情赞助',8=>'温馨通道',9=>'友情链接',10=>'头部菜单',11=>'页脚链接',12=>'移动首页幻灯',13=>'首页右栏广告'];
return $slid_type[$value];
}

View File

@ -18,7 +18,7 @@ class UpgradeAuth extends Model
public function getAuthLevelAttr($value)
{
$level = [0=>'免费版',1=>'初级版',2=>'高级版'];
$level = [0=>'免费版', 1=>'初级版', 2=>'中级版', 3=>'高级版'];
return $level[$value];
}

View File

@ -40,6 +40,11 @@ class User extends Model
{
return $this->belongsTo('UserArea','user_raea_id','id');
}
public function article()
{
return $this->hasMany(Article::class);
}
//登陆校验
public function login($data)

View File

@ -1,4 +1,13 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-18 18:32:40
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \TaoLer\app\common\model\UserZan.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\common\model;
use think\Model;
@ -26,5 +35,11 @@ class UserZan extends Model
//评论关联用户
return $this->belongsTo('User','user_id','id');
}
public function article()
{
//评论关联用户
return $this->belongsTo(Article::class);
}
}

View File

@ -0,0 +1,115 @@
<?php
/*
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2022-05-17 13:08:11
* @LastEditTime: 2022-07-23 09:39:52
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\common\taglib\Article.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
//declare (strict_types = 1);
namespace app\common\taglib;
use think\template\TagLib;
use app\common\model\Article as ArticleModel;
class Article extends TagLib
{
//
protected $tags = [
// 标签定义: attr 属性列表 close 是否闭合0 或者1 默认1 alias 标签别名 level 嵌套层次
'id' => ['attr' => '', 'close' => 0],
'title' => ['attr' => 'cid', 'close' => 0],
'content' => ['attr' => 'name', 'close' => 0],
'istop' => ['attr' => '', 'close' => 0],
'aname' => ['attr' => 'name', 'close' => 0],
'commentnum' => ['attr' => 'name', 'close' => 0],
'comment' => ['attr' => '', 'close' => 1],
];
// public function __construct($a)
// {
// $id = (int) input('id');
// $this->id = $id;
// $page = input('page') ? (int) input('page') : 1;
// //parent::__construct();
// if(request()->action() == 'detail') {
// $article = new ArticleModel();
// $this->article = $article->getArtDetail($id);
// // dump($this->article);
// }
// }
public function tagId($tag): string
{
//dump($tag);
$parseStr = $this->article;
//return $parseStr;
return '<?php echo "' . $parseStr['id'] . '"; ?>';
}
public function tagTitle(array $tag, string $content): string
{
$cid = (int) $this->tpl->get('cid');
$article = new ArticleModel();
$art = $article->getArtDetail($cid);
//dump($art);
$parseStr = $art['title'];
//$parseStr = 123;
//return $parseStr;
return '<?php echo "' . $parseStr . '"; ?>';
}
public function tagContent($tag): string
{
$parseStr = $this->article['content'];
//return $parseStr;
return '<?php echo "' . $parseStr . '"; ?>';
}
public function tagAname($tag): string
{
$parseStr = $this->article['user']['nickname'] ?: $this->article['user']['name'];
// dump($parseStr);
return $parseStr;
}
public function tagCommentnum($tag): string
{
$parseStr = $this->article['comments_count'];
// dump($parseStr);
return $parseStr;
}
public function tagIstop($tag): string
{
//dump($this->article);
$parseStr = '{if($article.is_top == 0)}';
$parseStr .= '<span class="layui-btn layui-btn-xs jie-admin" type="set" field="top" rank="1" style="background-color: #ccc" title="置顶">顶</span>';
$parseStr .= '{else /}';
$parseStr .= '<span class="layui-btn layui-btn-xs jie-admin" type="set" field="top" rank="0" title="取消置顶">顶</span>';
$parseStr .= '{/if}';
return $parseStr;
}
// public function tagComment($tag, $content): string
// {
// //
// //$arr = $this->getComments($this->id, $this->page);
// $parse = '<?php ';
// $parse .= '$comment_arr=[[1,3,5,7,9],[2,4,6,8,10]];'; // 这里是模拟数据
// $parse .= '$__LIST__ = $comment_arr[' . $type . '];';
/** $parse .= ' ?>';*/
// $parse .= '{volist name="__LIST__" id="' . $name . '"}';
// $parse .= $content;
// $parse .= '{/volist}';
// return $parse;
// }
}

View File

@ -1,4 +1,13 @@
<?php
/*
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-06-22 16:19:38
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\common\validate\User.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\common\validate;
use think\Validate;
@ -42,7 +51,7 @@ class User extends Validate
//注册验证场景
public function sceneReg()
{
return $this->only(['name','email','password','repassword','captcha']);
return $this->only(['name','email','password','repassword']);
}

43
app/index/config/view.php Normal file
View File

@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
use think\facade\Db;
//如果网站安装从数据库查询选择的模板
if(file_exists('./install.lock')){
$template = Db::name('system')->where('id',1)->value('template');
} else {
$template = '';
}
return [
// 模板引擎类型使用Think
'type' => 'Think',
// 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
'auto_rule' => 1,
// 模板目录名
'view_dir_name' => 'view' . DIRECTORY_SEPARATOR . $template,
// 模板后缀
'view_suffix' => 'html',
// 预先加载的标签库
'taglib_pre_load' => 'app\common\taglib\Article',
// 模板文件名分隔符
'view_depr' => DIRECTORY_SEPARATOR,
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '{',
// 标签库标签结束标记
'taglib_end' => '}',
'default_filter' => 'htmlspecialchars',
//模板输出替换
// 'tpl_replace_string' => [
// '__STATIC__'=>'/static/layui',
// '__JS__' => '/static/res/',
// ],
];

View File

@ -1,4 +1,5 @@
<?php
namespace app\index\controller;
use app\common\controller\BaseController;
@ -10,11 +11,13 @@ use think\facade\Config;
use app\common\model\Comment;
use app\common\model\Article as ArticleModel;
use app\common\model\Slider;
use think\exception\ValidateException;
use app\common\model\UserZan;
use taoler\com\Message;
use app\common\lib\Msgres;
use app\common\lib\Uploads;
use taoser\SetArr;
use taoler\com\Api;
use Overtrue\Pinyin\Pinyin;
class Article extends BaseController
{
@ -43,7 +46,6 @@ class Article extends BaseController
//分类列表
$article = new ArticleModel();
$artList = $article->getCateList($ename,$type,$page);
// 热议文章
$artHot = $article->getArtHot(10);
//广告
@ -52,7 +54,7 @@ class Article extends BaseController
$ad_cateImg = $ad->getSliderList(3);
//分类钻展赞助
$ad_comm = $ad->getSliderList(6);
View::assign(['type'=>$type,'artList'=>$artList,'artHot'=>$artHot,'ad_cateImg'=>$ad_cateImg,'ad_comm'=>$ad_comm,'jspage'=>'jie','ename'=>$ename,'path'=>$path]);
return View::fetch('article/'.$tpl.'/cate');
}
@ -70,20 +72,55 @@ class Article extends BaseController
//输出内容
$page = input('page') ? input('page') : 1;
$article = new ArticleModel();
$artDetail = $article->getArtDetail($id,$page);
// 设置tag内链
$artDetail = $article->getArtDetail($id);
//用户个人tag标签
$userTags = $article->where(['user_id'=>$artDetail['user_id'],'status'=>1])->where('tags','<>','')->column('tags');
//转换为字符串
$tagStr = implode(",",$userTags);
//转换为数组并去重
$tagArr = array_unique(explode(",",$tagStr));
$userTagCount = count($tagArr);
//赞列表
$userZanList = [];
$userZan = UserZan::where(['article_id'=>$id,'type'=>1])->select();
foreach($userZan as $v){
$userZanList[] = ['userImg'=>$v->user->user_img,'name'=>$v->user->name];
}
// 设置内容的tag内链
$artDetail['content'] = $this->setArtTagLink($artDetail['content']);
// tag
$attr = explode(',', $artDetail['tags']);
$tags = [];
foreach($attr as $v){
if ($v !='') {
$tags[] = $v;
}
// $tags = [];
// if(!is_null($artDetail['tags'])){
// $attr = explode(',', $artDetail['tags']);
// foreach($attr as $v){
// if ($v !='') {
// $tags[] = $v;
// }
// }
// } else {
// $tags[] = $artDetail['title'];
// }
// $tag = new Tag();
// $tags = $tag->getArtTag($artDetail['tags']);
$pinyin = new Pinyin();
$tags = [];
if(!is_null($artDetail['tags'])){
$attr = explode(',', $artDetail['tags']);
foreach($attr as $v){
if ($v !='') {
$tags[] = ['tag'=>$v,'pinyin'=>$pinyin->permalink($v,''), 'url'=> (string) url('tag_list',['tag'=>$pinyin->permalink($v,'')])];
}
}
}
$arId = $artDetail['cate_id'];
$tpl = Db::name('cate')->where('id',$arId)->value('detpl');
$tpl = Db::name('cate')->where('id', $artDetail['cate_id'])->value('detpl');
$download = $artDetail['upzip'] ? download($artDetail['upzip'],'file') : '';
//$count = $comments->total();
@ -95,7 +132,8 @@ class Article extends BaseController
//评论
$comments = $this->getComments($id, $page);
//最新评论时间
$lrDate_time = Db::name('comment')->where('article_id', $id)->max('update_time',false) ?? time();
// 热议文章
$artHot = $article->getArtHot(10);
//广告
@ -104,6 +142,7 @@ class Article extends BaseController
$ad_artImg = $ad->getSliderList(4);
//分类钻展赞助
$ad_comm = $ad->getSliderList(7);
//push
$push_js = Db::name('push_jscode')->where(['delete_time'=>0])->cache(true)->select();
View::assign([
@ -115,11 +154,15 @@ class Article extends BaseController
'tags' => $tags,
'page' => $page,
'comments' => $comments,
'jspage' => 'jie',
'push_js' => $push_js,
'cid' => $id,
'lrDate_time' => $lrDate_time,
'userZanList' => $userZanList,
'userTagCount'=> $userTagCount,
'jspage' => 'jie',
$download,
]);
return View::fetch('article/'.$tpl.'/detail');
}
@ -133,16 +176,20 @@ class Article extends BaseController
//文章评论
public function comment()
{
// 检验发帖是否开放
if(config('taoler.config.is_reply') == 0 ) return json(['code'=>-1,'msg'=>'抱歉,系统维护中,暂时禁止评论!']);
if (Request::isAjax()){
//获取评论
$data = Request::only(['content','article_id','user_id']);
$sendId = $data['user_id'];
$art = Db::name('article')->field('id,status,is_reply,delete_time')->find($data['article_id']);
if($art['delete_time'] != 0 || $art['status'] != 1 || $art['is_reply'] != 1){
return json(['code'=>-1, 'msg'=>'评论不可用状态']);
}
if(empty($data['content'])){
return json(['code'=>0, 'msg'=>'评论不能为空!']);
return json(['code'=>-1, 'msg'=>'评论不能为空!']);
}
$superAdmin = Db::name('user')->where('id',$sendId)->value('auth');
$data['status'] = $superAdmin ? 1 : Config::get('taoler.config.commnets_check');
@ -151,9 +198,12 @@ class Article extends BaseController
//用户留言存入数据库
if (Comment::create($data)) {
//站内信
$article = Db::name('article')->field('id,title,user_id')->where('id',$data['article_id'])->find();
$article = Db::name('article')->field('id,title,user_id,cate_id')->where('id',$data['article_id'])->find();
// 获取分类ename
$cate_ename = Db::name('cate')->where('id',$article['cate_id'])->value('ename');
$title = $article['title'];
$link = (string) url('article/detail',['id'=>$data['article_id']]);
//$link = (string) url('article_detail',['id'=>$data['article_id']]);
$link = $this->getRouteUrl($data['article_id'], $cate_ename);
//评论中回复@user comment
$preg = "/@([^@\s]*)\s/";
@ -180,9 +230,12 @@ class Article extends BaseController
*/
public function add()
{
//dump(empty(config('taoler.baidu.client_id')));
if (Request::isAjax()) {
$data = Request::only(['cate_id', 'title', 'title_color', 'user_id', 'content', 'upzip', 'tags', 'description', 'captcha']);
// 检验发帖是否开放
if(config('taoler.config.is_post') == 0 ) return json(['code'=>-1,'msg'=>'抱歉,系统维护中,暂时禁止发帖!']);
$data = Request::only(['cate_id', 'title', 'title_color', 'user_id', 'tiny_content', 'content', 'upzip', 'tags', 'description', 'captcha']);
// 验证码
if(Config::get('taoler.config.post_captcha') == 1)
{
@ -201,6 +254,8 @@ class Article extends BaseController
// 获取内容图片音视频标识
$iva= $this->hasIva($data['content']);
$data = array_merge($data,$iva);
// 获取分类ename
$cate_ename = Db::name('cate')->where('id',$data['cate_id'])->value('ename');
$article = new ArticleModel();
$result = $article->add($data);
@ -211,25 +266,28 @@ class Article extends BaseController
Cache::tag('tagArtDetail')->clear();
// 发提醒邮件
if(Config::get('taoler.config.email_notice')) mailto($this->showUser(1)['email'],'发帖审核通知','Hi亲爱的管理员:</br>用户'.$this->showUser($this->uid)['name'].'刚刚发表了 <b>'.$data['title'].'</b> 新的帖子,请尽快处理。');
if(Config::get('taoler.config.posts_check')){
$link = (string)url('article/detail', ['id' => $aid]);
}else{
$link = (string)url('index/');
}
// 推送给百度收录接口
if(empty(config('taoler.baidu.push_api'))) {
$this->baiduPush($aid);
}
$res = Msgres::success($result['msg'], $link);
$link = $this->getRouteUrl((int)$aid, $cate_ename);
// 推送给百度收录接口
$this->baiduPush($link);
$url = $result['data']['status'] ? $link : (string)url('index/');
$res = Msgres::success($result['msg'], $url);
} else {
$res = Msgres::error('add_error');
}
return $res;
}
View::assign(['jspage'=>'jie']);
return View::fetch();
$tpl = Db::name('cate')->where('ename', input('cate'))->value('detpl');
$appName = $this->app->http->getName();
$viewRoot = root_path() . config('view.view_dir_name') . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR;
$view = 'article' . DIRECTORY_SEPARATOR . $tpl . DIRECTORY_SEPARATOR . 'add.html';
$vfile = $viewRoot . $view;
$addTpl = is_file($vfile) ? $vfile : 'add';
return View::fetch($addTpl);
}
/**
@ -268,11 +326,9 @@ class Article extends BaseController
if($result == 1) {
//删除原有缓存显示编辑后内容
Cache::delete('article_'.$id);
$link = (string) url('article/detail',['id'=> $id]);
$link = $this->getRouteUrl((int) $id, $article->cate->ename);
// 推送给百度收录接口
if(empty(config('taoler.baidu.push_api'))) {
$this->baiduPush($data['id']);
}
$this->baiduPush($link);
$editRes = Msgres::success('edit_success',$link);
} else {
$editRes = Msgres::error($result);
@ -282,16 +338,27 @@ class Article extends BaseController
}
// 查询标签
$tag = $article->tags;
$attr = explode(',',$tag);
$tags = [];
foreach($attr as $key => $v){
if ($v !='') {
$tags[] = $v;
}
if(!is_null($tag)) {
$attr = explode(',',$tag);
foreach($attr as $key => $v){
if ($v !='') {
$tags[] = $v;
}
}
}
View::assign(['article'=>$article,'tags'=>$tags,'jspage'=>'jie']);
return View::fetch();
// 编辑多模板支持
$tpl = Db::name('cate')->where('id', $article['cate_id'])->value('detpl');
$appName = $this->app->http->getName();
$viewRoot = root_path() . config('view.view_dir_name') . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR;
$view = 'article' . DIRECTORY_SEPARATOR . $tpl . DIRECTORY_SEPARATOR . 'edit.html';
$vfile = $viewRoot . $view;
$editTpl = is_file($vfile) ? $vfile : 'edit';
return View::fetch($editTpl);
}
/**
@ -368,6 +435,33 @@ class Article extends BaseController
return json(['code'=>0,'data'=>$description]);
}
/**
* 标题调用百度关键词词条
*
* @return void
*/
public function getWordList()
{
$title = input('title');
if(empty($title)) return json(['code'=>-1,'msg'=>'null']);
$url = 'https://www.baidu.com/sugrec?prod=pc&from=pc_web&wd='.$title;
//$result = Api::urlGet($url);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$datas = curl_exec($curl);
curl_close($curl);
$data = json_decode($datas,true);
if(isset($data['g'])) {
return json(['code'=>0,'msg'=>'success','data'=>$data['g']]);
} else {
return json(['code'=>-1,'msg'=>'null']);
}
}
/**
* 关键词
*
@ -415,9 +509,9 @@ class Article extends BaseController
} else {
// 接口正常但获取数据失败可能参数错误重新获取token
$url = 'https://aip.baidubce.com/oauth/2.0/token';
$post_data['grant_type'] = config('taoler.baidu.grant_type');;
$post_data['grant_type'] = config('taoler.baidu.grant_type');;
$post_data['client_id'] = config('taoler.baidu.client_id');
$post_data['client_secret'] = config('taoler.baidu.client_secret');
$post_data['client_secret'] = config('taoler.baidu.client_secret');
$o = "";
foreach ( $post_data as $k => $v )
@ -432,7 +526,8 @@ class Article extends BaseController
'access_token' => json_decode($res)->access_token,
]
]);
echo 'api接口数据错误,重新自动尝试链接';
echo 'api接口数据错误 - ';
echo $dataItem->error_msg;
}
}
}
@ -471,8 +566,9 @@ class Article extends BaseController
return $data;
}
//文章置顶,状态
public function jieset(){
// 文章置顶、加精、评论状态
public function jieset()
{
$data = Request::param();
$article = ArticleModel::field('id,is_top,is_hot,is_reply')->find($data['id']);
switch ($data['field']){
@ -482,22 +578,22 @@ class Article extends BaseController
$res = ['status'=>0,'msg'=>'置顶成功'];
} else {
$article->save(['is_top' => 0]);
$res = ['status'=>0,'msg'=>'已取消置顶'];
$res = ['status'=>0,'msg'=>'置顶已取消'];
}
break;
case 'hot':
if($data['rank']==1){
$article->save(['is_hot' => 1]);
$res = ['status'=>0,'msg'=>'已设精贴'];
$res = ['status'=>0,'msg'=>'加精成功'];
} else {
$article->save(['is_hot' => 0]);
$res = ['status'=>0,'msg'=>'已取消'];
$res = ['status'=>0,'msg'=>'精已取消'];
}
break;
case 'reply':
if($data['rank']==1){
$article->save(['is_reply' => 1]);
$res = ['status'=>0,'msg'=>'本帖禁评'];
$res = ['status'=>0,'msg'=>'禁评成功'];
} else {
$article->save(['is_reply' => 0]);
$res = ['status'=>0,'msg'=>'禁评已取消'];
@ -510,7 +606,7 @@ class Article extends BaseController
return json($res);
}
//改变标题颜色
// 改变标题颜色
public function titleColor()
{
$data = Request::param();
@ -555,33 +651,64 @@ class Article extends BaseController
foreach($tag as $key=>$value) {
// 匹配所有
//$content = str_replace("$key", 'a('.$value.')['.$key.']',$content);
// 限定匹配数量
$content = preg_replace('/'.$key.'/','a('.$value.')['.$key.']',$content,2);
// 限定匹配数量 '/'.$key.'/'
// 匹配不包含[和]的内容
$pats = '/(?<!\[)'.$key.'(?!\])/';
//preg_match($pats,$content,$arr);
//halt($arr[0]);
// 开启和关闭编辑器使用不同的链接方式
$rpes = hook('taonystatus') ? '<a href="'.$value.'" target="_blank" title="'.$key.'" style="font-weight: bold;color:#31BDEC">'.$key.'</a>' : 'a('.$value.')['.$key.']';
$content = preg_replace($pats,$rpes,$content,2);
}
}
return $content;
}
// baidu push api
protected function baiduPush($id)
/**
* baidu push api
*
* @param string $link
* @return void
*/
protected function baiduPush(string $link)
{
// baidu 接口
$api = config('taoler.baidu.push_api');
$artUrl = $this->getRouteUrl((int)$id);
$url = [$artUrl];
$ch = curl_init();
$options = array(
CURLOPT_URL => $api,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => implode("\n", $url),
CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
);
curl_setopt_array($ch, $options);
curl_exec($ch);
curl_close($ch);
if(!empty($api)) {
$url[] = $link;
$ch = curl_init();
$options = array(
CURLOPT_URL => $api,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => implode("\n", $url),
CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
);
curl_setopt_array($ch, $options);
curl_exec($ch);
curl_close($ch);
}
}
public function userZanArticle()
{
//
if(Request::isPost()) {
$data = Request::post();
$data['user_id'] = $this->uid;
$userZan = Db::name('user_zan')->where(['user_id'=>$this->uid,'article_id'=>$data['article_id']])->find();
if($userZan){
return json(['code'=> -1, 'msg'=>'您已赞过了哦']);
}
$res = Db::name('user_zan')->insert($data);
if($res) {
return json(['code'=> 0, 'msg'=>'点赞成功']);
}
}
}
}

View File

@ -1,8 +1,16 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-27 09:14:12
* @LastEditors: TaoLer
* @Description: 首页优化版
* @FilePath: \github\TaoLer\app\index\controller\Index.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\index\controller;
use app\common\controller\BaseController;
use think\App;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;
@ -25,21 +33,21 @@ class Index extends BaseController
$slider = new Slider();
//幻灯
$sliders = $slider->getSliderList(1);
$sliders = Request::isMobile() ? $slider->getSliderList(12) : $slider->getSliderList(1);
//置顶文章
$artTop = Article::getArtTop(5);
//首页文章列表,显示20个
$artList = Article::getArtList(22);
//热议文章
$artHot = Article::getArtHot(10);
//首页广告
$indexAd = $slider->getSliderList(13);
//温馨通道
$fast_links = $slider->getSliderList(8);
//首页赞助
$ad_index = $slider->getSliderList(5);
//首页右栏图片
$ad_comm = $slider->getSliderList(2);
//友情链接
$friend_links = $slider->getSliderList(9);
//友情链接申请
$adminEmail = Db::name('user')->where('id',1)->cache(true)->value('email');
@ -49,11 +57,11 @@ class Index extends BaseController
'artTop' => $artTop,
'artList' => $artList,
'artHot' => $artHot,
'ad_index_r'=> $indexAd,
'type' => $types,
'ad_index' => $ad_index,
'ad_comm' => $ad_comm,
'fastlinks' => $fast_links,
'flinks' => $friend_links,
'adminEmail' => $adminEmail,
'jspage' => '',
];
@ -69,34 +77,6 @@ class Index extends BaseController
return $comment->reply(20);
}
//搜索功能
public function search()
{
//$t = input('keywords');
//halt($t);
$ser = Request::only(['keywords']);
$search = new \app\index\controller\Search();
$artList = $search->getSearch($ser['keywords']);
$counts = $artList->count();
$slider = new Slider();
//首页右栏
$ad_comm = $slider->getSliderList(2);
// 查询热议
$artHot = Article::getArtHot(10);
$searchs = [
'artList' => $artList,
'keywords' => $ser['keywords'],
'counts' => $counts,
'ad_comm'=>$ad_comm,
'artHot'=>$artHot,
'jspage'=>''
];
View::assign($searchs);
return View::fetch('search');
}
public function jump()
{
$username = Request::param('username');

View File

@ -38,7 +38,8 @@ class Login extends BaseController
//获取登录前访问页面refer
$refer = Request::server('HTTP_REFERER');
if(Request::isAjax()) {
// 检验登录是否开放
if(config('taoler.config.is_login') == 0 ) return json(['code'=>-1,'msg'=>'抱歉,网站维护中,暂时不能登录哦!']);
//登陆前数据校验
$data = Request::param();
if(Config::get('taoler.config.login_captcha') == 1)
@ -94,8 +95,31 @@ class Login extends BaseController
//注册
public function reg()
{
if(Request::isAjax()){
$data = Request::only(['name','email','password','repassword','captcha']);
// 检验注册是否开放
if(config('taoler.config.is_regist') == 0 ) return json(['code'=>-1,'msg'=>'抱歉,注册暂时未开放']);
$data = Request::only(['name','email','email_code','password','repassword','captcha']);
if(Config::get('taoler.config.regist_type') == 1) {
//先校验验证码
if(!captcha_check($data['captcha'])){
// 验证失败
return json(['code'=>-1,'msg'=> '验证码失败']);
};
}
if(Config::get('taoler.config.regist_type') == 2) {
$emailCode = Cache::get($data['email']);
if($emailCode) {
if($data['email_code'] != $emailCode) {
// 验证失败
return json(['code' => -1,'msg' => '验证码不正确']);
}
} else {
return json(['code' => -1,'msg' => '验证码过期,请重试']);
}
}
//校验场景中reg的方法数据
try{
@ -203,12 +227,35 @@ class Login extends BaseController
$user = new User();
$res = $user->respass($data);
if ($res == 1) {
return json(['code'=>0,'msg'=>'修改成功','url'=>(string) url('login/index')]);
return json(['code'=> 0, 'msg'=> '修改成功', 'url'=>(string) url('login/index')]);
} else {
return json(['code'=>-1,'msg'=>'$res']);
return json(['code'=> -1, 'msg'=> '$res']);
}
}
return View::fetch('forget');
}
// 邮箱注册验证
public function sentMailCode()
{
if(Request::isAjax()) {
// 用户邮箱
$email = input('email');
//dump($email);
if(empty($email)) return json(['code'=>-1,'msg'=>'邮箱不能为空']);
$code = mt_rand('1111','9999');
Cache::set($email, $code, 600);
$result = mailto($email,'注册邮箱验证码','Hi亲爱的新用户:</br>您正在注册我们站点的新账户请在10分钟内验证您的验证码为:'.$code);
if($result == 1) {
$res = ['code' => 0, 'msg' => '验证码已发送成功,请去邮箱查看!'];
} else {
$res = ['code' => -1, 'msg' => $result];
}
return json($res);
}
}
}

View File

@ -1,4 +1,13 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-27 21:29:43
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \github\TaoLer\app\index\controller\Message.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\index\controller;
use app\common\controller\BaseController;
@ -14,13 +23,12 @@ class Message extends BaseController
//消息数目
public function nums()
{
$msg = Db::name('message_to')->where('receve_id',Session::get('user_id'))->where(['is_read'=>0,'delete_time'=>0])->select();
$count = $msg->count();
if($count){
$res=['status' =>0,'count' => $count, 'msg' => 'nums'];
$messgeto = new MessageTo();
$num = $messgeto->getMsgNum($this->uid);
if(!is_null($num)){
$res = ['status' =>0,'count' => $num, 'msg' => 'ok'];
} else {
$res=['status' =>0,'count' => 0, 'msg' => $count];
$res = ['status' =>-1,'count' => 0, 'msg' => 'message error'];
}
return json($res);
}
@ -28,8 +36,7 @@ class Message extends BaseController
//消息查询
public function find()
{
$uid = Session::get('user_id');
$msg = MessageApi::receveMsg($uid);
$msg = MessageApi::receveMsg($this->uid);
$count = $msg->count();
$res = [];
if($count){
@ -39,7 +46,7 @@ class Message extends BaseController
$res['rows'][] = $data;
}
} else {
$res = ['status'=>0,'msg'=>'','rows'=>''];;
$res = ['status'=>-1,'msg'=>'message find error','rows'=>''];;
}
//var_dump($res);
return json($res);
@ -62,7 +69,7 @@ class Message extends BaseController
}
}
} else {
return json(['status' =>0]);
return json(['status' =>0, 'url'=>(string) url('User/message')]);
}
}

View File

@ -1,23 +1,45 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-20 13:21:54
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \TaoLer\app\index\controller\Search.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\index\controller;
use app\common\model\Article;
use app\common\controller\BaseController;
use think\facade\View;
use think\facade\Request;
use app\facade\Article;
use app\common\model\Slider;
class Search
class Search extends BaseController
{
public function getSearch(string $keywords)
{
//全局查询条件
$map = []; //所有的查询条件封装到数组中
//条件1
$map[] = ['status','=',1]; //这里等号不能省略
//搜索功能
public function getSearch()
{
$ser = Request::only(['keywords']);
$artList = Article::getSearchKeyWord($ser['keywords']);
$counts = $artList->count();
$slider = new Slider();
//首页右栏
$ad_comm = $slider->getSliderList(2);
// 查询热议
$artHot = Article::getArtHot(10);
if(!empty($keywords)){
//条件2
$map[] = ['title','like','%'.$keywords.'%'];
$res = Article::where($map)->withCount('comments')->order('create_time','desc')->paginate(10);
return $res;
}
}
$searchs = [
'artList' => $artList,
'keywords' => $ser['keywords'],
'counts' => $counts,
'ad_comm'=>$ad_comm,
'artHot'=>$artHot,
'jspage'=>''
];
View::assign($searchs);
return View::fetch('search');
}
}

View File

@ -64,7 +64,7 @@ class Sign extends BaseController
*/
public function status()
{
if(session('user_id')){
if($this->uid){
$res = $this->todayData()->getData();
if($res['is_sign'] == 1){

View File

@ -0,0 +1,86 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2022-07-24 15:58:51
* @LastEditTime: 2022-07-24 21:28:52
* @LastEditors: TaoLer
* @Description: Tag优化版
* @FilePath: \TaoLer\app\index\controller\Tag.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
namespace app\index\controller;
use app\common\controller\BaseController;
use app\facade\Article;
use think\cache\driver\Redis;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;
use app\common\model\Slider;
use Overtrue\Pinyin\Pinyin;
class Tag extends BaseController
{
//
public function index()
{
return View::fetch();
}
// 获取tag列表
public function List()
{
//
$tag = Request::param('tag');
$artList = Article::getAllTags($tag);
$slider = new Slider();
//首页右栏
$ad_comm = $slider->getSliderList(2);
// 查询热议
$artHot = Article::getArtHot(10);
$assign = [
'tag'=>$tag,
'artList'=>$artList,
'ad_comm'=>$ad_comm,
'artHot'=>$artHot,
'jspage'=>''
];
View::assign($assign);
return View::fetch('index');
//halt($tag);
}
//获取文章的tag
public function getArtTag($tag)
{
//
$pinyin = new Pinyin();
$tags = [];
if(!is_null($tag)){
$attr = explode(',', $tag);
foreach($attr as $v){
if ($v !='') {
$tags[] = ['tag'=>$v, 'url'=> (string) url('tag_list',['tag'=>$pinyin->permalink($v,'')])];
}
}
}
return $tags;
}
//获取热门tag
public function getHotTag()
{
//
}
//获取tag链接
public function setTagUrl()
{
}
}

View File

@ -13,7 +13,7 @@ use think\facade\View;
use app\common\model\Article;
use app\common\model\Collection;
use app\common\model\User as userModel;
use think\facade\Config;
use app\common\model\Comment;
use taoler\com\Message;
class User extends BaseController
@ -29,11 +29,10 @@ class User extends BaseController
}
//发帖list
// 发帖list
public function artList()
{
$article = Article::withCount('comments')->where(['user_id'=>$this->uid])->order('update_time','desc')->paginate(10);
//var_dump($article);
$count = $article->total();
$res = [];
if($count){
@ -43,6 +42,7 @@ class User extends BaseController
$res['data'][] = ['id'=>$v['id'],
'title' => htmlspecialchars($v['title']),
'url' => (string) url('article/detail',['id'=>$v['id']]),
'url' => $this->getRouteUrl($v['id'], $v->cate->ename),
'status' => $v['status'] ? '正常':'待审核',
'ctime' => $v['create_time'],
'datas' => $v['pv'].'阅/'.$v['comments_count'].'答'
@ -55,8 +55,9 @@ class User extends BaseController
return json($res);
}
//收藏list
public function collList(){
// 收藏list
public function collList()
{
//收藏的帖子
$collect = Collection::with(['article'=>function($query){
$query->withCount('comments')->where('status',1);
@ -71,7 +72,7 @@ class User extends BaseController
$res['data'][] = [
'id' =>$v['id'],
'title' => htmlspecialchars($v['collect_title']),
'url' => (string) url('article/detail',['id'=>$v['article_id']]),
'url' => $this->getRouteUrl($v['article_id'], $v->article->cate->ename),
'auther' => $v['auther'],
'status' => is_null(Db::name('article')->field('id')->where('delete_time',0)->find($v['article_id'])) ? '已失效' : '正常',
'ctime' => $v['create_time']
@ -112,6 +113,15 @@ class User extends BaseController
{
if(Request::isAjax()){
$data = Request::only(['user_id','email','nickname','sex','city','area_id','sign']);
// 过滤
$sign = strtolower($data['sign']);
if(strstr($sign, 'script')) return json(['code'=>-1,'msg'=>'包含有非法字符串script脚本']);
if(strstr($sign, 'alert')) return json(['code'=>-1,'msg'=>'包含有非法字符alert']);
if(strstr($sign, 'img')) return json(['code'=>-1,'msg'=>'禁用img标签']);
if(strstr($sign, 'body')) return json(['code'=>-1,'msg'=>'禁用img标签']);
if(strstr($sign, 'video')) return json(['code'=>-1,'msg'=>'禁用video标签']);
// 验证
$validate = new userValidate;
$result = $validate->scene('Set')->check($data);
if(!$result){
@ -131,7 +141,7 @@ class User extends BaseController
$result = $user->setNew($data);
if($result == 1){
Cache::tag('user')->clear();
return ['code'=>0,'msg'=>'资料更新成功'];
return json(['code'=>0,'msg'=>'资料更新成功']);
} else {
$this->error($result);
}
@ -167,14 +177,14 @@ class User extends BaseController
->update(['user_img'=>$name_path]);
Cache::tag(['user','tagArtDetail','tagArt'])->clear();
if($result) {
$res = ['status'=>0,'msg'=>'头像更新成功'];
$res = ['code'=>0,'msg'=>'头像更新成功'];
} else {
$res = ['status'=>1,'msg'=>'头像更新失败'];
$res = ['code'=>1,'msg'=>'头像更新失败'];
}
} else {
$res = ['status'=>1,'msg'=>'上传错误'];
$res = ['code'=>1,'msg'=>'上传错误'];
}
return json($res);
return json($res);
}
@ -196,11 +206,21 @@ class User extends BaseController
$u = Db::name('user')->field('name,nickname,city,sex,sign,user_img,point,vip,create_time')->cache(3600)->find($id);
}
//用户发贴
$arts = Db::name('user')->alias('u')->join('article a','u.id = a.user_id')->field('u.id,a.id,a.title,a.pv,a.is_hot,a.create_time,a.delete_time,a.status')->where(['a.delete_time'=>0,'a.status'=>1])->where('a.user_id',$id)->order(['a.create_time'=>'desc'])->cache(3600)->select();
$article = new Article();
$commont = new Comment();
$arts = $article->getUserArtList((int) $id);
// $reys = $commont->getUserCommentList((int) $id);
// dump($reys);
//用户回答
$reys = Db::name('comment')->alias('c')->join('article a','c.article_id = a.id')->field('a.id,a.title,c.content,c.create_time,c.delete_time,c.status')->where(['a.delete_time'=>0,'c.delete_time'=>0,'c.status'=>1])->where('c.user_id',$id)->order(['c.create_time'=>'desc'])->cache(3600)->select();
$reys = Db::name('comment')
->alias('c')
->join('article a','c.article_id = a.id')
->field('a.id,a.title,c.content,c.create_time,c.delete_time,c.status')
->where(['a.delete_time'=>0,'c.delete_time'=>0,'c.status'=>1])
->where('c.user_id',$id)
->order(['c.create_time'=>'desc'])
->cache(3600)->select();
View::assign(['u'=>$u,'arts'=>$arts,'reys'=>$reys,'jspage'=>'']);
return View::fetch();

View File

@ -67,9 +67,9 @@ return [
'go sign' => '去签到',
'more post' => '更多帖子',
'friendly link' => '友情链接',
'reviewers list' => '回帖热榜',
'reviewers list' => '活跃榜',
'hot post list' => '本周热议',
'links list' => '温馨通道',
'links list' => '快捷导航',
'statement' => '说明',
'trends' => '动态',
'sponsor' => '钻级赞助商',
@ -105,7 +105,7 @@ return [
'submit' => '提交',
'go back' => '返回',
'register now' => '立即注册',
'mail/username' => '邮箱/用户名',
'mail/username/mobile' => '邮箱/用户名/手机号',
'6-16 characters' => '6-16 字符',
'strong type encryption' => '经过强类型加密',
'it cannot be changed' => '不能更改',

View File

@ -2,11 +2,11 @@
/*
* @Author: TaoLer <alipey_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-04-22 16:25:14
* @LastEditTime: 2022-07-26 13:58:17
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\index\route\route.php
* Copyright (c) 2020~2022 http://www.aieok.com All rights reserved.
* @Description: 前端路由设置
* @FilePath: \github\TaoLer\app\index\route\route.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
use think\facade\Route;
@ -17,30 +17,58 @@ $cate_as = config('taoler.url_rewrite.cate_as');
Route::get('captcha/[:config]','\\think\\captcha\\CaptchaController@index');
Route::rule('/', 'index'); // 首页访问路由
Route::get('index/reply','index/reply')->name('user_reply');
Route::rule('search','Search/getSearch')->name('user_search');
Route::get('message/nums','message/nums')->name('user_message');
Route::get('tag/:tag', 'Tag/list')->name('tag_list');
// 用户中心
Route::group(function () {
Route::get('u/:id$', 'user/home')->name('user_home');
Route::get('user/index', 'user/index');
Route::get('user/set', 'user/set');
Route::get('user/message', 'user/message');
Route::get('user/post', 'user/post');
Route::get('user/article','user/artList');
Route::get('user/coll','user/collList');
Route::get('user/colldel','user/collDel');
Route::get('user/setpass','user/setPass');
Route::get('user/activate','user/activate');
Route::get('user/active','user/active');
Route::get('user/uploadHeadImg','user/uploadHeadImg');
Route::get('logout', 'user/logout');
});
// 登录注册
Route::group(function () {
Route::rule('login','login/index')->name('user_login');
Route::rule('forget','login/forget')->name('user_forget');
Route::rule('postcode','login/postcode');
Route::rule('sentemailcode','login/sentMailCode');
Route::rule('respass','login/respass');
Route::rule('reg$','Login/reg')->name('user_reg')
->middleware(\app\middleware\CheckRegister::class);
});
// article
Route::group(function () use($detail_as,$cate_as){
Route::get("$detail_as<id>", 'article/detail');
Route::get("$cate_as<ename>$",'article/cate')->name('cate');
Route::get("$cate_as<ename>/<type>$", 'article/cate')->name('cate_type');
Route::rule("$cate_as<ename>/<type>/<page>", 'article/cate')->name('cate_page');
Route::rule('add','Article/add');
Route::rule('add/[:cate]','Article/add')->name('add_article');
Route::rule('delete/[:id]','Article/delete');
Route::rule('tags','Article/tags')->allowCrossDomain();
Route::rule('edit/[:id]','Article/edit');
})->pattern([
'ename' => '\w+',
'type' => '\w+',
'page' => '\d+',
'id' => '\d+',
]);
// 动态路径路由会影响下面的路由,所以动态路由放下面
Route::get($detail_as . ':id$', 'article/detail')->name('article_detail');
Route::get($cate_as . '<ename>$','article/cate')->name('cate');
Route::get($cate_as . '<ename>/<type>$', 'article/cate')->name('cate_type');
Route::get($cate_as . '<ename>/<type>/<page>', 'article/cate')->name('cate_page');
})->pattern([
'ename' => '\w+',
'type' => '\w+',
'page' => '\d+',
'id' => '\d+',
]);
Route::group(function () {
Route::rule('u/:id', 'user/home');
});
Route::rule('login','login/index');
Route::rule('forget','login/forget');
Route::rule('postcode','login/postcode');
Route::rule('respass','login/respass');
Route::rule('reg$','Login/reg')
->middleware(\app\middleware\CheckRegister::class);
Route::rule('search/[:keywords]', 'index/search'); // 搜索

View File

@ -54,6 +54,7 @@ CREATE TABLE `tao_article` (
`status` enum('0','-1','1') NOT NULL DEFAULT '1' COMMENT '状态1显示0待审-1禁止',
`cate_id` int(11) NOT NULL COMMENT '分类id',
`user_id` int(11) NOT NULL COMMENT '用户id',
`goods_detail_id` int DEFAULT NULL COMMENT '商品ID',
`is_top` enum('0','1') NOT NULL DEFAULT '0' COMMENT '置顶1否0',
`is_hot` enum('0','1') NOT NULL DEFAULT '0' COMMENT '推荐1否0',
`is_reply` enum('1','0') NOT NULL DEFAULT '1' COMMENT '0禁评1可评',
@ -76,7 +77,7 @@ CREATE TABLE `tao_article` (
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`) USING BTREE COMMENT '文章的用户索引',
KEY `cate_id` (`cate_id`) USING BTREE COMMENT '文章分类索引'
) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tao_article
@ -141,7 +142,7 @@ CREATE TABLE `tao_auth_group_copy` (
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
`delete_time` int(11) NOT NULL DEFAULT '0' COMMENT '删除时间',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tao_auth_group_copy
@ -310,7 +311,7 @@ CREATE TABLE `tao_collection` (
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`delete_time` int(11) NOT NULL DEFAULT '0' COMMENT '删除时间',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='文章收藏表';
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='文章收藏表';
-- ----------------------------
-- Table structure for tao_comment
@ -350,7 +351,7 @@ CREATE TABLE `tao_cunsult` (
`create_time` int(10) NOT NULL DEFAULT '0' COMMENT '创建时间',
`delete_time` int(10) NOT NULL DEFAULT '0' COMMENT '删除时间',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for tao_friend_link
@ -460,7 +461,7 @@ CREATE TABLE `tao_slider` (
`slid_name` varchar(30) NOT NULL COMMENT '幻灯名',
`slid_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '类型',
`slid_img` varchar(70) NOT NULL DEFAULT '' COMMENT '幻灯图片地址',
`slid_href` varchar(70) NOT NULL DEFAULT '' COMMENT '链接',
`slid_href` varchar(255) NOT NULL DEFAULT '' COMMENT '链接',
`slid_color` varchar(10) NOT NULL DEFAULT '' COMMENT '广告块颜色',
`slid_start` int(11) NOT NULL DEFAULT '0' COMMENT '开始时间',
`slid_over` int(11) NOT NULL DEFAULT '0' COMMENT '结束时间',
@ -488,12 +489,14 @@ CREATE TABLE `tao_system` (
`domain` varchar(50) NOT NULL,
`template` varchar(30) NOT NULL DEFAULT '' COMMENT '模板',
`logo` varchar(70) NOT NULL DEFAULT '' COMMENT '网站logo',
`m_logo` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '/static/res/images/logo-m.png' COMMENT '移动端logo',
`cache` tinyint(5) NOT NULL DEFAULT '0' COMMENT '缓存时间分钟',
`upsize` int(5) NOT NULL DEFAULT '0' COMMENT '上传文件大小KB',
`uptype` varchar(255) NOT NULL DEFAULT '0' COMMENT '上传文件类型',
`copyright` varchar(100) NOT NULL DEFAULT '' COMMENT '版权',
`keywords` tinytext NOT NULL COMMENT '网站关键字',
`descript` tinytext NOT NULL COMMENT '网站描述',
`state` tinytext CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '网站声明',
`is_open` enum('0','1') NOT NULL DEFAULT '1' COMMENT '是否开启站点1开启0关闭',
`is_comment` enum('0','1') NOT NULL DEFAULT '1' COMMENT '是否开启评论1开启0关闭',
`is_reg` enum('0','1') NOT NULL DEFAULT '1' COMMENT '是否开放注册1开启0禁止',
@ -515,7 +518,7 @@ CREATE TABLE `tao_system` (
-- ----------------------------
-- Records of tao_system
-- ----------------------------
INSERT INTO `tao_system` VALUES ('1', 'TaoLer社区演示站', '轻论坛系统', 'http://www.xxx.com', 'taoler', '/storage/logo/logo.png', '10', '2048', 'image:png|gif|jpg|jpeg,application:zip|rar,video:mp4,audio:mp3|m4a|mp4', '<a href="https://www.aieok.com" target="_blank">TaoLer</a>', 'TaoLer,轻社区系统,bbs,论坛,Thinkphp6,layui,fly模板,', '这是一个Taoler轻社区论坛系统', '1', '1', '1', '0.0.0.0-1', '', '管理员|admin|审核员|超级|垃圾', '1.6.3', '','0', 'http://api.aieok.com', 'http://api.aieok.com/v1/cy', 'http://api.aieok.com/v1/upload/check', 'http://api.aieok.com/v1/upload/api', '1581221008', '1577419197');
INSERT INTO `tao_system` VALUES (1, 'TaoLer', 'TaoLer社区-www.aieok.com', 'www.tp6.com', 'taoler', '/storage/logo/logo.png', '/static/res/images/logo-m.png', 10, 2048, 'image:png|gif|jpg|jpeg,application:zip|rar|docx,video:mp4,audio:mp3|m4a|mp4,zip:zip,application/msword:docx', '<a href=\"https://www.aieok.com\" target=\"_blank\">TaoLer</a>', 'TaoLer,轻社区系统,bbs,论坛,Thinkphp6,layui,fly模板,', '这是一个Taoler轻社区论坛系统', '网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。', '1', '1', '1', '0.0.0.0-1', '', '管理员|admin|审核员|超级|垃圾', '1.6.3', '', 0, 'http://api.aieok.com', 'http://api.aieok.com/v1/cy', 'http://api.aieok.com/v1/upload/check', 'http://api.aieok.com/v1/upload/api', 1641004619, 1652345050);
-- ----------------------------
-- Table structure for tao_user
@ -532,7 +535,7 @@ CREATE TABLE `tao_user` (
`city` varchar(50) NOT NULL DEFAULT '' COMMENT '归属地',
`sex` enum('0','1') NOT NULL DEFAULT '0' COMMENT '性别0男1女',
`sign` varchar(255) NOT NULL DEFAULT '' COMMENT '签名',
`user_img` varchar(70) NOT NULL DEFAULT '' COMMENT '头像',
`user_img` varchar(150) NOT NULL DEFAULT '' COMMENT '头像',
`auth` enum('1','0') NOT NULL DEFAULT '0' COMMENT '管理员权限0普通1超级',
`point` int(11) NOT NULL DEFAULT '0' COMMENT '积分',
`area_id` int(11) DEFAULT NULL COMMENT '用户所属区域ID',
@ -648,12 +651,11 @@ INSERT INTO `tao_user_viprule` VALUES ('4', '501-699', '3', '土豪', '', '15855
DROP TABLE IF EXISTS `tao_user_zan`;
CREATE TABLE `tao_user_zan` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '点赞主键id',
`article_id` int DEFAULT NULL COMMENT '文章id',
`comment_id` int(11) NOT NULL COMMENT '评论id',
`user_id` int(11) NOT NULL COMMENT '用户id',
`type` tinyint NOT NULL DEFAULT '2' COMMENT '1文章点赞2评论点赞',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '点赞时间',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tao_user_zan
-- ----------------------------

View File

@ -1,3 +1,12 @@
<!--
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-01 13:48:22
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \TaoLer\app\install\view\index\agreement.html
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
-->
{extend name="index/base" /}
{block name="body"}
<div class="inside2">
@ -15,7 +24,7 @@
<p>9、在理解、同意、并遵守本协议的全部条款后方可开始使用本程序。本许可协议条款的解释效力及纠纷的解决适用于中华人民共和国大陆法律。</p>
<p>10、您使用本系统需要遵循许可协议一旦安装表示您已接受该系统各项条款。</p>
<div class="inout1">
<a>拒绝安装</a>
<a id="no-install">拒绝安装</a>
</div>
<div class="inout2">
<a href="{:url('index/test')}">同意安装</a>
@ -24,3 +33,19 @@
</br>
</div>
{/block}
{block name="script"}
<script>
// 关闭当前页
$("#no-install").on('click',function(){
var userAgent = navigator.userAgent;
if (userAgent.indexOf("Firefox") != -1 || userAgent.indexOf("Chrome") != -1) {
location.href = "about:blank";
} else {
window.opener = null;
window.open('', '_self');
}
window.close();
});
</script>
{/block}

View File

@ -1,10 +1,17 @@
<!--
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-01 13:44:37
* @LastEditors: TaoLer
* @Description: 安装引导程序优化版
* @FilePath: \TaoLer\app\install\view\index\base.html
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>TaoLer安装程序</title>
<script type="text/javascript" src="/static/layui/jquery.min.js"></script>
<link rel="stylesheet" href="/static/res/css/admin.css">
<link rel="stylesheet" href="/static/layui/css/layui.css">
<script src="/static/layui/layui.js"></script>
@ -34,7 +41,10 @@
</div>
</div>
{block name="body"}主题{/block}
<script>
var $ = layui.jquery;
var layer = layui.layer;
</script>
{block name="script"}{/block}
</body>
</html>

View File

@ -5,16 +5,13 @@
<div class="inwp cl">
<form class="layui-form layui-form-pane" >
<h2>创建数据库:</h2>
<input type="hidden" name="DB_TYPE" value="mysql">
<div class="layui-form-item">
<label class="layui-form-label">数据库服务器</label>
<div class="layui-input-block">
<input type="text" name="DB_HOST" value="127.0.0.1" required lay-verify="required" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">数据库账号</label>
<div class="layui-input-block">
@ -91,49 +88,41 @@
<input type="submit" lay-submit lay-filter="formDemo" value="确认安装">
</div>
</form>
<script>
layui.use('form', function() {
var $ = layui.jquery,
form = layui.form;
form.on('submit(formDemo)', function(data){
var field = data.field;
//console.log(field); //当前容器的全部表单字段,名值对形式:{name: value}
loading = layer.load(2, {
shade: [0.2, '#000'],
time: 2000,
});
$.ajax({
type:"post",
url:"{:url('index/install')}",
data:{"DB_TYPE":field.DB_TYPE,"DB_HOST":field.DB_HOST,"DB_USER":field.DB_USER,"DB_PWD":field.DB_PWD,"DB_PORT":field.DB_PORT,"DB_NAME":field.DB_NAME,"DB_PREFIX":field.DB_PREFIX,"webname":field.webname,"webtitle":field.webtitle,"admin_user":field.admin_user,"admin_email":field.admin_email,"admin_pass":field.admin_pass,"admin_pass2":field.admin_pass2},
daType:"json",
success:function (data){
if (data.code == 0) {
layer.close(loading);
layer.msg(data.msg,{
icon:6,
time:2000
}, function(){
location.href = data.url;
});
} else {
layer.open({
tiele:'安装失败',
content:data.msg,
icon:5,
anim:6
});
}
}
});
return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。
});
});
</script>
</div>
</div>
{/block}
{block name="script"}
<script>
layui.use('form', function() {
var $ = layui.jquery,
form = layui.form;
form.on('submit(formDemo)', function(data){
var field = data.field;
loading = layer.load(2, {
shade: [0.2, '#000'],
time: 2000,
});
$.ajax({
type:"post",
url:"{:url('index/install')}",
data:{"DB_TYPE":field.DB_TYPE,"DB_HOST":field.DB_HOST,"DB_USER":field.DB_USER,"DB_PWD":field.DB_PWD,"DB_PORT":field.DB_PORT,"DB_NAME":field.DB_NAME,"DB_PREFIX":field.DB_PREFIX,"webname":field.webname,"webtitle":field.webtitle,"admin_user":field.admin_user,"admin_email":field.admin_email,"admin_pass":field.admin_pass,"admin_pass2":field.admin_pass2},
daType:"json",
success:function (data){
if (data.code == 0) {
layer.close(loading);
layer.msg(data.msg,{icon:6,time:2000}, function(){
location.href = data.url;
});
} else {
layer.open({tiele:'安装失败',content:data.msg,icon:5,anim:6});
}
}
});
return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。
});
});
</script>
{/block}

View File

@ -119,13 +119,16 @@
</div>
</div>
</div>
<script>
function testClick() {
if ($('.yes').length != 7) {
alert('您的配置或权限不符合要求');
} else {
location.href = '{:url('index/create')}';
}
{/block}
{block name="script"}
<script>
function testClick() {
if ($('.yes').length != 7) {
alert('您的配置或权限不符合要求');
} else {
location.href = "{:url('index/create')}";
}
</script>
}
</script>
{/block}

View File

@ -1,15 +1,24 @@
<!--
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-01 13:30:39
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \TaoLer\app\install\view\success\complete.html
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
-->
{extend name="index/base" /}
{block name="body"}
<div class="inside2">
<div class="inwp cl">
<h2>恭喜您安装成功</h2>
{block name="body"}
<div class="inside2">
<div class="inwp cl">
<h2>恭喜您安装成功</h2>
<div class="inout1">
<a href="/" target="_blank">去前台首页</a>
</div>
<div class="inout2">
<a href="/admin/login" target="_blank">去后台首页</a>
</div>
<div class="inout1">
<a href="/" target="_blank">去前台首页</a>
</div>
<div class="inout2">
<a href="/admin" target="_blank">去后台首页</a>
</div>
</div>
{/block}
</div>
{/block}

View File

@ -1,4 +1,13 @@
<?php
/*
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-06-19 16:35:30
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\listener\UserLogin.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
declare (strict_types = 1);
namespace app\listener;
@ -7,6 +16,7 @@ use think\facade\Db;
use think\facade\Log;
use app\common\model\User;
use think\facade\Lang;
use taoler\com\Api;
class UserLogin
{
@ -25,21 +35,17 @@ class UserLogin
if($type == 'log'){
//$name = $user->user['name'];
$ip = request()->ip();
/*
$url = 'http://ip-api.com/json/'.$ip.'?lang=zh-CN';
//$url = 'http://ip-api.com/json/?lang=zh-CN';
$add = Api::urlGet($url);
if($add->status == 'success'){
$city = $add->city;
} else {
$city ='未知';
}
*/
$u->allowField(['last_login_ip','last_login_time','login_error_num'])->save(
$url = 'http://ip-api.com/json/' . $ip . '?lang=zh-CN&fields=57361';
$ipJson = Api::urlGet($url);
if($ipJson->status == 'success'){
$city = $ipJson->city;
} else {
$city ='未知';
}
$u->allowField(['city','last_login_ip','last_login_time','login_error_num'])->save(
[
//'city' => $city,
'city' => $city,
'last_login_ip' => $ip,
'last_login_time' => time(),
'login_error_num' => 0

View File

@ -11,13 +11,15 @@ class CheckRegister
//排除禁止注册用户名的字段
if($request->action(true)=='reg'){
$name = $request->param('name');
$disname = Db::name('system')->where('id',1)->value('blackname');
$data = explode("|",$disname);
foreach($data as $v){
if(stripos($name,$v) !== false){
return json(['msg'=>'非法字段或该用户名禁止注册,请更换']);
if(!is_null($name)) {
$disname = Db::name('system')->where('id',1)->value('blackname');
$data = explode("|",$disname);
foreach($data as $v){
if(stripos($name,$v) !== false){
return json(['msg'=>'非法字段或该用户名禁止注册,请更换']);
}
}
}
}
}
return $next($request);
}

View File

@ -30,7 +30,13 @@
"taoser/think-addons": "^1.0",
"liliuwei/thinkphp-social": "^1.3",
"taoser/think-setarr": "^0.0.3",
"topthink/think-migration": "^3.0"
"topthink/think-migration": "^3.0",
"workerman/workerman": "^4.0",
"endroid/qr-code": "^4.4",
"overtrue/pinyin": "^4.0",
"yansongda/pay": "~3.1.0",
"guzzlehttp/guzzle": "7.0",
"php-di/php-di": "^6.4"
},
"require-dev": {
"symfony/var-dumper": "^4.2",

1250
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
/*
* @Author: TaoLer <alipey_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-04-21 20:56:48
* @LastEditTime: 2022-07-03 04:21:02
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\config\app.php
@ -28,15 +28,17 @@ return [
// 应用映射(自动多应用模式有效)
'app_map' => [
//'bbs' => 'index'
],
// 域名绑定(自动多应用模式有效)
'domain_bind' => [
//'www' => 'index',
//'adm' => 'admin'
],
// 禁止URL访问的应用列表自动多应用模式有效
// 异常页面的模板文件
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
//'exception_tmpl' => app()->getAppPath() . '404.html',
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',

View File

@ -1,4 +1,13 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-24 09:57:31
* @LastEditors: TaoLer
* @Description: 文件存储优化版
* @FilePath: \TaoLer\config\filesystem.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
return [
// 默认磁盘
@ -19,6 +28,11 @@ return [
// 可见性
'visibility' => 'public',
],
'sys' => [
'type' => 'local',
'root' => app()->getRootPath() . 'public/sys',
'url' => '/sys',
],
// 更多的磁盘配置信息
],
];

View File

@ -1,3 +1,5 @@
<?php
return [
'一个' => 'http://www.bi.com',
'描述' => 'http://ww.com',
];

View File

@ -1,12 +1,12 @@
<?php
/*
* @Author: TaoLer <alipey_tao@qq.com>
* @Author: TaoLer <alipay_tao@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-04-22 06:57:15
* @LastEditTime: 2022-06-27 13:14:46
* @LastEditors: TaoLer
* @Description: 网站公共配置
* @FilePath: \TaoLer\config\taoler.php
* Copyright (c) 2020~2022 http://www.aieok.com All rights reserved.
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
// +----------------------------------------------------------------------
// | 网站公共配置
@ -16,7 +16,7 @@ return [
// 应用名,此项不可更改
'appname' => 'TaoLer',
// 版本配置
'version' => '1.9.3',
'version' => '1.9.20',
// 加盐
'salt' => 'taoler',
// 数据库备份目录
@ -24,23 +24,43 @@ return [
// 配置
'config' =>[
'email_notice' => 0,
'cate_show' => 1,
'area_show' => 1,
'regist_check' => 0,
'posts_check' => 0,
'commnets_check' => 0,
'login_captcha' => 0,
'post_captcha' => 0,
// 注册开关
'is_regist' => 1,
// 登录开关
'is_login' => 1,
// 发帖开关
'is_post' => 1,
// 评论开关
'is_reply' => 1,
// 注册审核
'regist_check' => 0,
// 发帖审核
'posts_check' => 0,
// 评论审核
'commnets_check' => 0,
// 注册验证类型 1验证码2邮箱3手机短信
'regist_type' => 1,
// 登录验证码
'login_captcha' => 0,
// 发帖验证码
'post_captcha' => 0,
// 显示分类
'cate_show' => 0,
// 显示用户归属地简称
'area_show' => 0,
// 邮件通知
'email_notice' => 0,
// 百度词条开关
'baidu_title_switch' => 0,
],
// 百度标签分词
'baidu' => [
'grant_type' => '',
'grant_type' => 'client_credentials',
'client_id' => '',
'client_secret' => '',
'access_token' => '',
'push_api' => 'http://',
'push_api' => '',
],
// sitemap
@ -50,14 +70,14 @@ return [
'map_time' => 'daily',
'map_level' => '0.5',
// 已生成id位标记
'write_id' => 12,
'write_id' => 21,
],
// URL美化
'url_rewrite' => [
// 详情url
'article_as' => 'article/',
'article_as' => '<ename>/',
// 分类url
'cate_as' => 'column/',
],

View File

@ -1,10 +1,23 @@
<?php
/*
* @Author: TaoLer <317927823@qq.com>
* @Date: 2021-12-06 16:04:50
* @LastEditTime: 2022-07-03 04:55:42
* @LastEditors: TaoLer
* @Description: 优化版
* @FilePath: \TaoLer\config\trace.php
* Copyright (c) 2020~2022 https://www.aieok.com All rights reserved.
*/
// +----------------------------------------------------------------------
// | Trace设置 开启调试模式后有效
// +----------------------------------------------------------------------
return [
// 内置Html和Console两种方式 支持扩展
'type' => 'Html',
// 读取的日志通道名
'channel' => '',
'type' => 'console',
'tabs' => [
'base' => '基本',
'file' => '文件',
'error|notice|warning' => '错误',
'sql' => 'SQL',
'debug|info' => '调试',
],
];

View File

@ -2,21 +2,12 @@
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
use think\facade\Db;
//如果网站安装从数据库查询选择的模板
if(file_exists('./install.lock')){
$template = Db::name('system')->where('id',1)->value('template');
} else {
$template = '';
}
return [
// 模板引擎类型使用Think
'type' => 'Think',
// 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
'auto_rule' => 1,
// 模板目录名
'view_dir_name' => 'view/'.$template,
// 模板后缀
'view_suffix' => 'html',
// 模板文件名分隔符
@ -31,6 +22,8 @@ return [
'taglib_end' => '}',
'default_filter' => 'htmlspecialchars',
//模板输出替换
'tpl_replace_string' => [
'__STATIC__'=>'/static/layui',

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?> <!-- XML文件需以utf-8编码-->
<urlset>
<url>
<loc>http://www.test.com/index/jie/7.html</loc>
<lastmod>2022-01-01</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>http://www.test.com/index/jie/8.html</loc>
<lastmod>2022-01-01</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>http://www.test.com/index/jie/9.html</loc>
<lastmod>2022-04-12</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
</urlset>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?> <!-- XML文件需以utf-8编码-->
<urlset>
<url>
<loc>http://www.test.com/index/jie/10.html</loc>
<lastmod>2022-04-15</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>http://www.test.com/index/jie/11.html</loc>
<lastmod>2022-04-12</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>http://www.test.com/index/jie/12.html</loc>
<lastmod>2022-04-12</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
</urlset>

View File

@ -127,9 +127,9 @@ var forms = table.render({
,cols: [[
{type: 'checkbox'}
,{field: 'id', width: 80, title: 'ID', sort: true}
,{field: 'replyer', title: '回帖人', width: 80}
,{field: 'title', title: '帖ID',templet: '#title'}
,{field: 'avatar', title: '头像', width: 80, templet: '#imgTpl'}
,{field: 'title', title: '标题',minWidth: 150, templet: '<div><a href="{{d.url}}" target="_blank">{{d.title}}</a></div>'}
,{field: 'replyer', title: '账号', width: 80}
,{field: 'avatar', title: '头像', width: 60, templet: '#imgTpl'}
,{field: 'content', title: '评论', minWidth: 200}
,{field: 'replytime', title: '回复时间', width: 120, sort: true}
,{field: 'check', title: '审核', templet: '#buttonCheck', width: 100}

View File

@ -1,4 +1,4 @@
/**
/**
images压缩扩展模块
changlin_zhao@qq.com
2021.5.25
@ -10,9 +10,8 @@ var layer = layui.layer;
var compressImage = {
uploads: function(obj){
//obj.preview(function(index, file, result){
//执行实例
//执行实例
var files = obj.pushFile();
var filesArry = [];
for (var key in files) { //将上传的文件转为数组形式
@ -54,7 +53,7 @@ var compressImage = {
reader.readAsDataURL(file)
reader.onload = function (e) {
const img = new Image()
const quality = 0.5 // 图像质量
const quality = 0.8 // 图像质量
const canvas = document.createElement('canvas')
const drawer = canvas.getContext('2d')
img.src = this.result
@ -64,7 +63,7 @@ var compressImage = {
originHeight = img.height; /* 图片的高度 */
// 设置最大尺寸限制将所有图片都压缩到小于1m
const maxWidth = 1024, maxHeight = 1024;
const maxWidth = 2560, maxHeight = 1600;
// 需要压缩的目标尺寸
let targetWidth = originWidth, targetHeight = originHeight;
// 等比例计算超过最大限制时缩放后的图片尺寸
@ -105,7 +104,7 @@ var compressImage = {
//})
}
}
}
//输出 imgcom 接口
exports('imgcom', compressImage);
});

View File

@ -20,19 +20,19 @@ layui.define(['table', 'form'], function(exports){
,cols: [[
{type: 'checkbox'}
,{field: 'id', width: 60, title: 'ID', sort: true}
,{field: 'username', title: '用户名', minWidth: 100}
,{field: 'nick', title: '昵称',minWidth: 100}
,{field: 'avatar', title: '头像', width: 80, templet: '#imgTpl'}
,{field: 'username', title: '用户名', minWidth: 80}
,{field: 'nick', title: '昵称',Width: 80}
,{field: 'avatar', title: '头像', width: 60, templet: '#imgTpl'}
//,{field: 'phone', title: '手机',width: 80}
,{field: 'email', title: '邮箱', width: 120}
,{field: 'email', title: '邮箱', minWidth: 120}
,{field: 'sex', width: 60, title: '性别',templet: '#sex'}
,{field: 'ip', title: '登录IP', width: 100}
,{field: 'city', title: '城市', width: 80}
,{field: 'logintime', title: '最后登录',width: 150, sort: true}
,{field: 'city', title: '城市', width: 80}
,{field: 'logintime', title: '最后登录',width: 150, sort: true}
,{field: 'jointime', title: '注册时间',width: 110, sort: true}
,{field: 'check', title: '状态', templet: '#buttonCheck', width: 95, align: 'center'}
,{field: 'auth', title: '超级管理员', templet: '#buttonAuth', width: 80, align: 'center'}
,{title: '操作', width: 150, align:'center', toolbar: '#table-useradmin-webuser'}
,{field: 'check', title: '状态', templet: '#buttonCheck', width: 95, align: 'center'}
,{field: 'auth', title: '超级管理员', templet: '#buttonAuth', width: 80, align: 'center'}
,{title: '操作', width: 100, align:'center', toolbar: '#table-useradmin-webuser'}
]]
,page: true
,limit: 30
@ -52,30 +52,21 @@ layui.define(['table', 'form'], function(exports){
layer.confirm('真的删除行么', function(index){
//obj.del();
$.ajax({
type:'post',
url:userDelete,
data:{id:data.id},
dataType:'json',
success:function(data){
if(data.code == 0){
layer.msg(data.msg,{
icon:6,
time:2000
},function(){
location.reload();
});
} else {
layer.open({
title:'删除失败',
content:data.msg,
icon:5,
adim:6
})
}
}
});
$.ajax({
type:'post',
url:userDelete,
data:{id:data.id},
dataType:'json',
success:function(data){
if(data.code == 0){
layer.msg(data.msg,{icon:6,time:2000});
} else {
layer.open({title:'删除失败',content:data.msg,icon:5,adim:6})
}
}
});
table.reload('LAY-user-manage');
layer.close(index);
});
});
@ -97,34 +88,23 @@ layui.define(['table', 'form'], function(exports){
//监听提交
iframeWindow.layui.form.on('submit('+ submitID +')', function(data){
var field = data.field; //获取提交的字段
var field = data.field; //获取提交的字段
//提交 Ajax 成功后,静态更新表格中的数据
$.ajax({
type:"post",
url:userEdit,
data:{"id":field.id,"name":field.username,"phone":field.phone,"email":field.email,"user_img":field.avatar,"sex":field.sex},
daType:"json",
success:function (res){
if (res.code == 0) {
layer.msg(res.msg,{
icon:6,
time:2000
}, function(){
location.reload();
});
} else {
layer.open({
tiele:'修改失败',
content:res.msg,
icon:5,
anim:6
});
}
}
});
table.reload('LAY-user-front-submit'); //数据刷新
type:"post",
url:userEdit,
data:{"id":field.id,"name":field.username,"phone":field.phone,"email":field.email,"user_img":field.avatar,"sex":field.sex},
daType:"json",
success:function (res){
if(data.code == 0){
layer.msg(data.msg,{icon:6,time:2000});
} else {
layer.open({title:'修改失败',content:data.msg,icon:5,adim:6})
}
}
});
table.reload('LAY-user-manage'); //数据刷新
layer.close(index); //关闭弹层
});
@ -149,7 +129,7 @@ layui.define(['table', 'form'], function(exports){
,{field: 'email', title: '邮箱', minWidth: 150}
,{field: 'check', title:'审核状态', templet: '#buttonTpl', width: 100, align: 'center'}
,{field: 'ip', title: 'IP', width: 100}
,{field: 'logintime', title: '最后登陆', width: 150}
,{field: 'logintime', title: '最后登陆', width: 150}
,{title: '操作', width: 150, align: 'center', toolbar: '#table-useradmin-admin'}
]]
,text: '对不起,加载出现异常!'

2
public/static/jquery-3.6.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
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 #eee;border-left-width:6px;background-color:#FAFAFA;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee}.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 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view .layui-code-ol li:first-child{padding-top:10px}.layui-code-view .layui-code-ol li:last-child{padding-bottom:10px}.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}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none}
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-view{display:block;position:relative;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#fafafa;color:#333;font-family:Courier New;font-size:13px}.layui-code-title{position:relative;padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee;font-size:12px}.layui-code-title>.layui-code-about{position:absolute;right:10px;top:0;color:#b7b7b7}.layui-code-about>a{padding-left:10px}.layui-code-view>.layui-code-ol,.layui-code-view>.layui-code-ul{position:relative;overflow:auto}.layui-code-view>.layui-code-ol>li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view>.layui-code-ol>li:first-child,.layui-code-view>.layui-code-ul>li:first-child{padding-top:10px}.layui-code-view>.layui-code-ol>li:last-child,.layui-code-view>.layui-code-ul>li:last-child{padding-bottom:10px}.layui-code-view>.layui-code-ul>li{position:relative;line-height:20px;padding:0 10px;list-style-type:none;*list-style-type:none;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-dark{border:1px solid #0c0c0c;border-left-color:#3f3f3f;background-color:#0c0c0c;color:#c2be9e}.layui-code-dark>.layui-code-title{border-bottom:none}.layui-code-dark>.layui-code-ol>li,.layui-code-dark>.layui-code-ul>li{background-color:#3f3f3f;border-left:none}.layui-code-dark>.layui-code-ul>li{margin-left:6px}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,4 @@
/**
/**
@Name: Fly社区
@Author: 贤心
@Site: fly.layui.com
@ -221,8 +220,8 @@ pre{position: relative; margin: 10px 0; padding: 15px; line-height: 20px; border
/* 底部 */
.fly-footer {margin: 50px 0 0; padding: 20px 0 30px; line-height: 30px; text-align: center; color: #737573; border-top: 1px solid #e2e2e2;}
.fly-footer a{padding:0 6px; font-weight: 300; color: #333;}
.fly-footer a:hover{color: #777;}
.fly-footer a{padding:0 6px; font-weight: 300;color: rgb(230, 227, 227);}
.fly-footer a:hover{color: #fff;}
.fly-union{margin-top: 10px; color: #999;}
.fly-union>*{display: inline-block; vertical-align: middle;}
.fly-union a[upyun] img{width: 80px;}
@ -319,7 +318,7 @@ pre{position: relative; margin: 10px 0; padding: 15px; line-height: 20px; border
.fly-list-top li h2 a{display: inline-block; padding-right: 10px; font-size: 16px;}
/* 列表 */
.fly-list li{position: relative; height: 45px; line-height: 22px; padding: 15px 15px 15px 75px; border-bottom: 1px dotted #e2e2e2;}
.fly-list li{position: relative; height: 45px; line-height: 22px; padding: 15px 15px 15px 75px; border-bottom: 1px dotted #c3c1c1;}
.fly-list li:last-child{border-bottom: none;}
.fly-list li h2,
.fly-list li h2 a,
@ -329,11 +328,12 @@ pre{position: relative; margin: 10px 0; padding: 15px; line-height: 20px; border
.fly-list li h2 .layui-badge{top: -2px; height: 16px; line-height: 16px; padding: 0 5px; margin-right: 10px; font-size: 12px; border: 1px solid #5FB878; background: none; color: #5FB878;}
.fly-list-info{position: relative; font-size: 13px; color: #999;}
.fly-list-info>*{padding-right: 15px;}
.fly-list-info>*{padding-right: 5px;}
.fly-list-info a[link]{color: #999;}
.fly-list-info a[link]:hover{color: #5FB878;}
.fly-list-info .icon-renzheng{position: relative; top: 1px; margin-right: 3px;}
.fly-list-info .fly-badge-vip{position: relative; margin-left: 2px;}
.fly-list-info .layui-badge{height: 16px; line-height: 16px; padding: 0 5px; margin-right: 5px; font-size: 12px; border: 1px solid #5FB878; background: none; color: #5FB878;}
.fly-list-kiss{color: #FF5722;}
.fly-list-nums{position: absolute; right: 0; top: 0; padding-right: 0!important;}
.fly-list-nums i{position: relative; padding: 0 3px 0 15px;}
@ -343,10 +343,10 @@ pre{position: relative; margin: 10px 0; padding: 15px; line-height: 20px; border
/* 单行列表 */
.fly-list-one .fly-panel-title{margin-bottom: 5px;}
.fly-list-one dd{margin: 0 15px; line-height: 26px; white-space: nowrap; overflow: hidden; list-style: decimal-leading-zero inside; *list-style-type: decimal inside; color: #009E94;}
.fly-list-one dd{margin: 0 15px; line-height: 28px; white-space: nowrap; overflow: hidden; list-style: decimal-leading-zero inside; *list-style-type: decimal inside; color: #009E94;}
.fly-list-one dd a,
.fly-list-one dd span{display: inline-block; *display: inline; *zoom: 1; vertical-align: top; font-style: normal}
.fly-list-one dd a{max-width: 85%; margin-right: 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px;}
.fly-list-one dd a{max-width: 85%; margin-right: 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 16px;}
.fly-list-one dd span{font-size: 12px; color: #ccc;}
.fly-list-one dd:last-child{padding-bottom: 5px;}
@ -359,22 +359,26 @@ body .layui-edit-face .layui-layer-content{padding:0; background-color:#fff; co
/*问题列表*/
.question-list{width: 100%;}
.question-list li{line-height: 30px; padding: 10px 15px 15px 20px; border-bottom: 1px dotted #e2e2e2; }
.question-list li{line-height: 30px; padding: 10px 15px 15px 20px; border-bottom: 1px dotted #cccbcb; }
.que-sta-jie,
.que-sta-ask{float: left; margin-top:5px; margin-right:10px; text-align:center; padding:2px; width:38px; height:38px; line-height: 20px; border-radius: 10%; color: #fff;}
.que-sta-jie{background: #5FB878;}
.que-sta-ask{background: #FF5722;}
.que-sta-ask,
.que-sta-view{float: left; margin-top:5px; margin-right:10px; text-align:center; padding:2px; width:46px; height:46px; line-height: 23px; border-radius: 10%;}
.que-sta-jie{color: #fff; background: #5FB878;}
.que-sta-ask{color: #fff; background: #FF5722;}
.que-sta-jie span{display: block;width:46px; height:23px;}
.que-sta-ask span{display: block;width:46px; height:23px;}
.que-sta-view{color: rgb(84, 81, 81);background: #f7f6f5;}
.que-sta-view span{display: block;width:46px; height:23px;}
.que-body{width:100%; padding: 0px; }
.que-body h2{margin-right:10px; line-height: 26px; font-size: 16px; overflow: hidden; white-space: nowrap;text-overflow: ellipsis;}
.que-body h2 a{display: inline-block; max-width: 95%; height: 20px; font-size: 16px;}
.que-body .que-user-info{display: block; text-overflow: ellipsis;}
.que-body .que-user-info a{margin-right: 10px;}
.que-body .que-user-info .que-avatar{top: 20px;}
.que-body .que-user-info .que-avatar img{width: 25px; height: 25px; margin-top: 10; border-radius: 100%;}
.que-body .que-user-info .que-avatar i{position: absolute; left: 35px; top: 15px; }
.que-body .que-user-info span{display: inline-block; font-size: 12px; padding-left: 5px;}
.que-content{font-size: 14px; color:#999;}
/* 签到 */
.fly-signin cite{padding: 0 5px; color: #FF5722; font-style: normal;}
@ -452,9 +456,24 @@ body .layui-edit-face .layui-layer-content{padding:0; background-color:#fff; co
.fly-detail-user a{padding-right: 10px; font-size: 14px;}
.fly-detail-user .guanzhu{position: absolute; right:10px; }
.detail-assist{position: relative; height:22px; margin-top: 10px; line-height: 15px; padding: 5px 10px 5px 10px; font-size: 13px; background-color: #f8f8f8; color: #999;border-radius:5px;}
.detail-assist .fly-admin-box{position: absolute; top: 6px;right:10px;}
.detail-assist span{height: 20px; line-height: 20px;}
/*详情页管理工具条*/
.detail-assist{
position: fixed;
width: 35px;
height:185px;
right: calc(50% - 625px);
top: 200px;
margin: 0 auto;
display: block;
line-height: 30px;
font-size: 13px;
background-color: #e7acac;
color: #999;
border-radius:5px;
z-index: 100;
}
.detail-assist .fly-admin-box{text-align: center;}
.detail-assist span{height: 30px;width:30px; line-height:30px;}
.detail-assist .layui-btn{border-radius: 0;}
.detail-assist .layui-btn+.layui-btn{margin-left: 1px;}
.detail-assist .jie-admin{margin-right: 1px;}
@ -499,6 +518,12 @@ body .layui-edit-face .layui-layer-content{padding:0; background-color:#fff; co
.wenda-user .user-img i{posation:absolute;right:20px;top:30px;width: 25px; height:25px; color:#fff; font-site:18px; border-radius: 100%;background-color:#FFB800;}
.wenda-user .questions{height:30px;margin:20px 20px;}
/*详情页-文章post*/
.detail-zan{margin-top: 15px;}
.detail-zan span{padding-right:5px; color:#999; cursor:pointer;}
.detail-zan span:hover{color:#666;}
.detail-zan span .icon-zan{font-size: 22px;}
.detail-zan span img{height: 25px; border-radius: 100%;}
/* 详情页的底部操作条 */
@ -518,7 +543,9 @@ body .layui-edit-face .layui-layer-content{padding:0; background-color:#fff; co
/* 发帖 */
.layui-form-item.layui-col-space15{margin-bottom: 7.5px;}
.bdsug{height: auto; position: absolute; left: 0; top: 30px; z-index: 100; background: #fff; border-radius: 0 0 10px 10px; border: 1px solid #dadade!important; border-top: 0!important; box-shadow: none;}
.bdsug ul{display: block;margin: 5px 2px 0; padding: 5px 0 7px; background: 0 0; border-top: 0px solid #f5f5f6;}
.bdsug ul>li{margin-top: 0;height:30px;line-height: 25px;}
/* 求解管理 */
.jie-admin{cursor: pointer;}
.detail-hits .jie-admin{color: #fff; padding: 0 10px; }
@ -705,7 +732,7 @@ body .fly-user-main{position: relative; min-height: 600px;}
.laypage-main .laypage-next{display: inline-block;}
/* 列表 */
.fly-list li h2 a{max-width: 72%;}
.fly-list li h2 a{max-width: 90%;}
/* Detail
.fly-admin-box{display: block; margin: 0; margin-top: 10px;}
@ -730,38 +757,3 @@ body .fly-user-main{position: relative; min-height: 600px;}
/*前台公用样式*/
/*分页*/
.pagination {
display: inline-block;
padding: 0 auto;
margin: 20px 0;
border-radius: 4px;
}
.pagination li {
display: inline;
}
.pagination li a,
.pagination li span {
position: relative;
float: left;
padding: 6px 12px;
line-height: 1.42857143;
color: #393D49;
background: #fff;
margin: 0 0 0 8px;
border: 1px solid #eee;
}
.pagination li a:hover {
color: #fff;
background: #009688;
}
.pagination .active span{
background: #009688;
color: #fff;
}
.pagination .disabled{
display: none;
@media screen and (max-width: 992px) {
body .header .layui-nav .layui-nav-item{margin: 0 5px;}
}

View File

@ -17,6 +17,8 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
,device = layui.device()
,DISABLED = 'layui-btn-disabled';
var uid = layui.cache.user.uid;
var login = $('.fly-nav-user').attr('userlogin');
//阻止IE7以下访问
if(device.ie && device.ie < 8){
layer.alert('如果您非得使用 IE 浏览器访问Fly社区那么请使用 IE8+');
@ -442,9 +444,7 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
,preview: function(editor, span){ //预览
var othis = $(span), getContent = function(){
var content = editor.val();
return /^\{html\}/.test(content)
? content.replace(/^\{html\}/, '')
: fly.content(content)
return /^\{html\}/.test(content) ? content.replace(/^\{html\}/, '') : fly.content(content)
}, isMobile = device.ios || device.android;
if(mod.preview.isOpen) return layer.close(mod.preview.index);
@ -517,7 +517,7 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
//转义图片
.replace(/img\[([^\s]+?)\]/g, function(img){
return '<div style="text-align: center;"><img src="' + img.replace(/(^img\[)|(\]$)/g, '') + '"></div>';
return '<div><img src="' + img.replace(/(^img\[)|(\]$)/g, '') + '"></div>';
})
//转义@
@ -607,7 +607,9 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
//新消息通知
,newmsg: function(){
var elemUser = $('.fly-nav-user');
if(layui.cache.user.uid !== -1 && elemUser[0]){
var messageNums = elemUser.attr('msg-url'),
messageRead = elemUser.attr('readMsg-url');
if(uid != -1 && elemUser[0]){
fly.json(messageNums, {
_: new Date().getTime()
}, function(res){
@ -617,7 +619,7 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
msg.on('click', function(){
fly.json(messageRead, {}, function(res){
if(res.status === 0){
location.href = userMessage;
location.href = res.url;
}
});
});
@ -730,189 +732,28 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
});
}
//签到
var jName = "金币";
var tplSignin = ['{{# if(d.signed){ }}'
,'<button class="layui-btn layui-btn-disabled">今日已签到</button>'
,'<span>获得了<cite>{{ d.experience }}</cite>' + jName + '</span>'
,'{{# } else { }}'
,'<button class="layui-btn layui-btn-danger" id="LAY_signin">今日签到</button>'
,'<span>可获得<cite>{{ d.experience }}</cite>' + jName + '</span>'
,'{{# } }}'].join('')
,tplSigninDay = '已连续签到<cite>{{ d.days }}</cite>天'
,signRender = function(data){
laytpl(tplSignin).render(data, function(html){
elemSigninMain.html(html);
});
laytpl(tplSigninDay).render(data, function(html){
elemSigninDays.html(html);
});
}
,elemSigninHelp = $('#LAY_signinHelp')
,elemSigninTop = $('#LAY_signinTop')
,elemSigninMain = $('.fly-signin-main')
,elemSigninDays = $('.fly-signin-days');
if(elemSigninMain[0]){
fly.json(signStatusUrl, function(res){
if(!res.data) return;
signRender.token = res.data.token;
signRender(res.data);
});
}
$('body').on('click', '#LAY_signin', function(){
//登录判断
if(uid == -1){
layer.msg('请登录再签到', {icon: 6}, function(){
location.href = login;
})
return false;
}
var othis = $(this);
if(othis.hasClass(DISABLED)) return;
fly.json(signInUrl, {
token: signRender.token || 1
}, function(res){
signRender(res.data);
}, {
error: function(){
othis.removeClass(DISABLED);
}
});
othis.addClass(DISABLED);
});
//签到说明
elemSigninHelp.on('click', function(){
$.getJSON(signRuleUrl, function(data) {
//拼接表格字符串
var $str = '';
$.each(data.msg, function(k, v) {
$str += '<tr><td>≥' + v.days + '</td><td>' + v.score + '</td></tr>';
});
layer.open({
type: 1
,title: '签到说明'
,area: '300px'
,shade: 0.8
,shadeClose: true
,content: ['<div class="layui-text" style="padding: 20px;">'
,'<blockquote class="layui-elem-quote">“签到”可获得社区' + jName + ',规则如下</blockquote>'
,'<table class="layui-table">'
,'<thead>'
,'<tr><th>连续签到天数</th><th>每天可获' + jName + '</th></tr>'
,'</thead>'
,'<tbody>'
,$str
,'</tbody>'
,'</table>'
,'<ul>'
,'<li>中间若有间隔,则连续天数重新计算</li>'
,'<li style="color: #FF5722;">不可利用程序自动签到,否则' + jName + '清零</li>'
,'</ul>'
,'</div>'].join('')
});
});
});
//签到活跃榜
var tplSigninTop = ['{{# layui.each(d.data, function(index, item){ }}'
,'<li>'
,'<a href="/u/{{item.uid}}" target="_blank">'
,'<img src="{{item.user.avatar}}">'
,'<cite class="fly-link">{{item.user.username}}</cite>'
,'</a>'
,'{{# var date = new Date(item.time); if(d.index === 0) { }}'
,'<span class="fly-grey"> {{ layui.laytpl.digit(date.getFullYear()) + "-" + layui.laytpl.digit(date.getMonth()+1) + "-" + layui.laytpl.digit(date.getDate())}} 签到 <i class="layui-icon layui-icon-ok"></i></span>'
,'{{# } else if(d.index == 1) { }}'
,'<span class="fly-grey">签到于 {{ layui.laytpl.digit(date.getHours()) + ":" + layui.laytpl.digit(date.getMinutes()) + ":" + layui.laytpl.digit(date.getSeconds()) }} <i class="layui-icon layui-icon-flag"></i></span>'
,'{{# } else { }}'
,'<span class="fly-grey">已连续签到 <i>{{ item.days }}</i> 天 <i class="layui-icon layui-icon-face-smile"></i></span>'
,'{{# } }}'
,'</li>'
,'{{# }); }}'
,'{{# if(d.data.length === 0) { }}'
,'{{# if(d.index < 2) { }}'
,'<li class="fly-none fly-grey">今天还没有人签到</li>'
,'{{# } else { }}'
,'<li class="fly-none fly-grey">还没有签到记录</li>'
,'{{# } }}'
,'{{# } }}'].join('');
elemSigninTop.on('click', function(){
var loadIndex = layer.load(1, {shade: 0.8});
fly.json(signJsonUrl, function(res){ //实际使用,请将 url 改为真实接口
var tpl = $(['<div class="layui-tab layui-tab-brief" style="margin: 5px 0 0;">'
,'<ul class="layui-tab-title">'
,'<li class="layui-this">最新签到</li>'
,'<li>今日最快</li>'
,'<li>总签到榜</li>'
,'</ul>'
,'<div class="layui-tab-content fly-signin-list" id="LAY_signin_list">'
,'<ul class="layui-tab-item layui-show"></ul>'
,'<ul class="layui-tab-item">2</ul>'
,'<ul class="layui-tab-item">3</ul>'
,'</div>'
,'</div>'].join(''))
,signinItems = tpl.find('.layui-tab-item');
layer.close(loadIndex);
layui.each(signinItems, function(index, item){
var html = laytpl(tplSigninTop).render({
data: res.data[index]
,index: index
});
$(item).html(html);
});
layer.open({
type: 1
,title: '签到活跃榜 - TOP 20'
,area: '300px'
,shade: 0.8
,shadeClose: true
,id: 'layer-pop-signintop'
,content: tpl.prop('outerHTML')
});
}, {type: 'get'});
});
//回帖榜
//活跃榜
var tplReply = ['{{# layui.each(d.data, function(index, item){ }}'
,'<dd>'
,'<a href="{{item.uid}}">'
,'<img src="{{item.user.avatar}}">'
,'<cite>{{item.user.username}}</cite>'
,'<i>{{item["count(*)"]}}' +replyNum+'</i>'
,'<i>{{item["count"]}}' + replyNum + '</i>'
,'</a>'
,'</dd>'
,'{{# }); }}'].join('')
,elemReply = $('#LAY_replyRank');
var replyUrl = elemReply.attr('data-url');
if(elemReply[0]){
fly.json(replyUrl, {
limit: 20
}, function(res){
var html = laytpl(tplReply).render(res);
elemReply.find('dl').html(html);
});
};
//相册
@ -930,16 +771,18 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
//搜索
$('.fly-search').on('click', function(){
$('.fly-search').on('click', function(data){
var searchUrl = $('.fly-search').attr('data-url');
var forms = '<form action='+ searchUrl + '>';
layer.open({
type: 1
,title: false
,closeBtn: false
//,shade: [0.1, '#fff']
,shade: [0.1, '#fff']
,shadeClose: true
,maxWidth: 10000
,skin: 'fly-layer-search'
,content: ['<form action='+searchUrl+'>'
,content: [forms
,'<input autocomplete="off" placeholder="搜索内容,回车跳转" type="text" name="keywords">'
,'</form>'].join('')
,success: function(layero){
@ -1030,7 +873,7 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
elem: '.fly-editor'
});
//手机设备的简单适配 底部左侧栏导航
//手机设备的简单适配 用户中心底部左侧栏导航
var treeMobile = $('.site-tree-mobile')
,shadeMobile = $('.site-mobile-shade')
@ -1136,6 +979,7 @@ layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util', 'imgcom'],
});
return false;
});
//移动端左侧栏监听多语言切换
$('#language1').on('change',function(){
var data = $(this).val();

View File

@ -75,34 +75,34 @@ layui.define('fly', function(exports){
//删帖子
del: function(div){
layer.confirm('确认删除该贴么?', function(index){
layer.close(index);
$.ajax({
type:'get',
url:articleDelete,
data:{id: div.data('id')},
dataType:'json',
success:function(data){
if(data.code == 0){
layer.msg(data.msg,{
icon:6,
time:2000
},function(){
location.href = '/';
});
} else {
layer.open({
title:'删除失败',
content:data.msg,
icon:5,
adim:6
})
}
}
});
layer.close(index);
$.ajax({
type:'get',
url:articleDelete,
data:{id: div.data('id')},
dataType:'json',
success:function(data){
if(data.code == 0){
layer.msg(data.msg,{
icon:6,
time:2000
},function(){
location.href = '/';
});
} else {
layer.open({
title:'删除失败',
content:data.msg,
icon:5,
adim:6
})
}
}
});
});
}
//设置置顶、加精、禁评、状态
// 设置置顶、加精、禁评、状态
,set: function(div){
var othis = $(this);
fly.json(articleJieset, {
@ -111,13 +111,13 @@ layui.define('fly', function(exports){
,field: othis.attr('field')
}, function(res){
if(res.status === 0){
layer.msg(res.msg);
location.reload();
}
layer.msg(res.msg);
location.reload();
}
});
}
//收藏
// 收藏
,collect: function(div){
var othis = $(this), type = othis.data('type');
fly.json(collection+ type +'/', {

View File

@ -33,34 +33,34 @@ layui.define(['laypage', 'fly', 'element', 'flow', 'imgcom'], function(exports){
var post = table.render({
elem: '#art-post'
,url: artListUrl
,title: ''
,title: ''
,cols: [[
{type: 'numbers', fixed: 'left'}
,{field: 'title', title: '标题',minWidth: 250 ,templet: '<div><a href="{{d.url}}" target="_blank">{{d.title}}</a></div>'}
,{field: 'status', title: '状态', width: 80}
,{field: 'ctime', title: '时间', width: 120}
,{field: 'title', title: '标题',minWidth: 250 ,templet: '<div><a href="{{d.url}}" target="_blank">{{-d.title}}</a></div>'}
,{field: 'status', title: '状态', width: 80}
,{field: 'ctime', title: '时间', width: 120}
,{field: 'datas', title: '数据', width: 120}
,{title: '操作', width: 150, align: 'center', toolbar: '#artTool'}
]]
,text: '对不起,加载出现异常!'
,page: true
,page: true
});
//收藏list
table.render({
elem: '#coll-post'
,url: collListUrl
,title: ''
,title: ''
,cols: [[
{type: 'numbers', fixed: 'left'}
,{field: 'title', title: '标题',minWidth: 250,templet: '<div><a href="{{d.url}}" target="_blank">{{d.title}}</a></div>'}
,{field: 'auther', title: '作者', width: 120}
,{field: 'status', title: '状态', width: 80}
,{field: 'ctime', title: '时间', width: 120}
,{field: 'auther', title: '作者', width: 120}
,{field: 'status', title: '状态', width: 80}
,{field: 'ctime', title: '时间', width: 120}
,{title: '取消', width: 80, align: 'center', toolbar: '#collTool'}
]]
,text: '对不起,加载出现异常!'
,page: true
,page: true
});
//监听行工具事件
@ -68,33 +68,24 @@ layui.define(['laypage', 'fly', 'element', 'flow', 'imgcom'], function(exports){
var data = obj.data;
var id = data.id;
if(obj.event === 'del'){
layer.confirm('确定删除吗?',{
title:'删除文章',
icon:3
},function(index){
layer.close(index);
$.post(atrDelUrl,{"id":id},function(data){
if(data.code == 0){
layer.msg(data.msg,{
icon:6,
time:2000
});
} else {
layer.open({
title:'删除失败',
content:data.msg,
icon:5,
adim:6
})
}
}
);
table.reload('art-post');
});
layer.confirm('确定删除吗?',{
title:'删除文章',
icon:3
},function(index){
layer.close(index);
$.post(atrDelUrl,{"id":id},function(data){
if(data.code == 0){
layer.msg(data.msg,{icon:6,time:2000});
} else {
layer.open({title:'删除失败',content:data.msg,icon:5,adim:6})
}
}
);
table.reload('art-post');
});
} else if(obj.event === 'edit'){//编辑
$.post(artEditUrl,{"id":id},function(){
location.href = artEditUrl + '?id=' + id;
location.href = artEditUrl + '?id=' + id;
});
}
@ -141,14 +132,14 @@ layui.define(['laypage', 'fly', 'element', 'flow', 'imgcom'], function(exports){
location.hash = layid;
}
});
/*
//根据ip获取城市
if($('#L_city').val() === ''){
$.getScript('http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js', function(){
$('#L_city').val(remote_ip_info.city||'');
});
}
*/
//上传图片
if($('.upload-img')[0]){
layui.use('upload', function(upload){
@ -156,27 +147,25 @@ layui.define(['laypage', 'fly', 'element', 'flow', 'imgcom'], function(exports){
upload.render({
elem: '.upload-img'
,accept: 'images'
,acceptMime: 'image/*'
,exts: 'jpg|png|gif|bmp|jpeg'
,accept: 'images'
,acceptMime: 'image/*'
,exts: 'jpg|png|gif|bmp|jpeg'
,url: uploadHeadImg
,size: 10240
,auto: false
,choose: function (obj) { //选择文件后的回调
,auto: false
,choose: function (obj) { //选择文件后的回调
imgcom.uploads(obj);
}
,before: function(){
avatarAdd.find('.loading').show();
}
,done: function(res){
if(res.status == 0){
$.post(userSet, {
avatar: res.url
}, function(res){
if(res.code == 0){
layer.msg(res.msg, { icon: 6, time: 2000 },function(){
location.reload();
});
} else {
layer.msg(res.msg, {icon: 5});
layer.open({ content: data.msg, icon: 5, adim: 6 });
}
avatarAdd.find('.loading').hide();
}

2
runtime/.gitignore vendored
View File

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

5
vendor/autoload.php vendored
View File

@ -2,6 +2,11 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
exit(1);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit1b32198725235c8d6500c87262ef30c2::getLoader();

22
vendor/bacon/bacon-qr-code/LICENSE vendored Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2017, Ben Scholzen 'DASPRiD'
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

39
vendor/bacon/bacon-qr-code/README.md vendored Normal file
View File

@ -0,0 +1,39 @@
# QR Code generator
[![PHP CI](https://github.com/Bacon/BaconQrCode/actions/workflows/ci.yml/badge.svg)](https://github.com/Bacon/BaconQrCode/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/Bacon/BaconQrCode/branch/master/graph/badge.svg?token=rD0HcAiEEx)](https://codecov.io/gh/Bacon/BaconQrCode)
[![Latest Stable Version](https://poser.pugx.org/bacon/bacon-qr-code/v/stable)](https://packagist.org/packages/bacon/bacon-qr-code)
[![Total Downloads](https://poser.pugx.org/bacon/bacon-qr-code/downloads)](https://packagist.org/packages/bacon/bacon-qr-code)
[![License](https://poser.pugx.org/bacon/bacon-qr-code/license)](https://packagist.org/packages/bacon/bacon-qr-code)
## Introduction
BaconQrCode is a port of QR code portion of the ZXing library. It currently
only features the encoder part, but could later receive the decoder part as
well.
As the Reed Solomon codec implementation of the ZXing library performs quite
slow in PHP, it was exchanged with the implementation by Phil Karn.
## Example usage
```php
use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer;
$renderer = new ImageRenderer(
new RendererStyle(400),
new ImagickImageBackEnd()
);
$writer = new Writer($renderer);
$writer->writeFile('Hello World!', 'qrcode.png');
```
## Available image renderer back ends
BaconQrCode comes with multiple back ends for rendering images. Currently included are the following:
- `ImagickImageBackEnd`: renders raster images using the Imagick library
- `SvgImageBackEnd`: renders SVG files using XMLWriter
- `EpsImageBackEnd`: renders EPS files

View File

@ -0,0 +1,38 @@
{
"name": "bacon/bacon-qr-code",
"description": "BaconQrCode is a QR code generator for PHP.",
"license" : "BSD-2-Clause",
"homepage": "https://github.com/Bacon/BaconQrCode",
"require": {
"php": "^7.1 || ^8.0",
"ext-iconv": "*",
"dasprid/enum": "^1.0.3"
},
"suggest": {
"ext-imagick": "to generate QR code images"
},
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/",
"role": "Developer"
}
],
"autoload": {
"psr-4": {
"BaconQrCode\\": "src/"
}
},
"require-dev": {
"phpunit/phpunit": "^7 | ^8 | ^9",
"spatie/phpunit-snapshot-assertions": "^4.2.9",
"squizlabs/php_codesniffer": "^3.4",
"phly/keep-a-changelog": "^2.1"
},
"config": {
"allow-plugins": {
"ocramius/package-versions": true
}
}
}

View File

@ -0,0 +1,372 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
use BaconQrCode\Exception\InvalidArgumentException;
use SplFixedArray;
/**
* A simple, fast array of bits.
*/
final class BitArray
{
/**
* Bits represented as an array of integers.
*
* @var SplFixedArray<int>
*/
private $bits;
/**
* Size of the bit array in bits.
*
* @var int
*/
private $size;
/**
* Creates a new bit array with a given size.
*/
public function __construct(int $size = 0)
{
$this->size = $size;
$this->bits = SplFixedArray::fromArray(array_fill(0, ($this->size + 31) >> 3, 0));
}
/**
* Gets the size in bits.
*/
public function getSize() : int
{
return $this->size;
}
/**
* Gets the size in bytes.
*/
public function getSizeInBytes() : int
{
return ($this->size + 7) >> 3;
}
/**
* Ensures that the array has a minimum capacity.
*/
public function ensureCapacity(int $size) : void
{
if ($size > count($this->bits) << 5) {
$this->bits->setSize(($size + 31) >> 5);
}
}
/**
* Gets a specific bit.
*/
public function get(int $i) : bool
{
return 0 !== ($this->bits[$i >> 5] & (1 << ($i & 0x1f)));
}
/**
* Sets a specific bit.
*/
public function set(int $i) : void
{
$this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f);
}
/**
* Flips a specific bit.
*/
public function flip(int $i) : void
{
$this->bits[$i >> 5] ^= 1 << ($i & 0x1f);
}
/**
* Gets the next set bit position from a given position.
*/
public function getNextSet(int $from) : int
{
if ($from >= $this->size) {
return $this->size;
}
$bitsOffset = $from >> 5;
$currentBits = $this->bits[$bitsOffset];
$bitsLength = count($this->bits);
$currentBits &= ~((1 << ($from & 0x1f)) - 1);
while (0 === $currentBits) {
if (++$bitsOffset === $bitsLength) {
return $this->size;
}
$currentBits = $this->bits[$bitsOffset];
}
$result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits);
return $result > $this->size ? $this->size : $result;
}
/**
* Gets the next unset bit position from a given position.
*/
public function getNextUnset(int $from) : int
{
if ($from >= $this->size) {
return $this->size;
}
$bitsOffset = $from >> 5;
$currentBits = ~$this->bits[$bitsOffset];
$bitsLength = count($this->bits);
$currentBits &= ~((1 << ($from & 0x1f)) - 1);
while (0 === $currentBits) {
if (++$bitsOffset === $bitsLength) {
return $this->size;
}
$currentBits = ~$this->bits[$bitsOffset];
}
$result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits);
return $result > $this->size ? $this->size : $result;
}
/**
* Sets a bulk of bits.
*/
public function setBulk(int $i, int $newBits) : void
{
$this->bits[$i >> 5] = $newBits;
}
/**
* Sets a range of bits.
*
* @throws InvalidArgumentException if end is smaller than start
*/
public function setRange(int $start, int $end) : void
{
if ($end < $start) {
throw new InvalidArgumentException('End must be greater or equal to start');
}
if ($end === $start) {
return;
}
--$end;
$firstInt = $start >> 5;
$lastInt = $end >> 5;
for ($i = $firstInt; $i <= $lastInt; ++$i) {
$firstBit = $i > $firstInt ? 0 : $start & 0x1f;
$lastBit = $i < $lastInt ? 31 : $end & 0x1f;
if (0 === $firstBit && 31 === $lastBit) {
$mask = 0x7fffffff;
} else {
$mask = 0;
for ($j = $firstBit; $j < $lastBit; ++$j) {
$mask |= 1 << $j;
}
}
$this->bits[$i] = $this->bits[$i] | $mask;
}
}
/**
* Clears the bit array, unsetting every bit.
*/
public function clear() : void
{
$bitsLength = count($this->bits);
for ($i = 0; $i < $bitsLength; ++$i) {
$this->bits[$i] = 0;
}
}
/**
* Checks if a range of bits is set or not set.
* @throws InvalidArgumentException if end is smaller than start
*/
public function isRange(int $start, int $end, bool $value) : bool
{
if ($end < $start) {
throw new InvalidArgumentException('End must be greater or equal to start');
}
if ($end === $start) {
return true;
}
--$end;
$firstInt = $start >> 5;
$lastInt = $end >> 5;
for ($i = $firstInt; $i <= $lastInt; ++$i) {
$firstBit = $i > $firstInt ? 0 : $start & 0x1f;
$lastBit = $i < $lastInt ? 31 : $end & 0x1f;
if (0 === $firstBit && 31 === $lastBit) {
$mask = 0x7fffffff;
} else {
$mask = 0;
for ($j = $firstBit; $j <= $lastBit; ++$j) {
$mask |= 1 << $j;
}
}
if (($this->bits[$i] & $mask) !== ($value ? $mask : 0)) {
return false;
}
}
return true;
}
/**
* Appends a bit to the array.
*/
public function appendBit(bool $bit) : void
{
$this->ensureCapacity($this->size + 1);
if ($bit) {
$this->bits[$this->size >> 5] = $this->bits[$this->size >> 5] | (1 << ($this->size & 0x1f));
}
++$this->size;
}
/**
* Appends a number of bits (up to 32) to the array.
* @throws InvalidArgumentException if num bits is not between 0 and 32
*/
public function appendBits(int $value, int $numBits) : void
{
if ($numBits < 0 || $numBits > 32) {
throw new InvalidArgumentException('Num bits must be between 0 and 32');
}
$this->ensureCapacity($this->size + $numBits);
for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) {
$this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) === 1);
}
}
/**
* Appends another bit array to this array.
*/
public function appendBitArray(self $other) : void
{
$otherSize = $other->getSize();
$this->ensureCapacity($this->size + $other->getSize());
for ($i = 0; $i < $otherSize; ++$i) {
$this->appendBit($other->get($i));
}
}
/**
* Makes an exclusive-or comparision on the current bit array.
*
* @throws InvalidArgumentException if sizes don't match
*/
public function xorBits(self $other) : void
{
$bitsLength = count($this->bits);
$otherBits = $other->getBitArray();
if ($bitsLength !== count($otherBits)) {
throw new InvalidArgumentException('Sizes don\'t match');
}
for ($i = 0; $i < $bitsLength; ++$i) {
$this->bits[$i] = $this->bits[$i] ^ $otherBits[$i];
}
}
/**
* Converts the bit array to a byte array.
*
* @return SplFixedArray<int>
*/
public function toBytes(int $bitOffset, int $numBytes) : SplFixedArray
{
$bytes = new SplFixedArray($numBytes);
for ($i = 0; $i < $numBytes; ++$i) {
$byte = 0;
for ($j = 0; $j < 8; ++$j) {
if ($this->get($bitOffset)) {
$byte |= 1 << (7 - $j);
}
++$bitOffset;
}
$bytes[$i] = $byte;
}
return $bytes;
}
/**
* Gets the internal bit array.
*
* @return SplFixedArray<int>
*/
public function getBitArray() : SplFixedArray
{
return $this->bits;
}
/**
* Reverses the array.
*/
public function reverse() : void
{
$newBits = new SplFixedArray(count($this->bits));
for ($i = 0; $i < $this->size; ++$i) {
if ($this->get($this->size - $i - 1)) {
$newBits[$i >> 5] = $newBits[$i >> 5] | (1 << ($i & 0x1f));
}
}
$this->bits = $newBits;
}
/**
* Returns a string representation of the bit array.
*/
public function __toString() : string
{
$result = '';
for ($i = 0; $i < $this->size; ++$i) {
if (0 === ($i & 0x07)) {
$result .= ' ';
}
$result .= $this->get($i) ? 'X' : '.';
}
return $result;
}
}

View File

@ -0,0 +1,313 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
use BaconQrCode\Exception\InvalidArgumentException;
use SplFixedArray;
/**
* Bit matrix.
*
* Represents a 2D matrix of bits. In function arguments below, and throughout
* the common module, x is the column position, and y is the row position. The
* ordering is always x, y. The origin is at the top-left.
*/
class BitMatrix
{
/**
* Width of the bit matrix.
*
* @var int
*/
private $width;
/**
* Height of the bit matrix.
*
* @var int
*/
private $height;
/**
* Size in bits of each individual row.
*
* @var int
*/
private $rowSize;
/**
* Bits representation.
*
* @var SplFixedArray<int>
*/
private $bits;
/**
* @throws InvalidArgumentException if a dimension is smaller than zero
*/
public function __construct(int $width, int $height = null)
{
if (null === $height) {
$height = $width;
}
if ($width < 1 || $height < 1) {
throw new InvalidArgumentException('Both dimensions must be greater than zero');
}
$this->width = $width;
$this->height = $height;
$this->rowSize = ($width + 31) >> 5;
$this->bits = SplFixedArray::fromArray(array_fill(0, $this->rowSize * $height, 0));
}
/**
* Gets the requested bit, where true means black.
*/
public function get(int $x, int $y) : bool
{
$offset = $y * $this->rowSize + ($x >> 5);
return 0 !== (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1);
}
/**
* Sets the given bit to true.
*/
public function set(int $x, int $y) : void
{
$offset = $y * $this->rowSize + ($x >> 5);
$this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f));
}
/**
* Flips the given bit.
*/
public function flip(int $x, int $y) : void
{
$offset = $y * $this->rowSize + ($x >> 5);
$this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f));
}
/**
* Clears all bits (set to false).
*/
public function clear() : void
{
$max = count($this->bits);
for ($i = 0; $i < $max; ++$i) {
$this->bits[$i] = 0;
}
}
/**
* Sets a square region of the bit matrix to true.
*
* @throws InvalidArgumentException if left or top are negative
* @throws InvalidArgumentException if width or height are smaller than 1
* @throws InvalidArgumentException if region does not fit into the matix
*/
public function setRegion(int $left, int $top, int $width, int $height) : void
{
if ($top < 0 || $left < 0) {
throw new InvalidArgumentException('Left and top must be non-negative');
}
if ($height < 1 || $width < 1) {
throw new InvalidArgumentException('Width and height must be at least 1');
}
$right = $left + $width;
$bottom = $top + $height;
if ($bottom > $this->height || $right > $this->width) {
throw new InvalidArgumentException('The region must fit inside the matrix');
}
for ($y = $top; $y < $bottom; ++$y) {
$offset = $y * $this->rowSize;
for ($x = $left; $x < $right; ++$x) {
$index = $offset + ($x >> 5);
$this->bits[$index] = $this->bits[$index] | (1 << ($x & 0x1f));
}
}
}
/**
* A fast method to retrieve one row of data from the matrix as a BitArray.
*/
public function getRow(int $y, BitArray $row = null) : BitArray
{
if (null === $row || $row->getSize() < $this->width) {
$row = new BitArray($this->width);
}
$offset = $y * $this->rowSize;
for ($x = 0; $x < $this->rowSize; ++$x) {
$row->setBulk($x << 5, $this->bits[$offset + $x]);
}
return $row;
}
/**
* Sets a row of data from a BitArray.
*/
public function setRow(int $y, BitArray $row) : void
{
$bits = $row->getBitArray();
for ($i = 0; $i < $this->rowSize; ++$i) {
$this->bits[$y * $this->rowSize + $i] = $bits[$i];
}
}
/**
* This is useful in detecting the enclosing rectangle of a 'pure' barcode.
*
* @return int[]|null
*/
public function getEnclosingRectangle() : ?array
{
$left = $this->width;
$top = $this->height;
$right = -1;
$bottom = -1;
for ($y = 0; $y < $this->height; ++$y) {
for ($x32 = 0; $x32 < $this->rowSize; ++$x32) {
$bits = $this->bits[$y * $this->rowSize + $x32];
if (0 !== $bits) {
if ($y < $top) {
$top = $y;
}
if ($y > $bottom) {
$bottom = $y;
}
if ($x32 * 32 < $left) {
$bit = 0;
while (($bits << (31 - $bit)) === 0) {
$bit++;
}
if (($x32 * 32 + $bit) < $left) {
$left = $x32 * 32 + $bit;
}
}
}
if ($x32 * 32 + 31 > $right) {
$bit = 31;
while (0 === BitUtils::unsignedRightShift($bits, $bit)) {
--$bit;
}
if (($x32 * 32 + $bit) > $right) {
$right = $x32 * 32 + $bit;
}
}
}
}
$width = $right - $left;
$height = $bottom - $top;
if ($width < 0 || $height < 0) {
return null;
}
return [$left, $top, $width, $height];
}
/**
* Gets the most top left set bit.
*
* This is useful in detecting a corner of a 'pure' barcode.
*
* @return int[]|null
*/
public function getTopLeftOnBit() : ?array
{
$bitsOffset = 0;
while ($bitsOffset < count($this->bits) && 0 === $this->bits[$bitsOffset]) {
++$bitsOffset;
}
if (count($this->bits) === $bitsOffset) {
return null;
}
$x = intdiv($bitsOffset, $this->rowSize);
$y = ($bitsOffset % $this->rowSize) << 5;
$bits = $this->bits[$bitsOffset];
$bit = 0;
while (0 === ($bits << (31 - $bit))) {
++$bit;
}
$x += $bit;
return [$x, $y];
}
/**
* Gets the most bottom right set bit.
*
* This is useful in detecting a corner of a 'pure' barcode.
*
* @return int[]|null
*/
public function getBottomRightOnBit() : ?array
{
$bitsOffset = count($this->bits) - 1;
while ($bitsOffset >= 0 && 0 === $this->bits[$bitsOffset]) {
--$bitsOffset;
}
if ($bitsOffset < 0) {
return null;
}
$x = intdiv($bitsOffset, $this->rowSize);
$y = ($bitsOffset % $this->rowSize) << 5;
$bits = $this->bits[$bitsOffset];
$bit = 0;
while (0 === BitUtils::unsignedRightShift($bits, $bit)) {
--$bit;
}
$x += $bit;
return [$x, $y];
}
/**
* Gets the width of the matrix,
*/
public function getWidth() : int
{
return $this->width;
}
/**
* Gets the height of the matrix.
*/
public function getHeight() : int
{
return $this->height;
}
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
/**
* General bit utilities.
*
* All utility methods are based on 32-bit integers and also work on 64-bit
* systems.
*/
final class BitUtils
{
private function __construct()
{
}
/**
* Performs an unsigned right shift.
*
* This is the same as the unsigned right shift operator ">>>" in other
* languages.
*/
public static function unsignedRightShift(int $a, int $b) : int
{
return (
$a >= 0
? $a >> $b
: (($a & 0x7fffffff) >> $b) | (0x40000000 >> ($b - 1))
);
}
/**
* Gets the number of trailing zeros.
*/
public static function numberOfTrailingZeros(int $i) : int
{
$lastPos = strrpos(str_pad(decbin($i), 32, '0', STR_PAD_LEFT), '1');
return $lastPos === false ? 32 : 31 - $lastPos;
}
}

View File

@ -0,0 +1,180 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
use BaconQrCode\Exception\InvalidArgumentException;
use DASPRiD\Enum\AbstractEnum;
/**
* Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 of ISO 18004.
*
* @method static self CP437()
* @method static self ISO8859_1()
* @method static self ISO8859_2()
* @method static self ISO8859_3()
* @method static self ISO8859_4()
* @method static self ISO8859_5()
* @method static self ISO8859_6()
* @method static self ISO8859_7()
* @method static self ISO8859_8()
* @method static self ISO8859_9()
* @method static self ISO8859_10()
* @method static self ISO8859_11()
* @method static self ISO8859_12()
* @method static self ISO8859_13()
* @method static self ISO8859_14()
* @method static self ISO8859_15()
* @method static self ISO8859_16()
* @method static self SJIS()
* @method static self CP1250()
* @method static self CP1251()
* @method static self CP1252()
* @method static self CP1256()
* @method static self UNICODE_BIG_UNMARKED()
* @method static self UTF8()
* @method static self ASCII()
* @method static self BIG5()
* @method static self GB18030()
* @method static self EUC_KR()
*/
final class CharacterSetEci extends AbstractEnum
{
protected const CP437 = [[0, 2]];
protected const ISO8859_1 = [[1, 3], 'ISO-8859-1'];
protected const ISO8859_2 = [[4], 'ISO-8859-2'];
protected const ISO8859_3 = [[5], 'ISO-8859-3'];
protected const ISO8859_4 = [[6], 'ISO-8859-4'];
protected const ISO8859_5 = [[7], 'ISO-8859-5'];
protected const ISO8859_6 = [[8], 'ISO-8859-6'];
protected const ISO8859_7 = [[9], 'ISO-8859-7'];
protected const ISO8859_8 = [[10], 'ISO-8859-8'];
protected const ISO8859_9 = [[11], 'ISO-8859-9'];
protected const ISO8859_10 = [[12], 'ISO-8859-10'];
protected const ISO8859_11 = [[13], 'ISO-8859-11'];
protected const ISO8859_12 = [[14], 'ISO-8859-12'];
protected const ISO8859_13 = [[15], 'ISO-8859-13'];
protected const ISO8859_14 = [[16], 'ISO-8859-14'];
protected const ISO8859_15 = [[17], 'ISO-8859-15'];
protected const ISO8859_16 = [[18], 'ISO-8859-16'];
protected const SJIS = [[20], 'Shift_JIS'];
protected const CP1250 = [[21], 'windows-1250'];
protected const CP1251 = [[22], 'windows-1251'];
protected const CP1252 = [[23], 'windows-1252'];
protected const CP1256 = [[24], 'windows-1256'];
protected const UNICODE_BIG_UNMARKED = [[25], 'UTF-16BE', 'UnicodeBig'];
protected const UTF8 = [[26], 'UTF-8'];
protected const ASCII = [[27, 170], 'US-ASCII'];
protected const BIG5 = [[28]];
protected const GB18030 = [[29], 'GB2312', 'EUC_CN', 'GBK'];
protected const EUC_KR = [[30], 'EUC-KR'];
/**
* @var int[]
*/
private $values;
/**
* @var string[]
*/
private $otherEncodingNames;
/**
* @var array<int, self>|null
*/
private static $valueToEci;
/**
* @var array<string, self>|null
*/
private static $nameToEci;
public function __construct(array $values, string ...$otherEncodingNames)
{
$this->values = $values;
$this->otherEncodingNames = $otherEncodingNames;
}
/**
* Returns the primary value.
*/
public function getValue() : int
{
return $this->values[0];
}
/**
* Gets character set ECI by value.
*
* Returns the representing ECI of a given value, or null if it is legal but unsupported.
*
* @throws InvalidArgumentException if value is not between 0 and 900
*/
public static function getCharacterSetEciByValue(int $value) : ?self
{
if ($value < 0 || $value >= 900) {
throw new InvalidArgumentException('Value must be between 0 and 900');
}
$valueToEci = self::valueToEci();
if (! array_key_exists($value, $valueToEci)) {
return null;
}
return $valueToEci[$value];
}
/**
* Returns character set ECI by name.
*
* Returns the representing ECI of a given name, or null if it is legal but unsupported
*/
public static function getCharacterSetEciByName(string $name) : ?self
{
$nameToEci = self::nameToEci();
$name = strtolower($name);
if (! array_key_exists($name, $nameToEci)) {
return null;
}
return $nameToEci[$name];
}
private static function valueToEci() : array
{
if (null !== self::$valueToEci) {
return self::$valueToEci;
}
self::$valueToEci = [];
foreach (self::values() as $eci) {
foreach ($eci->values as $value) {
self::$valueToEci[$value] = $eci;
}
}
return self::$valueToEci;
}
private static function nameToEci() : array
{
if (null !== self::$nameToEci) {
return self::$nameToEci;
}
self::$nameToEci = [];
foreach (self::values() as $eci) {
self::$nameToEci[strtolower($eci->name())] = $eci;
foreach ($eci->otherEncodingNames as $name) {
self::$nameToEci[strtolower($name)] = $eci;
}
}
return self::$nameToEci;
}
}

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
/**
* Encapsulates the parameters for one error-correction block in one symbol version.
*
* This includes the number of data codewords, and the number of times a block with these parameters is used
* consecutively in the QR code version's format.
*/
final class EcBlock
{
/**
* How many times the block is used.
*
* @var int
*/
private $count;
/**
* Number of data codewords.
*
* @var int
*/
private $dataCodewords;
public function __construct(int $count, int $dataCodewords)
{
$this->count = $count;
$this->dataCodewords = $dataCodewords;
}
/**
* Returns how many times the block is used.
*/
public function getCount() : int
{
return $this->count;
}
/**
* Returns the number of data codewords.
*/
public function getDataCodewords() : int
{
return $this->dataCodewords;
}
}

View File

@ -0,0 +1,74 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
/**
* Encapsulates a set of error-correction blocks in one symbol version.
*
* Most versions will use blocks of differing sizes within one version, so, this encapsulates the parameters for each
* set of blocks. It also holds the number of error-correction codewords per block since it will be the same across all
* blocks within one version.
*/
final class EcBlocks
{
/**
* Number of EC codewords per block.
*
* @var int
*/
private $ecCodewordsPerBlock;
/**
* List of EC blocks.
*
* @var EcBlock[]
*/
private $ecBlocks;
public function __construct(int $ecCodewordsPerBlock, EcBlock ...$ecBlocks)
{
$this->ecCodewordsPerBlock = $ecCodewordsPerBlock;
$this->ecBlocks = $ecBlocks;
}
/**
* Returns the number of EC codewords per block.
*/
public function getEcCodewordsPerBlock() : int
{
return $this->ecCodewordsPerBlock;
}
/**
* Returns the total number of EC block appearances.
*/
public function getNumBlocks() : int
{
$total = 0;
foreach ($this->ecBlocks as $ecBlock) {
$total += $ecBlock->getCount();
}
return $total;
}
/**
* Returns the total count of EC codewords.
*/
public function getTotalEcCodewords() : int
{
return $this->ecCodewordsPerBlock * $this->getNumBlocks();
}
/**
* Returns the EC blocks included in this collection.
*
* @return EcBlock[]
*/
public function getEcBlocks() : array
{
return $this->ecBlocks;
}
}

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
use BaconQrCode\Exception\OutOfBoundsException;
use DASPRiD\Enum\AbstractEnum;
/**
* Enum representing the four error correction levels.
*
* @method static self L() ~7% correction
* @method static self M() ~15% correction
* @method static self Q() ~25% correction
* @method static self H() ~30% correction
*/
final class ErrorCorrectionLevel extends AbstractEnum
{
protected const L = [0x01];
protected const M = [0x00];
protected const Q = [0x03];
protected const H = [0x02];
/**
* @var int
*/
private $bits;
protected function __construct(int $bits)
{
$this->bits = $bits;
}
/**
* @throws OutOfBoundsException if number of bits is invalid
*/
public static function forBits(int $bits) : self
{
switch ($bits) {
case 0:
return self::M();
case 1:
return self::L();
case 2:
return self::H();
case 3:
return self::Q();
}
throw new OutOfBoundsException('Invalid number of bits');
}
/**
* Returns the two bits used to encode this error correction level.
*/
public function getBits() : int
{
return $this->bits;
}
}

View File

@ -0,0 +1,203 @@
<?php
/**
* BaconQrCode
*
* @link http://github.com/Bacon/BaconQrCode For the canonical source repository
* @copyright 2013 Ben 'DASPRiD' Scholzen
* @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
*/
namespace BaconQrCode\Common;
/**
* Encapsulates a QR Code's format information, including the data mask used and error correction level.
*/
class FormatInformation
{
/**
* Mask for format information.
*/
private const FORMAT_INFO_MASK_QR = 0x5412;
/**
* Lookup table for decoding format information.
*
* See ISO 18004:2006, Annex C, Table C.1
*/
private const FORMAT_INFO_DECODE_LOOKUP = [
[0x5412, 0x00],
[0x5125, 0x01],
[0x5e7c, 0x02],
[0x5b4b, 0x03],
[0x45f9, 0x04],
[0x40ce, 0x05],
[0x4f97, 0x06],
[0x4aa0, 0x07],
[0x77c4, 0x08],
[0x72f3, 0x09],
[0x7daa, 0x0a],
[0x789d, 0x0b],
[0x662f, 0x0c],
[0x6318, 0x0d],
[0x6c41, 0x0e],
[0x6976, 0x0f],
[0x1689, 0x10],
[0x13be, 0x11],
[0x1ce7, 0x12],
[0x19d0, 0x13],
[0x0762, 0x14],
[0x0255, 0x15],
[0x0d0c, 0x16],
[0x083b, 0x17],
[0x355f, 0x18],
[0x3068, 0x19],
[0x3f31, 0x1a],
[0x3a06, 0x1b],
[0x24b4, 0x1c],
[0x2183, 0x1d],
[0x2eda, 0x1e],
[0x2bed, 0x1f],
];
/**
* Offset i holds the number of 1 bits in the binary representation of i.
*
* @var array
*/
private const BITS_SET_IN_HALF_BYTE = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4];
/**
* Error correction level.
*
* @var ErrorCorrectionLevel
*/
private $ecLevel;
/**
* Data mask.
*
* @var int
*/
private $dataMask;
protected function __construct(int $formatInfo)
{
$this->ecLevel = ErrorCorrectionLevel::forBits(($formatInfo >> 3) & 0x3);
$this->dataMask = $formatInfo & 0x7;
}
/**
* Checks how many bits are different between two integers.
*/
public static function numBitsDiffering(int $a, int $b) : int
{
$a ^= $b;
return (
self::BITS_SET_IN_HALF_BYTE[$a & 0xf]
+ self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 4) & 0xf)]
+ self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 8) & 0xf)]
+ self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 12) & 0xf)]
+ self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 16) & 0xf)]
+ self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 20) & 0xf)]
+ self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 24) & 0xf)]
+ self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 28) & 0xf)]
);
}
/**
* Decodes format information.
*/
public static function decodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self
{
$formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2);
if (null !== $formatInfo) {
return $formatInfo;
}
// Should return null, but, some QR codes apparently do not mask this info. Try again by actually masking the
// pattern first.
return self::doDecodeFormatInformation(
$maskedFormatInfo1 ^ self::FORMAT_INFO_MASK_QR,
$maskedFormatInfo2 ^ self::FORMAT_INFO_MASK_QR
);
}
/**
* Internal method for decoding format information.
*/
private static function doDecodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self
{
$bestDifference = PHP_INT_MAX;
$bestFormatInfo = 0;
foreach (self::FORMAT_INFO_DECODE_LOOKUP as $decodeInfo) {
$targetInfo = $decodeInfo[0];
if ($targetInfo === $maskedFormatInfo1 || $targetInfo === $maskedFormatInfo2) {
// Found an exact match
return new self($decodeInfo[1]);
}
$bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo);
if ($bitsDifference < $bestDifference) {
$bestFormatInfo = $decodeInfo[1];
$bestDifference = $bitsDifference;
}
if ($maskedFormatInfo1 !== $maskedFormatInfo2) {
// Also try the other option
$bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo);
if ($bitsDifference < $bestDifference) {
$bestFormatInfo = $decodeInfo[1];
$bestDifference = $bitsDifference;
}
}
}
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match.
if ($bestDifference <= 3) {
return new self($bestFormatInfo);
}
return null;
}
/**
* Returns the error correction level.
*/
public function getErrorCorrectionLevel() : ErrorCorrectionLevel
{
return $this->ecLevel;
}
/**
* Returns the data mask.
*/
public function getDataMask() : int
{
return $this->dataMask;
}
/**
* Hashes the code of the EC level.
*/
public function hashCode() : int
{
return ($this->ecLevel->getBits() << 3) | $this->dataMask;
}
/**
* Verifies if this instance equals another one.
*/
public function equals(self $other) : bool
{
return (
$this->ecLevel === $other->ecLevel
&& $this->dataMask === $other->dataMask
);
}
}

View File

@ -0,0 +1,76 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
use DASPRiD\Enum\AbstractEnum;
/**
* Enum representing various modes in which data can be encoded to bits.
*
* @method static self TERMINATOR()
* @method static self NUMERIC()
* @method static self ALPHANUMERIC()
* @method static self STRUCTURED_APPEND()
* @method static self BYTE()
* @method static self ECI()
* @method static self KANJI()
* @method static self FNC1_FIRST_POSITION()
* @method static self FNC1_SECOND_POSITION()
* @method static self HANZI()
*/
final class Mode extends AbstractEnum
{
protected const TERMINATOR = [[0, 0, 0], 0x00];
protected const NUMERIC = [[10, 12, 14], 0x01];
protected const ALPHANUMERIC = [[9, 11, 13], 0x02];
protected const STRUCTURED_APPEND = [[0, 0, 0], 0x03];
protected const BYTE = [[8, 16, 16], 0x04];
protected const ECI = [[0, 0, 0], 0x07];
protected const KANJI = [[8, 10, 12], 0x08];
protected const FNC1_FIRST_POSITION = [[0, 0, 0], 0x05];
protected const FNC1_SECOND_POSITION = [[0, 0, 0], 0x09];
protected const HANZI = [[8, 10, 12], 0x0d];
/**
* @var int[]
*/
private $characterCountBitsForVersions;
/**
* @var int
*/
private $bits;
protected function __construct(array $characterCountBitsForVersions, int $bits)
{
$this->characterCountBitsForVersions = $characterCountBitsForVersions;
$this->bits = $bits;
}
/**
* Returns the number of bits used in a specific QR code version.
*/
public function getCharacterCountBits(Version $version) : int
{
$number = $version->getVersionNumber();
if ($number <= 9) {
$offset = 0;
} elseif ($number <= 26) {
$offset = 1;
} else {
$offset = 2;
}
return $this->characterCountBitsForVersions[$offset];
}
/**
* Returns the four bits used to encode this mode.
*/
public function getBits() : int
{
return $this->bits;
}
}

View File

@ -0,0 +1,468 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
use BaconQrCode\Exception\InvalidArgumentException;
use BaconQrCode\Exception\RuntimeException;
use SplFixedArray;
/**
* Reed-Solomon codec for 8-bit characters.
*
* Based on libfec by Phil Karn, KA9Q.
*/
final class ReedSolomonCodec
{
/**
* Symbol size in bits.
*
* @var int
*/
private $symbolSize;
/**
* Block size in symbols.
*
* @var int
*/
private $blockSize;
/**
* First root of RS code generator polynomial, index form.
*
* @var int
*/
private $firstRoot;
/**
* Primitive element to generate polynomial roots, index form.
*
* @var int
*/
private $primitive;
/**
* Prim-th root of 1, index form.
*
* @var int
*/
private $iPrimitive;
/**
* RS code generator polynomial degree (number of roots).
*
* @var int
*/
private $numRoots;
/**
* Padding bytes at front of shortened block.
*
* @var int
*/
private $padding;
/**
* Log lookup table.
*
* @var SplFixedArray
*/
private $alphaTo;
/**
* Anti-Log lookup table.
*
* @var SplFixedArray
*/
private $indexOf;
/**
* Generator polynomial.
*
* @var SplFixedArray
*/
private $generatorPoly;
/**
* @throws InvalidArgumentException if symbol size ist not between 0 and 8
* @throws InvalidArgumentException if first root is invalid
* @throws InvalidArgumentException if num roots is invalid
* @throws InvalidArgumentException if padding is invalid
* @throws RuntimeException if field generator polynomial is not primitive
*/
public function __construct(
int $symbolSize,
int $gfPoly,
int $firstRoot,
int $primitive,
int $numRoots,
int $padding
) {
if ($symbolSize < 0 || $symbolSize > 8) {
throw new InvalidArgumentException('Symbol size must be between 0 and 8');
}
if ($firstRoot < 0 || $firstRoot >= (1 << $symbolSize)) {
throw new InvalidArgumentException('First root must be between 0 and ' . (1 << $symbolSize));
}
if ($numRoots < 0 || $numRoots >= (1 << $symbolSize)) {
throw new InvalidArgumentException('Num roots must be between 0 and ' . (1 << $symbolSize));
}
if ($padding < 0 || $padding >= ((1 << $symbolSize) - 1 - $numRoots)) {
throw new InvalidArgumentException(
'Padding must be between 0 and ' . ((1 << $symbolSize) - 1 - $numRoots)
);
}
$this->symbolSize = $symbolSize;
$this->blockSize = (1 << $symbolSize) - 1;
$this->padding = $padding;
$this->alphaTo = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false);
$this->indexOf = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false);
// Generate galous field lookup table
$this->indexOf[0] = $this->blockSize;
$this->alphaTo[$this->blockSize] = 0;
$sr = 1;
for ($i = 0; $i < $this->blockSize; ++$i) {
$this->indexOf[$sr] = $i;
$this->alphaTo[$i] = $sr;
$sr <<= 1;
if ($sr & (1 << $symbolSize)) {
$sr ^= $gfPoly;
}
$sr &= $this->blockSize;
}
if (1 !== $sr) {
throw new RuntimeException('Field generator polynomial is not primitive');
}
// Form RS code generator polynomial from its roots
$this->generatorPoly = SplFixedArray::fromArray(array_fill(0, $numRoots + 1, 0), false);
$this->firstRoot = $firstRoot;
$this->primitive = $primitive;
$this->numRoots = $numRoots;
// Find prim-th root of 1, used in decoding
for ($iPrimitive = 1; ($iPrimitive % $primitive) !== 0; $iPrimitive += $this->blockSize) {
}
$this->iPrimitive = intdiv($iPrimitive, $primitive);
$this->generatorPoly[0] = 1;
for ($i = 0, $root = $firstRoot * $primitive; $i < $numRoots; ++$i, $root += $primitive) {
$this->generatorPoly[$i + 1] = 1;
for ($j = $i; $j > 0; $j--) {
if ($this->generatorPoly[$j] !== 0) {
$this->generatorPoly[$j] = $this->generatorPoly[$j - 1] ^ $this->alphaTo[
$this->modNn($this->indexOf[$this->generatorPoly[$j]] + $root)
];
} else {
$this->generatorPoly[$j] = $this->generatorPoly[$j - 1];
}
}
$this->generatorPoly[$j] = $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[0]] + $root)];
}
// Convert generator poly to index form for quicker encoding
for ($i = 0; $i <= $numRoots; ++$i) {
$this->generatorPoly[$i] = $this->indexOf[$this->generatorPoly[$i]];
}
}
/**
* Encodes data and writes result back into parity array.
*/
public function encode(SplFixedArray $data, SplFixedArray $parity) : void
{
for ($i = 0; $i < $this->numRoots; ++$i) {
$parity[$i] = 0;
}
$iterations = $this->blockSize - $this->numRoots - $this->padding;
for ($i = 0; $i < $iterations; ++$i) {
$feedback = $this->indexOf[$data[$i] ^ $parity[0]];
if ($feedback !== $this->blockSize) {
// Feedback term is non-zero
$feedback = $this->modNn($this->blockSize - $this->generatorPoly[$this->numRoots] + $feedback);
for ($j = 1; $j < $this->numRoots; ++$j) {
$parity[$j] = $parity[$j] ^ $this->alphaTo[
$this->modNn($feedback + $this->generatorPoly[$this->numRoots - $j])
];
}
}
for ($j = 0; $j < $this->numRoots - 1; ++$j) {
$parity[$j] = $parity[$j + 1];
}
if ($feedback !== $this->blockSize) {
$parity[$this->numRoots - 1] = $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[0])];
} else {
$parity[$this->numRoots - 1] = 0;
}
}
}
/**
* Decodes received data.
*/
public function decode(SplFixedArray $data, SplFixedArray $erasures = null) : ?int
{
// This speeds up the initialization a bit.
$numRootsPlusOne = SplFixedArray::fromArray(array_fill(0, $this->numRoots + 1, 0), false);
$numRoots = SplFixedArray::fromArray(array_fill(0, $this->numRoots, 0), false);
$lambda = clone $numRootsPlusOne;
$b = clone $numRootsPlusOne;
$t = clone $numRootsPlusOne;
$omega = clone $numRootsPlusOne;
$root = clone $numRoots;
$loc = clone $numRoots;
$numErasures = (null !== $erasures ? count($erasures) : 0);
// Form the Syndromes; i.e., evaluate data(x) at roots of g(x)
$syndromes = SplFixedArray::fromArray(array_fill(0, $this->numRoots, $data[0]), false);
for ($i = 1; $i < $this->blockSize - $this->padding; ++$i) {
for ($j = 0; $j < $this->numRoots; ++$j) {
if ($syndromes[$j] === 0) {
$syndromes[$j] = $data[$i];
} else {
$syndromes[$j] = $data[$i] ^ $this->alphaTo[
$this->modNn($this->indexOf[$syndromes[$j]] + ($this->firstRoot + $j) * $this->primitive)
];
}
}
}
// Convert syndromes to index form, checking for nonzero conditions
$syndromeError = 0;
for ($i = 0; $i < $this->numRoots; ++$i) {
$syndromeError |= $syndromes[$i];
$syndromes[$i] = $this->indexOf[$syndromes[$i]];
}
if (! $syndromeError) {
// If syndrome is zero, data[] is a codeword and there are no errors to correct, so return data[]
// unmodified.
return 0;
}
$lambda[0] = 1;
if ($numErasures > 0) {
// Init lambda to be the erasure locator polynomial
$lambda[1] = $this->alphaTo[$this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[0]))];
for ($i = 1; $i < $numErasures; ++$i) {
$u = $this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[$i]));
for ($j = $i + 1; $j > 0; --$j) {
$tmp = $this->indexOf[$lambda[$j - 1]];
if ($tmp !== $this->blockSize) {
$lambda[$j] = $lambda[$j] ^ $this->alphaTo[$this->modNn($u + $tmp)];
}
}
}
}
for ($i = 0; $i <= $this->numRoots; ++$i) {
$b[$i] = $this->indexOf[$lambda[$i]];
}
// Begin Berlekamp-Massey algorithm to determine error+erasure locator polynomial
$r = $numErasures;
$el = $numErasures;
while (++$r <= $this->numRoots) {
// Compute discrepancy at the r-th step in poly form
$discrepancyR = 0;
for ($i = 0; $i < $r; ++$i) {
if ($lambda[$i] !== 0 && $syndromes[$r - $i - 1] !== $this->blockSize) {
$discrepancyR ^= $this->alphaTo[
$this->modNn($this->indexOf[$lambda[$i]] + $syndromes[$r - $i - 1])
];
}
}
$discrepancyR = $this->indexOf[$discrepancyR];
if ($discrepancyR === $this->blockSize) {
$tmp = $b->toArray();
array_unshift($tmp, $this->blockSize);
array_pop($tmp);
$b = SplFixedArray::fromArray($tmp, false);
continue;
}
$t[0] = $lambda[0];
for ($i = 0; $i < $this->numRoots; ++$i) {
if ($b[$i] !== $this->blockSize) {
$t[$i + 1] = $lambda[$i + 1] ^ $this->alphaTo[$this->modNn($discrepancyR + $b[$i])];
} else {
$t[$i + 1] = $lambda[$i + 1];
}
}
if (2 * $el <= $r + $numErasures - 1) {
$el = $r + $numErasures - $el;
for ($i = 0; $i <= $this->numRoots; ++$i) {
$b[$i] = (
$lambda[$i] === 0
? $this->blockSize
: $this->modNn($this->indexOf[$lambda[$i]] - $discrepancyR + $this->blockSize)
);
}
} else {
$tmp = $b->toArray();
array_unshift($tmp, $this->blockSize);
array_pop($tmp);
$b = SplFixedArray::fromArray($tmp, false);
}
$lambda = clone $t;
}
// Convert lambda to index form and compute deg(lambda(x))
$degLambda = 0;
for ($i = 0; $i <= $this->numRoots; ++$i) {
$lambda[$i] = $this->indexOf[$lambda[$i]];
if ($lambda[$i] !== $this->blockSize) {
$degLambda = $i;
}
}
// Find roots of the error+erasure locator polynomial by Chien search.
$reg = clone $lambda;
$reg[0] = 0;
$count = 0;
$i = 1;
for ($k = $this->iPrimitive - 1; $i <= $this->blockSize; ++$i, $k = $this->modNn($k + $this->iPrimitive)) {
$q = 1;
for ($j = $degLambda; $j > 0; $j--) {
if ($reg[$j] !== $this->blockSize) {
$reg[$j] = $this->modNn($reg[$j] + $j);
$q ^= $this->alphaTo[$reg[$j]];
}
}
if ($q !== 0) {
// Not a root
continue;
}
// Store root (index-form) and error location number
$root[$count] = $i;
$loc[$count] = $k;
if (++$count === $degLambda) {
break;
}
}
if ($degLambda !== $count) {
// deg(lambda) unequal to number of roots: uncorrectable error detected
return null;
}
// Compute err+eras evaluate poly omega(x) = s(x)*lambda(x) (modulo x**numRoots). In index form. Also find
// deg(omega).
$degOmega = $degLambda - 1;
for ($i = 0; $i <= $degOmega; ++$i) {
$tmp = 0;
for ($j = $i; $j >= 0; --$j) {
if ($syndromes[$i - $j] !== $this->blockSize && $lambda[$j] !== $this->blockSize) {
$tmp ^= $this->alphaTo[$this->modNn($syndromes[$i - $j] + $lambda[$j])];
}
}
$omega[$i] = $this->indexOf[$tmp];
}
// Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = inv(X(l))**(firstRoot-1) and
// den = lambda_pr(inv(X(l))) all in poly form.
for ($j = $count - 1; $j >= 0; --$j) {
$num1 = 0;
for ($i = $degOmega; $i >= 0; $i--) {
if ($omega[$i] !== $this->blockSize) {
$num1 ^= $this->alphaTo[$this->modNn($omega[$i] + $i * $root[$j])];
}
}
$num2 = $this->alphaTo[$this->modNn($root[$j] * ($this->firstRoot - 1) + $this->blockSize)];
$den = 0;
// lambda[i+1] for i even is the formal derivativelambda_pr of lambda[i]
for ($i = min($degLambda, $this->numRoots - 1) & ~1; $i >= 0; $i -= 2) {
if ($lambda[$i + 1] !== $this->blockSize) {
$den ^= $this->alphaTo[$this->modNn($lambda[$i + 1] + $i * $root[$j])];
}
}
// Apply error to data
if ($num1 !== 0 && $loc[$j] >= $this->padding) {
$data[$loc[$j] - $this->padding] = $data[$loc[$j] - $this->padding] ^ (
$this->alphaTo[
$this->modNn(
$this->indexOf[$num1] + $this->indexOf[$num2] + $this->blockSize - $this->indexOf[$den]
)
]
);
}
}
if (null !== $erasures) {
if (count($erasures) < $count) {
$erasures->setSize($count);
}
for ($i = 0; $i < $count; $i++) {
$erasures[$i] = $loc[$i];
}
}
return $count;
}
/**
* Computes $x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, without a slow divide.
*/
private function modNn(int $x) : int
{
while ($x >= $this->blockSize) {
$x -= $this->blockSize;
$x = ($x >> $this->symbolSize) + ($x & $this->blockSize);
}
return $x;
}
}

View File

@ -0,0 +1,596 @@
<?php
declare(strict_types = 1);
namespace BaconQrCode\Common;
use BaconQrCode\Exception\InvalidArgumentException;
use SplFixedArray;
/**
* Version representation.
*/
final class Version
{
private const VERSION_DECODE_INFO = [
0x07c94,
0x085bc,
0x09a99,
0x0a4d3,
0x0bbf6,
0x0c762,
0x0d847,
0x0e60d,
0x0f928,
0x10b78,
0x1145d,
0x12a17,
0x13532,
0x149a6,
0x15683,
0x168c9,
0x177ec,
0x18ec4,
0x191e1,
0x1afab,
0x1b08e,
0x1cc1a,
0x1d33f,
0x1ed75,
0x1f250,
0x209d5,
0x216f0,
0x228ba,
0x2379f,
0x24b0b,
0x2542e,
0x26a64,
0x27541,
0x28c69,
];
/**
* Version number of this version.
*
* @var int
*/
private $versionNumber;
/**
* Alignment pattern centers.
*
* @var SplFixedArray
*/
private $alignmentPatternCenters;
/**
* Error correction blocks.
*
* @var EcBlocks[]
*/
private $ecBlocks;
/**
* Total number of codewords.
*
* @var int
*/
private $totalCodewords;
/**
* Cached version instances.
*
* @var array<int, self>|null
*/
private static $versions;
/**
* @param int[] $alignmentPatternCenters
*/
private function __construct(
int $versionNumber,
array $alignmentPatternCenters,
EcBlocks ...$ecBlocks
) {
$this->versionNumber = $versionNumber;
$this->alignmentPatternCenters = $alignmentPatternCenters;
$this->ecBlocks = $ecBlocks;
$totalCodewords = 0;
$ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock();
foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) {
$totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords);
}
$this->totalCodewords = $totalCodewords;
}
/**
* Returns the version number.
*/
public function getVersionNumber() : int
{
return $this->versionNumber;
}
/**
* Returns the alignment pattern centers.
*
* @return int[]
*/
public function getAlignmentPatternCenters() : array
{
return $this->alignmentPatternCenters;
}
/**
* Returns the total number of codewords.
*/
public function getTotalCodewords() : int
{
return $this->totalCodewords;
}
/**
* Calculates the dimension for the current version.
*/
public function getDimensionForVersion() : int
{
return 17 + 4 * $this->versionNumber;
}
/**
* Returns the number of EC blocks for a specific EC level.
*/
public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel) : EcBlocks
{
return $this->ecBlocks[$ecLevel->ordinal()];
}
/**
* Gets a provisional version number for a specific dimension.
*
* @throws InvalidArgumentException if dimension is not 1 mod 4
*/
public static function getProvisionalVersionForDimension(int $dimension) : self
{
if (1 !== $dimension % 4) {
throw new InvalidArgumentException('Dimension is not 1 mod 4');
}
return self::getVersionForNumber(intdiv($dimension - 17, 4));
}
/**
* Gets a version instance for a specific version number.
*
* @throws InvalidArgumentException if version number is out of range
*/
public static function getVersionForNumber(int $versionNumber) : self
{
if ($versionNumber < 1 || $versionNumber > 40) {
throw new InvalidArgumentException('Version number must be between 1 and 40');
}
return self::versions()[$versionNumber - 1];
}
/**
* Decodes version information from an integer and returns the version.
*/
public static function decodeVersionInformation(int $versionBits) : ?self
{
$bestDifference = PHP_INT_MAX;
$bestVersion = 0;
foreach (self::VERSION_DECODE_INFO as $i => $targetVersion) {
if ($targetVersion === $versionBits) {
return self::getVersionForNumber($i + 7);
}
$bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion);
if ($bitsDifference < $bestDifference) {
$bestVersion = $i + 7;
$bestDifference = $bitsDifference;
}
}
if ($bestDifference <= 3) {
return self::getVersionForNumber($bestVersion);
}
return null;
}
/**
* Builds the function pattern for the current version.
*/
public function buildFunctionPattern() : BitMatrix
{
$dimension = $this->getDimensionForVersion();
$bitMatrix = new BitMatrix($dimension);
// Top left finder pattern + separator + format
$bitMatrix->setRegion(0, 0, 9, 9);
// Top right finder pattern + separator + format
$bitMatrix->setRegion($dimension - 8, 0, 8, 9);
// Bottom left finder pattern + separator + format
$bitMatrix->setRegion(0, $dimension - 8, 9, 8);
// Alignment patterns
$max = count($this->alignmentPatternCenters);
for ($x = 0; $x < $max; ++$x) {
$i = $this->alignmentPatternCenters[$x] - 2;
for ($y = 0; $y < $max; ++$y) {
if (($x === 0 && ($y === 0 || $y === $max - 1)) || ($x === $max - 1 && $y === 0)) {
// No alignment patterns near the three finder paterns
continue;
}
$bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5);
}
}
// Vertical timing pattern
$bitMatrix->setRegion(6, 9, 1, $dimension - 17);
// Horizontal timing pattern
$bitMatrix->setRegion(9, 6, $dimension - 17, 1);
if ($this->versionNumber > 6) {
// Version info, top right
$bitMatrix->setRegion($dimension - 11, 0, 3, 6);
// Version info, bottom left
$bitMatrix->setRegion(0, $dimension - 11, 6, 3);
}
return $bitMatrix;
}
/**
* Returns a string representation for the version.
*/
public function __toString() : string
{
return (string) $this->versionNumber;
}
/**
* Build and cache a specific version.
*
* See ISO 18004:2006 6.5.1 Table 9.
*
* @return array<int, self>
*/
private static function versions() : array
{
if (null !== self::$versions) {
return self::$versions;
}
return self::$versions = [
new self(
1,
[],
new EcBlocks(7, new EcBlock(1, 19)),
new EcBlocks(10, new EcBlock(1, 16)),
new EcBlocks(13, new EcBlock(1, 13)),
new EcBlocks(17, new EcBlock(1, 9))
),
new self(
2,
[6, 18],
new EcBlocks(10, new EcBlock(1, 34)),
new EcBlocks(16, new EcBlock(1, 28)),
new EcBlocks(22, new EcBlock(1, 22)),
new EcBlocks(28, new EcBlock(1, 16))
),
new self(
3,
[6, 22],
new EcBlocks(15, new EcBlock(1, 55)),
new EcBlocks(26, new EcBlock(1, 44)),
new EcBlocks(18, new EcBlock(2, 17)),
new EcBlocks(22, new EcBlock(2, 13))
),
new self(
4,
[6, 26],
new EcBlocks(20, new EcBlock(1, 80)),
new EcBlocks(18, new EcBlock(2, 32)),
new EcBlocks(26, new EcBlock(3, 24)),
new EcBlocks(16, new EcBlock(4, 9))
),
new self(
5,
[6, 30],
new EcBlocks(26, new EcBlock(1, 108)),
new EcBlocks(24, new EcBlock(2, 43)),
new EcBlocks(18, new EcBlock(2, 15), new EcBlock(2, 16)),
new EcBlocks(22, new EcBlock(2, 11), new EcBlock(2, 12))
),
new self(
6,
[6, 34],
new EcBlocks(18, new EcBlock(2, 68)),
new EcBlocks(16, new EcBlock(4, 27)),
new EcBlocks(24, new EcBlock(4, 19)),
new EcBlocks(28, new EcBlock(4, 15))
),
new self(
7,
[6, 22, 38],
new EcBlocks(20, new EcBlock(2, 78)),
new EcBlocks(18, new EcBlock(4, 31)),
new EcBlocks(18, new EcBlock(2, 14), new EcBlock(4, 15)),
new EcBlocks(26, new EcBlock(4, 13), new EcBlock(1, 14))
),
new self(
8,
[6, 24, 42],
new EcBlocks(24, new EcBlock(2, 97)),
new EcBlocks(22, new EcBlock(2, 38), new EcBlock(2, 39)),
new EcBlocks(22, new EcBlock(4, 18), new EcBlock(2, 19)),
new EcBlocks(26, new EcBlock(4, 14), new EcBlock(2, 15))
),
new self(
9,
[6, 26, 46],
new EcBlocks(30, new EcBlock(2, 116)),
new EcBlocks(22, new EcBlock(3, 36), new EcBlock(2, 37)),
new EcBlocks(20, new EcBlock(4, 16), new EcBlock(4, 17)),
new EcBlocks(24, new EcBlock(4, 12), new EcBlock(4, 13))
),
new self(
10,
[6, 28, 50],
new EcBlocks(18, new EcBlock(2, 68), new EcBlock(2, 69)),
new EcBlocks(26, new EcBlock(4, 43), new EcBlock(1, 44)),
new EcBlocks(24, new EcBlock(6, 19), new EcBlock(2, 20)),
new EcBlocks(28, new EcBlock(6, 15), new EcBlock(2, 16))
),
new self(
11,
[6, 30, 54],
new EcBlocks(20, new EcBlock(4, 81)),
new EcBlocks(30, new EcBlock(1, 50), new EcBlock(4, 51)),
new EcBlocks(28, new EcBlock(4, 22), new EcBlock(4, 23)),
new EcBlocks(24, new EcBlock(3, 12), new EcBlock(8, 13))
),
new self(
12,
[6, 32, 58],
new EcBlocks(24, new EcBlock(2, 92), new EcBlock(2, 93)),
new EcBlocks(22, new EcBlock(6, 36), new EcBlock(2, 37)),
new EcBlocks(26, new EcBlock(4, 20), new EcBlock(6, 21)),
new EcBlocks(28, new EcBlock(7, 14), new EcBlock(4, 15))
),
new self(
13,
[6, 34, 62],
new EcBlocks(26, new EcBlock(4, 107)),
new EcBlocks(22, new EcBlock(8, 37), new EcBlock(1, 38)),
new EcBlocks(24, new EcBlock(8, 20), new EcBlock(4, 21)),
new EcBlocks(22, new EcBlock(12, 11), new EcBlock(4, 12))
),
new self(
14,
[6, 26, 46, 66],
new EcBlocks(30, new EcBlock(3, 115), new EcBlock(1, 116)),
new EcBlocks(24, new EcBlock(4, 40), new EcBlock(5, 41)),
new EcBlocks(20, new EcBlock(11, 16), new EcBlock(5, 17)),
new EcBlocks(24, new EcBlock(11, 12), new EcBlock(5, 13))
),
new self(
15,
[6, 26, 48, 70],
new EcBlocks(22, new EcBlock(5, 87), new EcBlock(1, 88)),
new EcBlocks(24, new EcBlock(5, 41), new EcBlock(5, 42)),
new EcBlocks(30, new EcBlock(5, 24), new EcBlock(7, 25)),
new EcBlocks(24, new EcBlock(11, 12), new EcBlock(7, 13))
),
new self(
16,
[6, 26, 50, 74],
new EcBlocks(24, new EcBlock(5, 98), new EcBlock(1, 99)),
new EcBlocks(28, new EcBlock(7, 45), new EcBlock(3, 46)),
new EcBlocks(24, new EcBlock(15, 19), new EcBlock(2, 20)),
new EcBlocks(30, new EcBlock(3, 15), new EcBlock(13, 16))
),
new self(
17,
[6, 30, 54, 78],
new EcBlocks(28, new EcBlock(1, 107), new EcBlock(5, 108)),
new EcBlocks(28, new EcBlock(10, 46), new EcBlock(1, 47)),
new EcBlocks(28, new EcBlock(1, 22), new EcBlock(15, 23)),
new EcBlocks(28, new EcBlock(2, 14), new EcBlock(17, 15))
),
new self(
18,
[6, 30, 56, 82],
new EcBlocks(30, new EcBlock(5, 120), new EcBlock(1, 121)),
new EcBlocks(26, new EcBlock(9, 43), new EcBlock(4, 44)),
new EcBlocks(28, new EcBlock(17, 22), new EcBlock(1, 23)),
new EcBlocks(28, new EcBlock(2, 14), new EcBlock(19, 15))
),
new self(
19,
[6, 30, 58, 86],
new EcBlocks(28, new EcBlock(3, 113), new EcBlock(4, 114)),
new EcBlocks(26, new EcBlock(3, 44), new EcBlock(11, 45)),
new EcBlocks(26, new EcBlock(17, 21), new EcBlock(4, 22)),
new EcBlocks(26, new EcBlock(9, 13), new EcBlock(16, 14))
),
new self(
20,
[6, 34, 62, 90],
new EcBlocks(28, new EcBlock(3, 107), new EcBlock(5, 108)),
new EcBlocks(26, new EcBlock(3, 41), new EcBlock(13, 42)),
new EcBlocks(30, new EcBlock(15, 24), new EcBlock(5, 25)),
new EcBlocks(28, new EcBlock(15, 15), new EcBlock(10, 16))
),
new self(
21,
[6, 28, 50, 72, 94],
new EcBlocks(28, new EcBlock(4, 116), new EcBlock(4, 117)),
new EcBlocks(26, new EcBlock(17, 42)),
new EcBlocks(28, new EcBlock(17, 22), new EcBlock(6, 23)),
new EcBlocks(30, new EcBlock(19, 16), new EcBlock(6, 17))
),
new self(
22,
[6, 26, 50, 74, 98],
new EcBlocks(28, new EcBlock(2, 111), new EcBlock(7, 112)),
new EcBlocks(28, new EcBlock(17, 46)),
new EcBlocks(30, new EcBlock(7, 24), new EcBlock(16, 25)),
new EcBlocks(24, new EcBlock(34, 13))
),
new self(
23,
[6, 30, 54, 78, 102],
new EcBlocks(30, new EcBlock(4, 121), new EcBlock(5, 122)),
new EcBlocks(28, new EcBlock(4, 47), new EcBlock(14, 48)),
new EcBlocks(30, new EcBlock(11, 24), new EcBlock(14, 25)),
new EcBlocks(30, new EcBlock(16, 15), new EcBlock(14, 16))
),
new self(
24,
[6, 28, 54, 80, 106],
new EcBlocks(30, new EcBlock(6, 117), new EcBlock(4, 118)),
new EcBlocks(28, new EcBlock(6, 45), new EcBlock(14, 46)),
new EcBlocks(30, new EcBlock(11, 24), new EcBlock(16, 25)),
new EcBlocks(30, new EcBlock(30, 16), new EcBlock(2, 17))
),
new self(
25,
[6, 32, 58, 84, 110],
new EcBlocks(26, new EcBlock(8, 106), new EcBlock(4, 107)),
new EcBlocks(28, new EcBlock(8, 47), new EcBlock(13, 48)),
new EcBlocks(30, new EcBlock(7, 24), new EcBlock(22, 25)),
new EcBlocks(30, new EcBlock(22, 15), new EcBlock(13, 16))
),
new self(
26,
[6, 30, 58, 86, 114],
new EcBlocks(28, new EcBlock(10, 114), new EcBlock(2, 115)),
new EcBlocks(28, new EcBlock(19, 46), new EcBlock(4, 47)),
new EcBlocks(28, new EcBlock(28, 22), new EcBlock(6, 23)),
new EcBlocks(30, new EcBlock(33, 16), new EcBlock(4, 17))
),
new self(
27,
[6, 34, 62, 90, 118],
new EcBlocks(30, new EcBlock(8, 122), new EcBlock(4, 123)),
new EcBlocks(28, new EcBlock(22, 45), new EcBlock(3, 46)),
new EcBlocks(30, new EcBlock(8, 23), new EcBlock(26, 24)),
new EcBlocks(30, new EcBlock(12, 15), new EcBlock(28, 16))
),
new self(
28,
[6, 26, 50, 74, 98, 122],
new EcBlocks(30, new EcBlock(3, 117), new EcBlock(10, 118)),
new EcBlocks(28, new EcBlock(3, 45), new EcBlock(23, 46)),
new EcBlocks(30, new EcBlock(4, 24), new EcBlock(31, 25)),
new EcBlocks(30, new EcBlock(11, 15), new EcBlock(31, 16))
),
new self(
29,
[6, 30, 54, 78, 102, 126],
new EcBlocks(30, new EcBlock(7, 116), new EcBlock(7, 117)),
new EcBlocks(28, new EcBlock(21, 45), new EcBlock(7, 46)),
new EcBlocks(30, new EcBlock(1, 23), new EcBlock(37, 24)),
new EcBlocks(30, new EcBlock(19, 15), new EcBlock(26, 16))
),
new self(
30,
[6, 26, 52, 78, 104, 130],
new EcBlocks(30, new EcBlock(5, 115), new EcBlock(10, 116)),
new EcBlocks(28, new EcBlock(19, 47), new EcBlock(10, 48)),
new EcBlocks(30, new EcBlock(15, 24), new EcBlock(25, 25)),
new EcBlocks(30, new EcBlock(23, 15), new EcBlock(25, 16))
),
new self(
31,
[6, 30, 56, 82, 108, 134],
new EcBlocks(30, new EcBlock(13, 115), new EcBlock(3, 116)),
new EcBlocks(28, new EcBlock(2, 46), new EcBlock(29, 47)),
new EcBlocks(30, new EcBlock(42, 24), new EcBlock(1, 25)),
new EcBlocks(30, new EcBlock(23, 15), new EcBlock(28, 16))
),
new self(
32,
[6, 34, 60, 86, 112, 138],
new EcBlocks(30, new EcBlock(17, 115)),
new EcBlocks(28, new EcBlock(10, 46), new EcBlock(23, 47)),
new EcBlocks(30, new EcBlock(10, 24), new EcBlock(35, 25)),
new EcBlocks(30, new EcBlock(19, 15), new EcBlock(35, 16))
),
new self(
33,
[6, 30, 58, 86, 114, 142],
new EcBlocks(30, new EcBlock(17, 115), new EcBlock(1, 116)),
new EcBlocks(28, new EcBlock(14, 46), new EcBlock(21, 47)),
new EcBlocks(30, new EcBlock(29, 24), new EcBlock(19, 25)),
new EcBlocks(30, new EcBlock(11, 15), new EcBlock(46, 16))
),
new self(
34,
[6, 34, 62, 90, 118, 146],
new EcBlocks(30, new EcBlock(13, 115), new EcBlock(6, 116)),
new EcBlocks(28, new EcBlock(14, 46), new EcBlock(23, 47)),
new EcBlocks(30, new EcBlock(44, 24), new EcBlock(7, 25)),
new EcBlocks(30, new EcBlock(59, 16), new EcBlock(1, 17))
),
new self(
35,
[6, 30, 54, 78, 102, 126, 150],
new EcBlocks(30, new EcBlock(12, 121), new EcBlock(7, 122)),
new EcBlocks(28, new EcBlock(12, 47), new EcBlock(26, 48)),
new EcBlocks(30, new EcBlock(39, 24), new EcBlock(14, 25)),
new EcBlocks(30, new EcBlock(22, 15), new EcBlock(41, 16))
),
new self(
36,
[6, 24, 50, 76, 102, 128, 154],
new EcBlocks(30, new EcBlock(6, 121), new EcBlock(14, 122)),
new EcBlocks(28, new EcBlock(6, 47), new EcBlock(34, 48)),
new EcBlocks(30, new EcBlock(46, 24), new EcBlock(10, 25)),
new EcBlocks(30, new EcBlock(2, 15), new EcBlock(64, 16))
),
new self(
37,
[6, 28, 54, 80, 106, 132, 158],
new EcBlocks(30, new EcBlock(17, 122), new EcBlock(4, 123)),
new EcBlocks(28, new EcBlock(29, 46), new EcBlock(14, 47)),
new EcBlocks(30, new EcBlock(49, 24), new EcBlock(10, 25)),
new EcBlocks(30, new EcBlock(24, 15), new EcBlock(46, 16))
),
new self(
38,
[6, 32, 58, 84, 110, 136, 162],
new EcBlocks(30, new EcBlock(4, 122), new EcBlock(18, 123)),
new EcBlocks(28, new EcBlock(13, 46), new EcBlock(32, 47)),
new EcBlocks(30, new EcBlock(48, 24), new EcBlock(14, 25)),
new EcBlocks(30, new EcBlock(42, 15), new EcBlock(32, 16))
),
new self(
39,
[6, 26, 54, 82, 110, 138, 166],
new EcBlocks(30, new EcBlock(20, 117), new EcBlock(4, 118)),
new EcBlocks(28, new EcBlock(40, 47), new EcBlock(7, 48)),
new EcBlocks(30, new EcBlock(43, 24), new EcBlock(22, 25)),
new EcBlocks(30, new EcBlock(10, 15), new EcBlock(67, 16))
),
new self(
40,
[6, 30, 58, 86, 114, 142, 170],
new EcBlocks(30, new EcBlock(19, 118), new EcBlock(6, 119)),
new EcBlocks(28, new EcBlock(18, 47), new EcBlock(31, 48)),
new EcBlocks(30, new EcBlock(34, 24), new EcBlock(34, 25)),
new EcBlocks(30, new EcBlock(20, 15), new EcBlock(61, 16))
),
];
}
}

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