存客宝应用接口初始化

This commit is contained in:
Ghost
2026-01-05 10:25:32 +08:00
parent fa37227954
commit 02797ba50a
414 changed files with 85530 additions and 75 deletions

View File

@@ -0,0 +1,79 @@
<?php
namespace app\common\util;
use OSS\OssClient;
use OSS\Core\OssException;
use think\facade\Env;
class AliyunOSS
{
// OSS配置信息
const ACCESS_KEY_ID = 'LTAIxvJUmlt2gLiY';
const ACCESS_KEY_SECRET = '0WUo8r6BT4I8ZVUQxflmD8rLHrFNHO';
const ENDPOINT = 'oss-cn-shenzhen.aliyuncs.com';
const BUCKET = 'karuosiyujzk';
const ossUrl = 'https://res.quwanzhi.com';
/**
* 获取OSS客户端实例
* @return OssClient
* @throws OssException
*/
public static function getClient()
{
try {
return new OssClient(
self::ACCESS_KEY_ID,
self::ACCESS_KEY_SECRET,
self::ENDPOINT
);
} catch (OssException $e) {
throw new OssException('创建OSS客户端失败' . $e->getMessage());
}
}
/**
* 上传文件到OSS
* @param string $filePath 本地文件路径
* @param string $objectName OSS对象名称
* @return array
* @throws OssException
*/
public static function uploadFile($filePath, $objectName)
{
try {
$client = self::getClient();
// 上传文件
$result = $client->uploadFile(self::BUCKET, $objectName, $filePath);
// 获取文件访问URL
$url = !empty($result['oss-request-url']) ? $result['oss-request-url'] : $client->signUrl(self::BUCKET, $objectName, 3600);
return [
'success' => true,
'url' => $url,
'object_name' => $objectName,
'size' => filesize($filePath),
'mime_type' => mime_content_type($filePath)
];
} catch (OssException $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* 生成OSS对象名称
* @param string $originalName 原始文件名
* @return string
*/
public static function generateObjectName($originalName)
{
$ext = pathinfo($originalName, PATHINFO_EXTENSION);
$name = md5(uniqid(mt_rand(), true));
return date('Y/m/d/') . $name . '.' . $ext;
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace app\common\util;
use Darabonba\OpenApi\Models\Config;
use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
class AliyunSMS {
const ACCESS_KEY_ID = 'LTAI5tFjVRYAFmo6fayvv2Te';
const ACCESS_KEY_SECRET = 'mdc7KETPGVon8PiA2kfM47rAOpJne8';
const SIGN_NAME = '广州宏科网络';
const TC_VCODE = 'SMS_464445466';
static public function createClient() {
$config = new Config([
// AccessKey ID
'accessKeyId' => static::ACCESS_KEY_ID,
// AccessKey Secret
'accessKeySecret' => static::ACCESS_KEY_SECRET
]);
// 访问的域名
$config->endpoint = 'dysmsapi.aliyuncs.com';
return new Dysmsapi($config);
}
/**
* 发送验证码
*
* @param $phoneNumbers
* @param $templateCode
* @param array $templateParam
* @return bool
*/
static public function send($phoneNumbers, $templateCode, array $templateParam = array()) {
$client = static::createClient();
$sendSmsRequest = new SendSmsRequest([
'phoneNumbers' => $phoneNumbers,
'signName' => static::SIGN_NAME,
'templateCode' => $templateCode,
'templateParam' => json_encode($templateParam)
]);
$runtime = new RuntimeOptions([]);
$logFile = ROOT_PATH . DS . 'aliyun-sms.txt';
try {
$data = $client->sendSmsWithOptions($sendSmsRequest, $runtime);
if ($data->body->code === 'OK') {
return TRUE;
}
$logData = print_r($data, TRUE);
} catch (\Exception $ex) {
$logData = print_r($ex, TRUE);
}
file_put_contents($logFile, '[' . date('Y-m-d H:i:s') . ']' . PHP_EOL . $logData . PHP_EOL . PHP_EOL, FILE_APPEND);
return FALSE;
}
}

View File

@@ -0,0 +1,137 @@
<?php
namespace app\common\util;
use think\facade\Config;
use think\facade\Request;
/**
* JWT工具类
* 用于生成和验证JWT令牌
*/
class JwtUtil
{
/**
* 密钥
* @var string
*/
protected static $secret = 'YiShi@2023#JWT';
/**
* 头部
* @var array
*/
protected static $header = [
'alg' => 'HS256', // 加密算法
'typ' => 'JWT' // 类型
];
/**
* 创建JWT令牌
* @param array $payload 载荷信息
* @param int $expire 过期时间(秒)默认2小时
* @return string
*/
public static function createToken($payload, $expire = 7200)
{
$header = self::base64UrlEncode(json_encode(self::$header, JSON_UNESCAPED_UNICODE));
// 附加过期时间
$payload['exp'] = time() + $expire;
$payload['iat'] = time(); // 签发时间
unset($payload['passwordMd5']);
$payload = self::base64UrlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE));
$signature = self::signature($header . '.' . $payload, self::$secret);
return $header . '.' . $payload . '.' . $signature;
}
/**
* 验证令牌
* @param string $token 令牌
* @return array|bool 验证通过返回载荷信息失败返回false
*/
public static function verifyToken($token)
{
if (empty($token)) {
return false;
}
$tokenArray = explode('.', $token);
if (count($tokenArray) != 3) {
return false;
}
list($header, $payload, $signature) = $tokenArray;
// 验证签名
if (self::signature($header . '.' . $payload, self::$secret) !== $signature) {
return false;
}
// 解码载荷
$payload = json_decode(self::base64UrlDecode($payload), true);
// 验证是否过期
if (isset($payload['exp']) && $payload['exp'] < time()) {
return false;
}
return $payload;
}
/**
* 生成签名
* @param string $input 输入
* @param string $key 密钥
* @return string
*/
private static function signature($input, $key)
{
return self::base64UrlEncode(hash_hmac('sha256', $input, $key, true));
}
/**
* URL安全的Base64编码
* @param string $input
* @return string
*/
private static function base64UrlEncode($input)
{
return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($input));
}
/**
* URL安全的Base64解码
* @param string $input
* @return string
*/
private static function base64UrlDecode($input)
{
$remainder = strlen($input) % 4;
if ($remainder) {
$input .= str_repeat('=', 4 - $remainder);
}
return base64_decode(str_replace(['-', '_'], ['+', '/'], $input));
}
/**
* 从请求头中获取Token
* @return string|null
*/
public static function getRequestToken()
{
$authorization = Request::header('Authorization');
if (!$authorization) {
return null;
}
// 检查Bearer前缀
if (strpos($authorization, 'Bearer ') !== 0) {
return null;
}
return substr($authorization, 7);
}
}

View File

@@ -0,0 +1,255 @@
<?php
namespace app\common\util;
/**
* 支付工具类
* 用于处理第三方支付相关功能
* 仅限内部调用
*/
class PaymentUtil
{
/**
* 签名算法类型
*/
const SIGN_TYPE_MD5 = 'MD5';
const SIGN_TYPE_RSA_1_256 = 'RSA_1_256';
const SIGN_TYPE_RSA_1_1 = 'RSA_1_1';
/**
* 生成支付签名
*
* @param array $params 待签名参数
* @param string $secretKey 签名密钥
* @param string $signType 签名类型 MD5/RSA_1_256/RSA_1_1
* @return string 签名结果
*/
public static function generateSign(array $params, string $secretKey, string $signType = self::SIGN_TYPE_MD5): string
{
// 1. 移除sign字段
unset($params['sign']);
// 2. 过滤空值
$params = array_filter($params, function($value) {
return $value !== '' && $value !== null;
});
// 3. 按字段名ASCII码从小到大排序
ksort($params);
// 4. 拼接成QueryString格式
$queryString = self::buildQueryString($params);
// 5. 根据签名类型生成签名
switch (strtoupper($signType)) {
case self::SIGN_TYPE_MD5:
return self::generateMd5Sign($queryString, $secretKey);
case self::SIGN_TYPE_RSA_1_256:
return self::generateRsa256Sign($queryString, $secretKey);
case self::SIGN_TYPE_RSA_1_1:
return self::generateRsa1Sign($queryString, $secretKey);
default:
throw new \InvalidArgumentException('不支持的签名类型: ' . $signType);
}
}
/**
* 验证支付签名
*
* @param array $params 待验证参数包含sign字段
* @param string $secretKey 签名密钥
* @param string $signType 签名类型
* @return bool 验证结果
*/
public static function verifySign(array $params, string $secretKey, string $signType = self::SIGN_TYPE_MD5): bool
{
if (!isset($params['sign'])) {
return false;
}
$receivedSign = $params['sign'];
$generatedSign = self::generateSign($params, $secretKey, $signType);
return $receivedSign === $generatedSign;
}
/**
* 构建QueryString
*
* @param array $params 参数数组
* @return string QueryString
*/
private static function buildQueryString(array $params): string
{
$pairs = [];
foreach ($params as $key => $value) {
$pairs[] = $key . '=' . $value;
}
return implode('&', $pairs);
}
/**
* 生成MD5签名
*
* @param string $queryString 待签名字符串
* @param string $secretKey 密钥
* @return string MD5签名
*/
private static function generateMd5Sign(string $queryString, string $secretKey): string
{
$signString = $queryString . '&key=' . $secretKey;
return strtoupper(md5($signString));
}
/**
* 生成RSA256签名
*
* @param string $queryString 待签名字符串
* @param string $privateKey 私钥
* @return string RSA256签名
*/
private static function generateRsa256Sign(string $queryString, string $privateKey): string
{
$privateKey = self::formatPrivateKey($privateKey);
$key = openssl_pkey_get_private($privateKey);
if (!$key) {
throw new \Exception('RSA私钥格式错误');
}
$signature = '';
$result = openssl_sign($queryString, $signature, $key, OPENSSL_ALGO_SHA256);
openssl_pkey_free($key);
if (!$result) {
throw new \Exception('RSA256签名失败');
}
return base64_encode($signature);
}
/**
* 生成RSA1签名
*
* @param string $queryString 待签名字符串
* @param string $privateKey 私钥
* @return string RSA1签名
*/
private static function generateRsa1Sign(string $queryString, string $privateKey): string
{
$privateKey = self::formatPrivateKey($privateKey);
$key = openssl_pkey_get_private($privateKey);
if (!$key) {
throw new \Exception('RSA私钥格式错误');
}
$signature = '';
$result = openssl_sign($queryString, $signature, $key, OPENSSL_ALGO_SHA1);
openssl_pkey_free($key);
if (!$result) {
throw new \Exception('RSA1签名失败');
}
return base64_encode($signature);
}
/**
* 格式化私钥
*
* @param string $privateKey 原始私钥
* @return string 格式化后的私钥
*/
private static function formatPrivateKey(string $privateKey): string
{
$privateKey = str_replace(['-----BEGIN PRIVATE KEY-----', '-----END PRIVATE KEY-----', "\n", "\r"], '', $privateKey);
$privateKey = chunk_split($privateKey, 64, "\n");
return "-----BEGIN PRIVATE KEY-----\n" . $privateKey . "-----END PRIVATE KEY-----";
}
/**
* 格式化公钥
*
* @param string $publicKey 原始公钥
* @return string 格式化后的公钥
*/
private static function formatPublicKey(string $publicKey): string
{
$publicKey = str_replace(['-----BEGIN PUBLIC KEY-----', '-----END PUBLIC KEY-----', "\n", "\r"], '', $publicKey);
$publicKey = chunk_split($publicKey, 64, "\n");
return "-----BEGIN PUBLIC KEY-----\n" . $publicKey . "-----END PUBLIC KEY-----";
}
/**
* 验证RSA签名
*
* @param string $queryString 原始字符串
* @param string $signature 签名
* @param string $publicKey 公钥
* @param string $signType 签名类型
* @return bool 验证结果
*/
public static function verifyRsaSign(string $queryString, string $signature, string $publicKey, string $signType = self::SIGN_TYPE_RSA_1_256): bool
{
$publicKey = self::formatPublicKey($publicKey);
$key = openssl_pkey_get_public($publicKey);
if (!$key) {
return false;
}
$algorithm = $signType === self::SIGN_TYPE_RSA_1_1 ? OPENSSL_ALGO_SHA1 : OPENSSL_ALGO_SHA256;
$result = openssl_verify($queryString, base64_decode($signature), $key, $algorithm);
openssl_pkey_free($key);
return $result === 1;
}
/**
* 生成随机字符串
*
* @param int $length 长度
* @return string 随机字符串
*/
public static function generateNonceStr(int $length = 32): string
{
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= $chars[mt_rand(0, strlen($chars) - 1)];
}
return $str;
}
/**
* 生成时间戳
*
* @return int 时间戳
*/
public static function generateTimestamp(): int
{
return time();
}
/**
* 格式化金额(分转元)
*
* @param int $amount 金额(分)
* @return string 格式化后的金额(元)
*/
public static function formatAmount(int $amount): string
{
return number_format($amount / 100, 2, '.', '');
}
/**
* 解析金额(元转分)
*
* @param string $amount 金额(元)
* @return int 金额(分)
*/
public static function parseAmount(string $amount): int
{
return (int) round(floatval($amount) * 100);
}
}

View File

@@ -0,0 +1,135 @@
<?php
namespace app\common\util;
/**
* 第三方支付签名工具(仅内部调用)
* 规则:
* 1. 除 sign 外的所有非空参数,按字段名 ASCII 升序,使用 QueryString 形式拼接key1=value1&key2=value2
* 2. 参与签名的字段名与值均为原始值,不做 URL Encode
* 3. 支持算法MD5默认/ RSA_1_256 / RSA_1_1
*/
class Signer
{
/**
* 生成签名
*
* @param array $params 参与签名的参数(会自动剔除 sign 及空值)
* @param string $algorithm 签名算法md5 | RSA_1_256 | RSA_1_1
* @param array $options 额外选项:
* - secret: string MD5 签名时可选的密钥,若提供则会在原串末尾以 &key=SECRET 追加
* - private_key: string RSA 签名所需私钥PEM 字符串,支持带头尾)
* - passphrase: string 可选RSA 私钥口令
* @return string 返回签名串MD5 为32位小写RSA为base64编码
* @throws \InvalidArgumentException
*/
public static function sign(array $params, $algorithm = 'md5', array $options = [])
{
$signString = self::buildSignString($params);
$algo = strtolower($algorithm);
switch ($algo) {
case 'md5':
return self::signMd5($signString, isset($options['secret']) ? (string)$options['secret'] : null);
case 'rsa_1_256':
return self::signRsa($signString, $options, 'sha256');
case 'rsa_1_1':
return self::signRsa($signString, $options, 'sha1');
default:
throw new \InvalidArgumentException('Unsupported algorithm: ' . $algorithm);
}
}
/**
* 构建签名原始串
* - 剔除 sign 字段
* - 过滤空值null、''
* - 按键名 ASCII 升序
* - 使用原始值拼接为 key1=value1&key2=value2
*
* @param array $params
* @return string
*/
public static function buildSignString(array $params)
{
$filtered = [];
foreach ($params as $key => $value) {
if ($key === 'sign') {
continue;
}
if ($value === '' || $value === null) {
continue;
}
$filtered[$key] = $value;
}
ksort($filtered, SORT_STRING);
$pairs = [];
foreach ($filtered as $key => $value) {
// 原始值拼接,不做 urlencode
$pairs[] = $key . '=' . (is_bool($value) ? ($value ? '1' : '0') : (string)$value);
}
return implode('&', $pairs);
}
/**
* MD5 签名
* - 若提供 secret则原串末尾追加 &key=SECRET
* - 返回 32 位小写
*
* @param string $signString
* @param string|null $secret
* @return string
*/
protected static function signMd5($signString, $secret = null)
{
if ($secret !== null && $secret !== '') {
$signString .= '&key=' . $secret;
}
return strtolower(md5($signString));
}
/**
* RSA 签名
*
* @param string $signString
* @param array $options 必填private_key可选passphrase
* @param string $hashAlgo sha256|sha1
* @return string base64 签名
* @throws \InvalidArgumentException
*/
protected static function signRsa($signString, array $options, $hashAlgo = 'sha256')
{
if (empty($options['private_key'])) {
throw new \InvalidArgumentException('RSA signing requires private_key.');
}
$privateKey = $options['private_key'];
$passphrase = isset($options['passphrase']) ? (string)$options['passphrase'] : '';
// 兼容无头尾私钥,自动包裹为 PEM
if (strpos($privateKey, 'BEGIN') === false) {
$privateKey = "-----BEGIN PRIVATE KEY-----\n" . trim(chunk_split(str_replace(["\r", "\n"], '', $privateKey), 64, "\n")) . "\n-----END PRIVATE KEY-----";
}
$pkeyId = openssl_pkey_get_private($privateKey, $passphrase);
if ($pkeyId === false) {
throw new \InvalidArgumentException('Invalid RSA private key or passphrase.');
}
$signature = '';
$algoConst = $hashAlgo === 'sha1' ? OPENSSL_ALGO_SHA1 : OPENSSL_ALGO_SHA256;
$ok = openssl_sign($signString, $signature, $pkeyId, $algoConst);
openssl_free_key($pkeyId);
if (!$ok) {
throw new \InvalidArgumentException('OpenSSL sign failed.');
}
return base64_encode($signature);
}
}