上一篇讲到成功获取 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_VERIFYPEERCURLOPT_SSL_VERIFYHOST 的明确设置,在增加这两句之前curl本身会报60错误。

返回值

按微信文档,访问(非业务)成功将返回(至少)包含 return_codereturn_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 调用统一下单接口获取预支付交易数据的更多相关文章

  1. 微信支付 第一篇 JSAPI 支付配置与获取 OpenID

    开通微信支付支付产品 首先要在微信支付申请成为 微信支付商户. 选择开通具体的支付产品 成为微信支付商户后在管理后台选择微信支付中的具体支付产品并申请开通如 JSAPI . 将支付商户与公众号关联 这 ...

  2. 微信支付 第三篇 微信调用H5页面进行支付

    上一篇讲到拿到了 预支付交易标识 wx251xxxxxxxxxxxxxxxxxxxxxxxxxxxxx078700 第四步,是时候微信内H5调起支付了! 先准备网页端接口请求参数列表 微信文档中已经明 ...

  3. 在.net core上,Web网站调用微信支付-统一下单接口(xml传参)一直返回错误:mch_id参数格式错误

    这是 微信支付-统一下单 接口文档 一.问题描述 在调用统一下单接口时,报mch_id参数格式错误,但商户ID确实是10位数字正确的,可就是一直报这个错误 返回的错误xml如下: 二.排错过程 1.多 ...

  4. SpringBoot项目后台对接微信支付开发——微信统一下单接口开发

    开始没找到微信支付的sdk.自己根据官方给的接口文档纯手写,各种xml转JSON,JSON转xml,加密解密,签名....整个人都是崩溃的 开发的第三天,发现有官方的sdk.心情一下子豁然开朗,整个人 ...

  5. [88221008]调用新下单接口失败,result:162020004,resInfo

    [88221008]调用新下单接口失败,result:162020004,resInfo

  6. php微信支付(仅Jsapi支付)详细步骤.----仅适合第一次做微信开发的程序员

    本人最近做了微信支付开发,是第一次接触.其中走了很多弯路,遇到的问题也很多.为了让和我一样的新人不再遇到类似的问题,我把我的开发步骤和问题写出来,以供参考. 开发时间是2016/8/2,所以微信支付的 ...

  7. asp.net微信支付发起页面jsapi.aspx

    jsapi.aspx 后台核心代码 //创建支付应答对象 RequestHandler packageReqHandler = new RequestHandler(Context); //初始化 p ...

  8. 微信支付中的jsapi返回提示信息

    jsapi中跳转到微信支付中触发的方法是js中的getBrandWCPayRequest方法. 改方法中的返回结果msg提示信息如下: err_msg:get_brand_wcpay_request: ...

  9. 微信支付(公众号支付APIJS、app支付)服务端统一下单接口java版

    一.微信公众号支付APIJS: 要完整的实现微信支付功能,需要前后端一起实现,还需要微信商户平台的配置.这里只是涉及服务端的代码. jar包:pom.xml <!-- ↓↓↓↓↓↓↓↓ 支付相关 ...

随机推荐

  1. 【转】java对象——new对象的理解

    学了好长时间的java对于java中的对象一直没有理清楚,今天楼主对java中的对象进行了整理,希望对大家有帮助. 理解和使用java中的对象,我们首先了解一下构造方法与对象的创建.  类是面向对象语 ...

  2. Gulp安装及配合组件构建前端开发一体化(转)

    Gulp安装及配合组件构建前端开发一体化 所有功能前提需要安装nodejs(本人安装版本v0.10.26)和ruby(本人安装版本1.9.3p484). Gulp 是一款基于任务的设计模式的自动化工具 ...

  3. Table View Programming Guide for iOS---(六)---A Closer Look at Table View Cells

    A Closer Look at Table View Cells A table view uses cell objects to draw its visible rows and then c ...

  4. 设计模式——模板模式(Template Pattern)

    在读Spring源码的时候,发现Spring代码中运用了大量的模板模式,比如根据文件系统目录加载配置文件(FileSystemXmlApplicationContext),类路径加载配置文件(Clas ...

  5. HDU6050: Funny Function(推公式+矩阵快速幂)

    传送门 题意 利用给出的式子求\(F_{m,1}\) 分析 直接推公式(都是找规律大佬) \(n为偶数,F_{m,1}=\frac{2(2^n-1)^{m-1}}3\) \(n为奇数,F_{m,1}= ...

  6. POJ2365【几何】

    因为给出的点已经是顺时针了, 整个长度=相邻点距离+一个圆周长: C++ac代码-G++wa-因为标准不一样.G++用f //#include <bits/stdc++.h> #inclu ...

  7. poj1651【区间DP·基础】

    题意: 给你一串数字,头尾不能动,每次取出一个数字,这个数字贡献=该数字与左右相邻数字的乘积,求一个最小值. 思路: 用dp[s][t]去代表s到t的最小值,包括a[s]和a[t],然后从区间为3开始 ...

  8. 一篇文章搞定面试中的链表题目(java实现)

    最近总结了一下数据结构和算法的题目,这是第二篇文章,关于链表的,第一篇文章关于二叉树的参见 废话少说,上链表的数据结构 class ListNode { ListNode next; int val; ...

  9. .net mvc中一种简单的工作流的设计

    开篇前的废话:工作流是我们在做互联网应用开发时经常需要用到的一种技术,复杂的工作流我们基本是借助一些开源的 工作流项目来做,比如 ccflow等,但是有时候,我们只需要实现一些简单的工作流流程,这时候 ...

  10. Hadoop Hive概念学习系列之HDFS、Hive、MySQL、Sqoop之间的数据导入导出(强烈建议去看)

    Hive总结(七)Hive四种数据导入方式 (强烈建议去看) Hive几种数据导出方式 https://www.iteblog.com/archives/955 (强烈建议去看) 把MySQL里的数据 ...