This commit is contained in:
2026-02-28 16:18:52 +08:00
parent d75fea32f7
commit 73f67b4143
10 changed files with 712 additions and 2 deletions
+2
View File
@@ -0,0 +1,2 @@
* text=auto eol=lf
*.txt -text
+2
View File
@@ -143,6 +143,8 @@ class ThaliController extends BaseController{
],$user->expire_at-time());
\app\model\User::score($user->id,-$amount,\app\enum\BalanceType::PURCHASE_ROLE,json_encode(['role_id'=>$role_id,'quantity'=>$quantity,'role_name'=>$thali->title]));
cache('user_rights_'.$user->id,null);
//Hook('user.roleup', $user);
// $data = [
// 'role_id' => $role_id,
+5 -1
View File
@@ -244,9 +244,13 @@ class HookController{
//群成员进群之前的回调
public function callbackBeforeMembersJoinGroupCommand(Request $request):Response
{
log_alert(Input());
$groupID = Input('groupID');
$memberList = Input('memberList');
$ownerID = $this->getGroupOwner($groupID);
if(!$ownerID){
return $this->success();
}
//获取群组当前用户数量
$group_user_count = cache('group_'.$groupID.'_user_count');
if($group_user_count === null){
@@ -353,7 +357,7 @@ class HookController{
"actionCode" => 0,
"errCode" => $code,
"errMsg" => $msg,
"errDlt" => $msg,
"errDlt" => '',
"nextCode"=> $nextCode
]);
}
+467
View File
@@ -0,0 +1,467 @@
<?php
namespace app\controller;
use support\Request;
use support\Response;
/**
* 指标
* 提供Prometheus格式的监控指标
*/
class MetricsController extends Base
{
/**
* 无需登录及鉴权的方法
* @var array
*/
protected $noNeedLogin = ['index'];
/**
* 指标数据存储
*/
protected static $metrics = [];
/**
* 指标类型定义
*/
const TYPE_COUNTER = 'counter';
const TYPE_GAUGE = 'gauge';
const TYPE_HISTOGRAM = 'histogram';
const TYPE_SUMMARY = 'summary';
/**
* 获取指标数据
*
* @param Request $request
* @return Response
*/
public function index(Request $request): Response
{
$metrics = [];
// 系统基础指标
$metrics[] = $this->getSystemMetrics();
// PHP运行指标
$metrics[] = $this->getPhpMetrics();
// 应用业务指标
$metrics[] = $this->getAppMetrics();
// 数据库指标
$metrics[] = $this->getDatabaseMetrics();
// Redis指标
$metrics[] = $this->getRedisMetrics();
// HTTP请求指标
$metrics[] = $this->getHttpMetrics();
$content = implode("\n", array_filter($metrics));
return response($content, 200, [
'Content-Type' => 'text/plain; charset=utf-8'
]);
}
/**
* 获取系统指标
*/
protected function getSystemMetrics(): string
{
$metrics = [];
// 内存使用
$memoryUsage = memory_get_usage(true);
$memoryPeak = memory_get_peak_usage(true);
$memoryLimit = $this->getBytes(ini_get('memory_limit'));
$metrics[] = $this->formatGauge('webman_memory_usage_bytes', 'Current memory usage in bytes', [], $memoryUsage);
$metrics[] = $this->formatGauge('webman_memory_peak_bytes', 'Peak memory usage in bytes', [], $memoryPeak);
$metrics[] = $this->formatGauge('webman_memory_limit_bytes', 'Memory limit in bytes', [], $memoryLimit);
// CPU负载
if (function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
$metrics[] = $this->formatGauge('webman_system_load1', 'System load average over 1 minute', [], $load[0]);
$metrics[] = $this->formatGauge('webman_system_load5', 'System load average over 5 minutes', [], $load[1]);
$metrics[] = $this->formatGauge('webman_system_load15', 'System load average over 15 minutes', [], $load[2]);
}
// 磁盘使用
$diskTotal = disk_total_space('/');
$diskFree = disk_free_space('/');
$diskUsed = $diskTotal - $diskFree;
$metrics[] = $this->formatGauge('webman_disk_total_bytes', 'Total disk space in bytes', [], $diskTotal);
$metrics[] = $this->formatGauge('webman_disk_free_bytes', 'Free disk space in bytes', [], $diskFree);
$metrics[] = $this->formatGauge('webman_disk_used_bytes', 'Used disk space in bytes', [], $diskUsed);
return implode("\n", $metrics);
}
/**
* 获取PHP指标
*/
protected function getPhpMetrics(): string
{
$metrics = [];
// PHP版本信息
$metrics[] = $this->formatGauge('webman_php_version_info', 'PHP version information', [
'version' => PHP_VERSION,
'sapi' => PHP_SAPI
], 1);
// OPcache指标
if (function_exists('opcache_get_status')) {
$opcache = opcache_get_status(false);
if ($opcache) {
$metrics[] = $this->formatGauge('webman_opcache_enabled', 'OPcache enabled status', [], $opcache['opcache_enabled'] ? 1 : 0);
$metrics[] = $this->formatGauge('webman_opcache_hit_rate', 'OPcache hit rate', [], $opcache['opcache_statistics']['opcache_hit_rate'] ?? 0);
$metrics[] = $this->formatCounter('webman_opcache_hits_total', 'Total OPcache hits', [], $opcache['opcache_statistics']['hits'] ?? 0);
$metrics[] = $this->formatCounter('webman_opcache_misses_total', 'Total OPcache misses', [], $opcache['opcache_statistics']['misses'] ?? 0);
}
}
// 运行时间
if (function_exists('posix_times')) {
$times = posix_times();
$metrics[] = $this->formatCounter('webman_cpu_user_seconds_total', 'Total user CPU time', [], $times['utime'] ?? 0);
$metrics[] = $this->formatCounter('webman_cpu_system_seconds_total', 'Total system CPU time', [], $times['stime'] ?? 0);
}
return implode("\n", $metrics);
}
/**
* 获取应用业务指标
*/
protected function getAppMetrics(): string
{
$metrics = [];
// 应用信息
$metrics[] = $this->formatGauge('webman_app_info', 'Application information', [
'name' => config('app.name', 'webman'),
'version' => config('app.version', '1.0.0'),
'env' => config('app.debug') ? 'development' : 'production'
], 1);
// 启动时间
$metrics[] = $this->formatGauge('webman_start_time_seconds', 'Application start time', [], defined('WEBMAN_START_TIME') ? WEBMAN_START_TIME : time());
// 运行时长
$startTime = defined('WEBMAN_START_TIME') ? WEBMAN_START_TIME : time();
$uptime = time() - $startTime;
$metrics[] = $this->formatCounter('webman_uptime_seconds_total', 'Total uptime in seconds', [], $uptime);
return implode("\n", $metrics);
}
/**
* 获取数据库指标
*/
protected function getDatabaseMetrics(): string
{
$metrics = [];
try {
// 数据库连接信息
$dbConfig = config('database.connections.mysql');
if ($dbConfig) {
$metrics[] = $this->formatGauge('webman_db_config_info', 'Database configuration', [
'host' => $dbConfig['hostname'] ?? 'unknown',
'database' => $dbConfig['database'] ?? 'unknown',
'charset' => $dbConfig['charset'] ?? 'utf8'
], 1);
}
// 数据库连接状态 - 连接成功
$metrics[] = $this->formatGauge('webman_db_up', 'Database connection status', [], 1);
// 尝试获取数据库状态
$db = \think\facade\Db::connect();
$status = $db->query('SHOW STATUS');
$statusMap = [];
foreach ($status as $item) {
$statusMap[$item['Variable_name']] = $item['Value'];
}
// 关键指标
if (isset($statusMap['Threads_connected'])) {
$metrics[] = $this->formatGauge('webman_db_threads_connected', 'Number of currently connected threads', [], (int)$statusMap['Threads_connected']);
}
if (isset($statusMap['Threads_running'])) {
$metrics[] = $this->formatGauge('webman_db_threads_running', 'Number of threads running', [], (int)$statusMap['Threads_running']);
}
if (isset($statusMap['Queries'])) {
$metrics[] = $this->formatCounter('webman_db_queries_total', 'Total number of queries', [], (int)$statusMap['Queries']);
}
if (isset($statusMap['Slow_queries'])) {
$metrics[] = $this->formatCounter('webman_db_slow_queries_total', 'Total number of slow queries', [], (int)$statusMap['Slow_queries']);
}
if (isset($statusMap['Uptime'])) {
$metrics[] = $this->formatCounter('webman_db_uptime_seconds', 'Database uptime in seconds', [], (int)$statusMap['Uptime']);
}
} catch (\Exception $e) {
// 数据库连接失败,记录错误
$metrics[] = $this->formatGauge('webman_db_up', 'Database connection status', [], 0);
}
return implode("\n", $metrics);
}
/**
* 获取Redis指标
*/
protected function getRedisMetrics(): string
{
$metrics = [];
try {
$redis = \Bilulanlv\ThinkCache\facade\ThinkCache::handler();
$info = $redis->info();
// Redis连接状态
$metrics[] = $this->formatGauge('webman_redis_up', 'Redis connection status', [], 1);
// Redis版本
if (isset($info['redis_version'])) {
$metrics[] = $this->formatGauge('webman_redis_version_info', 'Redis version information', [
'version' => $info['redis_version']
], 1);
}
// 内存使用
if (isset($info['used_memory'])) {
$metrics[] = $this->formatGauge('webman_redis_memory_used_bytes', 'Redis memory used in bytes', [], (int)$info['used_memory']);
}
if (isset($info['used_memory_peak'])) {
$metrics[] = $this->formatGauge('webman_redis_memory_peak_bytes', 'Redis peak memory used in bytes', [], (int)$info['used_memory_peak']);
}
// 连接数
if (isset($info['connected_clients'])) {
$metrics[] = $this->formatGauge('webman_redis_connected_clients', 'Number of connected clients', [], (int)$info['connected_clients']);
}
// 命令统计
if (isset($info['total_commands_processed'])) {
$metrics[] = $this->formatCounter('webman_redis_commands_processed_total', 'Total commands processed', [], (int)$info['total_commands_processed']);
}
// 键数量
if (isset($info['db0'])) {
preg_match('/keys=(\d+)/', $info['db0'], $matches);
if (isset($matches[1])) {
$metrics[] = $this->formatGauge('webman_redis_keys_total', 'Total number of keys', [], (int)$matches[1]);
}
}
// 运行时间
if (isset($info['uptime_in_seconds'])) {
$metrics[] = $this->formatCounter('webman_redis_uptime_seconds', 'Redis uptime in seconds', [], (int)$info['uptime_in_seconds']);
}
} catch (\Exception $e) {
$metrics[] = $this->formatGauge('webman_redis_up', 'Redis connection status', [], 0);
}
return implode("\n", $metrics);
}
/**
* 获取HTTP请求指标
*/
protected function getHttpMetrics(): string
{
$metrics = [];
// 请求计数器(这里需要从中间件或日志中统计,示例使用静态数据)
$metrics[] = $this->formatCounter('webman_http_requests_total', 'Total HTTP requests', [
'method' => 'GET',
'status' => '200'
], 0);
$metrics[] = $this->formatCounter('webman_http_requests_total', 'Total HTTP requests', [
'method' => 'POST',
'status' => '200'
], 0);
// 请求处理时间(使用Gauge类型)
$metrics[] = $this->formatGauge('webman_http_request_duration_seconds', 'HTTP request duration in seconds', [
'method' => 'GET',
'path' => '/metrics'
], 0);
// 响应大小
$metrics[] = $this->formatCounter('webman_http_response_size_bytes_total', 'Total HTTP response size in bytes', [], 0);
// 请求大小
$metrics[] = $this->formatCounter('webman_http_request_size_bytes_total', 'Total HTTP request size in bytes', [], 0);
return implode("\n", $metrics);
}
/**
* 格式化Counter类型指标
*/
protected function formatCounter(string $name, string $help, array $labels, float $value): string
{
$output = [];
$output[] = "# HELP {$name} {$help}";
$output[] = "# TYPE {$name} counter";
$labelStr = $this->formatLabels($labels);
$output[] = $name . $labelStr . ' ' . $value;
return implode("\n", $output);
}
/**
* 格式化Gauge类型指标
*/
protected function formatGauge(string $name, string $help, array $labels, float $value): string
{
$output = [];
$output[] = "# HELP {$name} {$help}";
$output[] = "# TYPE {$name} gauge";
$labelStr = $this->formatLabels($labels);
$output[] = $name . $labelStr . ' ' . $value;
return implode("\n", $output);
}
/**
* 格式化Histogram类型指标
*/
protected function formatHistogram(string $name, string $help, array $labels, array $buckets): string
{
$output = [];
$output[] = "# HELP {$name} {$help}";
$output[] = "# TYPE {$name} histogram";
// 如果没有提供桶数据,返回空直方图
if (empty($buckets)) {
$labelStr = $this->formatLabels($labels);
$output[] = $name . '_bucket' . $labelStr . ',le="+Inf" 0';
$output[] = $name . '_sum' . $labelStr . ' 0';
$output[] = $name . '_count' . $labelStr . ' 0';
}
return implode("\n", $output);
}
/**
* 格式化标签
*/
protected function formatLabels(array $labels): string
{
if (empty($labels)) {
return '';
}
$pairs = [];
foreach ($labels as $key => $value) {
$pairs[] = $key . '="' . $this->escapeLabel($value) . '"';
}
return '{' . implode(',', $pairs) . '}';
}
/**
* 转义标签值
*/
protected function escapeLabel(string $value): string
{
return str_replace(['\\', '"', "\n"], ['\\\\', '\\"', '\\n'], $value);
}
/**
* 将PHP内存限制字符串转换为字节数
*/
protected function getBytes(string $val): int
{
$val = trim($val);
$last = strtolower($val[strlen($val) - 1]);
$val = (int) $val;
switch ($last) {
case 'g':
$val *= 1024;
case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
}
return $val;
}
/**
* 增加计数器值(供其他控制器调用)
*
* @param string $name
* @param array $labels
* @param float $value
*/
public static function incCounter(string $name, array $labels = [], float $value = 1): void
{
$key = $name . json_encode($labels);
if (!isset(self::$metrics[$key])) {
self::$metrics[$key] = [
'type' => 'counter',
'name' => $name,
'labels' => $labels,
'value' => 0
];
}
self::$metrics[$key]['value'] += $value;
}
/**
* 设置Gauge值(供其他控制器调用)
*
* @param string $name
* @param float $value
* @param array $labels
*/
public static function setGauge(string $name, float $value, array $labels = []): void
{
$key = $name . json_encode($labels);
self::$metrics[$key] = [
'type' => 'gauge',
'name' => $name,
'labels' => $labels,
'value' => $value
];
}
/**
* 记录HTTP请求指标(供中间件调用)
*
* @param string $method
* @param string $path
* @param int $status
* @param float $duration
* @param int $responseSize
*/
public static function recordHttpRequest(string $method, string $path, int $status, float $duration, int $responseSize = 0): void
{
$labels = [
'method' => $method,
'path' => $path,
'status' => (string)$status
];
// 请求总数
self::incCounter('webman_http_requests_total', $labels);
// 响应大小
self::incCounter('webman_http_response_size_bytes_total', $labels, $responseSize);
}
}
+76
View File
@@ -0,0 +1,76 @@
<?php
namespace app\middleware;
use app\controller\MetricsController;
use support\Request;
use support\Response;
/**
* 指标收集中间件
* 自动记录HTTP请求指标
*/
class MetricsMiddleware
{
/**
* 请求开始时间
*/
protected $startTime;
/**
* 处理请求
*
* @param Request $request
* @param callable $handler
* @return Response
*/
public function process(Request $request, callable $handler): Response
{
// 记录请求开始时间
$this->startTime = microtime(true);
// 处理请求
$response = $handler($request);
// 计算请求处理时间
$duration = microtime(true) - $this->startTime;
// 记录指标
$this->recordMetrics($request, $response, $duration);
return $response;
}
/**
* 记录指标
*
* @param Request $request
* @param Response $response
* @param float $duration
*/
protected function recordMetrics(Request $request, Response $response, float $duration): void
{
try {
$method = $request->method();
$path = $request->path();
$status = $response->getStatusCode();
// 获取响应大小
$responseSize = strlen($response->rawBody());
// 记录HTTP请求指标
MetricsController::recordHttpRequest($method, $path, $status, $duration, $responseSize);
// 记录请求处理时间
MetricsController::setGauge('webman_http_request_duration_seconds', $duration, [
'method' => $method,
'path' => $path,
'status' => (string)$status
]);
} catch (\Exception $e) {
// 记录指标失败不应影响正常请求
error_log('Metrics recording failed: ' . $e->getMessage());
}
}
}
+3
View File
@@ -92,6 +92,9 @@ class User extends Base
if(isset($changeData['status']) || $changeData['status'] == '0'){
request()->IM->user->forceLogout(idEncode($row->id));
}
if(isset($changeData['expire_at']) || isset($changeData['role_id'])){
cache('user_rights_'.$row->id,null);
}
}
public static function onAfterDelete($row)
{
+2 -1
View File
@@ -17,6 +17,7 @@ return [
\app\api\middleware\Auth::class
],
'' => [
\app\middleware\ActionHook::class
\app\middleware\ActionHook::class,
\app\middleware\MetricsMiddleware::class,
],
];
+3
View File
@@ -20,6 +20,9 @@ Route::get('/privacy_policy', [\app\controller\IndexController::class, 'privacy_
Route::get('/aboutus', [\app\controller\IndexController::class, 'aboutus']);
Route::get('/register/{code}', [\app\controller\CommonController::class, 'register']);
// Prometheus metrics endpoint
Route::get('/metrics', [\app\controller\MetricsController::class, 'index']);
Route::fallback(function(){
$fn = 'public/index.html';
if(file_exists($fn)){
+5
View File
@@ -29,6 +29,11 @@ define(['table', 'upload','form','qrcode'], function (Table,Upload,Form) {
filter: "number",
sortable: true // 是否排序
},
{
field: 'userID',
title: 'userID',
filter: "string"
},
{
title: "上级",
field: "referrer.username"
+147
View File
@@ -0,0 +1,147 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 核心中文语言包
return [
// 系统错误提示
'Undefined variable' => '未定义变量',
'Undefined index' => '未定义数组索引',
'Undefined offset' => '未定义数组下标',
'Parse error' => '语法解析错误',
'Type error' => '类型错误',
'Fatal error' => '致命错误',
'syntax error' => '语法错误',
// 框架核心错误提示
'dispatch type not support' => '不支持的调度类型',
'method param miss' => '方法参数错误',
'method not exists' => '方法不存在',
'function not exists' => '函数不存在',
'app not exists' => '应用不存在',
'controller not exists' => '控制器不存在',
'class not exists' => '类不存在',
'property not exists' => '类的属性不存在',
'template not exists' => '模板文件不存在',
'illegal controller name' => '非法的控制器名称',
'illegal action name' => '非法的操作名称',
'url suffix deny' => '禁止的URL后缀访问',
'Undefined cache config' => '缓存配置未定义',
'Route Not Found' => '当前访问路由未定义或不匹配',
'Undefined db config' => '数据库配置未定义',
'Undefined log config' => '日志配置未定义',
'Undefined db type' => '未定义数据库类型',
'variable type error' => '变量类型错误',
'PSR-4 error' => 'PSR-4 规范错误',
'not support type' => '不支持的分页索引字段类型',
'not support total' => '简洁模式下不能获取数据总数',
'not support last' => '简洁模式下不能获取最后一页',
'error session handler' => '错误的SESSION处理器类',
'not allow php tag' => '模板不允许使用PHP语法',
'not support' => '不支持',
'database config error' => '数据库配置信息错误',
'redisd master' => 'Redisd 主服务器错误',
'redisd slave' => 'Redisd 从服务器错误',
'must run at sae' => '必须在SAE运行',
'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务',
'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务',
'fields not exists' => '数据表字段不存在',
'where express error' => '查询表达式错误',
'no data to update' => '没有任何数据需要更新',
'miss data to insert' => '缺少需要写入的数据',
'miss complex primary data' => '缺少复合主键数据',
'miss update condition' => '缺少更新条件',
'model data Not Found' => '模型数据不存在',
'table data not Found' => '表数据不存在',
'delete without condition' => '没有条件不会执行删除操作',
'miss relation data' => '缺少关联表数据',
'tag attr must' => '模板标签属性必须',
'tag error' => '模板标签错误',
'cache write error' => '缓存写入失败',
'sae mc write error' => 'SAE mc 写入错误',
'route name not exists' => '路由标识不存在(或参数不够)',
'invalid request' => '非法请求',
'bind attr has exists' => '模型的属性已经存在',
'relation data not exists' => '关联数据不存在',
'relation not support' => '关联不支持',
'chunk not support order' => 'Chunk不支持调用order方法',
'route pattern error' => '路由变量规则定义错误',
'route behavior will not support' => '路由行为废弃(使用中间件替代)',
'closure not support cache(true)' => '使用闭包查询不支持cache(true),请指定缓存Key',
// 上传错误信息
'unknown upload error' => '未知上传错误!',
'file write error' => '文件写入失败!',
'upload temp dir not found' => '找不到临时文件夹!',
'no file to uploaded' => '没有文件被上传!',
'only the portion of file is uploaded' => '文件只有部分被上传!',
'upload File size exceeds the maximum value' => '上传文件大小超过了最大值!',
'upload write error' => '文件上传保存错误!',
'has the same filename: {:filename}' => '存在同名文件:{:filename}',
'upload illegal files' => '非法上传文件',
'illegal image files' => '非法图片文件',
'extensions to upload is not allowed' => '上传文件后缀不允许',
'mimetype to upload is not allowed' => '上传文件MIME类型不允许!',
'filesize not match' => '上传文件大小不符!',
'directory {:path} creation failed' => '目录 {:path} 创建失败!',
'The middleware must return Response instance' => '中间件方法必须返回Response对象实例',
'The queue was exhausted, with no response returned' => '中间件队列为空',
// Validate Error Message
':attribute require' => ':attribute不能为空',
':attribute must' => ':attribute必须',
':attribute must be numeric' => ':attribute必须是数字',
':attribute must be integer' => ':attribute必须是整数',
':attribute must be float' => ':attribute必须是浮点数',
':attribute must be bool' => ':attribute必须是布尔值',
':attribute not a valid email address' => ':attribute格式不符',
':attribute not a valid mobile' => ':attribute格式不符',
':attribute must be a array' => ':attribute必须是数组',
':attribute must be yes,on or 1' => ':attribute必须是yes、on或者1',
':attribute not a valid datetime' => ':attribute不是一个有效的日期或时间格式',
':attribute not a valid file' => ':attribute不是有效的上传文件',
':attribute not a valid image' => ':attribute不是有效的图像文件',
':attribute must be alpha' => ':attribute只能是字母',
':attribute must be alpha-numeric' => ':attribute只能是字母和数字',
':attribute must be alpha-numeric, dash, underscore' => ':attribute只能是字母、数字和下划线_及破折号-',
':attribute not a valid domain or ip' => ':attribute不是有效的域名或者IP',
':attribute must be chinese' => ':attribute只能是汉字',
':attribute must be chinese or alpha' => ':attribute只能是汉字、字母',
':attribute must be chinese,alpha-numeric' => ':attribute只能是汉字、字母和数字',
':attribute must be chinese,alpha-numeric,underscore, dash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-',
':attribute not a valid url' => ':attribute不是有效的URL地址',
':attribute not a valid ip' => ':attribute不是有效的IP地址',
':attribute must be dateFormat of :rule' => ':attribute必须使用日期格式 :rule',
':attribute must be in :rule' => ':attribute必须在 :rule 范围内',
':attribute be notin :rule' => ':attribute不能在 :rule 范围内',
':attribute must between :1 - :2' => ':attribute只能在 :1 - :2 之间',
':attribute not between :1 - :2' => ':attribute不能在 :1 - :2 之间',
'size of :attribute must be :rule' => ':attribute长度不符合要求 :rule',
'max size of :attribute must be :rule' => ':attribute长度不能超过 :rule',
'min size of :attribute must be :rule' => ':attribute长度不能小于 :rule',
':attribute cannot be less than :rule' => ':attribute日期不能小于 :rule',
':attribute cannot exceed :rule' => ':attribute日期不能超过 :rule',
':attribute not within :rule' => '不在有效期内 :rule',
'access IP is not allowed' => '不允许的IP访问',
'access IP denied' => '禁止的IP访问',
':attribute out of accord with :2' => ':attribute和确认字段:2不一致',
':attribute cannot be same with :2' => ':attribute和比较字段:2不能相同',
':attribute must greater than or equal :rule' => ':attribute必须大于等于 :rule',
':attribute must greater than :rule' => ':attribute必须大于 :rule',
':attribute must less than or equal :rule' => ':attribute必须小于等于 :rule',
':attribute must less than :rule' => ':attribute必须小于 :rule',
':attribute must equal :rule' => ':attribute必须等于 :rule',
':attribute has exists' => ':attribute已存在',
':attribute not conform to the rules' => ':attribute不符合指定规则',
'invalid Request method' => '无效的请求类型',
'invalid token' => '令牌数据无效',
'not conform to the rules' => '规则错误',
'record has update' => '记录已经被更新了',
];