接入公共服务

This commit is contained in:
2025-04-02 15:17:13 +08:00
parent 8bb0826b06
commit 522183cb71
8 changed files with 491 additions and 18 deletions
+227
View File
@@ -0,0 +1,227 @@
<?php
namespace app\util;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
class HttpClient
{
/**
* @var Client Guzzle客户端实例
*/
private static $client;
/**
* 获取Guzzle客户端单例
* @return Client
*/
private static function getClient(): Client
{
if (!self::$client) {
self::$client = new Client([
'timeout' => 10, // 默认超时时间10秒
'verify' => false, // 不验证SSL证书(生产环境建议设为true)
'http_errors' => false, // 不抛出HTTP异常,自己处理
]);
}
return self::$client;
}
/**
* 发送GET请求
* @param string $url 请求地址
* @param array $query 查询参数
* @param array $headers 请求头
* @return array
*/
public static function get(string $url, array $query = [], array $headers = []): array
{
$options = [
'query' => $query,
'headers' => $headers
];
return self::request('GET', $url, $options);
}
/**
* 发送POST请求
* @param string $url 请求地址
* @param array|string $data 请求数据
* @param array $headers 请求头
* @param string $contentType 内容类型(form/json/xml)
* @return array
*/
public static function post(string $url, $data = [], array $headers = [], string $contentType = 'form'): array
{
$options = ['headers' => $headers];
switch ($contentType) {
case 'json':
$options['json'] = $data;
$options['headers']['Content-Type'] = 'application/json';
break;
/*case 'xml':
$options['body'] = is_array($data) ? self::arrayToXml($data) : $data;
$options['headers']['Content-Type'] = 'application/xml';
break;*/
default: // form
$options['form_params'] = $data;
$options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
}
return self::request('POST', $url, $options);
}
/**
* 发送PUT请求
* @param string $url 请求地址
* @param array|string $data 请求数据
* @param array $headers 请求头
* @return array
*/
public static function put(string $url, $data = [], array $headers = []): array
{
$options = [
'json' => $data,
'headers' => $headers
];
return self::request('PUT', $url, $options);
}
/**
* 发送DELETE请求
* @param string $url 请求地址
* @param array $data 请求数据
* @param array $headers 请求头
* @return array
*/
public static function delete(string $url, array $data = [], array $headers = []): array
{
$options = [
'json' => $data,
'headers' => $headers
];
return self::request('DELETE', $url, $options);
}
/**
* 发送HTTP请求
* @param string $method 请求方法
* @param string $url 请求地址
* @param array $options 请求选项
* @return array
*/
public static function request(string $method, string $url, array $options = []): array
{
try {
$response = self::getClient()->request($method, $url, $options);
return self::formatResponse($response);
} catch (GuzzleException $e) {
return [
'status' => false,
'code' => $e->getCode(),
'message' => $e->getMessage(),
'data' => null
];
}
}
/**
* 上传文件
* @param string $url 请求地址
* @param array $files 文件数组 [['name' => 'field_name', 'path' => 'file_path']]
* @param array $form 其他表单数据
* @param array $headers 请求头
* @return array
*/
public static function upload(string $url, array $files, array $form = [], array $headers = []): array
{
$multipart = [];
// 添加文件
foreach ($files as $file) {
if (file_exists($file['path'])) {
$multipart[] = [
'name' => $file['name'],
'contents' => fopen($file['path'], 'r'),
'filename' => basename($file['path'])
];
}
}
// 添加其他表单数据
foreach ($form as $name => $value) {
$multipart[] = [
'name' => $name,
'contents' => $value
];
}
$options = [
'multipart' => $multipart,
'headers' => $headers
];
return self::request('POST', $url, $options);
}
/**
* 格式化响应
* @param ResponseInterface $response
* @return array
*/
private static function formatResponse(ResponseInterface $response): array
{
$contents = $response->getBody()->getContents();
$contentType = $response->getHeaderLine('Content-Type');
$data = $contents;
if (strpos($contentType, 'application/json') !== false) {
$data = json_decode($contents, true) ?? $contents;
}
return [
'status' => $response->getStatusCode() === 200,
'code' => $response->getStatusCode(),
'message' => $response->getReasonPhrase(),
'data' => $data,
'headers' => $response->getHeaders()
];
}
/**
* 数组转XML
* @param array $data
* @param string $rootNode
* @return string
*/
private static function arrayToXml(array $data, string $rootNode = 'root'): string
{
$xml = new \SimpleXMLElement('<' . $rootNode . '/>');
self::addDataToXml($xml, $data);
return $xml->asXML();
}
/**
* 递归添加数据到XML
* @param \SimpleXMLElement $xml
* @param array $data
*/
private static function addDataToXml(\SimpleXMLElement $xml, array $data)
{
foreach ($data as $key => $value) {
if (is_array($value)) {
if (is_numeric($key)) {
$key = 'item';
}
$subNode = $xml->addChild($key);
self::addDataToXml($subNode, $value);
} else {
$xml->addChild($key, htmlspecialchars($value));
}
}
}
}
+171
View File
@@ -0,0 +1,171 @@
<?php
namespace app\util;
use support\Redis;
use support\Log;
class RedisHelper
{
/**
* 存储数据(自动序列化数组)
* @param string $key 键名
* @param mixed $value 值
* @param int|null $ttl 过期时间(秒)
* @return bool
*/
public static function set(string $key, $value, ?int $ttl = null): bool
{
try {
$storageValue = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
if ($ttl !== null) {
return Redis::setex($key, $ttl, $storageValue);
}
return Redis::set($key, $storageValue);
} catch (\Throwable $e) {
Log::error("Redis存储失败: {$e->getMessage()}", ['key' => $key]);
return false;
}
}
/**
* 获取数据(自动反序列化数组)
* @param string $key 键名
* @param mixed $default 默认值
* @return mixed
*/
public static function get(string $key, $default = null)
{
try {
$value = Redis::get($key);
if ($value === false || $value === null) {
return $default;
}
// 尝试JSON解码
$decoded = json_decode($value, true);
return json_last_error() === JSON_ERROR_NONE ? $decoded : $value;
} catch (\Throwable $e) {
Log::error("Redis读取失败: {$e->getMessage()}", ['key' => $key]);
return $default;
}
}
/**
* 删除键
* @param string|array $keys 键名或键名数组
* @return int 删除的键数量
*/
public static function del($keys): int
{
try {
return Redis::del(...(array)$keys);
} catch (\Throwable $e) {
Log::error("Redis删除失败: {$e->getMessage()}", ['keys' => $keys]);
return 0;
}
}
/**
* 检查键是否存在
* @param string $key 键名
* @return bool
*/
public static function exists(string $key): bool
{
try {
return (bool)Redis::exists($key);
} catch (\Throwable $e) {
Log::error("Redis检查存在失败: {$e->getMessage()}", ['key' => $key]);
return false;
}
}
/**
* 设置带过期时间的缓存
* @param string $key 键名
* @param mixed $value 值
* @param int $ttl 过期时间(秒)
* @return bool
*/
public static function setex(string $key, $value, int $ttl): bool
{
return self::set($key, $value, $ttl);
}
/**
* 哈希表设置字段值
* @param string $key 键名
* @param string $field 字段名
* @param mixed $value 值
* @return bool
*/
public static function hSet(string $key, string $field, $value): bool
{
try {
$storageValue = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
return Redis::hSet($key, $field, $storageValue);
} catch (\Throwable $e) {
Log::error("Redis哈希设置失败: {$e->getMessage()}", ['key' => $key, 'field' => $field]);
return false;
}
}
/**
* 哈希表获取字段值
* @param string $key 键名
* @param string $field 字段名
* @param mixed $default 默认值
* @return mixed
*/
public static function hGet(string $key, string $field, $default = null)
{
try {
$value = Redis::hGet($key, $field);
if ($value === false) {
return $default;
}
$decoded = json_decode($value, true);
return json_last_error() === JSON_ERROR_NONE ? $decoded : $value;
} catch (\Throwable $e) {
Log::error("Redis哈希获取失败: {$e->getMessage()}", ['key' => $key, 'field' => $field]);
return $default;
}
}
/**
* 自增计数器
* @param string $key 键名
* @param int $increment 增量
* @return int|false
*/
public static function incr(string $key, int $increment = 1)
{
try {
return $increment === 1
? Redis::incr($key)
: Redis::incrBy($key, $increment);
} catch (\Throwable $e) {
Log::error("Redis自增失败: {$e->getMessage()}", ['key' => $key]);
return false;
}
}
/**
* 获取剩余过期时间
* @param string $key 键名
* @return int 剩余秒数(-2表示键不存在,-1表示没有设置过期时间)
*/
public static function ttl(string $key): int
{
try {
return Redis::ttl($key);
} catch (\Throwable $e) {
Log::error("Redis获取TTL失败: {$e->getMessage()}", ['key' => $key]);
return -2;
}
}
}