本文目录导读:

我来为您创建一个完整的PHP签名工具类,包含常见的签名算法实现:
<?php
/**
* 签名工具类
* 支持 MD5、SHA1、SHA256、HMAC 等常见签名算法
*/
class SignUtil
{
/**
* 签名算法常量
*/
const ALG_MD5 = 'md5';
const ALG_SHA1 = 'sha1';
const ALG_SHA256 = 'sha256';
const ALG_HMAC_MD5 = 'hmac_md5';
const ALG_HMAC_SHA1 = 'hmac_sha1';
const ALG_HMAC_SHA256 = 'hmac_sha256';
const ALG_RSA = 'rsa';
const ALG_ECDSA = 'ecdsa';
/**
* 生成签名
*
* @param array $params 待签名参数
* @param string $secret 密钥
* @param string $algorithm 签名算法
* @param array $options 额外选项
* @return string 签名结果
*/
public static function sign(array $params, string $secret, string $algorithm = self::ALG_MD5, array $options = []): string
{
// 1. 过滤空值和非签名参数
$params = self::filterParams($params, $options['exclude_keys'] ?? []);
// 2. 排序参数
ksort($params);
// 3. 拼接字符串
$str = self::buildSignStr($params, $options['separator'] ?? '&');
// 4. 根据算法生成签名
switch ($algorithm) {
case self::ALG_MD5:
return self::md5Sign($str, $secret);
case self::ALG_SHA1:
return self::sha1Sign($str, $secret);
case self::ALG_SHA256:
return self::sha256Sign($str, $secret);
case self::ALG_HMAC_MD5:
return self::hmacSign($str, $secret, 'md5');
case self::ALG_HMAC_SHA1:
return self::hmacSign($str, $secret, 'sha1');
case self::ALG_HMAC_SHA256:
return self::hmacSign($str, $secret, 'sha256');
case self::ALG_RSA:
return self::rsaSign($str, $secret, $options['private_key'] ?? null);
case self::ALG_ECDSA:
return self::ecdsaSign($str, $secret, $options['private_key'] ?? null);
default:
throw new InvalidArgumentException("不支持的签名算法: {$algorithm}");
}
}
/**
* 验证签名
*
* @param array $params 请求参数(包含签名)
* @param string $secret 密钥
* @param string $algorithm 签名算法
* @param string $signName 签名参数名
* @param array $options 额外选项
* @return bool
*/
public static function verify(array $params, string $secret, string $algorithm = self::ALG_MD5, string $signName = 'sign', array $options = []): bool
{
if (!isset($params[$signName])) {
throw new InvalidArgumentException("缺少签名参数: {$signName}");
}
$clientSign = $params[$signName];
// 复制参数并移除签名字段
$params = $params;
unset($params[$signName]);
// 生成服务端签名
$serverSign = self::sign($params, $secret, $algorithm, $options);
// 使用 hash_equals 防止时序攻击
return hash_equals($clientSign, $serverSign);
}
/**
* MD5 签名(微信支付风格)
*
* @param array $params 参数
* @param string $key 密钥
* @return string
*/
public static function wechatSign(array $params, string $key): string
{
// 过滤空值和sign
$params = self::filterParams($params, ['sign', 'sign_type']);
// 排序
ksort($params);
// 拼接
$str = self::buildSignStr($params);
$str .= '&key=' . $key;
return strtoupper(md5($str));
}
/**
* 阿里云签名(RPC风格)
*
* @param array $params 参数
* @param string $secret 密钥
* @return string
*/
public static function aliyunRpcSign(array $params, string $secret): string
{
// 排序并过滤
ksort($params);
$params = self::filterParams($params, ['Signature', 'signature']);
// 构造规范请求
$str = '';
foreach ($params as $key => $value) {
$str .= '&' . self::percentEncode($key) . '=' . self::percentEncode($value);
}
$str = substr($str, 1);
$stringToSign = 'GET&%2F&' . self::percentEncode($str);
return base64_encode(hash_hmac('sha1', $stringToSign, $secret . '&', true));
}
/**
* 腾讯云签名(TC3-HMAC-SHA256)
*
* @param array $params 参数
* @param string $secretId 密钥ID
* @param string $secretKey 密钥
* @param array $options 选项
* @return string
*/
public static function tencentCloudSign(array $params, string $secretId, string $secretKey, array $options = []): string
{
$timestamp = $options['timestamp'] ?? time();
$date = gmdate('Y-m-d', $timestamp);
$service = $options['service'] ?? '';
$host = $options['host'] ?? '';
$action = $options['action'] ?? '';
$version = $options['version'] ?? '';
$region = $options['region'] ?? '';
$method = $options['method'] ?? 'POST';
$payload = $options['payload'] ?? json_encode($params);
// 步骤1:拼接规范请求串
$payloadHash = hash('sha256', $payload);
$canonicalHeaders = "content-type:application/json; charset=utf-8\nhost:" . $host . "\n";
$signedHeaders = "content-type;host";
$canonicalRequest = $method . "\n/\n\n" . $canonicalHeaders . "\n" . $signedHeaders . "\n" . $payloadHash;
// 步骤2:拼接待签名字符串
$credentialScope = $date . "/" . $service . "/tc3_request";
$hashedCanonicalRequest = hash('sha256', $canonicalRequest);
$stringToSign = "TC3-HMAC-SHA256\n" . $timestamp . "\n" . $credentialScope . "\n" . $hashedCanonicalRequest;
// 步骤3:计算签名
$secretDate = hash_hmac('sha256', $date, "TC3" . $secretKey, true);
$secretService = hash_hmac('sha256', $service, $secretDate, true);
$secretSigning = hash_hmac('sha256', "tc3_request", $secretService, true);
$signature = hash_hmac('sha256', $stringToSign, $secretSigning);
// 步骤4:拼接Authorization
$authorization = "TC3-HMAC-SHA256 Credential=" . $secretId . "/" . $credentialScope . ", SignedHeaders=" . $signedHeaders . ", Signature=" . $signature;
return $authorization;
}
/**
* 过滤参数
*
* @param array $params 原参数
* @param array $excludeKeys 需要排除的键
* @return array
*/
protected static function filterParams(array $params, array $excludeKeys = []): array
{
$excludeKeys = array_merge(['sign', 'signature', 'sign_type'], $excludeKeys);
$result = [];
foreach ($params as $key => $value) {
// 排除指定的键
if (in_array($key, $excludeKeys)) {
continue;
}
// 过滤空值(保留0和'0')
if ($value === '' || $value === null || $value === false) {
continue;
}
// 数组转为JSON
if (is_array($value)) {
$value = json_encode($value);
}
$result[$key] = $value;
}
return $result;
}
/**
* 构建签名字符串
*
* @param array $params 参数
* @param string $separator 分隔符
* @return string
*/
protected static function buildSignStr(array $params, string $separator = '&'): string
{
$str = '';
foreach ($params as $key => $value) {
if ($str !== '') {
$str .= $separator;
}
$str .= $key . '=' . $value;
}
return $str;
}
/**
* MD5 签名
*/
protected static function md5Sign(string $str, string $key): string
{
return md5($str . $key);
}
/**
* SHA1 签名
*/
protected static function sha1Sign(string $str, string $key): string
{
return sha1($str . $key);
}
/**
* SHA256 签名
*/
protected static function sha256Sign(string $str, string $key): string
{
return hash('sha256', $str . $key);
}
/**
* HMAC 签名
*/
protected static function hmacSign(string $str, string $key, string $algo): string
{
return hash_hmac($algo, $str, $key);
}
/**
* RSA 签名
*/
protected static function rsaSign(string $str, string $key, ?string $privateKey): string
{
if (!$privateKey) {
throw new InvalidArgumentException('RSA签名需要提供私钥');
}
$privateKey = openssl_pkey_get_private($privateKey);
if (!$privateKey) {
throw new RuntimeException('无效的RSA私钥');
}
$signature = '';
openssl_sign($str, $signature, $privateKey, OPENSSL_ALGO_SHA256);
openssl_free_key($privateKey);
return base64_encode($signature);
}
/**
* ECDSA 签名
*/
protected static function ecdsaSign(string $str, string $key, ?string $privateKey): string
{
if (!$privateKey) {
throw new InvalidArgumentException('ECDSA签名需要提供私钥');
}
$privateKey = openssl_pkey_get_private($privateKey);
if (!$privateKey) {
throw new RuntimeException('无效的ECDSA私钥');
}
$signature = '';
openssl_sign($str, $signature, $privateKey, OPENSSL_ALGO_SHA256);
openssl_free_key($privateKey);
return base64_encode($signature);
}
/**
* URL编码(RFC 3986)
*
* @param string $str
* @return string
*/
protected static function percentEncode(string $str): string
{
$res = urlencode($str);
$res = str_replace(['+', '*', '%7E'], ['%20', '%2A', '~'], $res);
return $res;
}
}
// ==================== 使用示例 ====================
class SignUtilExample
{
public function testBasicSign()
{
$params = [
'name' => '张三',
'age' => 30,
'phone' => '13800138000',
];
$secret = 'my_secret_key';
// MD5签名
$sign = SignUtil::sign($params, $secret, SignUtil::ALG_MD5);
echo "MD5签名: " . $sign . PHP_EOL;
// HMAC-SHA256签名
$sign = SignUtil::sign($params, $secret, SignUtil::ALG_HMAC_SHA256);
echo "HMAC-SHA256签名: " . $sign . PHP_EOL;
// 验证签名
$params['sign'] = $sign;
$result = SignUtil::verify($params, $secret, SignUtil::ALG_HMAC_SHA256);
echo "签名验证: " . var_export($result, true) . PHP_EOL;
}
public function testWechatSign()
{
$params = [
'appid' => 'wx123456789',
'mch_id' => '123456',
'nonce_str' => 'abc123',
'body' => '测试商品',
'out_trade_no' => '2024000001',
'total_fee' => 100,
];
$apiKey = 'your_wechat_pay_api_key';
$sign = SignUtil::wechatSign($params, $apiKey);
echo "微信支付签名: " . $sign . PHP_EOL;
}
public function testGenerateRSAKeyPair()
{
// 生成RSA密钥对
$config = [
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $privateKey);
$details = openssl_pkey_get_details($res);
$publicKey = $details['key'];
$params = ['order_id' => '123456', 'amount' => 100];
// 使用私钥签名
$sign = SignUtil::sign($params, '', SignUtil::ALG_RSA, [
'private_key' => $privateKey
]);
// 使用公钥验证(需要额外实现)
echo "RSA私钥: " . $privateKey . PHP_EOL;
echo "RSA公钥: " . $publicKey . PHP_EOL;
echo "RSA签名: " . $sign . PHP_EOL;
}
}
// 执行示例
$example = new SignUtilExample();
$example->testBasicSign();
$example->testWechatSign();
$example->testGenerateRSAKeyPair();
这个签名工具类具有以下特点:
主要功能
- 多算法支持:MD5、SHA1、SHA256、HMAC系列和RSA/ECDSA
- 参数过滤:自动过滤空值和签名相关字段
- 密钥拼接:支持密钥直接拼接方式
- 防时序攻击:使用
hash_equals()验证签名 - URL编码:支持RFC 3986标准编码
使用场景
- API接口安全:防止参数篡改
- 支付系统:微信支付、支付宝等平台签名
- 开放平台:类似于阿里云、腾讯云的签名机制
- JWT令牌:JWT签名的基础
扩展建议
如果需要更多平台的特定签名,可以在类中添加:
// 支付宝签名
public static function alipaySign(array $params, string $privateKey) {}
// 百度云签名
public static function baiduSign(array $params, string $secret) {}
// JWT签名
public static function jwtSign(array $payload, string $secret) {}
这个工具类应该能满足大多数PHP项目的签名需求,如果有特定平台的需求,可以根据具体规范进行定制扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播