diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a3b5842 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto eol=lf +*.txt -text \ No newline at end of file diff --git a/app/api/controller/ThaliController.php b/app/api/controller/ThaliController.php index f45562a..3e0a470 100755 --- a/app/api/controller/ThaliController.php +++ b/app/api/controller/ThaliController.php @@ -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, diff --git a/app/controller/HookController.php b/app/controller/HookController.php index 5fc34a5..a90bfb7 100755 --- a/app/controller/HookController.php +++ b/app/controller/HookController.php @@ -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 ]); } diff --git a/app/controller/MetricsController.php b/app/controller/MetricsController.php new file mode 100644 index 0000000..3c65380 --- /dev/null +++ b/app/controller/MetricsController.php @@ -0,0 +1,467 @@ +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); + } +} diff --git a/app/middleware/MetricsMiddleware.php b/app/middleware/MetricsMiddleware.php new file mode 100644 index 0000000..1cf47be --- /dev/null +++ b/app/middleware/MetricsMiddleware.php @@ -0,0 +1,76 @@ +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()); + } + } +} diff --git a/app/model/User.php b/app/model/User.php index 7689e67..1258966 100755 --- a/app/model/User.php +++ b/app/model/User.php @@ -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) { diff --git a/config/middleware.php b/config/middleware.php index 96044b4..001d77a 100755 --- a/config/middleware.php +++ b/config/middleware.php @@ -17,6 +17,7 @@ return [ \app\api\middleware\Auth::class ], '' => [ - \app\middleware\ActionHook::class + \app\middleware\ActionHook::class, + \app\middleware\MetricsMiddleware::class, ], ]; \ No newline at end of file diff --git a/config/route.php b/config/route.php index be03ac0..cc9fdee 100755 --- a/config/route.php +++ b/config/route.php @@ -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)){ diff --git a/plugin/admin/public/js/user.js b/plugin/admin/public/js/user.js index c4f4c5a..22edba0 100755 --- a/plugin/admin/public/js/user.js +++ b/plugin/admin/public/js/user.js @@ -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" diff --git a/resource/translations/zh_CN/validate.php b/resource/translations/zh_CN/validate.php new file mode 100644 index 0000000..d3f26f3 --- /dev/null +++ b/resource/translations/zh_CN/validate.php @@ -0,0 +1,147 @@ + +// +---------------------------------------------------------------------- + +// 核心中文语言包 +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' => '记录已经被更新了', +];