value); } /** * 抛出未找到异常 2000 * * @param $msg * @return mixed * @throws Exception */ public function notFound($msg): mixed { return self::errorThrow($msg, ErrorEnum::NOT_FOUND); } /** * 未授权 401 * * @param $msg * @return mixed * @throws Exception */ public function notAuth($msg): mixed { return self::errorThrow($msg, ErrorEnum::NOT_AUTH); } /** * 生成密码 * @param $password * @return string */ public function genPassword($password): string { return password_hash($password, PASSWORD_DEFAULT); } /** * 密码验证 * * @param $password * @param $passwordAse * @return bool */ public function checkPassword($password, $passwordAse): bool { // 盐 return password_verify($password, $passwordAse); } /** * 生成OpenId * @return string * @throws RandomException */ public function genOpenId(): string { // 获取微秒级时间戳(提高时间精度) $microtime = microtime(true); $timestamp = dechex(floor($microtime)); // 秒部分 $microsec = dechex(($microtime - floor($microtime)) * 1000000); // 微秒部分 // 生成更多随机字节(20字节=160位熵) $randomBytes = random_bytes(20); $randomHex = bin2hex($randomBytes); // 获取进程ID和内存ID作为额外熵源 $pid = dechex(getmypid() % 65536); // 进程ID $memoryId = dechex(crc32(memory_get_usage(true))); // 内存使用哈希 // 打乱组合顺序并截取28个字符 $components = [ $timestamp, $microsec, substr($randomHex, 0, 16), substr($randomHex, 16, 8), $pid, $memoryId ]; shuffle($components); // 打乱顺序 $combined = implode('', $components); // 最终截取(确保固定长度) return 'nl_'. substr($combined, 0, 28); } /** * 递归生成树形结构 * @param $data * @param int $pid * @return array */ public function tree($data, int $pid = 0): array { $tree = []; foreach ($data as $v) { if ($v['pid'] == $pid) { $v['children'] = $this->tree($data, $v['id']); if (empty($v['children'])) { unset($v['children']); } $tree[] = $v; } } return $tree; } /** * 检查手机号格式 * * @param string $phone * @return bool * @throws Exception */ public function checkPhone(string $phone): bool { $phone = trim($phone); if (preg_match('/^1[3456789]\d{9}$/', $phone)) { return true; } else { self::errorThrow('手机号格式不正确'); } } /** * 检查身份证号格式 * @param string $idCard * @return true|void * @throws Exception */ public function checkIdCard(string $idCard) { $idCard = trim($idCard); if (preg_match('/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/', $idCard)) { return true; } else { self::errorThrow('身份证号格式不正确'); } } /** * 生成订单号 * @param int $type * @return string */ public function genOrderNo(int $type = 0): string { $prefix = ['NL', 'TX', 'TK']; $datePart = date('Ymd'); // 确保len不超过PHP_INT_MAX,避免整数溢出 $maxLen = PHP_INT_MAX; // 使用bcmath扩展生成安全的大数随机数 if (function_exists('bcadd') && function_exists('bcmul')) { // 生成一个10位的随机字符串作为基础 $randomBase = ''; for ($i = 0; $i < 10; $i++) { $randomBase .= mt_rand(0, 9); } // 使用bcmath计算一个大数随机数 $randomPart = bcadd( '1', // 确保最小值为1 bcmul( $randomBase, bcdiv((string)$maxLen, '10000000000', 0), 0 ) ); // 截取前11位数字 $randomStr = substr($randomPart, 0, 11); } else { // 备用方案:使用mt_rand并处理溢出 $randomNum = mt_rand(1, $maxLen); $randomStr = (string)$randomNum; // 如果长度不足11位,左侧补0 if (strlen($randomStr) < 11) { $randomStr = str_pad($randomStr, 11, '0', STR_PAD_LEFT); } else { // 如果长度超过11位,截取前11位 $randomStr = substr($randomStr, 0, 11); } } // 确保随机部分长度为11 $paddedRandom = str_pad($randomStr, 11, '0', STR_PAD_LEFT); $paddedRandom = substr($paddedRandom, -11); // 确保最终长度为11 // 返回格式化后的代码 return isset($prefix[$type]) ? $prefix[$type] . $datePart . $paddedRandom : ''; } /** * 是否是开发环境 * @return bool */ public static function isDev(): bool { return env('ECS') === 'localhost'; } /** * 根据身份证号计算年龄 * @param string $idno 身份证号(15位或18位) * @return int|false 成功返回年龄,失败返回false */ public function getAgeFromIdNo($idno = '') { // 校验身份证号长度 $len = strlen($idno); if (!in_array($len, [15, 18])) { return false; } // 提取出生日期部分 if ($len === 18) { $datePart = substr($idno, 6, 8); } else { // 15位身份证补全年份为19XX $datePart = '19' . substr($idno, 6, 6); } // 分解年月日 $year = substr($datePart, 0, 4); $month = substr($datePart, 4, 2); $day = substr($datePart, 6, 2); // 校验年月日是否为数字 if (!ctype_digit($year) || !ctype_digit($month) || !ctype_digit($day)) { return false; } // 尝试创建日期对象 try { $birthDate = new DateTime("$year-$month-$day"); } catch (Exception $e) { return false; } $currentDate = new DateTime(); // 检查出生日期是否在当前日期之前 if ($birthDate > $currentDate) { return false; } // 计算年龄差 $ageInterval = $currentDate->diff($birthDate); return $ageInterval->y; } public function autoRouteRegister($class): void { foreach ($class as $key => $value) { // 获取控制器$value的所有方法 $methods = (new ReflectionClass($value))->getMethods(); // 注册路由 foreach ($methods as $method) { // 获取方法注释 @Method $docComment = $method->getDocComment(); if ($method->name === '__construct' || preg_match('/@Method\s+(NO)\b/', $docComment, $matches)) { continue; } $httpMethod = 'any'; // 查询 @Method GET 或者 @Method POST if (preg_match('/@Method\s+(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD|ANY)\b/', $docComment, $matches)) { $httpMethod = $matches[1]; } Route::$httpMethod($key . '/' . cc_camel_case_to_dash($method->getName()), [$value, conjunction_symbol_processing($method->name)]); } } } // 获取项目根目录 public static function getRootPath(): string { return dirname(__DIR__, 3); } // 若文件不存在则创建文件 public static function createFileHolder($filePath): bool { if (!file_exists($filePath)) { return mkdir($filePath, 777, true); } return true; } // 若文件不存在则创建文件 public static function createFile($filePath): bool { if (!file_exists($filePath)) { $file = fopen($filePath, 'w'); fclose($file); } return true; } }