Files
nl-jqrl-api/app/Service/common/UtilsService.php
2025-05-12 13:12:57 +08:00

293 lines
7.4 KiB
PHP
Executable File
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
namespace App\Service\common;
use App\Enum\ErrorEnum;
use DateTime;
use Exception;
use Illuminate\Support\Facades\Route;
use Random\RandomException;
use ReflectionClass;
class UtilsService
{
private static mixed $_instance;
/**
* 获取实例
* @return null|static
*/
public static function getInstance(): null|static
{
$name = get_called_class();
if (!isset(self::$_instance[$name])) {
self::$_instance[$name] = new static();
}
return self::$_instance[$name];
}
/**
* 抛出异常
*
* @param string $msg
* @param ErrorEnum $code
* @return mixed
* @throws Exception
*/
public function errorThrow(string $msg = '请求出了问题!', ErrorEnum $code = ErrorEnum::FAIL): mixed
{
throw new Exception($msg, $code->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 int $type
* @return string
*/
public function genOrderNo(int $type = 0): string
{
$len = 9999999999;
switch ($type) {
case 0:
return 'DK' . date('Ymd') . str_pad(mt_rand(1, $len), 11, '0', STR_PAD_LEFT);
case 1:
return 'DD' . date('Ymd') . str_pad(mt_rand(1, $len), 11, '0', STR_PAD_LEFT);
default:
return '';
}
}
/**
* 是否是开发环境
* @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;
}
}