fix : update path And request

This commit is contained in:
2025-09-16 15:14:47 +08:00
parent c1d8f02491
commit be0d0913b6
42 changed files with 484 additions and 75 deletions

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Common\Trait;
use App\Cache\Redis\RedisCache;
use App\Cache\Redis\RedisKey;
use App\Common\Repository\AdminUserRepository;
use App\Model\AdminUser;
use Hyperf\Context\Context;
use Hyperf\Database\Model\Model;
use Hyperf\Di\Annotation\Inject;
trait AdminUserTrait
{
/**
* @var RedisCache
*/
#[Inject]
protected RedisCache $redis;
/**
* @var AdminUserRepository
*/
#[Inject]
protected AdminUserRepository $adminUserRepository;
/**
* @param int $adminId
* @return AdminUser|Model|mixed|string|null
*/
public function getAdminUserInfo(int $adminId): mixed
{
$key = RedisKey::getAdminUserInfoKey($adminId);
if (Context::has($key)) {
return Context::get($key,false);
}
if ($this->redis->with()->exists($key)) {
$userInfo = unserialize($this->redis->with()->get($key));
Context::set($key,$userInfo);
return $userInfo;
}
$userInfo = $this->adminUserRepository->findById($adminId) ?? null;
if (!$userInfo) return null;
Context::set($key, $userInfo);
$this->redis->with()->set($key, serialize($userInfo), 3600);
return $userInfo;
}
}

View File

@@ -0,0 +1,192 @@
<?php
namespace App\Common\Trait;
use App\Constants\Common\ClientIpRequestConstant;
use App\Exception\ErrException;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\HttpFoundation\IpUtils;
trait ClientIpTrait
{
/**
* @var RequestInterface
*/
#[Inject]
protected readonly RequestInterface $request;
/**
* @var string[]
*/
protected static array $trustedProxies = [];
/**
* @var int
*/
private static int $trustedHeaderSet = -1;
/**
* @var array
*/
private array $trustedValuesCache = [];
/**
* @var bool
*/
private bool $isForwardedValid = true;
/**
* @var bool
*/
private static bool $isTrustedRemoteAddr = false;
/**
* 设置可信代理
* @return bool
*/
public static function isTrustedRemoteAddr(): bool
{
return self::$isTrustedRemoteAddr;
}
/**
* 返回客户端IP地址。
* 在返回的数组中最可信的IP地址排在第一位最不可信的IP地址排在最后。“真正的”客户端IP地址是最后一个但这也是最不可信的一个。可信代理被剥离。
* @return array
*/
public function getClientIp(): array
{
$ip = $this->request->server('remote_addr');
if (! $this->isFromTrustedProxy()) return [$ip];
return $this->getTrustedValues(ClientIpRequestConstant::HEADER_X_FORWARDED_FOR, $ip) ?: [$ip];
}
/**
* 判断此请求是否来自受信任的代理。这可以用于确定是否信任
* @return bool
*/
private function isFromTrustedProxy(): bool
{
return (
self::$trustedProxies &&
IpUtils::checkIp($this->request->server('remote_addr',''),self::$trustedProxies) ||
self::isTrustedRemoteAddr()
);
}
/**
* @param int $type
* @param string|null $ip
* @return array|mixed|null[]|string[]
*/
private function getTrustedValues(int $type, ?string $ip = null): mixed
{
$cacheKey = $type . "\0" . ((self::$trustedHeaderSet & $type) ? $this->request->getHeaderLine(ClientIpRequestConstant::TRUSTED_HEADERS[$type]) : '');
$cacheKey .= "\0" . $ip . "\0" . $this->request->getHeaderLine(ClientIpRequestConstant::TRUSTED_HEADERS[ClientIpRequestConstant::HEADER_FORWARDED]);
if (isset($this->trustedValuesCache[$cacheKey])) return $this->trustedValuesCache[$cacheKey];
$clientValues = [];
$forwardedValues = [];
if (
(self::$trustedHeaderSet & $type) &&
$this->request->hasHeader(ClientIpRequestConstant::TRUSTED_HEADERS[$type])
) {
foreach (explode(',', $this->request->getHeaderLine(ClientIpRequestConstant::TRUSTED_HEADERS[$type])) as $value) {
$clientValues[] = ($type === ClientIpRequestConstant::HEADER_X_FORWARDED_PORT ? '0.0.0.0' : trim($value));
}
}
if (
(self::$trustedHeaderSet & ClientIpRequestConstant::HEADER_FORWARDED) &&
(isset(ClientIpRequestConstant::FORWARDED_PARAMS[$type])) &&
$this->request->hasHeader(ClientIpRequestConstant::TRUSTED_HEADERS[ClientIpRequestConstant::HEADER_FORWARDED])
) {
$forward = $this->request->getHeaderLine(ClientIpRequestConstant::TRUSTED_HEADERS[ClientIpRequestConstant::HEADER_FORWARDED]);
$parts = HeaderUtils::split($forward, ',;=');
$param = ClientIpRequestConstant::FORWARDED_PARAMS[$type];
foreach ($parts as $subParts) {
if (($value = HeaderUtils::combine($subParts)[$param] ?? null) === null) continue;
if ($type === ClientIpRequestConstant::HEADER_X_FORWARDED_PORT) {
if (
str_ends_with($value, ']') ||
($value = mb_strrchr($value, ':')) === false
) $value = $this->isSecure() ? ':443' : ':80';
$value = '0.0.0.0' . $value;
}
$forwardedValues[] = $value;
}
}
if (null !== $ip) {
$clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip);
$forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip);
}
if ($forwardedValues === $clientValues || !$clientValues) return $this->trustedValuesCache[$cacheKey] = $forwardedValues;
if (!$forwardedValues) return $this->trustedValuesCache[$cacheKey] = $clientValues;
if (!$this->isForwardedValid) return (($ip = $this->trustedValuesCache[$cacheKey]) !== null) ? ['0.0.0.0',$ip] : [];
$this->isForwardedValid = false;
throw new ErrException('转发报头无效,请检查服务器配置。');
}
/**
* @return bool
*/
private function isSecure(): bool
{
return $this->request->getHeaderLine(ClientIpRequestConstant::HEADER_X_FORWARDED_PROTO) === 'https'
|| ($this->request->getServerParams()['https'] ?? '') === 'on';
}
/**
* @param array $clientIps
* @param string $ip
* @return array|null[]|string[]
*/
private function normalizeAndFilterClientIps(array $clientIps, string $ip): array
{
if (!$clientIps) return [];
$clientIps[] = $ip;
$firstTrustedIp = null;
foreach ($clientIps as $key => $clientIp) {
if (mb_strpos($clientIp, '.')) {
// ipv4
$i = mb_strpos($clientIp, '.');
if ($i) $clientIps[$key] = $clientIp = mb_substr($clientIp, 0, $i);
} elseif (str_starts_with($clientIp, '[')) {
// ipv6
$i = mb_strpos($clientIp, ']',1);
$clientIps[$key] = $clientIp = mb_substr($clientIp, 1, $i - 1);
}
if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
unset($clientIps[$key]);
continue;
}
if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
unset($clientIps[$key]);
$firstTrustedIp ??= $clientIp;
}
}
return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp];
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Common\Trait;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
trait ClientOsTrait
{
/**
* @var RequestInterface
*/
#[Inject]
protected readonly RequestInterface $request;
/**
* @return string
*/
public function getClientOs(): string
{
$userAgent = $this->request->header('user-agent');
if (empty($userAgent)) return 'Unknown';
return match (true) {
preg_match('/win/i', $userAgent) => 'Windows',
preg_match('/mac/i', $userAgent) => 'MAC',
preg_match('/linux/i', $userAgent) => 'Linux',
preg_match('/unix/i', $userAgent) => 'Unix',
preg_match('/bsd/i', $userAgent) => 'BSD',
default => 'Other',
};
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace App\Common\Trait;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
trait HttpMethodTrait
{
/**
* @var RequestInterface
*/
#[Inject]
protected readonly RequestInterface $request;
/**
* @return bool
*/
public function isCreate(): bool
{
return $this->request->isMethod('POST');
}
/**
* @return bool
*/
public function isUpdate(): bool
{
return $this->request->isMethod('PATCH') || $this->request->isMethod('PUT');
}
/**
* @return bool
*/
public function isDelete(): bool
{
return $this->request->isMethod('DELETE');
}
/**
* @return bool
*/
public function isSearch(): bool
{
return $this->request->isMethod('GET');
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Common\Trait;
trait ParserRouterTrait
{
/**
* @param $callback
* @return array|string[]|null
*/
final protected function parse($callback): ?array
{
if (is_array($callback) && count($callback) == 2) return $callback;
if (is_string($callback)) {
if (str_contains($callback, '@')) $explode = explode('@', $callback);
if (str_contains($callback, '::')) $explode = explode('::', $callback);
if (isset($explode) && count($explode) === 2) return $explode;
}
return null;
}
}