上一篇讲到成功获取 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. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

    第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation ...

  2. A. Meeting of Old Friends

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  3. windows server安装zabbix-agent

    1.准备安装包: 下载链接:https://www.zabbix.com/downloads/3.4.0/zabbix_agents_3.4.0.win.zip 2.在C盘下创建一个zabbix目录, ...

  4. Python网络爬虫之BeautifulSoup模块

    一.介绍: Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮 ...

  5. linux中fork对打开文件的处理

    1 子进程复制父进程的数据段.BBS段.代码段.堆空间.栈空间和文件描述符 2 对于文件描述符采用共享的方式 后面这个例子可以清晰的看出 #include <sys/types.h> #i ...

  6. UVa 1644 Prime Gap (水题,暴力)

    题意:给定一个数 n,求它后一个素数和前一个素数差. 析:先打表,再二分查找. 代码如下: #pragma comment(linker, "/STACK:1024000000,102400 ...

  7. Unity3D教程:换装方法

    http://www.manew.com/4136.html 游戏内的角色,能够像纸娃娃换装那样子让玩家可以为自己的角色改变外观,一直是相当受欢迎的功能:一般而言,我们建好的 3D 模型,如果要将其中 ...

  8. Mac下怎么运行python3的py文件

    我的Mac现在是10.14.6系统,默认自带的python版本是2.7.(怎么查看版本?打开终端,输入python即可看到版本号) 由于现在需要运行python3写的py文件,需要将自带的python ...

  9. java笔记1:准备工作:java历史、Java环境、java编辑器、cmd常用命令

    java的历史 Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计语言和Java平台的总称. 由James Gosling和同事们共同研发,并在1995年正 ...

  10. hbase表结构 + hbase集群架构及表存储机制

    本博文的主要内容有    .hbase读取数据过程 .HBase表结构 .附带PPT http://hbase.apache.org/ 读写的时候,就需要用hbase了,换句话说,就是读写的时候.需要 ...