main
Wayne Hsu 3 years ago
commit d1dc80d1d0

25
.env

@ -0,0 +1,25 @@
APP_DEBUG = true
[APP]
DEFAULT_TIMEZONE = Asia/Taipei
[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = sso_h888_fun
USERNAME = sso_h888_fun
PASSWORD = EFyGDeDdnidrrsL3
HOSTPORT = 3306
CHARSET = utf8mb4
DEBUG = true
PREFIX = asc_
[LANG]
default_lang = zh-tw
[JWT]
SECRET=6dffd0dcd8d732d6b5e5e6c7bd7d1eff
refresh_ttl = 360
[ASC]
SMS_DISABLE = false

12
.vscode/sftp.json vendored

@ -0,0 +1,12 @@
{
"name": "My Server",
"host": "stage",
"protocol": "sftp",
"port": 22,
"username": "root",
"password": "%1WoCvN7FD.oUYhf",
"remotePath": "/www/wwwroot/sso.h888.fun",
"uploadOnSave": true,
"useTempFile": false,
"openSsh": false
}

@ -0,0 +1,32 @@
ThinkPHP遵循Apache2开源协议发布并提供免费使用。
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
Apache Licence是著名的非盈利开源组织Apache采用的协议。
该协议和BSD类似鼓励代码共享和尊重原作者的著作权
允许代码修改,再作为开源或商业软件发布。需要满足
的条件:
1 需要给代码的用户一份Apache Licence
2 如果你修改了代码,需要在被修改的文件中说明;
3 在延伸的代码中(修改和有源代码衍生的代码中)需要
带有原来代码中的协议,商标,专利声明和其他原来作者规
定需要包含的说明;
4 如果再发布的产品中包含一个Notice文件则在Notice文
件中需要带有本协议内容。你可以在Notice中增加自己的
许可但不可以表现为对Apache Licence构成更改。
具体的协议参考http://www.apache.org/licenses/LICENSE-2.0
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.

@ -0,0 +1 @@
# SSO 單點登入系統

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

@ -0,0 +1,22 @@
<?php
declare (strict_types = 1);
namespace app;
use think\Service;
/**
* 应用服务类
*/
class AppService extends Service
{
public function register()
{
// 服务注册
}
public function boot()
{
// 服务启动
}
}

@ -0,0 +1,94 @@
<?php
declare (strict_types = 1);
namespace app;
use think\App;
use think\exception\ValidateException;
use think\Validate;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
}

@ -0,0 +1,58 @@
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
// 其他错误交给系统处理
return parent::render($request, $e);
}
}

@ -0,0 +1,8 @@
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
}

@ -0,0 +1,128 @@
<?php
declare (strict_types = 1);
namespace app\adminapi;
use think\App;
use think\Response;
// use think\exception\ValidateException;
// use think\Validate;
/**
* 控制器基礎類
*/
abstract class ApiController
{
/**
* Request實例
* @var \think\Request
*/
protected $request;
/**
* 應用實例
* @var \think\App
*/
protected $app;
/**
* 是否批量驗證
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中間件
* @var array
*/
protected $middleware = [];
/**
* 構造方法
* @access public
* @param App $app 應用對象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
header('Access-Control-Allow-Origin: *');
//允許的請求頭信息
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
//允許的請求類型
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH');
//允許攜帶證書式訪問攜帶cookie
header('Access-Control-Allow-Credentials:true');
}
/**
* 驗證數據
* @access protected
* @param array $data 數據
* @param string|array $validate 驗證器名或者驗證規則數組
* @param array $message 提示信息
* @param bool $batch 是否批量驗證
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持場景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量驗證
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
public function Success($data,$message='請求成功',$code=200,$type='json',$header=[]){
$result = [
'code' => $code,
'message' => $message,
'time'=>time(),
'data'=>$data
];
return Response::create($result,$type)->header($header);
}
public function Error($data,$message='請求失敗',$code=500,$type='json',$header=[]){
$result = [
'code' => $code,
'message' => $message,
'time'=>time(),
'data'=>$data
];
return Response::create($result,$type)->header($header);
}
}

@ -0,0 +1,167 @@
<?php
namespace app\adminapi\controller\v1;
use app\adminapi\ApiController;
use think\facade\Db;
class Admin extends ApiController
{
public function getAdminUsers()
{
if(!input('search')){
$result=Db::name('admin')
->page(input('current'),input('size'))
->select();
$total=Db::name('admin')
->count();
}else{
$result=Db::name('admin')
->where('username','like','%'.input('search').'%')
->page(input('current'),input('size'))
->select();
$total=Db::name('admin')
->where('username','like','%'.input('search').'%')
->count();
}
if(!$result){
$result=[];
}
$rtn=[
'total' => $total,
'data' => $result
];
return $this->Success($rtn);
}
public function getUser(){
$id=input('id');
$result=Db::name('admin')
->field('id,username,email,status,role_id as role')
->where('id',$id)
->find();
if(!$result){
$result=[];
}
return $this->success($result);
}
public function addUser(){
$req=input();
$password_hash = password_hash($req['password'], PASSWORD_DEFAULT);
$data=[
'username' => $req['username'],
'password' => $password_hash,
'email' => $req['email'],
'action_list' => '',
'status' => $req['status'],
];
$result=Db::name('admin')
->insert($data);
if(!$result){
$result=[];
}
return $this->success($result);
}
public function updateUser(){
$req=input();
$data=[
'username' => $req['username'],
'email' => $req['email'],
'role_id' => $req['role'],
'action_list' => '',
'status' => $req['status'],
];
if(strlen($req['password'])>0){
$data['password']=$req['password'];
}
$result=Db::name('admin')
->where('id',$req['id'])
->update($data);
if(!$result){
$result=[];
}
return $this->success($result);
}
public function deleteUser(){
$id=input('id');
$result=Db::name('admin')
->where('id',$id)
->delete();
return $this->success($result);
}
public function updateStatus(){
$id=input('id');
$status=input('status');
$result=Db::name('admin')
->where('id',$id)
->update(['status'=>$status]);
if(!$result){
$result=[];
}
return $this->success($result);
}
public function getAdminLogs()
{
if(!input('search')){
$result=Db::name('admin_log')
->page(input('current'),input('size'))
->order('id','desc')
->select();
$total=Db::name('admin_log')
->count();
}else{
$result=Db::name('admin_log')
->where('admin_name','like','%'.input('search').'%')
->page(input('current'),input('size'))
->order('id','desc')
->select();
$total=Db::name('admin_log')
->where('admin_name','like','%'.input('search').'%')
->count();
}
if(!$result){
$result=[];
}
$rtn=[
'total' => $total,
'data' => $result
];
return $this->Success($rtn);
}
}

@ -0,0 +1,153 @@
<?php
namespace app\adminapi\controller\v1;
use app\adminapi\ApiController;
use think\facade\Db;
use think\facade\Session;
use thans\jwt\facade\JWTAuth;
use think\facade\Log;
class Auth extends ApiController
{
public function Login()
{
$username=input('username');
$password=input('password');
// $captcha=input('captcha');
// Log::write(json_encode(Session::all()));
// if(!captcha_check($captcha)){
// return $this->Error('驗證碼錯誤','請求失敗',301);
// }
$result=Db::name('admin')
->where('username',$username)
->find();
if(!$result){
return $this->Error('帳號或密碼錯誤','請求失敗',302);
}
if(!password_verify($password , $result['password'])){
return $this->Error('帳號或密碼錯誤','請求失敗',303);
}
$token = JWTAuth::builder(['uid' => $result['id']]);
$result=[
'user'=>[
'uid'=>$result['id'],
"name" => $result['username'],
"avatar" => "https://gw.alipayobjects.com/zos/rmsportal/ubnKSIfAJTxIgXOKlciN.png",
"address" => "固原市",
"position" => [
"CN" => "產品分析師 | 螞蟻金服-計算服務事業群-IOS平臺部",
"TW" => "產品分析師 | 螞蟻金服-計算服務事業群-IOS平臺部",
"US" => "Product analyst | Ant Financial - Computing services business group - IOS platform division"
]
],
'permissions'=>[
[
'id'=>'queryForm',
'operation'=>['add','edit','delete']
]
],
'roles'=>[
[
'id'=>'admin',
'operation'=>['add','edit','delete']
]
],
'token'=>$token,
'expireAt'=>time()+30*60*1000
];
return $this->Success($result);
}
public function check(){
print_r(JWTAuth::auth());
}
public function captcha($id=''){
return captcha($id);
}
public function checkC($value){
print_r(Session::all());
if(!captcha_check($value)){
//驗證失敗
echo 'failure';
};
echo 'Success';
}
public function getRoute(){
$routes=[
[
"router" => "root",
"children" => [
"DashBoard",
[
"router" => "system",
"children" => [
[
"router" => "systemConfig",
"name" => "站台設置",
"authority" => [
"permission" => "demo",
"role" => "admin"
]
]
]
],
[
"router" => "admin",
"children" => [
"adminUser",
"adminLog",
"adminRole",
]
],
[
"router" => "goods",
"children" => [
"goodsList",
"goodsCategory",
"goodsType",
]
],
[
"router" => "order",
"children" => [
"orderList",
]
],
[
"router" => "room",
"children" => [
"roomList",
]
],
[
"router" => "user",
"children" => [
"userList"
]
],
[
"router" => "setting",
"children" => [
"settingBase",
"settingConfig"
]
]
]
]
];
return $this->Success($routes);
}
}

@ -0,0 +1,187 @@
<?php
namespace app\adminapi\controller\v1;
use app\adminapi\ApiController;
use think\facade\Db;
use app\common\lib\Vcard;
use app\common\lib\Aes;
class Card extends ApiController
{
public function addPrecard(){
$req=input();
//取得prefix
$agent = Db::name('agent')
->where('id',$req['agent_id'])
->find();
$aes = new Aes([]);
for($i=0;$i<input('number');$i++){
// $user_id=genUniqid($agent['prefix']);
// $verify_code = genSerialNo();
// $params = urlencode($aes->encrypt('user_id='.$user_id.'&verify_code='.$verify_code));
// $nfcUrl = genQrCode(getUrl().'/card/?params='.$params,$user_id,'nfc');
$data[]=[
// 'user_id'=>$user_id,
'agent_id'=>$req['agent_id'],
'try_days'=>7,
'verify_code'=>'',
'expire_time'=>$req['expire_time'],
'status'=>0,
];
}
try{
Db::name('precard')
->insertAll($data);
}catch(\Exception $e){
print_r($e);
return $this->error('新增失敗');
}
return $this->success('新增成功');
}
// 取得預開卡資料
public function getPrecard(){
$do=Db::name('precard');
if(!input('search')){
$result=$do
->page(input('current'),input('size'))
->order('id','desc')
->select()->toArray();
$total=$do
->count();
}else{
$result=$do
->where('user_id','like','%'.input('search').'%')
->page(input('current'),input('size'))
->order('id','desc')
->select()->toArray();
$total=$do
->where('user_id','like','%'.input('search').'%')
->count();
}
if(!$result){
$result=[];
}
foreach($result as $key => $val){
// $aes = new Aes([]);
// $nfc_url = 'user_id='.$val['user_id'].'&verify_code='.$val['verify_code'];
// $result[$key]['params'] = getUrl().'/card/'.urlencode($aes->encrypt($nfc_url));
$result[$key]['agent_name'] = Db::name('agent')->where('id',$val['agent_id'])->value('name');
$result[$key]['expire'] = date('Y-m-d',$val['expire_time']);
switch($val['status']){
case 0:
$result[$key]['status_name']='未制卡';
break;
case 1:
$result[$key]['status_name']='已制卡';
break;
case 2:
$result[$key]['status_name']='已開通';
break;
case 3:
$result[$key]['status_name']='已作癈';
break;
}
$aes = new Aes([]);
$params = urlencode($aes->encrypt('verify_code='.$val['verify_code']));
$result[$key]['nfcurl']= getUrl().'/card/?params='.$params;
// $nfcUrl = genQrCode('https://'.$_SERVER['HTTP_HOST'].'/card/?params='.$params,$data['user_id'],'nfc');
}
$rtn=[
'total' => $total,
'data' => $result
];
return $this->Success($rtn);
}
public function deleteCard(){
$id=input('id');
$result=Db::name('precard')
->where('id',$id)
->delete();
return $this->success($result);
}
public function updateStatus(){
$id=input('id');
$status=input('status');
$result=Db::name('precard')
->where('id',$id)
->update(['status'=>$status]);
if(!$result){
$result=[];
}
return $this->success($result);
}
public function updateVerifyCode(){
$id=input('id');
$verify_code=strtoupper(input('code'));
$is_user = Db::name('user')
->where('uniqid',$verify_code)
->count();
if($is_user){
return $this->error('卡片已綁定會員');
}
$is_precard = Db::name('precard')
->where('verify_code',$verify_code)
->count();
if($is_precard){
return $this->error('已存在預製卡');
}
try{
$result=Db::name('precard')
->where('id',$id)
->update(['verify_code'=>$verify_code,'status'=>1]);
return $this->success('設定成功');
}catch(\Exception $e){
return $this->error('系統錯誤');
}
}
public function downloadQr(){
$id=input('id');
$pc=Db::name('precard')
->where('id',$id)
->find();
if(strlen($pc['nfc_qrcode'])>0){
$nfc_qrcode = $pc['nfc_qrcode'];
}else{
}
return $this->success($result);
}
}

@ -0,0 +1,18 @@
<?php
namespace app\adminapi\controller\v1;
use app\BaseController;
use app\common\lib\Vcard;
class Index extends BaseController
{
public function index()
{
return 'Admin Index';
}
public function test(){
Vcard::genVcf('mc638ac4d74c7e6');
}
}

@ -0,0 +1,87 @@
<?php
namespace app\admin\controller\v1;
use app\api\ApiController;
use think\facade\Db;
class Right extends ApiController
{
public function getTree()
{
$data=[
'title'=>'所有權限',
'key'=>'all',
'level'=>0,
'index'=>0
];
$data=$this->buildTree($data);
if(!$data){
$result=[];
}
// $result['children']=$children;
$rtn=[
// 'total' => $total,
$data
];
return $this->Success($rtn);
}
private static function buildTree($data,$level=0){
$level=$level+1;
$menu = Db::name('menu')
->where('pid',$data['index'])
->select();
if(!$menu){
return $data;
}
$children=[];
foreach($menu as $key => $val){
$children[$key]['title']=$val['title'];
$children[$key]['index']=$val['id'];
$children[$key]['level']=$level;
$children[$key]['key']=$val['node'];
if($level < 2){
$children[$key]=self::buildTree($children[$key],$level);
}else{
$children[$key]=self::appendPermission($children[$key]);
}
}
if($children){
$data['children'] = $children;
}
return $data;
}
private static function appendPermission($data){
$perm = Db::name('permission')
->where('menu_id',$data['index'])
->select();
if(!$perm){
return $data;
}
$children=[];
foreach($perm as $key => $val){
$children[$key]['title']=lang($val['code']);
$children[$key]['index']=$val['id'];
$children[$key]['key']=$val['code'];
}
if($children){
$data['children'] = $children;
}
return $data;
}
}

@ -0,0 +1,86 @@
<?php
namespace app\adminapi\controller\v1;
use app\adminapi\ApiController;
use think\facade\Db;
class Role extends ApiController
{
public function getRoles()
{
$result=Db::name('role')
->select();
if(!$result){
$result=[];
}
// foreach($result as $key=>$val){
// // $rtn=Db::name('goods')->where('gc_id',$val['id'])->select()->toArray();
// // if($rtn){
// // $result[$key]['goods']=[];
// // }
// $result[$key]['goods']=Db::name('goods')->where('gc_id',$val['id'])->select()->toArray();
// }
return $this->Success($result);
}
public function getRoleById(){
$id=input('id');
$result=Db::name('role')
->where('id',$id)
->find();
$rtn=[
'id' => $result['id'],
'name' => $result['name'],
'desc' => $result['desc'],
'permission'=>json_decode($result['limits'])
];
return $this->Success($rtn);
}
public function addRole(){
$req=input();
$data = [
'name'=>$req['name'],
'desc'=>$req['desc'],
'limits'=>json_encode($req['permission'])
];
$result=Db::name('role')
->insert($data);
return $this->Success($result);
}
public function updateRole(){
$req=input();
$data = [
'name' =>$req['name'],
'desc' =>$req['desc'],
'limits' =>json_encode($req['permission'])
];
$result=Db::name('role')
->where('id',$req['id'])
->update($data);
return $this->Success($result);
}
public function deleteRole(){
$id=input('id');
$result=Db::name('role')
->where('id',$id)
->delete();
return $this->Success($result);
}
}

@ -0,0 +1,45 @@
<?php
namespace app\adminapi\controller\v1;
use app\adminapi\ApiController;
use think\facade\Db;
class Site extends ApiController
{
public function getSiteConfig(){
$result = Db::name('site_config')
->where('parent_id','<>',0)
->select();
foreach($result as $key => $val){
$rtn[$val['code']]=$val['value'];
}
return $this->success($rtn);
}
public function setSiteConfig(){
$data = input();
unset($data['version']);
unset($data['controller']);
unset($data['action']);
try{
foreach($data as $key => $val){
Db::name('site_config')
->where('code',$key)
->update(['value'=>$val]);
}
}catch(\Exception $e){
return $this->error('更新失敗');
}
return $this->success('更新成功');
}
public function getAgents(){
$result = Db::name('agent')
->select();
return $this->success($result);
}
}

@ -0,0 +1,305 @@
<?php
namespace app\adminapi\controller\v1;
use app\adminapi\ApiController;
use think\facade\Db;
use app\common\lib\Vcard;
use app\common\lib\Aes;
class User extends ApiController
{
public function getInfo()
{
$id=$this->request->uid;
$result=Db::name('user')
->where('id',$id)
->find();
if(!$result){
$result=[];
}
// foreach($result as $key=>$val){
// // $rtn=Db::name('goods')->where('gc_id',$val['id'])->select()->toArray();
// // if($rtn){
// // $result[$key]['goods']=[];
// // }
// $result[$key]['goods']=Db::name('goods')->where('gc_id',$val['id'])->select()->toArray();
// }
return $this->Success($result);
}
// 取得會員資料
public function getUsers(){
$do=Db::name('user');
if(!input('search')){
$result=$do
->page(input('current'),input('size'))
->order('id','desc')
->select()->toArray();
$total=$do
->count();
}else{
$result=$do
->where('user_id','like','%'.input('search').'%')
->page(input('current'),input('size'))
->order('id','desc')
->select()->toArray();
$total=$do
->where('user_id','like','%'.input('search').'%')
->count();
}
if(!$result){
$result=[];
}
$aes = new Aes([]);
foreach($result as $key => $val){
$result[$key]['level_name']= Db::name('user_level')->where('level_id',$val['level'])->where('agent_id',$val['agent_id'])->value('name');
if($val['parent_id']>0){
$result[$key]['parent_name']=Db::name('user')->where('id',$val['parent_id'])->value('real_name');
}
if($val['overdue_time']>0){
$result[$key]['overdue'] = date('Y-m-d',$val['overdue_time']);
}else{
$result[$key]['overdue'] = '無限期';
}
if(strlen($val['uniqid'])>0){
$uniqid = $val['uniqid'];
}else{
$uniqid = '00000000';
}
$params = urlencode($aes->encrypt('user_id='.$val['user_id'].'&verify_code='.$uniqid));
$result[$key]['nfcurl']= getUrl().'/card/?params='.$params;
}
$rtn=[
'total' => $total,
'data' => $result
];
return $this->Success($rtn);
}
public function getUser(){
$id=input('id');
$result=Db::name('user')
->where('id',$id)
->find();
if(!$result){
$result=[];
}
$levels=Db::name('user_level')
->where('agent_id',$result['agent_id'])
->select();
$result['levels']=$levels;
return $this->success($result);
}
public function addUser(){
$req=input();
unset($req['version']);
unset($req['controller']);
unset($req['action']);
$req['user_id'] = 'mc'.uniqid();
$req['line_id'] = $req['user_id'];
$req['create_time']=date('Y-m-d H:i:s');
$req['update_time']=date('Y-m-d H:i:s');
$result=Db::name('user')
->insert($req);
if(!$result){
$result=[];
}
return $this->success($result);
}
public function updateUser(){
$req=input();
unset($req['version']);
unset($req['controller']);
unset($req['action']);
unset($req['levels']);
unset($req['status']);
$level_option = Db::name('user_level')
->where('agent_id',$req['agent_id'])
->where('level_id',$req['level'])
->find();
$req['nc_type']=$level_option['nc_type'];
$req['nc_func']=$level_option['nc_func'];
$req['update_time']=date('Y-m-d H:i:s');
$result=Db::name('user')
->where('id',$req['id'])
->update($req);
Vcard::genVcf(input('user_id'));
if(!$result){
$result=[];
}
return $this->success($result);
}
public function deleteUser(){
$id=input('id');
$result=Db::name('user')
->where('id',$id)
->delete();
return $this->success($result);
}
public function updateStatus(){
$id=input('id');
$status=input('status');
$result=Db::name('user')
->where('id',$id)
->update(['status'=>$status]);
if(!$result){
$result=[];
}
return $this->success($result);
}
public function getUserCard(){
$id=input('id');
$result=Db::name('user_card')
->field('id,type,title,content,nfc_show,sort_id')
->where('user_id',$id)
->order('sort_id')
->select();
if(!$result){
$result=[];
}
return $this->success($result);
}
public function uploadAvatar(){
$files = request()->file('avatar');
$savename = \think\facade\Filesystem::disk('public')->putFile( input('id'), $files);
$avatar = getUrl().'/storage/'.$savename;
return $this->Success($avatar);
}
public function updateUserCard(){
$user_id=input('id');
$cards=input('cards');
Db::name('user_card')
->where('user_id',$user_id)
->delete();
foreach($cards as $key => $val){
$nfc_show = $val['nfc_show']?1:0;
Db::name('user_card')
->insert([
'user_id' => $user_id,
'type' => $val['type'],
'title' => $val['title'],
'content' => $val['content'],
'nfc_show' => $nfc_show,
'sort_id' => $key,
'create_time' => time()
]);
}
// if(!$result){
// $result=[];
// }
return $this->success(['code'=>200]);
}
public function updateVerifyCode(){
$id=input('id');
$uniqid=strtoupper(input('code'));
$result=Db::name('user')
->where('id',$id)
->update(['uniqid'=>$uniqid]);
return $this->success('設定成功');
}
// 取得預開卡資料
public function getPrecard(){
$do=Db::name('precard');
if(!input('search')){
$result=$do
->page(input('current'),input('size'))
->order('id','desc')
->select()->toArray();
$total=$do
->count();
}else{
$result=$do
->where('user_id','like','%'.input('search').'%')
->page(input('current'),input('size'))
->order('id','desc')
->select()->toArray();
$total=$do
->where('user_id','like','%'.input('search').'%')
->count();
}
if(!$result){
$result=[];
}
foreach($result as $key => $val){
$aes = new Aes([]);
$nfc_url = 'user_id='.$val['user_id'].'&verify_code='.$val['verify_code'];
$result[$key]['params'] = getUrl().'/card/'.urlencode($aes->encrypt($nfc_url));
}
$rtn=[
'total' => $total,
'data' => $result
];
return $this->Success($rtn);
}
}

@ -0,0 +1,6 @@
<?php
return [
\think\middleware\SessionInit::class,
\think\middleware\AllowCrossDomain::class,
// app\api\middleware\CheckSiteCode::class
];

@ -0,0 +1,9 @@
<?php
use think\facade\Route;
// Route::group(function () {
// Route::rule(':version/user/:action', 'api/:version.user/:action');
// })->middleware(\app\api\middleware\JWT::class);
Route::rule(':version/:controller/:action','adminapi/:version.:controller/:action');

@ -0,0 +1,134 @@
<?php
declare (strict_types = 1);
namespace app\api;
use think\App;
use think\Response;
// use think\exception\ValidateException;
// use think\Validate;
/**
* 控制器基础类
*/
abstract class ApiController
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* user id
* @var array
*/
protected $uid = '';
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
header('Access-Control-Allow-Origin: *');
// //允許的請求頭信息
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
// //允許的請求類型
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH');
header('Access-Control-Expose-Headers: authorization');
// //允許攜帶證書式訪問攜帶cookie
header('Access-Control-Allow-Credentials:true');
$this->uid = input('uid');
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
public function Success($data,$code=200,$message='請求成功',$type='json',$header=[]){
$result = [
'code' => $code,
'message' => $message,
'time'=>time(),
'data'=>$data
];
return Response::create($result,$type)->header($header);
}
public function Error($data,$code=500,$message='請求失敗',$type='json',$header=[]){
$result = [
'code' => $code,
'message' => $message,
'time'=>time(),
'data'=>$data
];
return Response::create($result,$type)->header($header);
}
}

@ -0,0 +1,12 @@
<?php
// api公用函數
use think\facade\Db;
function getPrefixByAppId($appid){
return 'tg';
}
function checkParams(){
print_r('aaaaa');
}

@ -0,0 +1,222 @@
<?php
namespace app\api\controller\v1;
use app\api\ApiController;
use think\facade\Db;
use think\facade\Cache;
// use Lcobucci\JWT\Parser;
// use thans\jwt\facade\JWTAuth;
// use Firebase\JWT\JWT;
// use Firebase\JWT\Key;
use \asc\line\LineLogin;
use app\common\sms\Sms;
use app\common\lib\Token;
// use app\common\lib\Aes;
class Auth extends ApiController
{
//帳號登入
public function login()
{
$username = input('username');
$password = input('password');
//檢查帳號密碼
$verify = Cache::get($username);
if(!isset($verify) || $verify['code']!=$password){
return $this->error('帳號或密碼錯誤', 401);
}
Cache::delete($username);
$user = Db::name('user')
->where('phone', $username)
->find();
if (!$user) {
return $this->success('非會員', 201);
}
$payload = [
'user_id' => $user['user_id'],
];
$token = Token::genToken($payload);
// if(empty($user['uniqid'])){
// return $this->success(['uid'=>$user['user_id'],'token'=>'Bearer '.$token],202);
// }
return $this->success(['uid' => $user['user_id'], 'token' => 'Bearer ' . $token]);
}
/**
* Line 登入
*/
public function lineLogin()
{
$id_token = input('token');
$line_id = input('line_id');
$line_res = LineLogin::verifyIdToken('1657876696', $id_token);
if (!$line_res) {
return $this->Error('發生錯誤,請重新執行', 401);
}
$user = Db::name('user')
->where('line_id', $line_res['sub'])
->find();
if (!$user) {
return $this->success('非會員', 201);
}
$payload = [
'id' => $user['id'],
'user_id' => $user['user_id'],
];
$token = Token::genToken($payload);
// if(empty($user['uniqid'])){
// return $this->success(['uid'=>$user['user_id'],'token'=>'Bearer '.$token],202);
// }
return $this->success(['uid' => $user['user_id'], 'token' => 'Bearer ' . $token]);
}
public function checkPhone(){
$phone=input('phone');
$id_token = input('token');
$user = Db::name('user')
->where('phone',$phone)
->find();
if(!$user){
return $this->success('非會員',201);
}
if(strlen($user['line_id'])>0){
return $this->success('已綁定Line',202);
}
//更新Line資料
$line_res = LineLogin::verifyIdToken('1657876696', $id_token);
if(!$line_res){
return $this->Error('發生錯誤,請重新執行',401);
}
$data = [
'line_id'=>$line_res['sub'],
'line_name'=>$line_res['name'],
'create_time'=>date('Y-m-d H:i:s')
];
$avatar=isset($line_res['picture'])?$this->saveLineImage($line_res['picture'],$line_res['sub']):'';
if(!empty($avatar)){
$data['line_picture']= getUrl().'/storage/'.$user['user_id'].'/'.$avatar;
}else{
$data['line_picture']='';
}
if(empty($user['avatar'])){
$data['avatar']=$data['line_picture'];
}
Db::name('user')
->where('phone',$phone)
->update($data);
$payload = [
'id' => $user['id'],
'user_id' => $user['user_id'],
];
$token = Token::genToken($payload);
return $this->success(['uid' => $user['user_id'], 'token' => 'Bearer ' . $token]);
}
public function logout()
{
return $this->success('請求成功');
}
public function checkToken()
{
$token = input('token');
$result = Token::check($token);
if (!$result) {
return $this->error('Token無效');
}
return $this->success('請求成功');
}
public function sendVerify()
{
$username = input('username');
//在這裡檢查是否已經發送過驗證碼,如果已經發送過,則不再發送
$verifyData = Cache::get($username);
if ($verifyData) {
if (time() - $verifyData['time'] < 60) {
$countdown = 60 - (time() - $verifyData['time']);
return $this->error(['countdown'=>$countdown], 201,'請求時間過短,請稍後再試');
}
}else{
//清除舊的驗證碼
Cache::delete($username);
}
// 驗證碼不存在或已過期
// 重新生成驗證碼並存儲到Redis中
$verification_code = mt_rand(100000, 999999);
$message = '[SlashCard]' . $verification_code . '簡訊登入驗證碼請於5分鐘內輸入驗證碼完成登入。';
// 發送短信
$debug = env('asc.sms_disable');
$debug = false;
if(!$debug){
Sms::createSms(
'smsking',
[
'recipient' => $username,
'message' => $message
]
);
}else{
$verification_code = '123456';
}
Cache::set($username, ['code' => $verification_code, 'time' => time()], 300);
return $this->success('請求成功');
}
private function saveLineImage($pictureUrl,$uid)
{
if($pictureUrl){
$curl = curl_init($pictureUrl);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
$imageData=curl_exec($curl);
curl_close($curl);
$filename=$uid."_line.jpg";
$filedir=$_SERVER['DOCUMENT_ROOT'].'/storage/'.$uid;
if (!file_exists($filedir)) {
mkdir($filedir , 0777 , true);
}
$fp=fopen($filedir.'/'.$filename,'a');
fwrite($fp,$imageData);
fclose($fp);
return $filename;
}else{
return false;
}
}
}

@ -0,0 +1,194 @@
<?php
namespace app\api\controller\v1;
use app\api\ApiController;
use think\facade\Db;
// use app\api\validate\User as UserValidate;
// use think\exception\ValidateException;
use app\common\lib\Token;
class User extends ApiController
{
public function getInfo()
{
try {
$user = Db::name('user')
->field('user_id,avatar,line_id,line_name,line_picture,phone,real_name,email, code,parent_id')
->where('user_id', input('user_id'))
// ->whereNotNull('delete_time')
->find();
return $this->success($user);
} catch (\Exception $e) {
return $this->error('操作失敗');
}
}
public function getUsers()
{
try {
$users = Db::name('user')
->field('user_id,avatar,line_id,line_name,line_picture,phone,real_name,code')
->whereNotNull('delete_time')
->select();
return $this->success($users);
} catch (\Exception $e) {
return $this->error('操作失敗');
}
}
public function add()
{
$data = input();
unset($data['version']);
unset($data['action']);
unset($data['controller']);
$user_id = genUniqid($data['appid']);
$data['user_id'] = $user_id;
$avatar = isset($data['line_picture']) ? $this->saveLineImage($data['line_picture'], $data['user_id']) : '';
if (!empty($avatar)) {
$data['line_picture'] = getUrl() . '/storage/' . $data['user_id'] . '/' . $avatar;
} else {
$data['line_picture'] = '';
}
if (!isset($data['avatar'])) {
$data['avatar'] = $data['line_picture'];
} else {
$file_path = $_SERVER['DOCUMENT_ROOT'] . '/storage/' . $data['user_id'] . '/' . date('Ymd') . '/';
if (!is_dir($file_path)) {
mkdir($file_path, 0777, true);
}
$temp_file = str_replace(getUrl(), "", $data['avatar']);
$avatar_file = $file_path . basename($temp_file);
if (!rename($_SERVER['DOCUMENT_ROOT'] . $temp_file, $avatar_file)) {
return $this->error('搬移檔案失敗');
}
$data['avatar'] = getUrl() . '/storage/' . $data['user_id'] . '/' . date('Ymd') . '/' . basename($temp_file);
}
$phone_exist = Db::name('user')
->where('phone', input('phone'))
->find();
// 檢查會員電話是否存在
if (!$phone_exist) {
// 檢查推薦碼是否存在,存在的話取得推薦人的id
if (input('refer_code')) {
$refer_id = Db::name('user')
->where('code', input('refer_code'))
->value('user_id');
if ($refer_id) {
$data['parent_id'] = $refer_id;
}
}
}
unset($data['appid']);
unset($data['timestamp']);
unset($data['sign']);
unset($data['refer_code']);
try {
if ($phone_exist) {
Db::name('user')
->where('phone', input('phone'))
->update($data);
} else {
$id = Db::name('user')
->insertGetId($data);
$refer_code = encodeRefer($id);
Db::name('user')
->where('id', $id)
->update(['code' => $refer_code]);
}
//使用id取得user資料庫的資料
$result = Db::name('user')
->where('phone', input('phone'))
->find();
$payload = [
'user_id' => $data['user_id'],
];
$token = Token::genToken($payload);
return $this->success(['uid' => $data['user_id'], 'info' => $result, 'token' => 'Bearer ' . $token]);
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
public function delete()
{
try {
Db::name('user')
->where('user_id', input('user_id'))
->update([
'delete_time' => time()
]);
return $this->success('操作成功');
} catch (\Exception $e) {
return $this->error('操作失敗');
}
}
public function update()
{
$data = input('post.');
unset($data['appid']);
unset($data['timestamp']);
unset($data['sign']);
try {
Db::name('user')
->where('user_id', $data['user_id'])
->update($data);
return $this->success('操作成功');
} catch (\Exception $e) {
return $this->error('操作失敗');
}
}
private function saveLineImage($pictureUrl, $uid)
{
if ($pictureUrl) {
$curl = curl_init($pictureUrl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$imageData = curl_exec($curl);
curl_close($curl);
$filename = $uid . "_line.jpg";
$filedir = $_SERVER['DOCUMENT_ROOT'] . '/storage/' . $uid;
if (!file_exists($filedir)) {
mkdir($filedir, 0777, true);
}
$fp = fopen($filedir . '/' . $filename, 'a');
fwrite($fp, $imageData);
fclose($fp);
return $filename;
} else {
return false;
}
}
}

@ -0,0 +1,125 @@
<?php
declare (strict_types = 1);
namespace app\api\exception;
use think\App;
// use think\Response;
/**
* 控制器基础类
*/
abstract class BaseException
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
header('Access-Control-Allow-Origin: *');
// //允許的請求頭信息
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
// //允許的請求類型
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH');
header('Access-Control-Expose-Headers: authorization');
// //允許攜帶證書式訪問攜帶cookie
header('Access-Control-Allow-Credentials:true');
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
public function Success($data,$code=200,$message='請求成功',$type='json',$header=[]){
$result = [
'code' => $code,
'message' => $message,
'time'=>time(),
'data'=>$data
];
return Response::create($result,$type)->header($header);
}
public function Error($data,$code=500,$message='請求失敗',$type='json',$header=[]){
$result = [
'code' => $code,
'message' => $message,
'time'=>time(),
'data'=>$data
];
return Response::create($result,$type)->header($header);
}
}

@ -0,0 +1,7 @@
<?php
return [
// \think\middleware\SessionInit::class,
// \think\middleware\AllowCrossDomain::class,
// app\api\middleware\CheckParams::class
// app\api\middleware\CheckSiteCode::class
];

@ -0,0 +1,41 @@
<?php
declare (strict_types=1);
namespace app\api\middleware;
use think\exception\HttpException;
class CheckParams
{
public function handle($request, \Closure $next): object
{
$params = $request->param();
if(!isset($params['sign'])){
return json(['code'=>401,'message'=>'API驗證失敗','data'=>'No Sign','time'=>time()]);
}
$sign = $params['sign'];
unset($params['sign']);
unset($params['controller']);
unset($params['action']);
unset($params['version']);
ksort($params);
$string = md5(md5(strtolower(http_build_query($params))).'seckey');
// print_r($string === $sign);
// var_dump($sign);
// var_dump($string);
if($string !== $sign){
// throw new HttpException(401, 'Sign Error!!!');
return json(['code'=>401,'message'=>'API驗證失敗','data'=>'Sign Error','time'=>time()]);
}
$response = $next($request);
return $response;
}
}

@ -0,0 +1,62 @@
<?php
declare (strict_types=1);
namespace app\api\middleware;
use thans\jwt\exception\JWTException;
use thans\jwt\exception\TokenBlacklistException;
use thans\jwt\exception\TokenBlacklistGracePeriodException;
use thans\jwt\exception\TokenExpiredException;
use thans\jwt\middleware\JWTAuth;
use think\exception\HttpException;
/**
* JWT驗證刷新token機制
* Class JWTToken
* @package app\api\middleware
*/
class JWT extends JWTAuth
{
/**
* 刷新token
* @param $request
* @param \Closure $next
* @return mixed
* @throws JWTException
* @throws TokenBlacklistException
* @throws TokenBlacklistGracePeriodException
*/
public function handle($request, \Closure $next): object
{
try {
$payload = $this->auth->auth();
} catch (TokenExpiredException $e) { // token過期
// 嘗試刷新token會將舊token加入黑名單
try {
$this->auth->setRefresh();
$token = $this->auth->refresh();
$payload = $this->auth->auth(false);
} catch (TokenBlacklistGracePeriodException $e) {
$payload = $this->auth->auth(false);
} catch (JWTException $exception) {
// 如果捕獲到此異常,即代表 refresh 也過期了,用户無法刷新令牌,需要重新登錄。
throw new HttpException(401, $exception->getMessage());
}
} catch (TokenBlacklistGracePeriodException $e) { // 捕獲黑名單寬限期
$payload = $this->auth->auth(false);
} catch (TokenBlacklistException $e) { // 捕獲黑名單退出登錄或者已經自動刷新當前token就會被拉黑
throw new HttpException(401, 'not login...');
}
$request->uid = $payload['user_id']->getValue();
$response = $next($request);
if (isset($token)) {
$this->setAuthentication($response, $token);
}
return $response;
}
}

@ -0,0 +1,14 @@
<?php
use think\facade\Route;
Route::group(function () {
Route::rule(':version/user/:action', 'api/:version.user/:action');
})->middleware(\app\api\middleware\CheckParams::class);
Route::group(function(){
Route::rule(':version/:controller/:action','api/:version.:controller/:action');
})->allowCrossDomain([
'Access-Control-Allow-Headers' => 'Origin, X-Requested-With, Content-Type, Accept, Authorization, SessionId, sessionid',
'Access-Control-Expose-Headers' => 'Authorization, SessionId, sessionid'
]);

@ -0,0 +1,25 @@
<?php
namespace app\api\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'appid' => 'require',
'user_id' => 'require|max:255',
'name' => 'require|max:25',
'level' => 'number|between:0,3',
'overdue_time' => 'number'
];
protected $message = [
'appid.require' => 'appid 不可為空',
'user_id.require' => 'User Id不可為空',
'name.require' => 'Name不得為空',
'name.max' => 'Name不得超過25個字',
'level.number' => 'Level必需是數字',
'level.between' => 'Level只能在0-3之間',
'overdue_time.require' => 'overdue_time必需是數字',
];
}

@ -0,0 +1,24 @@
<?php
namespace app\api\validate;
use think\Validate;
class UserLevel extends Validate
{
protected $rule = [
'appid' => 'require',
'user_id' => 'require|max:255',
'level' => 'require|number|between:0,3',
'overdue_time' => 'require|number'
];
protected $message = [
'appid.require' => 'appid 不可為空',
'user_id.require' => 'User Id不可為空',
'level.require' => 'Level不可為空',
'level.number' => 'Level必需是數字',
'level.between' => 'Level只能在0-3之間',
'overdue_time.require' => 'overdue_time不可為空',
'overdue_time.number' => 'overdue_time必需是數字',
];
}

@ -0,0 +1,60 @@
<?php
declare (strict_types = 1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Db;
class CheckExpire extends Command
{
protected function configure()
{
// 指令配置
$this->setName('checkexpire')
->setDescription('the checkexpire command');
}
protected function execute(Input $input, Output $output)
{
// 取得代理資料
$t_agents = Db::name('agent')->select();
foreach($t_agents as $val){
$agents[$val['id']] = $val;
}
// 取得過期用戶
$e_users = Db::name('user')
->where('status',1)
->where('overdue_time','<',time())
->select();
// 更新過期用戶
foreach($e_users as $val){
$data['level']=0;
$data['status']=1;
$level_option = Db::name('user_level')
->where('agent_id',$val['agent_id'])
->where('level_id',$data['level'])
->find();
$data['nc_type']=$level_option['nc_type'];
$data['nc_func']=$level_option['nc_func'];
Db::name('user')
->where('id',$val['id'])
->update($data);
}
// 指令输出
$output->writeln('checkexpire');
}
}

@ -0,0 +1,62 @@
<?php
declare (strict_types = 1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Db;
class CheckTrial extends Command
{
protected function configure()
{
// 指令配置
$this->setName('checktrial')
->setDescription('the checktrial command');
}
protected function execute(Input $input, Output $output)
{
// 取得代理資料
$t_agents = Db::name('agent')
->select();
foreach($t_agents as $val){
$agents[$val['id']] = $val;
}
// 取得試用過期用戶
$e_users = Db::name('user')
->where('status',2)
->where('overdue_time','<',time())
->select();
// 更新試用過期用戶
foreach($e_users as $val){
$data['overdue_time']=strtotime("+".$agents[$val['agent_id']]['base_days']." days");
$data['level']=$agents[$val['agent_id']]['base_level'];
$level_option = Db::name('user_level')
->where('agent_id',$val['agent_id'])
->where('level_id',$data['level'])
->find();
$data['nc_type']=$level_option['nc_type'];
$data['nc_func']=$level_option['nc_func'];
$data['status']=1;
print_r($data);
Db::name('user')
->where('id',$val['id'])
->update($data);
}
// 指令输出
$output->writeln('檢查試用會員完成');
}
}

@ -0,0 +1,202 @@
<?php
// 應用公共文件
use think\facade\Db;
function getUrl(){
// $protocol = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$protocol = 'https://';
$http = $_SERVER['HTTP_HOST'];
return $protocol.$http;
}
function getIdByUid($uid){
$id =Db::name('user')
->where('user_id',$uid)
->value('id');
if(!$id){
return false;
}
return $id;
}
function getIdByLid($lid){
$id =Db::name('user')
->where('line_id',$lid)
->value('id');
if(!$id){
return false;
}
return $id;
}
function getUseridByCuid($cuid){
$id =Db::name('user')
->where('uniqid',$cuid)
->value('user_id');
if(!$id){
return false;
}
return $id;
}
function genUniqid($prefix='mc'){
$is_get = false;
while(!$is_get){
$uniqid = $prefix.uniqid();
$result = Db::name('user')
->where('user_id',$uniqid)
->count();
if(!$result){
$is_get=true;
}
}
return $uniqid;
}
/**
* 取得開通序號
*
* @author ayne <wwayne.hsu@gmail.com>
*
* @param integer $num 數量
*
* @return array
*/
function genSerialNo(){
$code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$rand = $code[rand(0,25)]
.strtoupper(dechex(date('m')))
.date('d').substr(time(),-5)
.substr(microtime(),2,5)
.sprintf('%02d',rand(0,99));
for(
$a = md5( $rand, true ),
$s = '0123456789ABCDEFGHIJKLMNOPQRSTUV',
$d = '',
$f = 0;
$f < 8;
$g = ord( $a[ $f ] ),
$d .= $s[ ( $g ^ ord( $a[ $f + 8 ] ) ) - $g & 0x1F ],
$f++
);
return $d;
}
function encodeRefer($userId)
{
$sourceString = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
$code = '';
while ($userId > 0) {
$mod = $userId % 35;
$userId = ($userId - $mod) / 35;
$code = $sourceString[$mod] . $code;
}
if (strlen($code) < 8)
$code = str_pad($code, 8, '0', STR_PAD_LEFT);
return $code;
}
function decodeRefer($code)
{
$sourceString = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
//移除左側的 0
if (strrpos($code, '0') !== false)
$code = substr($code, strrpos($code, '0') + 1);
$len = strlen($code);
$code = strrev($code);
$num = 0;
for ($i = 0; $i < $len; $i++) {
$num += strpos($sourceString, $code[$i]) * pow(35, $i);
}
return $num;
}
/**
* 功能:生成二維碼
* @param string $qrData 手機掃描後要跳轉的網址
* @param string $qrLevel 預設糾錯比例 分為L、M、Q、H四個等級H代表最高糾錯能力
* @param string $qrSize 二維碼圖大小110可選數字越大圖片尺寸越大
* @param string $savePath 圖片儲存路徑
* @param string $savePrefix 圖片名稱字首
*/
function createQRcode($savePath, $qrData = 'QR Code :)', $qrLevel = 'L', $qrSize = 4, $savePrefix = 'qrcode')
{
if (!isset($savePath)) return '';
//設定生成png圖片的路徑
$PNG_TEMP_DIR = $savePath;
//檢測並建立生成資料夾
if (!file_exists($PNG_TEMP_DIR)) {
mkdir($PNG_TEMP_DIR);
}
$filename = $PNG_TEMP_DIR . '/qrcode_temp.png';
$errorCorrectionLevel = 'L';
if (isset($qrLevel) && in_array($qrLevel, ['L', 'M', 'Q', 'H'])) {
$errorCorrectionLevel = $qrLevel;
}
$matrixPointSize = 4;
if (isset($qrSize)) {
$matrixPointSize = min(max((int)$qrSize, 1), 10);
}
if (isset($qrData)) {
if (trim($qrData) == '') {
die('data cannot be empty!');
}
//生成檔名 檔案路徑+圖片名字字首+md5(名稱)+.png
$filename = $PNG_TEMP_DIR . $savePrefix . '_qrcode.png';
//開始生成
\PHPQRCode\QRcode::png($qrData, $filename, $errorCorrectionLevel, $matrixPointSize, 2);
} else {
//預設生成
\PHPQRCode\QRcode::png('PHP QR Code :)', $filename, $errorCorrectionLevel, $matrixPointSize, 2);
}
if (file_exists($PNG_TEMP_DIR . basename($filename)))
return basename($filename);
else
return FALSE;
}
function genQrCode($url,$user_id,$prefix)
{
//$savePath 圖片儲存路徑
$savePath = $_SERVER['DOCUMENT_ROOT'].'/storage/'.$user_id.'/';
//路徑
$webPath = str_replace($_SERVER['DOCUMENT_ROOT'], '', $savePath);
//$qrData 手機掃描後要跳轉的網址
$qrData = $url;
// $qrLevel 預設糾錯比例 分為L、M、Q、H四個等級H代表最高糾錯能力
$qrLevel = 'H';
//$qrSize 二維碼圖大小110可選數字越大圖片尺寸越大
$qrSize = '4';
// $savePrefix 圖片名稱字首
$savePrefix = $user_id.'_'.$prefix;
$pic = '';
$filename = createQRcode($savePath, $qrData, $qrLevel, $qrSize, $savePrefix);
if($filename = createQRcode($savePath, $qrData, $qrLevel, $qrSize, $savePrefix)){
$pic = $webPath . $filename;
return $pic;
}
return false;
}
function asc_trim($val){
if(!is_array($val)){
return trim($val);
}else{
return $val;
}
}
function getUserIdByUid($uid){
return Db::name('users')->where('sso_user_id',$uid)->value('id');
}

@ -0,0 +1,29 @@
<?php
namespace app\common\lib;
class Aes{
private $key = 'iloveutel';
private $iv = '1234567890123456';
private $method = 'AES-128-CBC';
/**
* 構造方法
*/
public function __construct($config){
foreach($config as $k=>$v){
$this->$k = $v;
}
}
// 加密
public function encrypt($data){
return base64_encode(openssl_encrypt($data, $this->method,$this->key, OPENSSL_RAW_DATA , $this->iv));
}
//解密
public function descrypt($data){
return openssl_decrypt(base64_decode($data), $this->method, $this->key, OPENSSL_RAW_DATA, $this->iv);
}
}

@ -0,0 +1,63 @@
<?php
namespace app\common\lib;
use think\facade\Cache;
class IAuth{
/**
* md5 加密
*/
public static function serPassword($data){
return md5($data,\config('api.password_pre_halt'));
}
/**
* 生成每次請求Sign字符串
*/
public static function setSign($data = []) {
// 按字段排序
\ksort($data);
//拼接字符串數據
$string = \http_build_query($data);
//通過 aes 來加密
$string = (new Aes(\config('api.aes_key')))->aesEn($string);
return $string;
}
/**
* 檢測sign是否正常
*/
public static function checkSignPass($data) {
$str = (new Aes(\config('api.aes_key')))->aesDe($data);
// 判斷解析出來的數據是否為空
if(empty($str)){
return false;
}
// 字符串轉數組
parse_str($str,$arr);
// 判斷是否是數組,數組內的字段是否正確
if(!\is_array($arr) || empty($arr['mg'])){
return false;
}
// 檢測緩存,如果有緩存,説明這個sign已經被使用
if(Cache::get($data)){
return false;
}
return true;
}
}
?>
備註:
'aes_key' =>[
'key' => 'reter4446fdfgdfgdfg', //加密key這個可以隨便定義
'iv' => md5(time(). uniqid(),true), //保證偏移量為16位
'method' => 'AES-128-CBC' //加密方式 # AES-256-CBC等這個可以搭配的形式有很多具體的你可以去了解一下AES加密算法
],

@ -0,0 +1,38 @@
<?php
namespace app\common\lib;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class Token{
/**
* 構造方法
*/
public function __construct(){
}
public static function genToken($payload){
$payload = array_merge($payload,[
'aud' => '',
'exp' => time() + (365 * 24 * 60 * 60),
'iat' => time(),
'iss' => '',
'jti' => uniqid(mt_rand(), true),
'nbf' => time(),
'sub' => '',
]);
return JWT::encode($payload, \think\facade\Config::get('jwt.secret'), 'HS256');
}
public static function check($token){
try{
$decode = JWT::decode($token, new Key(\think\facade\Config::get('jwt.secret'), 'HS256'));
return true;
}catch(\Exception $e){
return false;
}
}
}

@ -0,0 +1,51 @@
<?php
namespace app\common\lib;
use think\facade\Db;
use JeroenDesloovere\VCard\VCard as VCardApi;
class Vcard{
public static function genVcf($userid){
$userInfo = Db::name('user')->where('user_id',$userid)->find();
if(!$userInfo){
return false;
}
$vcard = new VCardApi();
$lastname = $userInfo['real_name'];
$firstname = '';
$additional = '';
$prefix = '';
$suffix = '';
$vcard->addName($lastname, $firstname, $additional, $prefix, $suffix);
// add work data
$vcard->addCompany($userInfo['company']);
$vcard->addJobtitle($userInfo['title']);
// $vcard->addRole('Data Protection Officer');
$vcard->addEmail($userInfo['email']);
$vcard->addPhoneNumber($userInfo['phone'], 'PREF;CELL');
$vcard->addPhoneNumber($userInfo['tel'], 'WORK');
// $vcard->addAddress(null, null, 'street', 'worktown', null, 'workpostcode', 'Belgium');
// $vcard->addLabel('street, worktown, workpostcode Belgium');
if($userInfo['url']){
// $vcard->addURL(getUrl().'/card/?userid='.$userInfo['user_id']);
$vcard->addURL($userInfo['url']);
}
$vcard->addPhoto(__DIR__.'/../../../public/storage/'.$userInfo['user_id'].'/'.$userInfo['user_id'].'_line.jpg');
// return vcard as a string
//return $vcard->getOutput();
// return vcard as a download
// return $vcard->download();
$vcard->setSavePath(__DIR__.'/../../../public/storage/'.$userInfo['user_id'].'/');
$vcard->setFilename($userInfo['user_id']);
$vcard->save();
return true;
}
}

@ -0,0 +1,6 @@
<?php
namespace app\common\sms;
interface Isms {
public function sendSms(array $data);
}

@ -0,0 +1,23 @@
<?php
namespace app\common\sms;
use think\facade\Db;
use app\common\sms\SmsFactory;
class Sms
{
//使用靜態方法,建立物流單
public static function createSms($smscode,$data)
{
$sms = SmsFactory::createSmsService($smscode);
$result = $sms->sendSms($data);
if(!$result){
return FALSE;
}
return TRUE;
}
}

@ -0,0 +1,17 @@
<?php
namespace app\common\sms;
use app\common\sms\SmskingSms;
use think\Exception;
class SmsFactory
{
public static function createSmsService($serviceName) {
switch ($serviceName) {
case 'smsking':
return new SmskingSms('slash1000','a810309');
default:
throw new Exception("Unsupported sms service: $serviceName");
}
}
}

@ -0,0 +1,53 @@
<?php
namespace app\common\sms;
use GuzzleHttp\Client;
use app\common\sms\Isms;
use think\facade\Db;
//實作物流串接介面
class SmskingSms implements Isms
{
private $username;
private $password;
public function __construct(string $username, string $password)
{
$this->username = $username;
$this->password = $password;
}
public function sendSms(array $data)
{
// 將$message 轉為 Big5 編碼
$message = mb_convert_encoding($data['message'], 'BIG5', 'UTF-8');
$url = 'https://api.kotsms.com.tw/kotsmsapi-1.php';
$query = http_build_query([
'username' => $this->username,
'password' => $this->password,
'dstaddr' => $data['recipient'],
'smbody' => $message,
]);
$url .= '?' . $query;
// 使用 Guzzle 發送 API 請求
$client = new Client();
$response = $client->request('GET', $url);
// 處理 API 回應
$body = $response->getBody()->getContents();
$result =explode('=',$body);
// $result = json_decode($body, true);
if (is_numeric(intval($result[1])) && intval($result[1])>=0) {
return true;
} else {
return false;
}
return true;
}
}

@ -0,0 +1,12 @@
<?php
namespace app\controller;
use app\BaseController;
class Index extends BaseController
{
public function index()
{
return '';
}
}

@ -0,0 +1,19 @@
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Db;
use app\common\lib\Vcard;
class Vcf extends BaseController
{
public function index(){
$userid=input('userid');
$userid='mc622b0cda299c6';
Vcard::genVcf($userid);
}
}

@ -0,0 +1,17 @@
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [
],
];

@ -0,0 +1,10 @@
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
// \think\middleware\SessionInit::class
];

@ -0,0 +1,9 @@
<?php
use app\ExceptionHandle;
use app\Request;
// 容器Provider定义文件
return [
'think\Request' => Request::class,
'think\exception\Handle' => ExceptionHandle::class,
];

@ -0,0 +1,9 @@
<?php
use app\AppService;
// 系统服务定义文件
// 服务在完成全局初始化之后执行
return [
AppService::class,
];

@ -0,0 +1,55 @@
{
"name": "topthink/think",
"description": "the new thinkphp framework",
"type": "project",
"keywords": [
"framework",
"thinkphp",
"ORM"
],
"homepage": "http://thinkphp.cn/",
"license": "Apache-2.0",
"authors": [
{
"name": "liu21st",
"email": "liu21st@gmail.com"
},
{
"name": "yunwuxin",
"email": "448901948@qq.com"
}
],
"require": {
"php": ">=7.2.5",
"topthink/framework": "^6.0.0",
"topthink/think-orm": "^2.0",
"topthink/think-multi-app": "^1.0",
"thans/tp-jwt-auth": "^1.2",
"guzzlehttp/guzzle": "~6.0",
"aferrandini/phpqrcode": "^1.0",
"jeroendesloovere/vcard": "^1.7",
"topthink/think-filesystem": "^2.0",
"firebase/php-jwt": "^6.4"
},
"require-dev": {
"symfony/var-dumper": "^4.2",
"topthink/think-trace":"^1.0"
},
"autoload": {
"psr-4": {
"app\\": "app"
},
"psr-0": {
"": "extend/"
}
},
"config": {
"preferred-install": "dist"
},
"scripts": {
"post-autoload-dump": [
"@php think service:discover",
"@php think vendor:publish"
]
}
}

1796
composer.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
return [
// 应用地址
'app_host' => env('app.host', ''),
// 应用的命名空间
'app_namespace' => '',
// 是否启用路由
'with_route' => true,
// 默认应用
'default_app' => 'index',
// 默认时区
'default_timezone' => 'Asia/Shanghai',
// 应用映射(自动多应用模式有效)
'app_map' => [],
// 域名绑定(自动多应用模式有效)
'domain_bind' => [],
// 禁止URL访问的应用列表自动多应用模式有效
'deny_app_list' => [],
// 异常页面的模板文件
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',
// 显示错误信息
'show_error_msg' => false,
];

@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
return [
// 默认缓存驱动
'default' => env('cache.driver', 'file'),
// 缓存连接方式配置
'stores' => [
'file' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => '',
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制 例如 ['serialize', 'unserialize']
'serialize' => [],
],
// 更多的缓存连接
],
];

@ -0,0 +1,11 @@
<?php
// +----------------------------------------------------------------------
// | 控制台配置
// +----------------------------------------------------------------------
return [
// 指令定义
'commands' => [
'checktrial' => app\command\CheckTrial::class,
'checkexpire' => app\command\CheckExpire::class,
],
];

@ -0,0 +1,20 @@
<?php
// +----------------------------------------------------------------------
// | Cookie设置
// +----------------------------------------------------------------------
return [
// cookie 保存时间
'expire' => 0,
// cookie 保存路径
'path' => '/',
// cookie 有效域名
'domain' => '',
// cookie 启用安全传输
'secure' => false,
// httponly设置
'httponly' => false,
// 是否使用 setcookie
'setcookie' => true,
// samesite 设置,支持 'strict' 'lax'
'samesite' => '',
];

@ -0,0 +1,63 @@
<?php
return [
// 默认使用的数据库连接配置
'default' => env('database.driver', 'mysql'),
// 自定义时间查询规则
'time_query_rule' => [],
// 自动写入时间戳字段
// true为自动识别类型 false关闭
// 字符串则明确指定时间字段类型 支持 int timestamp datetime date
'auto_timestamp' => true,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 时间字段配置 配置格式create_time,update_time
'datetime_field' => '',
// 数据库连接配置信息
'connections' => [
'mysql' => [
// 数据库类型
'type' => env('database.type', 'mysql'),
// 服务器地址
'hostname' => env('database.hostname', '127.0.0.1'),
// 数据库名
'database' => env('database.database', ''),
// 用户名
'username' => env('database.username', 'root'),
// 密码
'password' => env('database.password', ''),
// 端口
'hostport' => env('database.hostport', '3306'),
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => env('database.charset', 'utf8'),
// 数据库表前缀
'prefix' => env('database.prefix', ''),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => false,
// 监听SQL
'trigger_sql' => env('app_debug', true),
// 开启字段缓存
'fields_cache' => false,
],
// 更多的数据库配置信息
],
];

@ -0,0 +1,24 @@
<?php
return [
// 默认磁盘
'default' => env('filesystem.driver', 'local'),
// 磁盘列表
'disks' => [
'local' => [
'type' => 'local',
'root' => app()->getRuntimePath() . 'storage',
],
'public' => [
// 磁盘类型
'type' => 'local',
// 磁盘路径
'root' => app()->getRootPath() . 'public/storage',
// 磁盘路径对应的外部URL路径
'url' => '/storage',
// 可见性
'visibility' => 'public',
],
// 更多的磁盘配置信息
],
];

@ -0,0 +1,21 @@
<?php
return [
'secret' => env('JWT_SECRET'),
//Asymmetric key
'public_key' => env('JWT_PUBLIC_KEY'),
'private_key' => env('JWT_PRIVATE_KEY'),
'password' => env('JWT_PASSWORD'),
//JWT time to live
'ttl' => env('JWT_TTL', 60),
//Refresh time to live
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
//JWT hashing algorithm
'algo' => env('JWT_ALGO', 'HS256'),
//token获取方式数组靠前值优先
'token_mode' => ['header', 'cookie', 'param'],
//黑名单后有效期
'blacklist_grace_period' => env('BLACKLIST_GRACE_PERIOD', 10),
'blacklist_storage' => thans\jwt\provider\storage\Tp5::class,
];

@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | 多语言设置
// +----------------------------------------------------------------------
return [
// 默认语言
'default_lang' => env('lang.default_lang', 'zh-cn'),
// 允许的语言列表
'allow_lang_list' => [],
// 多语言自动侦测变量名
'detect_var' => 'lang',
// 是否使用Cookie记录
'use_cookie' => true,
// 多语言cookie变量
'cookie_var' => 'think_lang',
// 多语言header变量
'header_var' => 'think-lang',
// 扩展语言包
'extend_list' => [],
// Accept-Language转义为对应语言包名称
'accept_language' => [
'zh-hans-cn' => 'zh-cn',
],
// 是否支持语言分组
'allow_group' => false,
];

@ -0,0 +1,45 @@
<?php
// +----------------------------------------------------------------------
// | 日志设置
// +----------------------------------------------------------------------
return [
// 默认日志记录通道
'default' => env('log.channel', 'file'),
// 日志记录级别
'level' => [],
// 日志类型记录的通道 ['error'=>'email',...]
'type_channel' => [],
// 关闭全局日志写入
'close' => false,
// 全局日志处理 支持闭包
'processor' => null,
// 日志通道列表
'channels' => [
'file' => [
// 日志记录方式
'type' => 'File',
// 日志保存目录
'path' => '',
// 单文件日志写入
'single' => false,
// 独立日志级别
'apart_level' => [],
// 最大日志文件数量
'max_files' => 0,
// 使用JSON格式记录
'json' => false,
// 日志处理
'processor' => null,
// 关闭通道日志写入
'close' => false,
// 日志输出格式化
'format' => '[%s][%s] %s',
// 是否实时写入
'realtime_write' => false,
],
// 其它日志通道配置
],
];

@ -0,0 +1,8 @@
<?php
// 中间件配置
return [
// 别名或分组
'alias' => [],
// 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
'priority' => [],
];

@ -0,0 +1,45 @@
<?php
// +----------------------------------------------------------------------
// | 路由设置
// +----------------------------------------------------------------------
return [
// pathinfo分隔符
'pathinfo_depr' => '/',
// URL伪静态后缀
'url_html_suffix' => 'html',
// URL普通方式参数 用于自动生成
'url_common_param' => true,
// 是否开启路由延迟解析
'url_lazy_route' => false,
// 是否强制使用路由
'url_route_must' => false,
// 合并路由规则
'route_rule_merge' => false,
// 路由是否完全匹配
'route_complete_match' => false,
// 访问控制器层名称
'controller_layer' => 'controller',
// 空控制器名
'empty_controller' => 'Error',
// 是否使用控制器后缀
'controller_suffix' => false,
// 默认的路由变量规则
'default_route_pattern' => '[\w\.]+',
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
'request_cache_key' => false,
// 请求缓存有效期
'request_cache_expire' => null,
// 全局请求缓存排除规则
'request_cache_except' => [],
// 默认控制器名
'default_controller' => 'Index',
// 默认操作名
'default_action' => 'index',
// 操作方法后缀
'action_suffix' => '',
// 默认JSONP格式返回的处理方法
'default_jsonp_handler' => 'jsonpReturn',
// 默认JSONP处理方法
'var_jsonp_handler' => 'callback',
];

@ -0,0 +1,19 @@
<?php
// +----------------------------------------------------------------------
// | 会话设置
// +----------------------------------------------------------------------
return [
// session name
'name' => 'PHPSESSID',
// SESSION_ID的提交变量,解决flash上传跨域
'var_session_id' => '',
// 驱动方式 支持file cache
'type' => 'file',
// 存储连接标识 当type使用cache的时候有效
'store' => null,
// 过期时间
'expire' => 1440,
// 前缀
'prefix' => '',
];

@ -0,0 +1,10 @@
<?php
// +----------------------------------------------------------------------
// | Trace设置 开启调试模式后有效
// +----------------------------------------------------------------------
return [
// 内置Html和Console两种方式 支持扩展
'type' => 'Html',
// 读取的日志通道名
'channel' => '',
];

@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
return [
// 模板引擎类型使用Think
'type' => 'Think',
// 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
'auto_rule' => 1,
// 模板目录名
'view_dir_name' => 'view',
// 模板后缀
'view_suffix' => 'html',
// 模板文件名分隔符
'view_depr' => DIRECTORY_SEPARATOR,
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '{',
// 标签库标签结束标记
'taglib_end' => '}',
];

2
extend/.gitignore vendored

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

6
package-lock.json generated

@ -0,0 +1,6 @@
{
"name": "ecard_api",
"lockfileVersion": 2,
"requires": true,
"packages": {}
}

@ -0,0 +1 @@
open_basedir=/www/wwwroot/sso.h888.fun/:/tmp/

@ -0,0 +1,198 @@
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Error!!!</title>
<style>
* {
margin:0px auto;
padding: 0px;
text-align:center;
}
body {
background-color: #D4D9ED;
}
.cont_principal {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}
.cont_error {
position: absolute;
width: 100%;
height: 300px;
top: 50%;
margin-top:-150px;
}
.cont_error > h1 {
font-family: 'Lato', sans-serif;
font-weight: 400;
font-size:150px;
color:#fff;
position: relative;
left:-100%;
transition: all 0.5s;
}
.cont_error > p {
font-family: 'Lato', sans-serif;
font-weight: 300;
font-size:24px;
letter-spacing: 5px;
color:#9294AE;
position: relative;
left:100%;
transition: all 0.5s;
transition-delay: 0.5s;
-webkit-transition: all 0.5s;
-webkit-transition-delay: 0.5s;
}
.cont_aura_1 {
position:absolute;
width:300px;
height: 120%;
top:25px;
right: -340px;
background-color: #8A65DF;
box-shadow: 0px 0px 60px 20px rgba(137,100,222,0.5);
-webkit-transition: all 0.5s;
transition: all 0.5s;
}
.cont_aura_2 {
position:absolute;
width:100%;
height: 300px;
right:-10%;
bottom:-301px;
background-color: #8B65E4;
box-shadow: 0px 0px 60px 10px rgba(131, 95, 214, 0.5),0px 0px 20px 0px rgba(0,0,0,0.1);
z-index:5;
transition: all 0.5s;
-webkit-transition: all 0.5s;
}
.cont_error_active > .cont_error > h1 {
left:0%;
}
.cont_error_active > .cont_error > p {
left:0%;
}
.cont_error_active > .cont_aura_2 {
animation-name: animation_error_2;
animation-duration: 4s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
transform: rotate(-20deg);
}
.cont_error_active > .cont_aura_1 {
transform: rotate(20deg);
right:-170px;
animation-name: animation_error_1;
animation-duration: 4s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
}
@-webkit-keyframes animation_error_1 {
from {
-webkit-transform: rotate(20deg);
transform: rotate(20deg);
}
to { -webkit-transform: rotate(25deg);
transform: rotate(25deg);
}
}
@-o-keyframes animation_error_1 {
from {
-webkit-transform: rotate(20deg);
transform: rotate(20deg);
}
to { -webkit-transform: rotate(25deg);
transform: rotate(25deg);
}
}
@-moz-keyframes animation_error_1 {
from {
-webkit-transform: rotate(20deg);
transform: rotate(20deg);
}
to { -webkit-transform: rotate(25deg);
transform: rotate(25deg);
}
}
@keyframes animation_error_1 {
from {
-webkit-transform: rotate(20deg);
transform: rotate(20deg);
}
to { -webkit-transform: rotate(25deg);
transform: rotate(25deg);
}
}
@-webkit-keyframes animation_error_2 {
from { -webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
to { -webkit-transform: rotate(-20deg);
transform: rotate(-20deg);
}
}
@-o-keyframes animation_error_2 {
from { -webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
to { -webkit-transform: rotate(-20deg);
transform: rotate(-20deg);
}
}
}
@-moz-keyframes animation_error_2 {
from { -webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
to { -webkit-transform: rotate(-20deg);
transform: rotate(-20deg);
}
}
@keyframes animation_error_2 {
from { -webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
to { -webkit-transform: rotate(-20deg);
transform: rotate(-20deg);
}
}
</style>
</head>
<body>
<div class="cont_principal">
<div class="cont_error">
<h1>Oops</h1>
<p>The Page you're looking for isn't here.</p>
</div>
<div class="cont_aura_1"></div>
<div class="cont_aura_2"></div>
</div>
</body>
<script>
window.onload = function(){
document.querySelector('.cont_principal').className= "cont_principal cont_error_active";
}
</script>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2019 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// [ 应用入口文件 ]
namespace think;
require __DIR__ . '/../vendor/autoload.php';
define('ROOT_PATH',$_SERVER['DOCUMENT_ROOT']);
// 执行HTTP应用并响应
$http = (new App())->http;
$response = $http->run();
$response->send();
$http->end($response);

@ -0,0 +1,17 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\facade\Route;
Route::get('think', function () {
return 'hello,ThinkPHP6!';
});
Route::get('hello/:name', 'index/hello');

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

10
think

@ -0,0 +1,10 @@
#!/usr/bin/env php
<?php
namespace think;
// 命令行入口文件
// 加载基础文件
require __DIR__ . '/vendor/autoload.php';
// 应用初始化
(new App())->console->run();

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

@ -0,0 +1,2 @@
1.1.5
2012021604

@ -0,0 +1,2 @@
<EFBFBD><EFBFBD>Á À E9³u<06><>`³"PÅ„CÛ牗T!0$
E•ɲQ™<EFBFBD>Ém½úhÛ¾9{kI" 9Ln)Ap¤åÖ¾Ë>ß^‡Õz³mënÅ´mßn†ú¦Ë

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

@ -0,0 +1 @@
xÚí™A E]sëIX´;¸Ün6€È`q”êêW6ñ奚`Œ%A/3!¢°‚¢Š!gÈÌ¡1N) éE¢Ï|;®—>6â¸<C3A2>Þ97$ëÄôëc]kkö<6B>wé1Öü[·m­CÍœcÊRºÄê¹>¦èµ¾šE,•hʼnp„#áxF<1C>yWÏÇVWGçòÕ3¼Õ+шþàË“úSŽâ}Äž<C384>#áG8b^c^cÏÀŽp„c&3YQ"ñŽ÷çÌvµù…ñàÎþþ¼¹kÞ9ŠÜ‡÷}”¹³ï×ú ¢Ä¿<C384>QäÿL—/ÝÔÀÏ

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

@ -0,0 +1,2 @@
xÚí™A
ƒ0E]çÖ…,2;sƒä&ÉÍšh¥ÛêO¡ôÝÈàã1&09OIv@DDÒ Ì&§Ù‰K<E280B0>XÈÕFv•<Ádqò9Ö<%h•¹ Yïs !(d¥²ës;~||b(ÏøYůg#µ`œK ±S¼Åô¹Ä¶˜ùsàidß<64>Lg:Ó™Îtþ/gmª<6D>™ƒkÅMâ3³{­4rTÈQýÿe¥·s·>ó<Ó™Ît¦3<C2A6>éÌ;ïH¼#Ñ™Ît¦3<C2A6>ÍYœ+og©hù¶óµÙ½¬lnðûF>Øi^»#awm;gè~pÛgìNs{6z»ãºïÞäp¾Ê'

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

@ -0,0 +1,3 @@
xÚíšA
Ä E»öÖ.ĚNo Ť¶iiRÚN2áW%đxÁ@ÚÚśę'­
u<EFBFBD>6×ę<EFBFBD>.ť*S;}<7D>«ŇĂ ĎT účĚztąď%ç,ŇĹÚâÎ}ç;“âç)ąź<C485>âÝZÚîLĺčą÷¬Pçç$Ż×÷ĎqËgśLÂôdJ‡;Üáw¸Ăý.]z#źľ«[Íť˝ďOg­Ćô"ĐË áBíî¦}Ç}‡;Üáw¸Ăî<>#1GbŽ„;Üáw¸Ăý_ÝC+w˘@Dfî÷ďç™uťř2™ĹÚÉNţű9R7|pWßkďű®ż“ßßkşöżşú»ĽÎÓ

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

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

Loading…
Cancel
Save