开始

V1(MD5签名)

每个请求都要带签名 sign,平台据此确认请求是你发的、参数没有被改过。平台发给你的支付结果通知也带签名,用同样的方法校验。

签名步骤

  1. 取出要发送的全部参数,去掉 sign、sign_type 和值为空的参数。文档没有列出、但你额外传了的参数,也要参与签名。
  2. 按参数名的 ASCII 码从小到大排序。
  3. 把参数按 参数名=参数值 的格式用 & 连接,得到待签名串。参数值用原文,不做 URL 编码。
  4. 在待签名串末尾直接接上 MD5密钥(中间不加任何字符),计算 MD5,得到的 32 位小写字符串就是 sign。
  5. 发送时带上 sign,sign_type 传 MD5(不传也按 MD5 处理)。
sign = md5(待签名串 + MD5密钥)

细节规则

  • 只有值为空字符串的参数不参与签名,值为 0 的参数照常参与。
  • 参数名区分大小写,只排除小写的 sign 和 sign_type。
  • 数组形式的参数(如 goods[]=1)不参与签名。
  • 参数值原样拼接:不去首尾空格,不转义 & 和 =,中文按 UTF-8 计算。
  • MD5 结果必须是小写,大写的签名校验不通过。

计算示例

下单参数:

pid=1001
type=alipay
out_trade_no=20260927123456
notify_url=https://你的域名/notify
return_url=https://你的域名/return
name=会员充值
money=1.00
sign_type=MD5

去掉 sign_type,排序、拼接后的待签名串:

money=1.00&name=会员充值&notify_url=https://你的域名/notify&out_trade_no=20260927123456&pid=1001&return_url=https://你的域名/return&type=alipay

MD5密钥取 你的MD5密钥 这七个字符时,接上密钥计算 MD5 得到:

sign=87b1ef8e501b2dbadb50379631290300

用你的程序按同样的参数和密钥计算,结果相同就说明实现正确;正式请求换成你自己的密钥。

PHP 示例

<?php
function zpay_sign(array $params, string $key): string
{
    unset($params['sign'], $params['sign_type']);
    $params = array_filter($params, function ($value) {
        return $value !== '' && $value !== null && !is_array($value);
    });
    ksort($params);
    $pairs = [];
    foreach ($params as $name => $value) {
        $pairs[] = $name . '=' . $value;
    }
    return md5(implode('&', $pairs) . $key);
}

$params = [
    'pid'          => '1001',
    'type'         => 'alipay',
    'out_trade_no' => '20260927123456',
    'notify_url'   => 'https://你的域名/notify',
    'return_url'   => 'https://你的域名/return',
    'name'         => '会员充值',
    'money'        => '1.00',
];
$params['sign']      = zpay_sign($params, '你的MD5密钥');
$params['sign_type'] = 'MD5';

// 校验收到的支付结果通知
$valid = hash_equals(zpay_sign($_GET, '你的MD5密钥'), $_GET['sign'] ?? '');

Python 示例

import hashlib
import hmac


def zpay_sign(params: dict, key: str) -> str:
    pairs = sorted(
        (name, str(value))
        for name, value in params.items()
        if name not in ("sign", "sign_type")
        and value is not None
        and value != ""
        and not isinstance(value, (list, tuple, dict))
    )
    content = "&".join(f"{name}={value}" for name, value in pairs)
    return hashlib.md5((content + key).encode("utf-8")).hexdigest()


params = {
    "pid": "1001",
    "type": "alipay",
    "out_trade_no": "20260927123456",
    "notify_url": "https://你的域名/notify",
    "return_url": "https://你的域名/return",
    "name": "会员充值",
    "money": "1.00",
}
params["sign"] = zpay_sign(params, "你的MD5密钥")
params["sign_type"] = "MD5"


# 校验收到的支付结果通知(received 为通知参数组成的字典)
def notify_valid(received: dict) -> bool:
    return hmac.compare_digest(zpay_sign(received, "你的MD5密钥"), received.get("sign", ""))