本文目录导读:

在 PHP 中生成签名 URL(通常用于实现 URL 防盗链、API 鉴权或 CDN 认证),常见的方法有两大类:
- 简单的对称加密签名(如 md5/timestamp 组合)
- 基于密钥的哈希签名(如 HMAC-SHA1)
- 阿里云/腾讯云等云服务商的 A/B 鉴权签名
下面给出这几种常见场景的 PHP 实现代码。
简单防盗链签名(MD5 + 时间戳)
常用于保护静态资源(如图片、视频),防止直接访问。
function signUrl(string $baseUrl, string $secretKey, int $expireTime = 3600): string
{
// 1. 生成过期时间戳
$expiration = time() + $expireTime;
// 2. 拼接待签名字符串(可加入路径、IP限制等)
$stringToSign = $baseUrl . '-' . $expiration . '-' . $secretKey;
// 3. 计算签名
$signature = md5($stringToSign);
// 4. 拼接签名参数
$signedUrl = $baseUrl . '?sign=' . $signature . '&expire=' . $expiration;
return $signedUrl;
}
// 使用示例
$url = 'http://example.com/files/video.mp4';
$key = 'MySecretKey123';
$signedUrl = signUrl($url, $key, 1800); // 30分钟有效
echo $signedUrl;
验证端(服务端):
function verifySignedUrl(string $url, string $secretKey): bool
{
$parsed = parse_url($url);
parse_str($parsed['query'] ?? '', $query);
$sign = $query['sign'] ?? '';
$expire = $query['expire'] ?? 0;
// 1. 过期判断
if (time() > $expire) return false;
// 2. 重新计算签名
$basePath = $parsed['scheme'] . '://' . $parsed['host'] . $parsed['path'];
$stringToSign = $basePath . '-' . $expire . '-' . $secretKey;
$expectedSign = md5($stringToSign);
// 3. 比较签名(防止时序攻击)
return hash_equals($expectedSign, $sign);
}
HMAC-SHA1 签名(更安全,常见于 API)
HMAC 配合 SHA1/SHA256 更安全,常用于 OAuth 或云 API 签名。
function signUrlHmac(string $uri, array $params, string $secretKey): string
{
// 1. 按参数名排序
ksort($params);
// 2. 拼接查询字符串
$queryString = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
// 3. 构建待签字符串(通常包含 HTTP 方法+路径+查询字符串)
$stringToSign = "GET\n{$uri}\n{$queryString}";
// 4. 计算 HMAC-SHA1 并 base64 编码
$signature = base64_encode(
hash_hmac('sha1', $stringToSign, $secretKey, true)
);
// 5. 将签名加入参数
$params['signature'] = $signature;
return $uri . '?' . http_build_query($params);
}
// 使用示例
$baseUri = '/api/v1/users';
$params = [
'uid' => 123,
'timestamp' => time(),
];
$secret = 'my-hmac-key';
$signedUrl = signUrlHmac($baseUri, $params, $secret);
echo "http://api.example.com" . $signedUrl;
阿里云 CDN URL 鉴权(A/B/C/D 类)
以阿里云 CDN 鉴权方式 C(最常见)为例:
原理
签名串 = md5(key + uri + expire_timestamp)
URL = http://domain/path?auth_key=expire-uid-rand-md5
PHP 实现
function aliyunCdnSign(string $path, string $key, int $expireTime, string $uid = '0', string $rand = ''): string
{
$timestamp = time() + $expireTime;
$rand = $rand ?: random_int(100000, 999999);
// 拼接待签字符串: key + path + timestamp
$stringToSign = $key . $path . $timestamp;
$md5 = md5($stringToSign);
// 生成 auth_key 参数
$authKey = "{$timestamp}-{$uid}-{$rand}-{$md5}";
return $path . '?auth_key=' . $authKey;
}
// 使用示例
$path = '/files/1.jpg';
$key = 'aliyun_cdn_secret';
$url = aliyunCdnSign($path, $key, 3600);
echo "http://cdn.example.com{$url}";
验证端(CDN 边缘节点自动验证,或你也可以自己写):
function verifyAliyunCdn(string $fullUrl, string $key): bool
{
$parts = parse_url($fullUrl);
parse_str($parts['query'] ?? '', $query);
$authKey = $query['auth_key'] ?? '';
$segments = explode('-', $authKey);
if (count($segments) !== 4) return false;
[$expire, $uid, $rand, $sign] = $segments;
// 过期判断
if (time() > intval($expire)) return false;
// 重新计算签名
$reSign = md5($key . $parts['path'] . $expire);
return hash_equals($reSign, $sign);
}
腾讯云 CDN URL 鉴权(时间戳防盗链)
腾讯云常用的 t=(时间戳) + key= 方式:
function tencentCdnSign(string $path, string $key, int $expireTime): string
{
// 1. 生成过期 Unix 时间戳(十进制)
$expire = time() + $expireTime;
// 2. 拼接待签字符串: path + key + t
$stringToSign = $path . $key . $expire;
// 3. 计算 md5
$sign = md5($stringToSign);
// 4. 拼接到 URL
return $path . "?t={$expire}&key={$sign}";
}
// 使用示例
echo tencentCdnSign('/resource/1.mp4', 'my_key', 1800);
总结建议
| 场景 | 推荐签名方式 | 关键点 |
|---|---|---|
| 简单 URL 防盗链 | MD5 + timestamp | 容易实现,但安全性一般 |
| 高安全 API/文件 | HMAC-SHA1/SHA256 | 防篡改,防重放 |
| 阿里云 CDN | 方式 C(auth_key) | 注意待签字符串顺序 |
| 腾讯云 CDN | key + t 模式 | 注意 t 是十进制时间戳 |
重要:
- 所有签名密钥应妥善保存(环境变量或配置文件,不出现在代码中)。
- 建议使用
hash_equals()比较签名,防止时序攻击。- 时间戳验证时注意时区(统一使用 UTC/Unix 时间戳)。