#PHP#微信支付 第二篇 JSAPI 调用统一下单接口获取预支付交易数据
上一篇讲到成功获取 openid,本篇要调用微信统一接口创建预支付交易单
除付款码支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易会话标识后再按Native、JSAPI、APP等不同场景生成交易串调起支付。
第三步,调用微信统一下单接口创建预支付交易单
微信统一下单API是微信支付的一个“统一”处理入口,官方给出的地址是
https://api.mch.weixin.qq.com/pay/unifiedorder
https://api2.mch.weixin.qq.com/pay/unifiedorder(备用域名)
首先先按照 统一下单 接口一问中给的 请求参数 准备必要的参数,在本例(JSAPI)中至少需要参数如下
- appid,公众号AppID
- mch_id,商户号,一串10位数字
- device_info,设备号,非必填但有一定作用,PC网页或公众号内支付可以传"WEB",本例中就设置为"WEB"
- nonce_str,随机字符串,请求方提供的随机信息,主要保证签名不可预测
- sign,通过签名算法计算得出的签名值,详见签名算法
- sign_type,签名类型,截止编辑时支持(默认)"MD5"和"HMAC-SHA256",用哪种算法进行的签名要通过该字段表示
- body,商品描述,商户按规范创建
- out_trade_no,商户系统内部订单号,按微信的规则生成
- total_fee,整型,单位分,订单总金额
- spbill_create_ip,"用户的客户端IP",这个词儿是微信给出的截止到编辑时从字面上我并不确定指的是请求服务器的服务器地址还是访问商户服务器的某个用户"手机"的地址,但通过代码应该是后者,详见之后的代码示例
- notify_url,异步接收微信支付结果通知的回调地址
- trade_type,交易类型的标识,JSAPI-JSAPI支付,NATIVE-Native支付,APP-APP支付,MWEB-H5支付
- openid,第一篇中来自微信用户的openid值
按照 签名算法 计算签名
- 把所有要传递的参数键值对去掉值是空的,剩下的参数名ASCII码从小到大排序后,使用URL键值对格式(key1=value1&key2=value2...)拼接成StringA
- 把StringA后面多加一组键值 &key=商户平台密钥 获得StringB
- 把StringB按要求做"MD5"或"HMAC-SHA256"计算,并将结果字符转为大写
- 微信甚至还提供了一个在线校验工具帮助开发者检查生成的签名是否正确,跳到工具。使用方法是选择好 签名类型,校验方式选择 XML (不是必须只是为了省事儿),XML源串 输入不带 sign 信息的部分如
<xml>
<appid>wxcxxxxx5bbf</appid>
<mch_id>15xxxxxxxxxxxx61</mch_id>
<device_info>WEB</device_info>
<nonce_str>6743482E92E61DE587B52D6C7DEBFE79</nonce_str>
<body>xx科技-测试</body>
<out_trade_no>TY-OUTTRADENO-TEST-1561440044</out_trade_no>
<total_fee>1</total_fee>
<spbill_create_ip>36.xx.xx.185</spbill_create_ip>
<notify_url>http://wxpay.txxxt.com/jsapi/unifiedOrderNotify.php</notify_url>
<trade_type>JSAPI</trade_type>
<openid>100003</openid>
</xml>
再输入正确的 商户密钥,点击按钮即可计算出结果,与自己计算的结果进行比对。
- 本例中 Sign 方法接收两个参数,$arrayobj 为数组类型,保存了所有参数名和参数值组成的字符串数组,方法输出计算后的签名结果。ToUrlParams 方法将参数数组拼接为URL格式字符串。
/**
* 生成签名
* @param 参与签名的内容组成的数组
* @param 是否使用 HMAC-SHA256算法,否则使用MD5
* @return 签名字符串
* @author 试试手气
* @version test pass
*/
public static function Sign($arrayobj, $hmacsha256 = true)
{
//步骤一:字典排序
ksort($arrayobj);
//步骤二:在
$str = Util::ToUrlParams($arrayobj);
//步骤三:在$str后面加KEY
$mchKey = "asdxxxxxxxxxxxxxxN82"; // 商户支付秘钥,生产代码中是不可能如此硬编码到这里的
$str .= "&key=" . $mchKey;
//步骤四:MD5或HMAC-SHA256C加密
if ($hmacsha256) {
$str = hash_hmac("sha256", $str, $mchKey);
} else {
$str = md5($str);
}
//步骤五:所有字符转大写
$result = strtoupper($str);
return $result;
}
public static function ToUrlParams($arrayobj)
{
$buff = "";
foreach ($arrayobj as $k => $v) {
if ($k != "sign" && $v != "" && !is_array($v)) {
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
将签名结果作为最后的参数一起创建XML格式的POST数据
除 sign 签名外,其它的参数要么是现成的,要么是可以运行时获取到的如 spbill_create_ip。计算完签名,所有的参数就都准备好了,把它们加工成XML,参数顺序没有提到有限制。
function toXML($paramsobj)
{
$xml = "<xml>\n";
foreach ($paramsobj as $key => $value) {
$xml .= "<" . $key . ">" . $value . "</" . $key . ">\n";
}
$xml .= "</xml>";
return $xml;
}
出来是这个样子的
<xml>
<appid>wxcxxxxx5bbf</appid>
<mch_id>15xxxxxxxxxxxx61</mch_id>
<device_info>WEB</device_info>
<nonce_str>6743482E92E61DE587B52D6C7DEBFE79</nonce_str>
<body>xx科技-测试</body>
<out_trade_no>TY-OUTTRADENO-TEST-1561440044</out_trade_no>
<total_fee>1</total_fee>
<spbill_create_ip>36.xx.xx.185</spbill_create_ip>
<notify_url>http://wxpay.txxxt.com/jsapi/unifiedOrderNotify.php</notify_url>
<trade_type>JSAPI</trade_type>
<openid>100003</openid>
<sign>42DDF6C558EC05E24AAD0Cxxxxxxxx1DC3A53C0053D4A6F42E31036132F74481</sign>
</xml>
向微信统一下单API提交XML
用POST方式向统一下单接口地址提交数据,本例中使用的是微信SDK中的 postXmlCurl 方法改造了一下,用的是 curl 访问网络
function postXmlCurl($config, $xml, $url, $useCert = false, $second = 30)
{
$ch = curl_init();
//$curlVersion = curl_version();
//$ua = "WXPaySDK/".self::$VERSION." (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." "
// .$config->GetMerchantId();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
// $proxyHost = "0.0.0.0";
// $proxyPort = 0;
// $config->GetProxy($proxyHost, $proxyPort);
// //如果有配置代理这里就设置代理
// if($proxyHost != "0.0.0.0" && $proxyPort != 0){
// curl_setopt($ch,CURLOPT_PROXY, $proxyHost);
// curl_setopt($ch,CURLOPT_PROXYPORT, $proxyPort);
// }
curl_setopt($ch, CURLOPT_URL, $url);
//curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
//curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
//curl_setopt($ch,CURLOPT_USERAGENT, $ua);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if ($useCert == true) {
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
//证书文件请放入服务器的非web目录下
$sslCertPath = "";
$sslKeyPath = "";
$config->GetSSLCertPath($sslCertPath, $sslKeyPath);
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERT, $sslCertPath);
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, $sslKeyPath);
}
//试试手气新增,增加之后 curl 不报 60# 错误,可以请求到微信的响应
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证 SSL 证书
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//不验证 SSL 证书域名
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
return "curl error, error code ".$error;
//throw new WxPayException("curl出错,错误码:$error");
}
}
没有删掉代码,不用的注释掉了,并增加了关于 CURLOPT_SSL_VERIFYPEER 和 CURLOPT_SSL_VERIFYHOST 的明确设置,在增加这两句之前curl本身会报60错误。
返回值
按微信文档,访问(非业务)成功将返回(至少)包含 return_code 和 return_msg 两个字段的XML文档,对照统一下单接口文档内的返回结果即可判断请求是否成功,如下例
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wxccxxxxbbf]]></appid>
<mch_id><![CDATA[15xxx61]]></mch_id>
<device_info><![CDATA[WEB]]></device_info>
<nonce_str><![CDATA[SMIpZtHhPPyTezlY]]></nonce_str>
<sign><![CDATA[7215B1BAB1C08A4887AAB0ECB2A6044729FE8A8BC6E70591660A6BCC11D7DC9A]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx251xxxxxxxxxxxxxxxxxxxxxxxxxxxxx078700]]></prepay_id>
<trade_type><![CDATA[JSAPI]]></trade_type>
</xml>
很明显是访问也成功了,业务也成功了,也就是接口业务成功生成了 预支付交易会话 wx251xxxxxxxxxxxxxxxxxxxxxxxxxxxxx078700 ,后面就该使用该会话标识调起H5支付了。
#PHP#微信支付 第二篇 JSAPI 调用统一下单接口获取预支付交易数据的更多相关文章
- 微信支付 第一篇 JSAPI 支付配置与获取 OpenID
开通微信支付支付产品 首先要在微信支付申请成为 微信支付商户. 选择开通具体的支付产品 成为微信支付商户后在管理后台选择微信支付中的具体支付产品并申请开通如 JSAPI . 将支付商户与公众号关联 这 ...
- 微信支付 第三篇 微信调用H5页面进行支付
上一篇讲到拿到了 预支付交易标识 wx251xxxxxxxxxxxxxxxxxxxxxxxxxxxxx078700 第四步,是时候微信内H5调起支付了! 先准备网页端接口请求参数列表 微信文档中已经明 ...
- 在.net core上,Web网站调用微信支付-统一下单接口(xml传参)一直返回错误:mch_id参数格式错误
这是 微信支付-统一下单 接口文档 一.问题描述 在调用统一下单接口时,报mch_id参数格式错误,但商户ID确实是10位数字正确的,可就是一直报这个错误 返回的错误xml如下: 二.排错过程 1.多 ...
- SpringBoot项目后台对接微信支付开发——微信统一下单接口开发
开始没找到微信支付的sdk.自己根据官方给的接口文档纯手写,各种xml转JSON,JSON转xml,加密解密,签名....整个人都是崩溃的 开发的第三天,发现有官方的sdk.心情一下子豁然开朗,整个人 ...
- [88221008]调用新下单接口失败,result:162020004,resInfo
[88221008]调用新下单接口失败,result:162020004,resInfo
- php微信支付(仅Jsapi支付)详细步骤.----仅适合第一次做微信开发的程序员
本人最近做了微信支付开发,是第一次接触.其中走了很多弯路,遇到的问题也很多.为了让和我一样的新人不再遇到类似的问题,我把我的开发步骤和问题写出来,以供参考. 开发时间是2016/8/2,所以微信支付的 ...
- asp.net微信支付发起页面jsapi.aspx
jsapi.aspx 后台核心代码 //创建支付应答对象 RequestHandler packageReqHandler = new RequestHandler(Context); //初始化 p ...
- 微信支付中的jsapi返回提示信息
jsapi中跳转到微信支付中触发的方法是js中的getBrandWCPayRequest方法. 改方法中的返回结果msg提示信息如下: err_msg:get_brand_wcpay_request: ...
- 微信支付(公众号支付APIJS、app支付)服务端统一下单接口java版
一.微信公众号支付APIJS: 要完整的实现微信支付功能,需要前后端一起实现,还需要微信商户平台的配置.这里只是涉及服务端的代码. jar包:pom.xml <!-- ↓↓↓↓↓↓↓↓ 支付相关 ...
随机推荐
- CodeBlocks+Qt(MinGW)配置
1.安装CodeBlocks 官网:http://www.codeblocks.org/ 下载地址:http://www.codeblocks.org/downloads/26 有以下两种选择 cod ...
- bzoj3302
树形dp 很明显我们可以枚举一条边,然后求两边的重心,这样是暴力,我们用一些奇怪的方法来优化这个找重心的过程,我们先预处理出来每个点最大和第二的儿子,然后每次把断掉的子树的贡献减掉,每次找重心就是向最 ...
- 死记硬背之Bunside
就是 本质不同的个数为 $$\frac{1}{|G|} \cdot \sum_{|s| \in |G|}{ C(|s|) }$$ 所以,虽然不知道为啥,但是等价类的个数为 $$\sum_{i=1}^{ ...
- E20180327-hm
renew vt. 补充; 重新开始; 使更新; 使恢复; vi. 重申,重复强调; 重新开始; renewal n. 重建,重生; 更新,革新; 重申; 合同的续订;
- 洛谷 - P1219 - 八皇后 - dfs
https://www.luogu.org/problemnew/show/P1219 一开始朴素检查对角线就TLE了,给对角线编码之后压缩了13倍时间? 找了很久的bug居然是&&写 ...
- The local variable fruit may not have been initialized 错误
eclipse错误提示如图: 错误代码如图: 首先这错误的翻译是:局部变量"水果"尚未初始化,所以对象该如何初始化呢,我百度之后找到了答案,修改过后如下图所示. 这个错误的问题所在 ...
- Educational Codeforces Round 19 B
Description You are given sequence a1, a2, ..., an of integer numbers of length n. Your task is to f ...
- Jamie and Binary Sequence (changed after round) - CodeForces 916B
http://codeforces.com/problemset/problem/916/B 好尬啊... #include<cstdio> #include<algorithm&g ...
- Coloring Trees CodeForces - 711C
Coloring Trees CodeForces - 711C 题意:有n个点,每个点有一个c值,如果为0表示它没有被染色,否则表示它被染成了c值的颜色.颜色有1到m.把第i棵树染成颜色j所需要的代 ...
- 题解报告:NYOJ #737 石子合并(一)(区间dp)
描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值 ...