Files
2026-10-14 14:00:29 +08:00

249 lines
9.2 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace app\index\controller;
use app\library\LogToKafka;
use app\BaseController;
use app\index\model\Navigator;
use app\index\model\SystemConfig;
use DeviceDetector\DeviceDetector;
use DeviceDetector\Parser\Device\AbstractDeviceParser;
use GeoIp2\Database\Reader;
use think\facade\Cache;
use think\facade\Env;
use think\facade\Lang;
use think\facade\View;
/**
* 控制器基类
*/
class Base extends BaseController
{
use LogToKafka;
/**
* 平台固定为1.不是多平台
* @var int
*/
protected $platformId = 1;
/**
* 查询条件,模糊字段与值。格式 ['name'=>'test']
* @var array
*/
protected $vague = [];
/**
* 精准查询,精确字段,格式['language_id'=> 1]
* @var array
*/
protected $focus = [];
/**
* 排序字段。格式 ['sort'=>'desc']
* @var array
*/
protected $sort = [];
/**
* 模型
* @var array
*/
protected $model = null;
/**
* 语言ID
* @var int|mixed
*/
protected $languageId = 1;
/**
* 导航栏模型
* @var null
*/
protected $navModel = null;
/**
* 系统配置模型
* @var null
*/
protected $systemConfigModel = null;
/**
* 接口监控数据
* @var string[]
*/
protected $apiLog = [
'items' => '', /*项目名称*/
'forum' => '', /*模块*/
'forum_code' => '', /*模块日志编码*/
'url' => '', /*访问页*/
'refer' => '', /*访问来源*/
'click' => '', /*点击次数*/
'content' => '', /*访问内容*/
'ip' => '', /*访客IP*/
'country' => '', /*国家*/
'province' => '', /*省*/
'city' => '', /*市*/
'start_time' => '', /*点击时间*/
'drive' => '', /*PC OR 移动端*/
'system' => '', /*设备系统*/
'brower' => '', /*浏览器*/
'models' => '', /*设备型号*/
'date_time' => '' /*生成时间*/
];
/**
* 判断请求来源是否是手机设备
* @return bool
*/
private function isMobile() : bool
{
//如果有HTTP_X_WAP_PROFILE则一定是移动设备
if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
return true;
}
//如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], 'wap')) {
return true;
}
//野蛮方法,判断手机发送的客户端标志,兼容性有待提高
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$clientKeywords = ['nokia','sony','ericsson','mot','samsung','htc','sgh','lg','sharp','sie-','philips','panasonic','alcatel','lenovo','iphone','ipod','blackberry','meizu','android','netfront','symbian','ucweb','windowsce','palm','operamini','operamobi','openwave','nexusone','cldc','midp','wap','mobile'];
//从HTTP_USER_AGENT中查找手机浏览器的关键字
if (preg_match("/(".implode('|', $clientKeywords).")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
return true;
}
}
//协议法,因为有可能不准确,放到最后判断
if (isset($_SERVER['HTTP_ACCEPT'])) {
//如果只支持wml并且不支持html那一定是移动设备
//如果支持wml和html但是wml在html之前则是移动设备
if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
return true;
}
}
return false;
}
/**
* 初始化
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function initialize()
{
$controller = $this->request->controller();
$this->languageId = $this->request->language_id??1;
//通过中间件过来的语言包,动态设置
Lang::setLangSet($this->request->language_code??'zh-cn');
//重新加载动态设置的语言包
$this->app->loadLangPack(Lang::getLangSet());
// 初始化公共模型
$this->navModel = new Navigator();
$this->systemConfigModel = new SystemConfig();
// 初始化公共页面,判断语言包
// 导航
$navInfo = $this->navModel->getNavInfo($this->languageId,$this->platformId,$controller);
$navInfo = recursion_func($navInfo);
$footerNavInfo = $this->navModel->getFootNavInfo($this->languageId,$this->platformId);
$footerNavInfo = recursion_func($footerNavInfo);
// 头部版本号
// 静态版本号
$version = Env::get('front.version');
// 尾部数据
$footerInfo = $this->systemConfigModel->getFooterInfo($this->languageId);
// 首页多网站切换
$multiLanguage = $this->systemConfigModel->getWebSiteInfo($this->languageId);
// 其他公共数据
// 增加标签显示
$metaTitle = $this->systemConfigModel->getMetaTitle($this->languageId,'common');
View::assign('meta',$metaTitle);
View::assign('nav_info',$navInfo);
View::assign('nav_footer_info',$footerNavInfo);
View::assign('footer_info',$footerInfo);
View::assign('multi_lang',$multiLanguage);
View::assign('ver',$version);
View::assign('is_dev',Env::get('APP_DEBUG'));
View::assign('is_mobile',$this->isMobile());
}
/**
* 访问日志监控,提交kafka生产者接口
* @return \think\response\Json
* @throws \GeoIp2\Exception\AddressNotFoundException
* @throws \MaxMind\Db\Reader\InvalidDatabaseException
*/
public function submitActionLog()
{
$inputData = $this->request->param();
$model = explode('//',$inputData['url']);
$model = explode('/',$model[1]);
$this->apiLog['items'] = Env::get('platform_name','官网');
$this->apiLog['forum'] = count($model) > 1 && $model[1] != '' ? $model[1] : 'index';
$this->apiLog['forum_code'] = 200;
$this->apiLog['url'] = $inputData['url'];
$this->apiLog['refer'] = $inputData['url'];
$this->apiLog['content'] = $inputData['content'];
$this->apiLog['click'] = $inputData['click'];
$this->apiLog['start_time'] = date('Y-m-d H:i:s',(int)ceil(($inputData['date_time'] - (int)ceil((int)$inputData['start_time'])) / 1000) );
$this->apiLog['date_time'] = date('Y-m-d H:i:s',(int)ceil($inputData['date_time'] / 1000) );
//获取应用启动时间
//获取访问设备,系统版本,浏览器,设备型号
$userAgent = $inputData['drive'];
AbstractDeviceParser::setVersionTruncation(AbstractDeviceParser::VERSION_TRUNCATION_NONE);
$dd = new DeviceDetector($userAgent);
$dd->parse();
if ($dd->isBot()) {
$this->apiLog['brower'] = '未知';
$this->apiLog['system'] = '未知';
$this->apiLog['drive'] = '未知';
$this->apiLog['models'] = '爬虫';
} else {
$clientInfo = $dd->getClient();
$osInfo = $dd->getOs();
$device = $dd->getDeviceName();
$brand = $dd->getBrandName();
$model = $dd->getModel();
$this->apiLog['brower'] = !empty($clientInfo) ? $clientInfo['name'].' '.$clientInfo['version'] : '未知';
$this->apiLog['system'] = !empty($osInfo) ? $osInfo['name'].' '.$osInfo['version'] : '未知';
$this->apiLog['models'] = $device . " " . $brand . " ". $model;
$this->apiLog['drive'] = $device;
}
//解析IP地址,得到国家,城市,地址,
$this->apiLog['ip'] = $inputData['ip'];
if (!filter_var($inputData['ip'],FILTER_VALIDATE_IP,FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE | FILTER_NULL_ON_FAILURE)) {
$this->apiLog['country'] = '本地';
$this->apiLog['province'] = '本地';
$this->apiLog['city'] = '本地';
} else {
$readerCity = new Reader(public_path() . 'GeoLite2-City.mmdb');
$record = $readerCity->city($inputData['ip']);
$country = $record->country->names['zh-CN'];
$province = $record->subdivisions[0]->names['zh-CN']??'';
$city = $record->city->names['zh-CN']??$record->city->names['en'];
$china = ['香港','澳门','台湾'];
if (in_array($country,$china)) {
$province = $city = $country;
$country = '中国';
}
$this->apiLog['country'] = $country;
$this->apiLog['province'] = $province;
$this->apiLog['city'] = $city;
}
// Cache::set('this-api-log',$this->apiLog);
// 返回信息前,写入kafka log日志
$result = $this->sendLogsToKafkaProduce($this->apiLog,'action_logs',Env::get('database.database'),'add');
return $result ? json('提交成功') : json('提交失败',504);
}
}