Files
YwxAppThink/ywxapp/middleware/SpiderStat.php
T
ywxapp 1d49e6f5ee feat: 公共表更名 common/member 前缀 + 插件命令自动加载 + 版本 1.1.1
- 18 张公共表更名(addon/attachment/configure/links/spider_log/spider_stat/sms/notice/ad/task/prop/medal/help/card -> common_*,member_wallets->member_wallet,score_rule/score_log -> member_*,addon_config->common_addonconf),模型全部对齐新表名,Db 直引用清零
- Attachment 模型补  表名绑定,修复富文本上传查 wxapp_attachment 1146 隐患
- install.sql + 迁移 SQL:backend_admin/backend_role delete_at 默认 0,修复软删除(NULL != 0)误过滤导致后台菜单为空
- AppService::boot() 支持插件 info.php 声明 commands 自动注册插件命令(psr-4 自动加载,坏类名自动跳过)
- 各插件(haonav/mqttbroker/wxchat/articles/blog/forum 等)字段与配置同步调整
- 框架版本 1.1.0 -> 1.1.1
2026-08-20 20:19:15 +08:00

117 lines
4.7 KiB
PHP
Raw 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
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace ywxapp\middleware;
use think\facade\Db;
use ywxapp\model\BaseModel;
use ywxapp\library\SpiderDetect;
/**
* 全站搜索蜘蛛统计中间件(全局注册于 app/middleware.php
*
* 设计要点:
* - 仅命中蜘蛛 UA 才落库,普通用户请求零额外查询;
* - 落库在响应生成之后($next 之后),不阻塞蜘蛛抓取响应;
* - 明细写 spider_log,按日聚合 upsert 到 spider_stat(报表免全表扫描);
* - 任何数据库异常静默吞掉(统计绝不能影响业务),缺表时经 BaseModel 自愈引擎 自愈一次;
* - install.sql 为唯一事实源,此处 DDL 仅为老库运行时兜底。
*
* @author ywxapp <admin@ywxapp.cn>
*/
class SpiderStat
{
public function handle($request, \Closure $next)
{
$response = $next($request);
try {
$ua = (string) $request->header('user-agent', '');
$spider = SpiderDetect::detect($ua);
if ($spider !== null) {
$this->record($request, $response, $spider, $ua);
}
} catch (\Throwable $e) {
// 统计失败绝不影响正常响应
}
return $response;
}
/**
* 落库:明细 + 按日聚合
*/
protected function record($request, $response, string $spider, string $ua): void
{
$prefix = config('database.connections.mysql.prefix', 'wxapp_');
$logTable = $prefix . 'common_spider_log';
$statTable = $prefix . 'common_spider_stat';
$data = [
'spider' => $spider,
'url' => mb_substr((string) $request->url(), 0, 500),
'ip' => mb_substr((string) $request->ip(), 0, 45),
'app' => mb_substr((string) (app('http')->getName() ?: ''), 0, 20),
'user_agent' => mb_substr($ua, 0, 500),
'http_code' => method_exists($response, 'getCode') ? (int) $response->getCode() : 200,
'create_at' => time(),
];
try {
$this->insert($logTable, $statTable, $data, $spider);
} catch (\Throwable $e) {
// 表可能不存在(老库未升级):自愈一次后重试
$this->ensureTables($logTable, $statTable);
$this->insert($logTable, $statTable, $data, $spider);
}
}
/**
* 写明细 + 聚合 upsert
*/
protected function insert(string $logTable, string $statTable, array $data, string $spider): void
{
Db::table($logTable)->insert($data);
// 按日聚合:主键(stat_date, spider),存在则计数+1
Db::execute(
"INSERT INTO `{$statTable}` (`stat_date`, `spider`, `count`) VALUES (?, ?, 1) "
. "ON DUPLICATE KEY UPDATE `count` = `count` + 1",
[date('Y-m-d'), $spider]
);
}
/**
* 缺表自愈(DDL 与 public/install/install.sql 保持一致)
*/
protected function ensureTables(string $logTable, string $statTable): void
{
BaseModel::ensureTable($logTable, "CREATE TABLE IF NOT EXISTS `{$logTable}` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`spider` varchar(20) NOT NULL DEFAULT '' COMMENT '蜘蛛标识',
`url` varchar(500) NOT NULL DEFAULT '' COMMENT '抓取URL',
`ip` varchar(45) NOT NULL DEFAULT '' COMMENT '来源IP',
`app` varchar(20) NOT NULL DEFAULT '' COMMENT '应用名',
`user_agent` varchar(500) NOT NULL DEFAULT '' COMMENT 'User-Agent',
`http_code` smallint unsigned NOT NULL DEFAULT '200' COMMENT '响应状态码',
`create_at` int NOT NULL DEFAULT '0' COMMENT '抓取时间',
PRIMARY KEY (`id`),
KEY `idx_spider_time` (`spider`,`create_at`),
KEY `idx_create_at` (`create_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='搜索蜘蛛抓取日志'");
BaseModel::ensureTable($statTable, "CREATE TABLE IF NOT EXISTS `{$statTable}` (
`stat_date` date NOT NULL COMMENT '统计日期',
`spider` varchar(20) NOT NULL DEFAULT '' COMMENT '蜘蛛标识',
`count` int unsigned NOT NULL DEFAULT '0' COMMENT '抓取次数',
PRIMARY KEY (`stat_date`,`spider`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='搜索蜘蛛按日统计'");
}
}