采用 WordPress 搭建的网站,并使用 WooCommerce 插件,现在需要接入支付宝支付功能。
1. 创建应用
1.1 登录
使用支付宝账号登录开放平台:
1.2 创建应用
登录之后是如下界面:
1.2.1 基础信息
基础信息中有应用名称和应用图标。应用名称之前已经填过了,现在上传自己的应用图标就行了。应用基础信息在开发应用过程中可以无需审核随时完善。但在应用申请上线时需要进行审核。
1.2.2 功能选项
功能选项模块中包含各种功能,您可以选择自己需要的功能添加到功能列表中,现在默认添加了当面付、手机网站支付、 APP 支付功能。不同的功能有不同的使用条件,如果某个功能的使用条件是签约,那么在使用此项功能之前,需要签约对应产品。点击 “+ 继续添加”,跳到添加功能页面,这里有非常多的功能供选择:
1.2.3 开发配置
- 应用网关:用于接收支付宝异步通知,这里可以不用设置。
- 授权回调地址:第三方授权或者用户信息授权后回调地址。授权链接中配置的 redirect_uri 值必须与此值保持一致。
- RSA2(SHA256) 密钥 (推荐):开发者要保证接口中使用的秘钥与此处的公钥匹配,否则无法调用接口。接口参数 sign_type=RSA2 。
- RSA(SHA1) 密钥:同上,接口参数为 sign_type=RSA 。
对接口加签方式中的 “设置应用公钥” 进行设置,会弹出如下窗口:
- 商户应用公钥:商户自己生成的 RSA 公钥,生成之后需要上传公钥到支付宝开放平台以便支付宝使用该公钥验证交易是否由该商户发起的;
- 商户应用私钥:商户自己生成的 RSA 私钥,商户开发者使用生成的私钥对请求字符串进行加签;
- 支付宝公钥:支付宝的 RSA 公钥,商户使用该公钥验证结果是否由支付宝返回的。
生成商户应用私钥和应用公钥:
点击右边的链接:https://docs.open.alipay.com/291/105971,这里介绍了生成商户 RSA 密钥的方法。根据指导,生成了应用公钥 2048.txt
和应用私钥 2048.txt
两个文件。生成的私钥一定要妥善保管。私钥需要填写到代码中供签名时使用;公钥需要上传到支付宝开放平台。
上传商户应用公钥到支付宝平台:
把应用公钥 2048.txt
中的内容复制粘贴到前面的框框中。然后保存,弹出如下窗口:
可以随时修改应用公钥。
使用应用私钥生成请求签名
把 AppID 、应用私钥、支付宝公钥配置在代码中,对请求内容进行签名,并对支付宝返回的内容进行验签。
支付宝开放平台 SDK 封装了签名和验签过程,只需配置账号和密钥参数即可,推荐使用 SDK 。这个在开发过程中会介绍。
创建应用时的应用状态为 “开发中”,无法在线上正式调用接口。按照上面的步骤设置好后,提交审核。
2 开发
应用审核通过后,变成已上线状态。现在我们可以尝试开发支付宝网站接口了。
2.1 下载服务端 SDK
为了帮助开发者调用开放接口,支付宝开放平台提供了 “开放平台服务端 SDK”,包含 JAVA 、 PHP 和.NET 三个版本,封装了签名&验签、 HTTP 接口请求等基础功能。
https://docs.open.alipay.com/54/103419,选择您熟悉的语言的 SDK 。我下载的是 PHP 版本的。这个页面中有关于各语言版本 SDK 的详细使用说明,可以仔细阅读一遍。
将下载的 alipay-sdk-PHP-20171121170331.zip
解压到项目目录中去,比如项目文件夹为 alipay/
,那么解压后的 SDK 为 alipay/alipay-sdk-PHP-20171121170331/
。
2.2 接口调用配置
在 SDK 调用前需要进行初始化,代码如下:
|
require_once(“alipay-sdk-PHP-20171121170331/AopSdk.php”);
//构造参数
$aop = new AopClient ();
$aop->gatewayUrl = ‘https://openapi.alipay.com/gateway.do’; // 向这个网址发送支付、退款、查询等请求
$aop->appId = ‘ 请填写 APPID’;
$aop->rsaPrivateKey = ‘ 请填写商户私钥’;
$aop->apiVersion = ‘1.0’;
$aop->signType = ‘RSA2’; // 对字符串进行前 ing 时使用的签名算法类型
$aop->postCharset= ‘utf-8’;
$aop->format=‘json’;
|
接下来,就可以用 $aop
来调用具体的 API 了。 $aop
只需要初始化一次,后续调用不同的 API 都可以使用同一个 $aop
对象。
2.3 向支付宝发送支付请求
通过向支付宝网关发送alipay.trade.page.pay
请求进行支付。
|
$request = new AlipayTradePagePayRequest ();
$request->setReturnUrl(‘ 请填写您的页面同步跳转地址’); // 在支付完成之后,支付宝服务器会跳转到这个页面,同时 GET 方式传送支付结果参数
$request->setNotifyUrl(‘ 请填写您的异步通知地址’); // 支付完成后,支付宝服务器会向这个网址发送异步通知消息,支付结果必须以异步通知为准,不能依赖同步跳转
$request->setBizContent(‘{“product_code”:”FAST_INSTANT_TRADE_PAY”,”out_trade_no”:”20150320010101001″,”subject”:”Iphone6 16G”,”total_amount”:”88.88″,”body”:”Iphone6 16G”}’);
// 请求
$result = $aop->pageExecute ($request); // $resule 是一个表单
// 输出
echo $result;
|
报文请求时会自动用应用私钥进行签名;支付宝收到请求之后,首先用应用公钥对请求参数验签,然后返回表单 $result
,打印这个表单会把用户重定向到支付页面。
请求返回的结果 $result
的内容如下:
|
<br /><form id=“alipaysubmit” action=“https://openapi.alipaydev.com/gateway.do?charset=UTF-8” method=“POST” name=“alipaysubmit”><input name=“biz_content” type=“hidden” value=“{“product_code“:”FAST_INSTANT_TRADE_PAY“,”body“:”hah“,”subject“:” 测试“,”total_amount“:”0.01“,”out_trade_no“:”201711279339773“}” /><input name=“app_id” type=“hidden” value=“2016090800411111” /><input name=“version” type=“hidden” value=“1.0” /><input name=“format” type=“hidden” value=“json” /><input name=“sign_type” type=“hidden” value=“RSA2” /><input name=“method” type=“hidden” value=“alipay.trade.page.pay” /><input name=“timestamp” type=“hidden” value=“2017-11-27 10:26:48” /><input name=“alipay_sdk” type=“hidden” value=“alipay-sdk-php-20161101” /><input name=“notify_url” type=“hidden” value=“https://www.example.com” /><input name=“return_url” type=“hidden” value=“https://www.example.com” /><input name=“charset” type=“hidden” value=“UTF-8” /><input name=“sign” type=“hidden” value=“nZG55zzL2PtHywMt0z93uCx+1W3JSo9tUk8AM32N2fvzeeapg6g55nVjGmdGRrSLDQzYibEP3imOqmS6I5u9e222v8BeZKPtZJUb4GMrvot0NXVSqRRDi/kmyURAI7d8+8wkpgQP3mEKg9YM4JddcWYQRFdM6W0kzKPd2N+hThjdchJ30wwwDtCAgZNs916t3YTW18ZTDxSSjDCHDDPd065PkUwNmLc1YwvumS+dKVEVDAy2/gcUjAyFTQx1A9fYW2kibyp2ohGQbjksogTEgOKE2yIuLVZWMTMcZ5k2en826OWV47UmKH07NzCjhqI45Wrkg8sXoY1mUZdvnXUvRQ==” /><input style=“display: none;” type=“submit” value=“ok” /></form><script>document.forms[‘alipaysubmit’].submit();</script>
|
当用户付过钱后,会跳转到设置的 return url
中,并以 GET 方式返回支付结果参数。
2.4 处理异步通知
由于同步返回的不可靠性,支付结果必须以异步通知或查询接口返回为准,不能依赖同步跳转。
2.4.1 验签
支付成功后,支付宝除了向 return url
发送同步通知外,还会以 POST 方式向 notify url
发送异步通知。商户系统受到异步通知后,首先需要用支付宝公钥进行验签,确定消息是否来自支付宝。 SDK 中封装了验签接口。
|
$arr = $_POST;
$arr[‘fund_bill_list’] = stripslashes($arr[‘fund_bill_list’]);
$aop = new AopClient();
$aop->alipayrsaPublicKey = ‘ 支付宝公钥’;
$signtype = ‘RSA2’
$flag = $aop->rsaCheckV1($arr, ‘ 支付宝公钥’, $signtype);
if ($flag) {
//验签成功
// 进行通知数据的二次检验
// 根据交易状态进行商户的自身业务
echo ‘success’;
}
else {
// 验签失败,记录异常日志
echo ‘fail’;
}
|
刚开始的时候,出现了验签失败的结果。后来在网上搜了一下,发现这是因为 PHP 自动将 fund_bill_list
中的特殊字符前加了转义符,需要把转义字符去掉才行。所以如果验签没通过,不妨加上 $arr['fund_bill_list'] = stripslashes($arr['fund_bill_list']);
试试。
2.4.2 二次检验
验签通过后,需要按照以下步骤检验数据的正确性:
- 1 、商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号;
- 2 、判断 total_amount 是否确实为该订单的实际金额(即商户订单创建时的金额);
- 3 、校验通知中的 seller_id(或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方(有的时候,一个商户可能有多个 seller_id/seller_email);
- 4 、验证 app_id 是否为该商户本身。
上述 1 、 2 、 3 、 4 有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
注意:
状态 TRADE_SUCCESS 的通知触发条件是商户签约的产品支持退款功能的前提下,买家付款成功;
交易状态 TRADE_FINISHED 的通知触发条件是商户签约的产品不支持退款功能的前提下,买家付款成功;或者,商户签约的产品支持退款功能的前提下,交易已经成功并且已经超过可退款期限。
2.4.3 继续商户自身的业务逻辑
在验签、二次校通过后,根据 trade_status
进行后续业务处理。
|
<br />// 交易状态
$trade_status = $_POST[‘trade_status’];
if($trade_status == ‘TRADE_FINISHED’ || $trade_status==‘TRADE_SUCCESS’) {
// 判断该订单是否在商户网站中已经做过处理,如果没有的话执行商户的业务程序
}
|
3 问题集锦
1. 调试错误,请回到请求来源地,重新发起请求。
错误代码 missing-signature 错误原因: 缺少签名参数
解答:
这是因为 alipay.trade.page.pay
请求结果里面没有 sign,为什么呢?https://openclub.alipay.com/read.php?tid=2333&fid=46 给出了原因。
php 环境必须 5.5 以上,而现在的服务器上通过 php -v
命令查看,版本是 PHP 5.3.28 。升级之后这个问题解决了。
2. 支付请求提交后,返回 “订单信息无法识别,建议联系卖家” 的错误提示?
解答:
$request->setBizContent();
中每个参数值都应该是字符串,比如'"' . $value1 . '"'
。
参考
[1] 电脑网站支付快速接入
[2] 创建应用
[3] 生成 RSA 密钥
[4] 上传应用公钥并获取支付宝公钥
[5] 使用应用私钥生成请求签名
[6] 服务端 SDK
[7] alipay.trade.page.pay
[8] 电脑网站支付结果异步通知
原文来自:victoriawy.com 感谢作者提供又一个支付宝解决方案。