1555 lines
59 KiB
PHP
1555 lines
59 KiB
PHP
<?php
|
||
defined('IN_MET') or exit('No permission');
|
||
|
||
load::sys_class('admin');
|
||
load::sys_func('file');
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | class index 主要入口 应用检测,授权校验,公众号关注,在线更新
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright: 1.0
|
||
// +----------------------------------------------------------------------
|
||
// | Author site: www.metinfo.wang,www.metinfo.cc
|
||
// +----------------------------------------------------------------------
|
||
// | Author QQ: 415420792
|
||
// +----------------------------------------------------------------------
|
||
|
||
//安装锁,存在说明已安装
|
||
define("INS_LOCK_FILE", PATH_APP_FILE."config/install.lock");
|
||
//更新锁,存在说明禁止更新
|
||
define("UPD_LOCK_FILE", PATH_APP_FILE."config/update.lock");
|
||
//更新文件存在要清除
|
||
define("APP_UPDATE_DIR", PATH_APP_FILE."update");
|
||
|
||
class index extends admin {
|
||
|
||
# 验证类型
|
||
private $method;
|
||
# 数据处理核心
|
||
private $ac_appcore;
|
||
# 数据缓存处理机制
|
||
private $ac_session;
|
||
# 进入应用正式页面
|
||
private $ac_get_url;
|
||
#当前时间
|
||
private $time;
|
||
|
||
|
||
# 初始化
|
||
public function __construct() {
|
||
global $_M;
|
||
parent::__construct();
|
||
$this->time = time();
|
||
$this->ac_appcore = new appcore();
|
||
//应用入口
|
||
$this->ac_get_url = $this->ac_appcore->get_app_url();
|
||
}
|
||
|
||
/**
|
||
* 检测入口
|
||
*/
|
||
public function doindex() {
|
||
global $_M;
|
||
if(!file_exists(INS_LOCK_FILE) || $_M['form']['check']){
|
||
//应用信息
|
||
$this->input['app'] = $this->ac_appcore->met_app();
|
||
$this->input['app']['icon'] = $_M['url']['app'].M_NAME.'/icon.png';
|
||
$this->input['app']['appname'] = get_word($this->input['app']['appname']);
|
||
$this->input['app']['addtime'] = date('Y-m-d H:i:s',$this->input['app']['addtime']);
|
||
//整理检查项
|
||
if(!file_exists(INS_LOCK_FILE) || file_exists(UPD_LOCK_FILE) ){
|
||
define("CHECK_ITEM", "server|system|accredit|appfile|weqrcode|appcheck");
|
||
}else{
|
||
define("CHECK_ITEM", "server|system|accredit|appfile|weqrcode|update|appcheck");
|
||
}
|
||
//页面检查项
|
||
$this->input['ckitem'] = CHECK_ITEM;
|
||
require $this->show('app/index',$this->input);
|
||
}else{
|
||
turnover($this->ac_get_url,'No prompt');
|
||
}
|
||
}
|
||
|
||
/*
|
||
+ Ajax 各种数据校验
|
||
+-------------------------------------------------------------------------------------------
|
||
+ doappcheck : 用来进行应用的各项检测入口
|
||
+-------------------------------------------------------------------------------------------
|
||
*/
|
||
public function doappcheck() {
|
||
global $_M;
|
||
$this->ac_session = new session();
|
||
$this->method = $_M['form']['type'];
|
||
//格式掉之前的旧数据
|
||
if($this->method == 'server') self::del_cache();
|
||
// 大于 PHP5.4
|
||
self::{$this->method}();
|
||
self::result();
|
||
|
||
echo $this->ac_appcore->resmsg(false);
|
||
}
|
||
|
||
/*
|
||
+ Ajax 下载更新应用文件
|
||
+-------------------------------------------------------------------------------------------
|
||
+ download : 应用文件的下载入口
|
||
+-------------------------------------------------------------------------------------------
|
||
*/
|
||
public function download() {
|
||
global $_M;
|
||
(new download($this->ac_appcore))->download($_M['form']['data']);
|
||
echo $this->ac_appcore->resmsg(false);
|
||
}
|
||
|
||
/*
|
||
+ Ajax modal body区域
|
||
+-------------------------------------------------------------------------------------------
|
||
+ domodal : 应用模态框数据处理入口
|
||
+-------------------------------------------------------------------------------------------
|
||
*/
|
||
public function domodal() {
|
||
global $_M;
|
||
$this->ac_session = new session();
|
||
switch ($_M['form']['type']) {
|
||
case 'appfile':
|
||
$modal = self::appfile_modal();
|
||
break;
|
||
case 'weqrcode':
|
||
$modal = self::weqrcode_modal();
|
||
break;
|
||
case 'wechat':
|
||
$modal = self::wechat_modal();
|
||
break;
|
||
case 'update':
|
||
$modal = self::update_modal();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
echo $this->ac_appcore->jsoncallback($modal);
|
||
}
|
||
|
||
/*
|
||
+ Ajax
|
||
+-------------------------------------------------------------------------------------------
|
||
+ doajax : 应用最终验证结果核对,以及应用程序使用过程中的应用校验数据延迟访问入口
|
||
+-------------------------------------------------------------------------------------------
|
||
*/
|
||
|
||
public function doajax() {
|
||
global $_M;
|
||
/*
|
||
* 查询API访问时间
|
||
* 若当天没有访问则访问API
|
||
* 若已访问则跳过执行下面
|
||
*
|
||
*/
|
||
|
||
//sign
|
||
$bool = false;
|
||
//wechat、update 值若为1 则是通过,0 为需要执行的,2为忽略的
|
||
if($_M['form']['sign'] == 'appcheck'){
|
||
$time = date('Y-m-d H:i:s',$this->time);
|
||
$ac_session = new session();
|
||
$cache = [
|
||
//记录时间
|
||
'time' => strtotime("{$time} +1 day"),
|
||
//授权结果
|
||
'check' => $ac_session->get('check'),
|
||
//公众号结果
|
||
'wechat' => (int) $ac_session->get('wechat'),
|
||
//是否有最新版本
|
||
'update' => (int) $ac_session->get('update')
|
||
];
|
||
|
||
$listkey = $ac_session->get('ckitem');
|
||
$ckitem = stringto_array(CHECK_ITEM,'|');
|
||
// 后期根据情况再进行具体处理
|
||
if(!in_array(0, $listkey)){
|
||
$bool = true;
|
||
if(file_exists(INS_LOCK_FILE)){
|
||
$msgtext = '<a href="'.$this->ac_get_url.'" class="btn btn-success" >进入应用</a>';
|
||
}else{
|
||
$msgtext = '<button type="button" class="btn btn-info appinstall">安装应用</button>';
|
||
}
|
||
}
|
||
$ac_session->del('ckitem');
|
||
}else{
|
||
//清除缓存
|
||
$this->ac_session = new session();
|
||
self::del_cache();
|
||
//进行检测
|
||
$ac_cache = $this->ac_appcore->mysql_config(array('ac_cache'));
|
||
//解密后的数组
|
||
$cache = (new curls($this->ac_appcore))->postr($ac_cache,'',false)->resdata();
|
||
$post = $this->ac_appcore->met_all();
|
||
//判断是否超时
|
||
if(empty($ac_cache) || $cache['time'] < strtotime("+1 hour") ){
|
||
//API获取
|
||
$this->method = 'check';
|
||
$ajax = self::curljson($post,false,25);
|
||
$cache = $ajax['code']?$ajax['cache']:[];
|
||
}
|
||
//查看本地是否存在禁止更新锁
|
||
if(file_exists(UPD_LOCK_FILE)) $cache['update'] = 1;
|
||
//需要对比数据
|
||
if(!empty($cache)){
|
||
$check = (new curls($this->ac_appcore))
|
||
->apikey_decode([$cache['check'],$post['web']['met_weburl'],$post['app']['m_name'],$post['app']['addtime'] ]);
|
||
$state = $check['state'] && $check['app']['v_m_name'] == M_NAME?true:false;
|
||
if($state){
|
||
if($check['vatime']['minute'] > 0){
|
||
//对有效时间计算
|
||
$time = date('Y-m-d H:i:s',$check['vatime']['stime']);
|
||
$endtime = strtotime("{$time} +{$check['vatime']['minute']} minute");
|
||
if($endtime <= $this->time ) $state = false;
|
||
}
|
||
//最终结果判断
|
||
$bool = $state && !empty($cache['wechat']) && !empty($cache['update'])?true:false;
|
||
}
|
||
}
|
||
//版本号
|
||
if($bool){
|
||
$vertype = ['Y','S','D'];
|
||
$msgtext = "版本号:{$vertype[$check['app']['v_vertype']]}.{$check['app']['v_ver']}";
|
||
if($check['vatime']['minute'] > 0){
|
||
//体验版本结束日期
|
||
$endtime = date('Y-m-d H:i:s',$endtime);
|
||
$msgtext .= " ({$endtime})";
|
||
}
|
||
}
|
||
}
|
||
|
||
$ac_cache['exetime'] = $this->time;
|
||
//缓存记录
|
||
$ac_cache = (new curls($this->ac_appcore))->apipost($cache)->resdata(true);
|
||
$this->ac_appcore->mysql_config(['ac_cache',$ac_cache],false);
|
||
//返回
|
||
$bool?$this->ac_appcore->msgkey(1)->msgmeet($msgtext,true):$this->ac_appcore->locmsg(4012);
|
||
echo $this->ac_appcore->resmsg(false);
|
||
}
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | 应用主方法 限制内部调用
|
||
// +----------------------------------------------------------------------
|
||
|
||
/*
|
||
+ 内部调用
|
||
+-------------------------------------------------------------------------------------------
|
||
+ server : 进行进行服务通信的验证,提供站点信息,站点应用信息给服务端,
|
||
+ 从服务端获取当前应用版本的详细信息,以及系统环境的检测结果并缓存到session
|
||
+-------------------------------------------------------------------------------------------
|
||
+ system : 直接获取缓存的session 直接将环境结果处理返回
|
||
+-------------------------------------------------------------------------------------------
|
||
+ accredit : 提供APP信息给服务端,从服务端获取验证结果
|
||
+-------------------------------------------------------------------------------------------
|
||
+ appfile : 根据APP版本信息,从服务端获取对应的对比指纹
|
||
+ 核心文件出现问题,会直接从服务端自动更新,
|
||
+ 非核心文件会提供手动处理方法,必须修复
|
||
+ 暂时不提供非应用文件进行删除处理。
|
||
+-------------------------------------------------------------------------------------------
|
||
+ weqrcode : 根据站点信息和用户信息,从服务端查询是否符合微信公众号关注要求
|
||
+-------------------------------------------------------------------------------------------
|
||
+ update : 应用在线更新功能
|
||
+-------------------------------------------------------------------------------------------
|
||
*/
|
||
|
||
# 服务端通信检测
|
||
# 通过加密进行处理可防止数据丢失,防止某些敏感参数被过滤掉
|
||
protected function server() {
|
||
global $_M;
|
||
//数据准备
|
||
$server = self::curljson($this->ac_appcore->met_web_app());
|
||
//进行结果处理
|
||
if($server['code']){
|
||
$this->ac_appcore->sucmsg($server['text']);
|
||
}else{
|
||
$this->ac_appcore->errmsg($server['errcode'],$server['errmsg']);
|
||
}
|
||
|
||
//缓存app版本以及环境检测结果
|
||
$this->ac_session->set('applist',$server['applist']);
|
||
$this->ac_session->set('system',$server['system']);
|
||
}
|
||
|
||
# 网站环境检测
|
||
# 环境不存在中间值,要么支持,要么不支持
|
||
protected function system() {
|
||
global $_M;
|
||
//读取缓存
|
||
$system = $this->ac_session->get('system');
|
||
//进行结果处理
|
||
$metver = $system['metver']['code'];
|
||
$phpver = $system['phpver']['code'];
|
||
|
||
$text = [
|
||
[$phpver,$system['phpver']['text']],
|
||
[$metver,$system['metver']['text']]
|
||
];
|
||
$this->ac_appcore->vagmsg($metver && $phpver?1:0,$text);
|
||
//清空缓存
|
||
$this->ac_session->del('system');
|
||
}
|
||
|
||
# 应用授权检测
|
||
protected function accredit() {
|
||
global $_M;
|
||
//数据准备
|
||
$post = $this->ac_appcore->met_web_app();
|
||
$accredit = self::curljson($post,false,20);
|
||
//进行结果处理
|
||
if($accredit['code']){
|
||
//解密
|
||
$apikey = (new curls($this->ac_appcore))->apikey_decode([$accredit['codekey'],$post['web']['met_weburl'],$post['app']['m_name'],$post['app']['addtime']]);
|
||
//校验
|
||
if(!empty($apikey['state']) && $apikey['vatime']['minute'] > 0){
|
||
//对有效时间计算
|
||
$time = date('Y-m-d H:i:s',$apikey['vatime']['stime']);
|
||
$text = '体验结束时间:'.date('Y-m-d H:i:s',strtotime("{$time} +{$apikey['vatime']['minute']} minute"));
|
||
}
|
||
$apikey['state']?$this->ac_appcore->sucmsg($accredit['text'].$text):$this->ac_appcore->locmsg(4024);
|
||
}else{
|
||
$this->ac_appcore->errmsg($accredit['errcode'],$accredit['errmsg']);
|
||
}
|
||
|
||
//记录授权结果
|
||
$this->ac_session->set('check',$accredit['codekey']);
|
||
}
|
||
|
||
#文件指纹对比
|
||
protected function appfile() {
|
||
global $_M;
|
||
//清空需要删的参数
|
||
$this->ac_session->del('repair');
|
||
//获取缓存
|
||
$appfile = $this->ac_session->get('appfile');
|
||
if(!$appfile){
|
||
$appfile = self::curljson($this->ac_appcore->met_web_app());
|
||
//进行结果处理
|
||
if($appfile['code']) {
|
||
$this->ac_session->set('appfile',$appfile);
|
||
}else{
|
||
return $this->ac_appcore->errmsg($appfile['errcode'],$appfile['errmsg']);
|
||
}
|
||
}
|
||
|
||
//文件修复
|
||
$dirfinger = new dirfinger();
|
||
$corelist = $dirfinger->fingers($appfile['corelist']);
|
||
//先自动修复核心框架,再强制让用户修复有问题的文件。
|
||
if(count($corelist['dllist']) > 0){
|
||
//核心文件异常则启动自动修复,若修复失败再进行提示
|
||
$this->ac_session->set('dllist',$corelist['dllist']);
|
||
$modal = $this->ac_appcore->msgkey()->msgtext(4004)->resmsg();
|
||
$modal['suc'] = false;
|
||
$modal['data'] = 'core|check';
|
||
return $this->ac_appcore->newres()->modalmsg($modal, 4001);
|
||
}
|
||
|
||
$fingers = $dirfinger->fingers($appfile['fingers']);
|
||
//删除应用多余的文件
|
||
//$dirfinger->del_appfile($appfile['fingers']);
|
||
//判断是否需要文件修复
|
||
$inslock = (int) file_exists(INS_LOCK_FILE); //安装锁不存在说明新安装,不需要执行文件修复
|
||
$dllock = count($fingers['dllist']) == 0?1:0; //需要修复的文件为0 说明不需要修复
|
||
if(!$inslock || $dllock) {
|
||
//清理掉不再需要的缓存
|
||
$this->ac_session->del('repair');
|
||
$this->ac_session->del('appfile');
|
||
//删除下载的缓存文件
|
||
$this->ac_appcore->del_update_dir();
|
||
return $this->ac_appcore->sucmsg()->msgtext(4003);
|
||
}
|
||
|
||
//非强制更新和非安装状态 且$fingers 大于0时才执行文件修复
|
||
if(count($fingers['dllist']) > 0){
|
||
$this->ac_session->set('dllist',$fingers['dllist']);
|
||
$this->ac_session->set('repair',$fingers);
|
||
$modal = [
|
||
'suc' => true,
|
||
'title' => '应用文件修复',
|
||
'body' => '<div class="text-xs-center"><i class="loader vertical-align-middle loader-ellipsis"></i></div>',
|
||
'url' => $_M['url']['own_form'].'a=domodal&type=appfile'
|
||
];
|
||
$text = '<a href="javascript:;" data-target="#appmodal" data-toggle="modal" data-type="appfile">修复异常文件</a>';
|
||
return $this->ac_appcore->modalmsg($modal, [4002,$text]);
|
||
}
|
||
}
|
||
|
||
# 微信公众号
|
||
protected function weqrcode() {
|
||
global $_M;
|
||
//缓存
|
||
$wechat = $this->ac_session->get('wechat');
|
||
if($wechat !== '') sleep(1);
|
||
//验证
|
||
$weqrcode = self::curljson($this->ac_appcore->met_all());
|
||
if($weqrcode['code']){
|
||
if($weqrcode['wx']['key'] == 1 ){
|
||
$this->ac_appcore->sucmsg($weqrcode['text']);
|
||
}else{
|
||
$modal = [
|
||
'suc' => true,
|
||
'title' => '关注微信公众号',
|
||
'body' => '<div class="text-xs-center"><i class="loader vertical-align-middle loader-ellipsis"></i></div>',
|
||
'url' => $_M['url']['own_form'].'a=domodal&type=weqrcode',
|
||
];
|
||
$text = '<a href="javascript:;" data-target="#appmodal" data-toggle="modal" data-type="weqrcode">关注公众号</a>';
|
||
$this->ac_appcore->modalmsg($modal)
|
||
->sucmsg($weqrcode['wx']['ret']['info'].$text,$weqrcode['wx']['key']);
|
||
}
|
||
}else{
|
||
$this->ac_appcore->errmsg($weqrcode['errcode'],$weqrcode['errmsg']);
|
||
}
|
||
$this->ac_session->set('wechat',$weqrcode['wx']['key']);
|
||
}
|
||
|
||
# 在线更新检测
|
||
protected function update() {
|
||
global $_M;
|
||
$this->ac_session->del('dllist');
|
||
$this->ac_session->del('newapp');
|
||
$applist = $this->ac_session->get('applist');
|
||
//当前版本禁止检测升级 直接报已是最新
|
||
//下个版本禁止升级,直接报已是最新
|
||
// UPD_LOCK_FILE 存在直接报最新
|
||
if(file_exists(UPD_LOCK_FILE) || empty($applist['v_ckupdate'])){
|
||
// 1 为无须无法升级
|
||
// 0、2 有升级
|
||
$this->ac_session->set('update',1);
|
||
return $this->ac_appcore->sucmsg('已是最新版。');
|
||
}
|
||
|
||
//直接检测
|
||
$update = self::curljson($this->ac_appcore->met_web_app());
|
||
if($update['code']){
|
||
//判断是否有指纹需要处理
|
||
if($update['code'] == 8002){
|
||
$this->ac_session->set('update',1);
|
||
return $this->ac_appcore->sucmsg($update['text']);
|
||
}
|
||
//升级文件处理
|
||
$this->ac_session->set('newapp',$update['newapp']);
|
||
$modal = [
|
||
'suc' => true,
|
||
'title' => $update['newapp']['v_ver'].' 更新内容',
|
||
'body' => '<div class="text-xs-center"><i class="loader vertical-align-middle loader-ellipsis"></i></div>',
|
||
'url' => $_M['url']['own_form'].'a=domodal&type=update'
|
||
];
|
||
$text = '<a href="javascript:;" data-target="#appmodal" data-toggle="modal" data-type="update">在线更新</a>';
|
||
$upkey = $update['newapp']['v_update'] == 1?0:2;
|
||
$this->ac_appcore->modalmsg($modal)
|
||
->sucmsg($update['text'].$text,$upkey);
|
||
}else{
|
||
$upkey = 1;
|
||
$this->ac_appcore->errmsg($update['errcode'],$update['errmsg']);
|
||
if(empty($update['system'])){
|
||
$phpver = arrayto_string($update['newapp']['v_phpver'],' -- ');
|
||
$metver = arrayto_string($update['newapp']['v_metver'],' -- ');
|
||
|
||
$phpli = count($update['newapp']['v_phpver']) == 1?'最低':'';
|
||
$metli = count($update['newapp']['v_metver']) == 1?'最低':'';
|
||
$text = "<div class='p-l-10'>
|
||
<h5>".$update['newapp']['v_ver']." 版本环境要求:</h5>
|
||
<ol><li>应用".$phpli."支持PHP ".$phpver." 版本;</li><li>应用".$metli."支持MetInfo ".$metver." 版本;</li></ol>
|
||
<h5>".$update['newapp']['v_ver']." 版本环境检测结果:</h5>
|
||
<ol>".$update['system']['text']."</ol>
|
||
</div>";
|
||
$this->ac_appcore->msgmeet($text);
|
||
}
|
||
}
|
||
//需要缓存的结果
|
||
$this->ac_session->set('update',$upkey);
|
||
}
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | 应用主方法 限制内部调用,主要处理模态框数据的交互
|
||
// +----------------------------------------------------------------------
|
||
|
||
// 文件修复列表
|
||
protected function appfile_modal() {
|
||
global $_M;
|
||
$download = new download($this->ac_appcore);
|
||
$download->download('filelist|check');
|
||
$dllist = $download->app_get_file();
|
||
if(count($dllist['dllist']) == 0){
|
||
return '<div class="text-xs-center">用文件不存在异常。</div>';
|
||
}
|
||
$resmsg = $this->ac_appcore->resmsg();
|
||
if($resmsg > 0){
|
||
$fingers = $this->ac_session->get('repair');
|
||
foreach ($dllist['dllist'] as $key => $val) {
|
||
$text = '';
|
||
if($fingers['updlist'][$val]) $text = '文件被修改';
|
||
if($fingers['dowlist'][$val]) $text = '文件不存在';
|
||
$html .=<<<EOT
|
||
<p>
|
||
<span class="m-r-50">{$text}</span>
|
||
<span class="file_name">{$val}</span>
|
||
<span class="pull-xs-right m-r-15 download_file" data-download="repair|dlfile|{$key}"><a href="javascript:;">点击下载</a></span>
|
||
</p>
|
||
EOT;
|
||
}
|
||
$html = [
|
||
'body' => "<div class='h-250 ov-body'>{$html}</div>",
|
||
'foot' => '<button type="button" class="btn btn-info apprepair">修复全部文件</button>'
|
||
];
|
||
}else{
|
||
$html = ['body' => $resmsg['text'] ];
|
||
}
|
||
return $html;
|
||
}
|
||
|
||
//微信公众号二维码
|
||
protected function weqrcode_modal() {
|
||
global $_M;
|
||
$this->method = 'qrcode';
|
||
$weqrcode = self::curljson($this->ac_appcore->met_all(),false,25,'wx');
|
||
if($weqrcode['code']){
|
||
$wehtml = [
|
||
'body' => '<div class="h-250 text-xs-center"><img style="height:100%;" src="data:image/jpg;base64,'.$weqrcode['qrcode']['img'].'"></div>',
|
||
'foot' => $weqrcode['qrcode']['text']['info'],
|
||
'callback' => 'wechat_qrcode'
|
||
];
|
||
}else{
|
||
$wehtml = [
|
||
'body' => "<p style='text-indent: 2em;'>({$weqrcode['errcode']}){$weqrcode['errmsg']}<p>"
|
||
];
|
||
}
|
||
return $wehtml;
|
||
}
|
||
|
||
//微信公众号轮询
|
||
protected function wechat_modal() {
|
||
global $_M;
|
||
$sign = random(6);
|
||
sleep(1);
|
||
$this->method = 'check';
|
||
$weqrcode = self::curljson($this->ac_appcore->met_all(),false,20,'wx');
|
||
//结果返回
|
||
if($weqrcode['code']){
|
||
$this->ac_appcore->sucmsg($weqrcode['wx']['ret']['info'],$weqrcode['wx']['key']);
|
||
}else{
|
||
$this->ac_appcore->errmsg($weqrcode['errcode'],$weqrcode['errmsg']);
|
||
}
|
||
|
||
//计算2分钟超时
|
||
if(empty($_M['form']['endtime'])){
|
||
$time = date('Y-m-d H:i:s', $this->time);
|
||
$endtime = strtotime("{$time} +2 minute");
|
||
}else{
|
||
if($_M['form']['endtime'] < $this->time){
|
||
$text = '<a class="weqrcode" href="javascript:;" data-type="weqrcode">刷新二维码</a>';
|
||
$this->ac_appcore->locmsg([4023,$text]);
|
||
}else{
|
||
$endtime = $_M['form']['endtime'];
|
||
}
|
||
}
|
||
|
||
$resmsg = $this->ac_appcore->resmsg();
|
||
$resmsg['endtime'] = $endtime;
|
||
$resmsg['sign'] = $sign;
|
||
return $resmsg;
|
||
}
|
||
|
||
//在线更新
|
||
protected function update_modal() {
|
||
global $_M;
|
||
$newapp = $this->ac_session->get('newapp');
|
||
return [
|
||
'body' => strlen($newapp['v_daily']) > 0?"<div class='h-250 ov-body'>{$newapp['v_daily']}</div>":'<p style="text-indent: 2em;">没有更新说明。<p>',
|
||
'foot' => '<button type="button" class="btn btn-info appupdate">更新至 '.$newapp['v_ver'].'</button>'
|
||
];
|
||
}
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | 辅助方法
|
||
// +----------------------------------------------------------------------
|
||
|
||
# 需要格式化掉的数据防止二次使用时错误
|
||
private function del_cache() {
|
||
global $_M;
|
||
$this->ac_session->del('applist');
|
||
$this->ac_session->del('system');
|
||
$this->ac_session->del('check');
|
||
$this->ac_session->del('appfile');
|
||
$this->ac_session->del('repair');
|
||
$this->ac_session->del('dllist');
|
||
$this->ac_session->del('wechat');
|
||
$this->ac_session->del('update');
|
||
$this->ac_session->del('ckitem');
|
||
}
|
||
|
||
# 记录各项检查结果
|
||
private function result() {
|
||
global $_M;
|
||
$code = false;
|
||
$ckitem = $this->ac_session->get('ckitem');
|
||
if($this->method != 'appcheck'){
|
||
$key = $this->ac_appcore->resmsg();
|
||
$ckitem[$this->method] = $key['key'];
|
||
$this->ac_session->set('ckitem',$ckitem);
|
||
}
|
||
}
|
||
|
||
# 将返回信息转为JSON数据
|
||
private function curljson($post = [],$type = false,$timeout = 15,$sign = 'ck' ) {
|
||
global $_M;
|
||
return (new curls($this->ac_appcore))->apiurl($this->method,$sign)
|
||
->apipost($post)
|
||
->curls($timeout)
|
||
->resdata($type);
|
||
}
|
||
|
||
# 应用内容呈现
|
||
protected function show($file, $data){
|
||
global $_M;
|
||
$view =load::sys_class('engine','new');
|
||
require_once $view->dodisplay($file, $data);
|
||
}
|
||
|
||
}
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | class appcore 应用客户端核心处理方法
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright: 1.0
|
||
// +----------------------------------------------------------------------
|
||
// | Author site: www.metinfo.wang,www.metinfo.cc
|
||
// +----------------------------------------------------------------------
|
||
// | Author QQ: 415420792
|
||
// +----------------------------------------------------------------------
|
||
class appcore{
|
||
|
||
# 应用文件名
|
||
private $m_name;
|
||
# 站点信息
|
||
private $web = [];
|
||
# 应用信息
|
||
private $app = [];
|
||
# 管理员权限
|
||
private $aop = [];
|
||
# 错误信息的提示
|
||
private $tipmsg = [];
|
||
# 返回的信息结果
|
||
private $resmsg = [];
|
||
|
||
# 初始化
|
||
public function __construct() {
|
||
global $_M;
|
||
$this->m_name = M_NAME;
|
||
}
|
||
|
||
# 获取应用入口
|
||
public function get_app_url() {
|
||
global $_M;
|
||
$settings = file_exists(INS_LOCK_FILE)?json_decode(file_get_contents(INS_LOCK_FILE),true):[];
|
||
if(empty($settings['url'])){
|
||
unset($settings['url'],$settings['time']);
|
||
$get_url = $_M['url']['own_name'].http_build_query($settings);
|
||
}else{
|
||
$get_url = $settings['url'];
|
||
}
|
||
return $get_url;
|
||
}
|
||
|
||
# 站点信息和应用信息
|
||
public function met_web_app() {
|
||
global $_M;
|
||
return [
|
||
'web' => self::met_web(),
|
||
'app' => self::met_app()
|
||
];
|
||
}
|
||
|
||
# 获取站点信息以及权限查询
|
||
public function met_all() {
|
||
global $_M;
|
||
$met = self::met_web_app();
|
||
$met['aop'] = self::met_aop();
|
||
return $met;
|
||
}
|
||
|
||
# 站点信息查询
|
||
public function met_web() {
|
||
global $_M;
|
||
// 站点信息
|
||
$name = ['met_weburl','met_webname','metcms_v','met_keywords','met_description','met_skin_user'];
|
||
foreach ($name as $val) {
|
||
$lang = $val == 'metcms_v'?'metinfo':$_M['lang'];
|
||
$met = DB::get_one("SELECT value FROM {$_M['table']['config']} WHERE name = '{$val}' AND lang = '{$lang}' ");
|
||
$this->web[$val] = $met['value'];
|
||
}
|
||
$this->web['webip'] = $_SERVER['SERVER_ADDR'];
|
||
$this->web['sysver'] = php_uname('s').' '.php_uname('r');
|
||
$this->web['phpver'] = PHP_VERSION;
|
||
$this->web['sqlver'] = DB::version();
|
||
$this->web['webver'] = str_replace("PHP/{$this->web['phpver']}","",$_SERVER['SERVER_SOFTWARE']);
|
||
$this->web['lang'] = $_M['lang'];
|
||
return $this->web;
|
||
}
|
||
|
||
# 应用信息查询
|
||
public function met_app() {
|
||
global $_M;
|
||
//应用信息
|
||
if(!empty($this->m_name)) {
|
||
$this->app = DB::get_one("SELECT no,ver,addtime,m_name,appname FROM {$_M['table']['applist']} WHERE m_name='{$this->m_name}' ");
|
||
}
|
||
$this->app['client_ip'] = self::get_client_ip();
|
||
return $this->app;
|
||
}
|
||
|
||
# 下载权限处理需求
|
||
public function met_adl() {
|
||
global $_M;
|
||
//应用信息
|
||
if(!empty($this->m_name)) {
|
||
$this->adl = DB::get_one("SELECT no,ver,addtime,m_name FROM {$_M['table']['applist']} WHERE m_name='{$this->m_name}' ");
|
||
}
|
||
//域名
|
||
$met = DB::get_one("SELECT value FROM {$_M['table']['config']} WHERE name = 'met_weburl' AND lang = '{$_M['lang']}' ");
|
||
$this->adl['met_weburl'] = $met['value'];
|
||
return $this->adl;
|
||
}
|
||
|
||
# 公众号关注管理员权限
|
||
public function met_aop() {
|
||
global $_M;
|
||
$admin = admin_information();
|
||
//管理员权限
|
||
$this->aop = [
|
||
'admin_id' => $admin['admin_id'],
|
||
'admin_op' => $admin['admin_op'],
|
||
'admin_ip' => $admin['admin_modify_ip'],
|
||
'admin_time' => $admin['admin_modify_date'],
|
||
];
|
||
return $this->aop;
|
||
}
|
||
|
||
# 对resmsg 初始化
|
||
public function newres() {
|
||
global $_M;
|
||
$this->resmsg = [];
|
||
return $this;
|
||
}
|
||
|
||
# 提示信息返回
|
||
# $type true 为数组,false 为json
|
||
# $unset true 清空避免重复使用出现问题 false 暂时不清空
|
||
public function resmsg($type = true,$unset = false) {
|
||
global $_M;
|
||
//检测值是否存在
|
||
if(strlen($this->resmsg['key']) == 0) self::locmsg(4012);
|
||
//检测项的值
|
||
$this->resmsg['eqkey'] = $_M['form']['eqkey'];
|
||
//返回值
|
||
$resmsg = $type?$this->resmsg: self::jsoncallback($this->resmsg);
|
||
//注销
|
||
if($unset) unset($this->resmsg);
|
||
return $resmsg;
|
||
}
|
||
|
||
# 正确结果返回
|
||
public function sucmsg($msg,$code = 1) {
|
||
global $_M;
|
||
$this->resmsg['key'] = $code;
|
||
$this->resmsg['text'] = self::fontcolor($code,$msg);
|
||
return $this;
|
||
}
|
||
|
||
# 多种结果返回
|
||
public function vagmsg($code,$msg = []) {
|
||
global $_M;
|
||
$text = '';
|
||
foreach ($msg as $val) {
|
||
list($k,$v) = $val;
|
||
$text .= self::fontcolor($k,$k?$v['info']:"({$v['coding']}){$v['info']}");
|
||
}
|
||
$this->resmsg['key'] = $code;
|
||
$this->resmsg['text'] = $text;
|
||
return $this;
|
||
}
|
||
|
||
# 错误结果返回
|
||
# $code 这个是错误的编码
|
||
# $msg 错误的信息提示
|
||
public function errmsg($coding,$msg,$code = 0) {
|
||
global $_M;
|
||
$this->resmsg['key'] = $code;
|
||
$this->resmsg['text'] = self::fontcolor(0,"({$coding}){$msg}");
|
||
return $this;
|
||
}
|
||
|
||
# 返回本地编码信息
|
||
# $code 状态
|
||
# $msg 错误的信息提示
|
||
public function locmsg($msg = [],$code = 0) {
|
||
global $_M;
|
||
if(!empty($msg)) self::codemsg($msg);
|
||
$this->resmsg['key'] = $code;
|
||
$this->resmsg['text'] = self::fontcolor($code,"({$this->tipmsg['errcode']}){$this->tipmsg['errmsg']}");
|
||
return $this;
|
||
}
|
||
|
||
# 错误结果返回
|
||
# $modal 模态框的内容
|
||
# $code 校验结果状态
|
||
# $error 错误信息提示 提示码以及需要增加的文字
|
||
public function modalmsg($modal = [], $error = [],$code = 0) {
|
||
global $_M;
|
||
self::locmsg($error,$code);
|
||
$this->resmsg['modal'] = $modal;
|
||
return $this;
|
||
}
|
||
|
||
# 替换key
|
||
public function msgkey($key = 4) {
|
||
global $_M;
|
||
$this->resmsg['key'] = $key;
|
||
return $this;
|
||
}
|
||
|
||
# 使用本地错误代码替换返回信息内的text
|
||
public function msgtext($error = []) {
|
||
global $_M;
|
||
self::codemsg($error);
|
||
$this->resmsg['text'] = self::fontcolor($this->resmsg['key'],$this->tipmsg['errmsg']);
|
||
return $this;
|
||
}
|
||
|
||
# text
|
||
# $type true 覆盖,false 为拼接
|
||
public function msgmeet($text,$type = false) {
|
||
global $_M;
|
||
$this->resmsg['text'] = $type?$text:$this->resmsg['text'].$text;
|
||
return $this;
|
||
}
|
||
|
||
# 对提示文字的HTML处理
|
||
private function fontcolor($code,$text) {
|
||
global $_M;
|
||
// 红、绿、黄
|
||
$color = ['#E9595B','#36AB7A','#EC9940','#76838f','#2a333c'];
|
||
return '<font style="color:'.$color[$code].';">'.$text.'</font>';
|
||
}
|
||
|
||
# 错误提示语返回字符串格式
|
||
# $type true 字符串,false 为JSON
|
||
public function coderes($type = true) {
|
||
global $_M;
|
||
return $type?$this->tipmsg['errmsg']:json_encode($this->tipmsg,JSON_UNESCAPED_UNICODE);
|
||
}
|
||
|
||
# 错误代码信息
|
||
public function codemsg($coding,$text = '') {
|
||
global $_M;
|
||
if(is_array($coding)) list($coding,$text) = $coding;
|
||
$msg = [
|
||
'4000' => "当前环境缺少CURL支持!",
|
||
'4001' => "核心文件存在异常,准备自动修复核心文件...", //修复文件
|
||
'4002' => "应用文件存在异常请点击 {$text} !", //修复文件
|
||
'4003' => "应用文件正常!",
|
||
'4004' => "文件权限检测中...",
|
||
'4005' => " {$text} 不存在,请手动创建!",
|
||
'4006' => " {$text} 权限不足,请修改为[777/775]增加写入权限!",
|
||
'4007' => " {$text} 数据写入错误,请自行检测权限!",
|
||
'4008' => "下载权限不足(请检查【网站网址】是否为购买应用的域名)!",
|
||
'4009' => "应用文件下载中...",
|
||
'4010' => "应用文件下载中...{$text} (正在进行下载,请不要操作页面!)",
|
||
'4011' => "服务端异常[{$text}],通信失败!",
|
||
'4012' => "系统异常!",
|
||
'4013' => "应用文件,开始修复...",
|
||
'4014' => "[核心文件自动修复] 修复完成。",
|
||
'4015' => "应用文件修复完成。",
|
||
'4016' => "[{$text}] 下载失败!",
|
||
'4017' => "修复失败!",
|
||
'4018' => "安装失败!",
|
||
'4019' => "安装成功!",
|
||
'4020' => "应用文件,开始安装...",
|
||
'4021' => "[{$text}] 写入失败!",
|
||
'4022' => "未检测到文件!",
|
||
'4023' => "微信公众号二维码扫描超时!{$text}",
|
||
'4024' => "域名未获得授权!",
|
||
'4025' => "安装锁权限不足!",
|
||
];
|
||
|
||
$this->tipmsg = ['errcode' => $coding,'errmsg' => $msg[$coding]];
|
||
return $this;
|
||
}
|
||
|
||
# 密钥获取和保存
|
||
# $mode true是读取 false是保存
|
||
public function mysql_config($arr = [],$mode = true) {
|
||
global $_M;
|
||
list($key,$val) = $arr;
|
||
$table = $_M['table']['cloud_config'];
|
||
$lang = 'cloud';
|
||
if($mode){
|
||
$config = DB::get_one("select value from {$table} where name = '{$key}' AND m_name = '{$this->m_name}' AND lang = '{$lang}' ");
|
||
$val = $config['value'];
|
||
}else{
|
||
DB::query("INSERT INTO {$table} (name,lang,m_name,value) VALUES ('{$key}','{$lang}','{$this->m_name}','{$val}') ON DUPLICATE KEY UPDATE value='{$val}' ");
|
||
}
|
||
return $val;
|
||
}
|
||
|
||
// 获取客户端IP
|
||
public function get_client_ip(){
|
||
$arr_ip_header = [
|
||
// 非常见
|
||
'HTTP_CDN_SRC_IP',
|
||
'HTTP_PROXY_CLIENT_IP',
|
||
'HTTP_WL_PROXY_CLIENT_IP',
|
||
// 一般用下面三个
|
||
'HTTP_CLIENT_IP',
|
||
'HTTP_X_FORWARDED_FOR',
|
||
'REMOTE_ADDR'
|
||
];
|
||
$client_ip = 'unknown';
|
||
foreach ($arr_ip_header as $key){
|
||
if (!empty($_SERVER[$key]) && strtolower($_SERVER[$key]) != 'unknown' && filter_var($_SERVER[$key], FILTER_VALIDATE_IP)){
|
||
$client_ip = $_SERVER[$key];
|
||
break;
|
||
}
|
||
}
|
||
return $client_ip;
|
||
}
|
||
|
||
/*
|
||
* 把数组转成JSON,用于ajax返回,可以用于普通json请求返回,也可以用于跨域的ajax的jsonp格式的数据请求返回。
|
||
* @param array $back 输出字符串或数组
|
||
* @param string $callback ajax的回调函数的名称
|
||
*/
|
||
public function jsoncallback($back, $callback = 'callback') {
|
||
global $_M;
|
||
header('Content-type: application/x-javascript');
|
||
$callback = $_M['form'][$callback];
|
||
$json = json_encode($back,JSON_UNESCAPED_UNICODE);
|
||
echo $callback?$callback . '(' . $json . ')':$json;
|
||
}
|
||
|
||
//删除更新文件夹
|
||
public function del_update_dir() {
|
||
global $_M;
|
||
@clearstatcache();
|
||
//检测文件是否存在,删除缓存的file
|
||
if(is_dir(APP_UPDATE_DIR) && file_exists(APP_UPDATE_DIR)) deldir(APP_UPDATE_DIR);
|
||
}
|
||
|
||
}
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | class curls 应用CURL
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright: 1.0
|
||
// +----------------------------------------------------------------------
|
||
// | Author site: www.metinfo.wang,www.metinfo.cc
|
||
// +----------------------------------------------------------------------
|
||
// | Author QQ: 415420792
|
||
// +----------------------------------------------------------------------
|
||
class curls{
|
||
|
||
# 应用主方法
|
||
private $appcore;
|
||
# 应用APIURL
|
||
private $urlarr = [];
|
||
# 应用API
|
||
private $apiurl = [];
|
||
# 网址协议
|
||
private $scheme;
|
||
# 提交数据和返回数据的缓存
|
||
private $data;
|
||
# 默认密钥
|
||
private $apikey;
|
||
# 信息
|
||
private $headers = [];
|
||
|
||
# 初始化
|
||
public function __construct($appcore) {
|
||
global $_M;
|
||
$this->appcore = $appcore;
|
||
// 选择执行URL,提交的数据,对数据的处理,提交服务端,数据的处理,返回结果
|
||
$this->urlarr = [
|
||
// 应用信息验证URL
|
||
'ck' => 'https://app.muban.net.cn/api/appcheck.php?a=do',
|
||
// 应用下载更新URL
|
||
'dl' => 'https://app.muban.net.cn/api/download.php?a=do',
|
||
//公众号
|
||
'wx' => 'https://app.muban.net.cn/api/wechat.php?a=do'
|
||
];
|
||
$this->apikey = md5($_M['config']['met_weburl']);
|
||
$this->headers = [
|
||
'METWEBURL:' . $_M['config']['met_weburl'],
|
||
'AUTHORIZATION:' . $this->apikey
|
||
];
|
||
}
|
||
|
||
# URL选择
|
||
public function apiurl($method,$type = 'ck') {
|
||
global $_M;
|
||
$this->apiurl = $this->urlarr[$type].$method;
|
||
$this->scheme = self::purl($this->apiurl,'scheme');
|
||
return $this;
|
||
}
|
||
|
||
# 数据处理
|
||
# $ende true加密 false 不执行加密
|
||
public function apipost($post,$ende = true) {
|
||
global $_M;
|
||
$this->data = $post;
|
||
// 若要采用非默认密钥这里设置false,单独调用加密方法
|
||
if($ende) self::auth_encode();
|
||
return $this;
|
||
}
|
||
|
||
# 对数据加密
|
||
# $str 加密数据 $key 加密密钥
|
||
public function auth_encode($key = null) {
|
||
global $_M;
|
||
if(!empty($key)) $this->apikey = $key;
|
||
if(is_array($this->data)) self::arrjson(false);
|
||
$this->data = authcode($this->data,'ENCODE', $this->apikey);
|
||
return $this;
|
||
}
|
||
|
||
# 授权查询 授权代码结束
|
||
public function curls($timeout = 15) {
|
||
global $_M;
|
||
if (get_extension_funcs('curl') && function_exists('curl_init') && function_exists('curl_setopt') && function_exists('curl_exec') && function_exists('curl_close')) {
|
||
$curl = curl_init();
|
||
curl_setopt($curl, CURLOPT_URL, $this->apiurl);
|
||
if($this->scheme === 'https') {
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //不做服务器认证
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); //不做客户端认证
|
||
}
|
||
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||
curl_setopt($curl, CURLOPT_REFERER, $_SERVER["HTTP_HOST"]);
|
||
curl_setopt($curl, CURLOPT_HTTPHEADER, $this->headers);
|
||
curl_setopt($curl, CURLOPT_FAILONERROR, 1); //返回http >= 400的错误代码
|
||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
|
||
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
|
||
curl_setopt($curl, CURLOPT_POST, 1);
|
||
curl_setopt($curl, CURLOPT_POSTFIELDS, ['dense' => $this->data]);
|
||
$data = curl_exec($curl);
|
||
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE); //http响应码
|
||
$errno = curl_errno($curl); //错误码
|
||
curl_close($curl);
|
||
$this->data = empty($errno)?$data:$this->appcore->codemsg(4011,"{$code}-{$errno}")->coderes(false);
|
||
}else{
|
||
$this->data = $this->appcore->codemsg(4000)->coderes(false);
|
||
}
|
||
return $this;
|
||
}
|
||
|
||
# 对数据解密
|
||
# $str 加密数据 $key 加密密钥
|
||
public function auth_decode($key = null) {
|
||
global $_M;
|
||
if(!empty($key)) $this->apikey = $key;
|
||
$this->data = authcode($this->data,'DECODE', $this->apikey);
|
||
return $this;
|
||
}
|
||
|
||
# 数据格式转换
|
||
# $type true 转为数组 false 转为json
|
||
public function arrjson($type = true) {
|
||
global $_M;
|
||
$this->data = $type?json_decode($this->data,true):json_encode($this->data,JSON_UNESCAPED_UNICODE);
|
||
return $this;
|
||
}
|
||
|
||
# 返回的数据处理
|
||
# $type true 返回源数据,false 返回数组
|
||
public function resdata($type = false) {
|
||
global $_M;
|
||
if($type == false) self::arrjson();
|
||
return $this->data;
|
||
}
|
||
|
||
# 单独处理数据的加密和解密
|
||
# $type true 加密,false 解密
|
||
# $post 有数据则执行,无数据则直接返回postr
|
||
public function postr($post = null,$key = null,$type = true) {
|
||
global $_M;
|
||
self::apipost($post,false);
|
||
if($type){
|
||
self::auth_encode($key);
|
||
}else{
|
||
self::auth_decode($key);
|
||
}
|
||
return $this;
|
||
}
|
||
|
||
# 授权密钥解密
|
||
public function apikey_decode($appkey = []) {
|
||
global $_M;
|
||
list($apikey,$domian,$m_name,$addtime) = $appkey;
|
||
$domian = self::purl($domian);
|
||
return self::postr($apikey, md5($domian.md5($m_name.$addtime)),false)->resdata();
|
||
}
|
||
|
||
# 分析网址
|
||
public function purl($url,$type = 'host') {
|
||
global $_M;
|
||
$url = url_standard($url);
|
||
$array = parse_url($url);
|
||
return $type == 'arr'?$array:$array[$type];
|
||
}
|
||
|
||
}
|
||
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | class session 应用检测会话缓存
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright: 1.0
|
||
// +----------------------------------------------------------------------
|
||
// | Author site: www.metinfo.wang,www.metinfo.cc
|
||
// +----------------------------------------------------------------------
|
||
// | Author QQ: 415420792
|
||
// +----------------------------------------------------------------------
|
||
class session{
|
||
|
||
# 应用文件名
|
||
private $se_m_name = M_NAME;
|
||
|
||
public function __construct() {
|
||
global $_M;
|
||
self::start();
|
||
}
|
||
|
||
public function start(){
|
||
$ip = self::getip();
|
||
session_id(md5($_SERVER['HTTP_USER_AGENT'].$this->se_m_name.$ip));
|
||
session_start();
|
||
}
|
||
|
||
public function set($name, $value){
|
||
self::start();
|
||
$_SESSION[$name] = $value;
|
||
}
|
||
|
||
public function get($name){
|
||
self::start();
|
||
return $_SESSION[$name];
|
||
}
|
||
|
||
public function del($name){
|
||
self::start();
|
||
unset($_SESSION[$name]);
|
||
}
|
||
|
||
public function getip() {
|
||
$unknown = 'unknown';
|
||
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], $unknown)){
|
||
$pro = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
|
||
$ip = $pro[0];
|
||
}elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], $unknown)) {
|
||
$ip = $_SERVER['REMOTE_ADDR'];
|
||
}
|
||
return $ip;
|
||
}
|
||
|
||
}
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | class dirfinger 应用检测指纹校对
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright: 1.0
|
||
// +----------------------------------------------------------------------
|
||
// | Author site: www.metinfo.wang,www.metinfo.cc
|
||
// +----------------------------------------------------------------------
|
||
// | Author QQ: 415420792
|
||
// +----------------------------------------------------------------------
|
||
class dirfinger {
|
||
|
||
# 应用所在目录
|
||
private $appfile;
|
||
# 需要跳过的文件,不分目录
|
||
private $skipfile = [];
|
||
# 需要跳过的目录以及按照目录跳过文件
|
||
private $skipdir = [];
|
||
# 跟服务端指纹不同的文件路径
|
||
private $updlist = [];
|
||
# 需要从服务器下载的文件
|
||
private $dllist = [];
|
||
|
||
# 初始化
|
||
public function __construct() {
|
||
global $_M;
|
||
$this->appfile = PATH_APP_FILE;
|
||
$this->skipfile = [];
|
||
$this->skipdir = [
|
||
'config/install.lock',
|
||
'config/update.lock',
|
||
'config/uninstall.lock',
|
||
'config/table'
|
||
];
|
||
@clearstatcache();
|
||
}
|
||
|
||
# 对比指纹入口
|
||
public function fingers($fingers = []) {
|
||
global $_M;
|
||
//指纹对比
|
||
self::fingerprint_check($fingers);
|
||
//记录已经进行过指纹对比
|
||
return [
|
||
'updlist' => $this->updlist, //需要更新的文件,跟服务端不同的文件
|
||
'dowlist' => $this->dowlist, //需要下载的文件,客户端不存在,而服务端存在的
|
||
'dllist' => $this->dllist //需要从服务器下载的文件,包含更新和下载
|
||
];
|
||
}
|
||
|
||
//删除应用文件以外的文件
|
||
public function del_appfile($fingers = [], $dir = '') {
|
||
global $_M;
|
||
$files = scandir($this->appfile.$dir);
|
||
foreach ($files as $file) {
|
||
$dirfile = $dir.$file;
|
||
if(stristr(PHP_OS, "WIN")){
|
||
$dirfiles = iconv("GBK","UTF-8", $dirfile);
|
||
$file = iconv("GBK","UTF-8", $file);
|
||
}else{
|
||
$dirfiles = $dirfile;
|
||
}
|
||
if(in_array($dirfiles,$this->skipdir) || in_array($file,$this->skipfile)) continue;
|
||
if(is_dir($this->appfile.$dirfile)){
|
||
self::del_appfile($fingers,$dirfile.'/');
|
||
}else{
|
||
//判断文件是否存在
|
||
if(!array_key_exists($dirfiles,$fingers) ) delfile($dirfile);
|
||
}
|
||
}
|
||
}
|
||
|
||
# 应用指纹校验
|
||
private function fingerprint_check($flist = ''){
|
||
global $_M;
|
||
foreach ($flist as $key => $val) {
|
||
//文件路径
|
||
$dirfile = $this->appfile.$key;
|
||
if(stristr(PHP_OS, "WIN")) $dirfile = iconv("UTF-8","GBK", $dirfile);
|
||
//检查文件是否存在
|
||
if(file_exists($dirfile)){
|
||
//比对MD5
|
||
if(md5_file($dirfile) != $val){
|
||
$this->updlist[$key] = $val;
|
||
$this->dllist[$key] = $val;
|
||
}
|
||
}else{
|
||
//需要下载的
|
||
$this->dowlist[$key] = $val;
|
||
$this->dllist[$key] = $val;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
// +----------------------------------------------------------------------
|
||
// | class download 应用文件下载更新
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright: 1.0
|
||
// +----------------------------------------------------------------------
|
||
// | Author site: www.metinfo.wang,www.metinfo.cc
|
||
// +----------------------------------------------------------------------
|
||
// | Author QQ: 415420792
|
||
// +----------------------------------------------------------------------
|
||
class download{
|
||
|
||
#传送的数据
|
||
private $modal;
|
||
#远端接口
|
||
private $method;
|
||
# 应用主方法
|
||
public $ac_appcore;
|
||
private $ac_session;
|
||
# 应用文件
|
||
private $appfile;
|
||
# 应用下载缓存文件夹
|
||
private $appupdir;
|
||
# 下载的文件存放目录,方便迁移
|
||
private $appupfile;
|
||
# 应用下载缓存文件
|
||
private $appdllist;
|
||
|
||
# 下载需要的网站应用数据
|
||
private $met_adl;
|
||
# 当前执行的状态
|
||
private $cksign;
|
||
|
||
# 初始化
|
||
public function __construct($appcore) {
|
||
global $_M;
|
||
$this->appfile = PATH_APP_FILE;
|
||
$this->appupdir = APP_UPDATE_DIR;
|
||
$this->appupfile = APP_UPDATE_DIR.'/file/';
|
||
$this->appdllist = APP_UPDATE_DIR.'/dllist.json';
|
||
$this->ac_appcore = $appcore;
|
||
$this->ac_session = new session();
|
||
$this->met_adl = $this->ac_appcore->met_adl();
|
||
}
|
||
|
||
# 下载更新入口
|
||
public function download($data) {
|
||
global $_M;
|
||
//执行方法,进度
|
||
list($cksign,$method,$step,$rate,$total) = explode('|', $data);
|
||
//正确时的回调值
|
||
$this->cksign = $cksign;
|
||
$this->method = $method;
|
||
//回调传送的数据
|
||
$this->modal = [
|
||
'suc' => false,
|
||
'data' => ['cksign' => $this->cksign, 'method' => $this->method, 'step' => $step]
|
||
];
|
||
//若是更新则获取最新版本的版本号
|
||
if($this->cksign == 'update') {
|
||
$this->met_adl['oldver'] = $this->met_adl['ver'];
|
||
$this->met_adl['ver'] = self::app_update_ver();
|
||
}
|
||
switch ($method) {
|
||
case 'check':
|
||
self::app_file_check();
|
||
break;
|
||
case 'dl':
|
||
self::app_file_dl($step);
|
||
break;
|
||
case 'core':
|
||
self::app_file_core();
|
||
break;
|
||
case 'repair':
|
||
self::app_file_repair();
|
||
break;
|
||
case 'dlfile':
|
||
$this->method = 'dl';
|
||
//单个文件下载并更新,只要返回的结果
|
||
self::app_file_dl($step);
|
||
self::app_file_repair();
|
||
$resmsg = $this->ac_appcore->resmsg();
|
||
if($resmsg['key'] == 4) $this->ac_appcore->msgkey(1);
|
||
break;
|
||
case 'update':
|
||
case 'install':
|
||
//全新安装
|
||
self::app_file_install();
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
# 检测应用版本是否存在
|
||
public function app_file_check() {
|
||
global $_M;
|
||
//检测文件是否存在,删除缓存的file
|
||
if(file_exists($this->appupdir)){
|
||
deldir($this->appupdir,1);
|
||
modifydirpower($this->appupdir,0777);
|
||
}else{
|
||
modifydirpower($this->appfile,0777);
|
||
makedir($this->appupdir);
|
||
}
|
||
|
||
//在这里查看文件是否存在
|
||
$dir = str_replace(PATH_WEB,'',$this->appupdir);
|
||
if(!file_exists($this->appupdir)) return $this->ac_appcore->locmsg([4005,$dir]);
|
||
|
||
//验证文件是否可写
|
||
if(!getdirpower($this->appupdir)) return $this->ac_appcore->locmsg([4006,$dir]);
|
||
|
||
//检查授权
|
||
$statekey = self::statekey();
|
||
if(empty($statekey)) return $this->ac_appcore->locmsg(4008);
|
||
|
||
//获取下载指纹列表
|
||
if(in_array($this->cksign,['install','update'])){
|
||
$check = self::curljson(['adl' => $this->met_adl]);
|
||
if($check['code']){
|
||
$dllist = $check['dllist'];
|
||
}else{
|
||
return $this->ac_appcore->errmsg($check['errcode'],$check['errmsg']);
|
||
}
|
||
}else{
|
||
$dllist = $this->ac_session->get('dllist');
|
||
$this->ac_session->del('dllist');
|
||
}
|
||
|
||
if(count($dllist) > 0){
|
||
//写入指纹文件
|
||
$phpcode = json_encode(['dllist' => array_keys($dllist),'fingers' => $dllist ],JSON_UNESCAPED_UNICODE);
|
||
if(file_put_contents($this->appdllist,$phpcode) === false){
|
||
$file = str_replace(PATH_WEB,'',$this->appdllist);
|
||
return $this->ac_appcore->locmsg([4007,$file]);
|
||
}
|
||
//返回开始下载文件
|
||
$this->ac_appcore->modalmsg(self::modal(0,'dl'))->msgkey()->msgtext(4009);
|
||
}else{
|
||
$this->ac_appcore->locmsg(4022);
|
||
}
|
||
|
||
}
|
||
|
||
# APP文件下载
|
||
public function app_file_dl($step) {
|
||
global $_M;
|
||
//获取缓存信息
|
||
$filelist = self::app_get_file();
|
||
if(count($filelist['dllist']) == $step){
|
||
$this->ac_appcore->modalmsg(self::modal($step,$this->cksign))
|
||
->msgkey()
|
||
->msgtext(in_array($this->cksign,['install','update'])?4020:4013);
|
||
}else{
|
||
set_time_limit(60);
|
||
//数据整理
|
||
$this->met_adl['dirfile'] = $filelist['dllist'][$step];
|
||
$this->met_adl['filehash'] = $filelist['fingers'][$this->met_adl['dirfile']];
|
||
$file = self::curljson(['adl' => $this->met_adl]);
|
||
//处理结果
|
||
if($file['code']){
|
||
$dirfile = $this->appupfile.$this->met_adl['dirfile'];
|
||
if (stristr(PHP_OS, "WIN")) $dirfile = iconv("UTF-8","GBK", $dirfile);
|
||
if (!file_exists($dirfile)) makefile($dirfile);
|
||
|
||
//写入文件
|
||
$defile = base64_decode($file['file']);
|
||
if(file_put_contents($dirfile, $defile) == false && strlen($defile) > 0){
|
||
$this->ac_appcore->locmsg([4021,$this->met_adl['dirfile']]);
|
||
}else{
|
||
//检查指纹
|
||
if($this->met_adl['filehash'] != md5_file($dirfile)){
|
||
$this->ac_appcore->locmsg([4016,$this->met_adl['dirfile']]);
|
||
}else{
|
||
$step++;
|
||
$text = floor((($step)/count($filelist['dllist']))*100)."%";
|
||
$this->ac_appcore->modalmsg(self::modal($step))->msgkey()->msgtext([4010,$text]);
|
||
}
|
||
}
|
||
} else {
|
||
$this->ac_appcore->errmsg($file['errcode'],$file['errmsg']);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
# 自动更新处理
|
||
public function app_file_core() {
|
||
global $_M;
|
||
//进行文件移动覆盖,成功则返回相关信息
|
||
if(movedir($this->appupfile, $this->appfile)){
|
||
@clearstatcache();
|
||
unset($this->modal['data']);
|
||
$this->ac_appcore->modalmsg(self::modal())
|
||
->msgkey(1)
|
||
->msgtext(4014);
|
||
}else{
|
||
$this->ac_appcore->locmsg(4017);
|
||
}
|
||
|
||
}
|
||
|
||
# 手动文件更新
|
||
public function app_file_repair() {
|
||
global $_M;
|
||
//进行文件复制,成功则返回相关信息
|
||
if(copydir($this->appupfile, $this->appfile)){
|
||
@clearstatcache();
|
||
unset($this->modal['data']);
|
||
$this->ac_appcore->modalmsg(self::modal())
|
||
->msgkey(1)
|
||
->msgtext(4015);
|
||
}else{
|
||
$this->ac_appcore->locmsg(4017);
|
||
}
|
||
}
|
||
|
||
# 文件全新安装
|
||
public function app_file_install() {
|
||
global $_M;
|
||
$bool = false;
|
||
//文件移动
|
||
if(file_exists($this->appupfile)){
|
||
$bool = movedir($this->appupfile, $this->appfile);
|
||
@clearstatcache();
|
||
}
|
||
if($bool){
|
||
//对升级文件处理
|
||
self::_require();
|
||
//检查安装锁
|
||
!file_exists(INS_LOCK_FILE)?$this->ac_appcore->locmsg(4025):$this->ac_appcore->msgkey(1)->msgtext(4019);
|
||
}else{
|
||
$this->ac_appcore->locmsg(4018);
|
||
}
|
||
}
|
||
|
||
# 读取本地文件
|
||
public function app_get_file() {
|
||
global $_M;
|
||
return file_exists($this->appdllist)?json_decode(file_get_contents($this->appdllist),true):[];
|
||
}
|
||
|
||
# 读取本地文件
|
||
public function app_update_ver() {
|
||
global $_M;
|
||
$newapp = $this->ac_session->get('newapp');
|
||
return $newapp['v_ver'];
|
||
}
|
||
|
||
# 获取下载权限
|
||
private function statekey() {
|
||
global $_M;
|
||
$state = false;
|
||
//解密
|
||
$apikey = $this->ac_session->get('check');
|
||
$retkey = (new curls($this->ac_appcore))->apikey_decode([$apikey,$this->met_adl['met_weburl'],$this->met_adl['m_name'],$this->met_adl['addtime']]);
|
||
//校验
|
||
if(!empty($retkey['state'])){
|
||
$state = true;
|
||
if($retkey['vatime']['minute'] > 0){
|
||
//对有效时间计算
|
||
$time = date('Y-m-d H:i:s',$retkey['vatime']['stime']);
|
||
if(strtotime("{$time} +{$retkey['vatime']['minute']} minute") <= time()) $state = false;
|
||
}
|
||
}
|
||
return $state;
|
||
}
|
||
|
||
# 模态框数据 modal
|
||
private function modal($step = '',$method) {
|
||
global $_M;
|
||
if(strlen($step) > 0) $this->modal['data']['step'] = $step;
|
||
if(strlen($method) > 0) $this->modal['data']['method'] = $method;
|
||
$modal = $this->modal;
|
||
if(count($this->modal['data']) > 0) $modal['data'] = arrayto_string($modal['data'],'|');
|
||
return $modal;
|
||
}
|
||
|
||
# CURL
|
||
private function curljson($post = [],$type = false,$timeout = 60,$sign = 'dl') {
|
||
global $_M;
|
||
return (new curls($this->ac_appcore))->apiurl($this->method,$sign)
|
||
->apipost($post)
|
||
->curls($timeout)
|
||
->resdata($type);
|
||
}
|
||
|
||
# 文件导入
|
||
private function _require() {
|
||
global $_M;
|
||
$dir = $this->appupdir.'/update.class.php';
|
||
$para = [];
|
||
if(file_exists($dir)){
|
||
$update = load::own_class('update/update','new');
|
||
$update->set($this->met_adl)->start();
|
||
}
|
||
//检测文件是否存在,删除缓存的file
|
||
$this->ac_appcore->del_update_dir();
|
||
}
|
||
}
|
||
|
||
|
||
?>
|