From 9f79d1465ba6ed4b4c0d0c30e23ffa34bbeece65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=B8=9C=E4=BA=91?= Date: Fri, 13 Jan 2023 18:00:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(utils):=20=E9=87=8D=E5=86=99=E4=BA=86?= =?UTF-8?q?=E6=9E=84=E9=80=A0URL=E7=9A=84=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E5=BA=94=E7=9A=84=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Service/UtilsService.php | 126 +++++++++++++++++++++----------- tests/Unit/OssServiceTest.php | 2 +- tests/Unit/UtilsServiceTest.php | 62 ++++++++++++++++ 3 files changed, 145 insertions(+), 45 deletions(-) create mode 100644 tests/Unit/UtilsServiceTest.php diff --git a/src/Service/UtilsService.php b/src/Service/UtilsService.php index 2a6f253..480fd5c 100644 --- a/src/Service/UtilsService.php +++ b/src/Service/UtilsService.php @@ -7,9 +7,8 @@ namespace Singularity\HDK\Core\Service; use Closure; use Exception; use Generator; -use Hyperf\Contract\StdoutLoggerInterface; -use Hyperf\Di\Annotation\Inject; use Hyperf\HttpServer\Contract\RequestInterface; +use JetBrains\PhpStorm\NoReturn; use JetBrains\PhpStorm\Pure; use Psr\Http\Message\ResponseInterface; @@ -18,47 +17,38 @@ use Psr\Http\Message\ResponseInterface; */ class UtilsService { - /** - * @Inject - * @var RequestInterface - */ - private RequestInterface $request; - - /** - * @Inject() - * @var StdoutLoggerInterface - */ - private StdoutLoggerInterface $logger; - /** * 生成验证码 * * @param int $length * * @return string + * @throws Exception */ + #[Pure] public function generateSecureCode(int $length = 4): string { $code = ''; for ($times = 0; $times < $length; $times++) { - $code .= rand(1, 9); + $code .= random_int(1, 9); } return $code; } - public function getRealIpAddress(): string + /** + * 获取真实IP + * @param RequestInterface $request + * @return string + */ + public function getRealIpAddress(RequestInterface $request): string { - $ip = $this->request->server('remote_addr'); - if (empty($ip) or in_array( - $ip, - [ - 'localhost', - '127.0.0.1', - ] - )) { - $ip = $this->request->header('x-real-ip'); - } - return $ip ?? 'unknown'; + $x_real_ip = $request->header('x-real-ip'); + var_dump(__METHOD__ . 'x-real-ip: ' . $x_real_ip); + $remote_addr = $request->server('remote_addr'); + var_dump(__METHOD__ . 'remote_addr: ' . $remote_addr); + return $x_real_ip + ?? $remote_addr + ?? 'unknown'; } /** @@ -108,18 +98,74 @@ class UtilsService * 构建 URL * * @param string $url - * @param array $params - * + * @param array $moreQueries 要附加的 query 参数 + * @param bool $anchorQuery 开启后,query 参数将被尽量组合到锚点中,以支持 spa 路由 * @return string */ - public function buildUrl(string $url, array $params = []): string + #[Pure] + public function buildUrl(string $url, array $moreQueries = [], bool $anchorQuery = false): string { - $url_info = parse_url($url); - $base_url = str_replace('?' . $url_info['query'], '', $url); - parse_str($url_info['query'], $origin_params); - $origin_params += $params; + if (count($moreQueries) === 0) { + return $url; + } - return $base_url . '?' . http_build_query($origin_params); + $url_info = parse_url($url); + + $result = ''; + // 协议 + if (isset($url_info['scheme'])) { + $result .= $url_info['scheme']; + } + // 域名 + if (isset($url_info['host'])) { + if (!empty($result)) { + $result .= ':'; + } + $result .= '//'; + // 用户名 + if (isset($url_info['user'])) { + $result .= $url_info['user']; + // 密码 + if (isset($url_info['pass'])) { + $result .= ':' . $url_info['pass']; + } + $result .= '@'; + } + $result .= $url_info['host']; + } + // 端口 + if (isset($url_info['port'])) { + $result .= ':' . $url_info['port']; + } + // 路径 + $result .= $url_info['path']; + // 查询参数 + if (!empty($url_info['query'])) { + $query_params = $url_info['query']; + parse_str($query_params, $origin_params); + if (!$anchorQuery) { + $origin_params += $moreQueries; + } + $result .= '?' . http_build_query($origin_params); + } else { + if (!$anchorQuery) { + $result .= '?' . http_build_query($moreQueries); + } + } + // 锚点 + if (!empty($url_info['fragment'])) { + $fragment = $url_info['fragment']; + if ($anchorQuery) { + $fragment_data = parse_url($url_info['fragment']); + parse_str($fragment_data['query'] ?? '', $hash_queries); + $hash_queries += $moreQueries; + + $fragment = $fragment_data['path'] . '?' . http_build_query($hash_queries); + } + $result .= '#' . $fragment; + } + + return $result; } /** @@ -191,6 +237,7 @@ class UtilsService * * @return void */ + #[NoReturn] public function unlimitedSubCategoriesQuicklyWithLevel( array &$list, int $level = 1, @@ -198,11 +245,7 @@ class UtilsService string $childrenName = 'children', ?Closure $filterCallback = null ): void { - $start_time = microtime(true); - $max_times = count($list); - $current_times = 0; foreach ($list as $i => &$item) { - $current_times++; if (!isset($item[$parentIdName])) { break; } @@ -221,11 +264,6 @@ class UtilsService } } $list = $list[$childrenName]; - $end_time = microtime(true); - $this->logger->debug("快速无极分类循环{$current_times}次,数组元素数量$max_times"); - - $cost_time = ($end_time - $start_time) * 1000; - $this->logger->debug("快速无极分类用时{$cost_time}ms"); } diff --git a/tests/Unit/OssServiceTest.php b/tests/Unit/OssServiceTest.php index 9ae1e57..dea5285 100644 --- a/tests/Unit/OssServiceTest.php +++ b/tests/Unit/OssServiceTest.php @@ -47,4 +47,4 @@ it('asserts oss policy can be generated', function ($setDir, $isImage, $maxSize) ->and($signature)->toBe($sign); })->with([ ['uploaded', true, 1048576000], -])->only(); +]); diff --git a/tests/Unit/UtilsServiceTest.php b/tests/Unit/UtilsServiceTest.php new file mode 100644 index 0000000..599b582 --- /dev/null +++ b/tests/Unit/UtilsServiceTest.php @@ -0,0 +1,62 @@ + + * Powered by PhpStorm + * Created on 2023/1/12 + */ + +use Singularity\HDK\Core\Service\UtilsService; + +$utils = new UtilsService(); + +$length_data = []; +for ($i = 0; $i < 5; $i++) { + try { + $length_data[] = random_int(1, 9); + } catch (Exception $e) { + continue; + } +} +test('断言验证码可以正常生成指定长度', function (int $length) use ($utils) { + try { + $code = $utils->generateSecureCode($length); + expect($code)->toHaveLength($length); + } catch (Exception $e) { + expect($e)->toBeNull(); + } +})->with($length_data)->group('pure', 'utils'); + +test('断言可以根据参数构建 URL', function (string $url, array $params, bool $anchorQuery, string $expect) use ($utils) { + $url = $utils->buildUrl(url: $url, moreQueries: $params, anchorQuery: $anchorQuery); + expect($url)->toBe($expect); +})->with([ + ['baidu.com/list', ['a' => 'b'], false, 'baidu.com/list?a=b'], + ['/api/v1/doc/categories/1?order=id', ['sort' => 'desc'], false, '/api/v1/doc/categories/1?order=id&sort=desc'], + ['//google.com/search?c=d', ['a' => 'b'], false, '//google.com/search?c=d&a=b'], + [ + 'https://support.luxcreo.com/#/support?id=123', + ['category' => 'abc'], + true, + 'https://support.luxcreo.com/#/support?id=123&category=abc', + ], + [ + 'https://support.luxcreo.com/#/support', + ['category' => 'abc'], + true, + 'https://support.luxcreo.com/#/support?category=abc', + ], + [ + 'ssh://username:password@127.0.0.1/git/resp?id=1#/page?a=b', + ['c' => 'd'], + false, + 'ssh://username:password@127.0.0.1/git/resp?id=1&c=d#/page?a=b', + ], + [ + 'http://username:password@127.0.0.1/git/resp?id=1#/page?a=b', + ['c' => 'd'], + true, + 'http://username:password@127.0.0.1/git/resp?id=1#/page?a=b&c=d', + ] +])->group('pure', 'utils');