您现在的位置是:首页 > 文章详情

php开发微信APP支付接口

日期:2018-12-20点击:408

之前在开发APP中用到了微信支付,因为是第一次用,所以中途也遇到了好多问题,通过查看文档和搜集资料,终于完成了该功能的实现。在这里简单分享一下后台php接口的开发实例。
个人博客:代码汇 http://www.codehui.net

开发流程

1:用户在商户APP中选择商品,提交订单,选择微信支付。
2:商户后台收到用户支付单,调用微信支付统一下单接口。参见【统一下单API】。
3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay
4:商户APP调起微信支付。api参见本章节【app端开发步骤说明
5:商户后台接收支付通知。api参见【支付结果通知API
6:商户后台查询支付结果。,api参见【查询订单API

开发中

首先呢我们需要拿到三个参数(appid,mch_id,key),这三个参数分别对应的是 在微信开发平台中创建的移动应用appid,微信支付商户号商户支付秘钥,详情看参考【支付结果通知API
然后我们先把统一下单所需要的参数列出来

$request_data = array( 'appid' => C('WX_APPID'), #应用APPID 'mch_id' => C('WX_MCHID'), #商户号 'trade_type' => 'APP', #支付类型 'nonce_str' => \Org\Util\String::randString(30), #随机字符串 不长于32位 'body' => '商品名称', #商品名称 'out_trade_no' => '12345678912456', #商户后台订单号 'total_fee' => '1', #商品价格 'spbill_create_ip' => get_client_ip(), #用户端实际ip 'notify_url' => 'http://***/app/index.php/Home/Wxpay/wx_notify', #异步通知回调地址 ); 

这些都是请求参数必填项,其他参数请查看文档
下来我们就要使用这些参数生成签名了

$request_data['sign'] = $this -> get_sign($request_data); 

我们下来需要把微信请求的数据拼装成 xml格式,注意:xml数据要使用<![CDATA[]]>包括

$xml_data = $this -> set_xmldata($request_data); 打印$xml_data结果如下 <xml> <appid><![CDATA[wx7ad3cc6c6111111]]></appid> <mch_id><![CDATA[1494741111]]></mch_id> <trade_type><![CDATA[APP]]></trade_type> <nonce_str><![CDATA[WXXWkMDOgLIqhUnITfNrBbJEVGQdRO]]></nonce_str> <body><![CDATA[u5546u54c1u540du79f0]]></body> <out_trade_no><![CDATA[12345678912456]]></out_trade_no> <total_fee><![CDATA[1]]></total_fee> <spbill_create_ip><![CDATA[1.86.242.193]]></spbill_create_ip> <notify_url><![CDATA[http://***/app/index.php/Home/Wxpay/wx_notify]]></notify_url> <sign><![CDATA[EC0BFB3434A72F20C2CA3378BF07264C]]></sign> </xml> 

现在就可以向微信发送请求了

$res = $this -> send_prePaycurl($xml_data); 这是请求的返回值 { return_code: "SUCCESS", #业务结果 只有这里返回SUCCESS才会有prepay_id return_msg: "OK", #返回结果描述 appid: "wx7ad3cc6c6111111", #应用APPID mch_id: "1494741111", #商户号 nonce_str: "jkh9mmRlmSHBJxO0", #随机字符串 sign: "AF3B26B1E58591D6565E61DDFBB7837B", #签名 result_code: "SUCCESS", #也是业务结果 prepay_id: "wx20171226005556c5c65b325a0132782836", #预支付交易会话标识,用于APP请求微信支付调用,有效期两小时 trade_type: "APP" #支付类型 } 

到这里拿到prepay_id还没完我们还需要对返回的数据进行二次签名

if($res['return_code'] == 'SUCCESS' && $res['result_code'] == 'SUCCESS'){ $two_data['appid'] = C('WX_APPID'); #APPID $two_data['partnerid'] = C('WX_MCHID'); #商户号 $two_data['prepayid'] = $res['prepay_id']; //预支付交易会话标识 $two_data['noncestr'] = \Org\Util\String::randString(30); $two_data['timestamp'] = time(); #时间戳 $two_data['package'] = "Sign=WXPay"; #固定值 $two_data['sign'] = $this -> get_twosign($two_data); #二次签名 $this->ajaxReturn(array('code'=>200,'info'=>$two_data)); }else{ $this->ajaxReturn(array('code'=>201,'info'=>$res['err_code_des'])); } 

然后就可以在商户APP端通过prepayid进行支付了
下面我们来列出上面调用的几个公共方法

 //一次签名的函数 private function get_sign($data){ ksort($data); $str = ''; foreach ($data as $key => $value) { $str .= !$str ? $key . '=' . $value : '&' . $key . '=' . $value; } $str.='&key='.C('WX_KEY'); $sign = strtoupper(md5($str)); return $sign; } //二次签名的函数 private function get_twosign($data){ $sign_data = array( "appid"=>$data['appid'], "partnerid"=>$data['partnerid'], "prepayid"=>$data['prepayid'], "noncestr"=>$data['noncestr'], "timestamp"=>$data['timestamp'], "package"=>$data['package'], ); return $this -> get_sign($sign_data); } //生成xml格式的函数 private function set_xmldata($data) { $xmlData = "<xml>"; foreach ($data as $key => $value) { $xmlData.="<".$key."><![CDATA[".$value."]]></".$key.">"; } $xmlData = $xmlData."</xml>"; return $xmlData; } //通过curl发送数据给微信接口的函数 private function send_prePaycurl($xmlData) { $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; $header[] = "Content-type: text/xml"; $curl = curl_init(); curl_setopt($curl, CURLOPT_HTTPHEADER, $header); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $xmlData); $data = curl_exec($curl); if (curl_errno($curl)) { print curl_error($curl); } curl_close($curl); return $this -> _xmldataparse($data); } //xml数据解析函数 private function _xmldataparse($data){ $msg = array(); $msg = (array)simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA); return $msg; } 

微信回调

支付有了,肯定还得有回调

 //微信回调 public function wx_notify(){ //允许从外部加载XML实体(防止XML注入攻击) libxml_disable_entity_loader(true); $postStr = $this -> post_data(); #接收微信返回数据xml格式 $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); #xml格式数据转换成对象 $arr = $this -> object_toarray($postObj); #对象转成数组 ksort($arr); # 对数据进行排序 $str = $this -> params_tourl($arr); #对数据拼接成字符串 $user_sign = strtoupper(md5($str)); //把微信返回的数据进行再次签名 //验证签名 if($user_sign == $arr['sign']){ //验证签名成功 处理商户订单逻辑 //给微信返回接收到数据通知 return '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; }else{ //签名验证失败 微信会再次访问回调方法 return '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; } } 

回调用到的方法如下

// 接收post数据  /* * 微信是用$GLOBALS['HTTP_RAW_POST_DATA'];这个函数接收post数据的 */ public function post_data(){ $receipt = $_REQUEST; if($receipt==null){ $receipt = file_get_contents("php://input"); if($receipt == null){ $receipt = $GLOBALS['HTTP_RAW_POST_DATA']; } } return $receipt; } //把对象转成数组  public function object_toarray($arr) { if(is_object($arr)) { $arr = (array)$arr; } if(is_array($arr)) { foreach($arr as $key=>$value) { $arr[$key] = $this->object_toarray($value); } } return $arr; } /** * 格式化参数格式化成url参数 */ private function params_tourl($arr) { $weipay_key = C('WX_KEY');//微信的key,这个是微信支付给你的key,不要瞎填。  $buff = ""; foreach ($arr as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff.'&key='.$weipay_key; } 

总结:首先微信支付的流程比较多,公众号 ,开放平台微信商户,配置参数的时候要看仔细,不要后面的坑特别多,因为是第一次写微信支付,可能会存在部分问题,欢迎大家可以在下面留言反馈。

下面分享一下全部的代码

<?php namespace Home\Controller; use Think\Controller; /** * php开发微信app支付接口 * @global WX_APPID 开放平台->移动应用appid * @global WX_MCHID 微信支付商户号 * @global WX_KEY 商户支付秘钥 * @author codehi <admin@codehui.net> 2017-12-23 */ class WxpayController extends Controller { /** * 微信支付统一下单 >>> 生成预支付交易单 */ public function wx_pay(){ $request_data = array( 'appid' => C('WX_APPID'), #应用APPID 'mch_id' => C('WX_MCHID'), #商户号 'trade_type' => 'APP', #支付类型 'nonce_str' => \Org\Util\String::randString(30), #随机字符串 不长于32位 'body' => '商品名称', #商品名称 'out_trade_no' => '12345678912456', #商户后台订单号 'total_fee' => '1', #商品价格 'spbill_create_ip' => get_client_ip(), #用户端实际ip 'notify_url' => 'http://shop.lsmrsd.com/app/index.php/Home/Wxpay/wx_notify', #异步通知回调地址 ); // 获取签名 $request_data['sign'] = $this -> get_sign($request_data); // 拼装数据 $xml_data = $this -> set_xmldata($request_data); // 发送请求 $res = $this -> send_prePaycurl($xml_data); $this->ajaxReturn($res); if($res['return_code'] == 'SUCCESS' && $res['result_code'] == 'SUCCESS'){ $two_data['appid'] = C('WX_APPID'); #APPID $two_data['partnerid'] = C('WX_MCHID'); #商户号 $two_data['prepayid'] = $res['prepay_id']; //预支付交易会话标识 $two_data['noncestr'] = \Org\Util\String::randString(30); $two_data['timestamp'] = time(); $two_data['package'] = "Sign=WXPay"; $two_data['sign'] = $this->get_twosign($two_data); $this->ajaxReturn(array('code'=>200,'info'=>$two_data)); }else{ $this->ajaxReturn(array('code'=>201,'info'=>$res['err_code_des'])); } } //通过curl发送数据给微信接口的函数 private function send_prePaycurl($xmlData) { $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; $header[] = "Content-type: text/xml"; $curl = curl_init(); curl_setopt($curl, CURLOPT_HTTPHEADER, $header); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $xmlData); $data = curl_exec($curl); if (curl_errno($curl)) { print curl_error($curl); } curl_close($curl); return $this->_xmldataparse($data); } //xml数据解析函数 private function _xmldataparse($data){ $msg = array(); $msg = (array)simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA); return $msg; } //生成xml格式的函数 private function set_xmldata($data) { $xmlData = "<xml>"; foreach ($data as $key => $value) { $xmlData.="<".$key."><![CDATA[".$value."]]></".$key.">"; } $xmlData = $xmlData."</xml>"; return $xmlData; } //一次签名的函数 private function get_sign($data){ ksort($data); $str = ''; foreach ($data as $key => $value) { $str .= !$str ? $key . '=' . $value : '&' . $key . '=' . $value; } $str.='&key='.C('WX_KEY'); $sign = strtoupper(md5($str)); return $sign; } //二次签名的函数 private function get_twosign($data){ $sign_data = array( "appid"=>$data['appid'], "partnerid"=>$data['partnerid'], "prepayid"=>$data['prepayid'], "noncestr"=>$data['noncestr'], "timestamp"=>$data['timestamp'], "package"=>$data['package'], ); return $this->get_sign($sign_data); } //微信回调 public function wx_notify(){ //允许从外部加载XML实体(防止XML注入攻击) libxml_disable_entity_loader(true); $postStr = $this -> post_data();//接收post数据  $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); $arr = $this -> object_toarray($postObj);//对象转成数组  ksort($arr);// 对数据进行排序  $str = $this -> params_tourl($arr);//对数据拼接成字符串  $user_sign = strtoupper(md5($str)); if($user_sign == $arr['sign']){//验证签名  return '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; }else{ return '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; } } // 接收post数据  /* * 微信是用$GLOBALS['HTTP_RAW_POST_DATA'];这个函数接收post数据的 */ public function post_data(){ $receipt = $_REQUEST; if($receipt==null){ $receipt = file_get_contents("php://input"); if($receipt == null){ $receipt = $GLOBALS['HTTP_RAW_POST_DATA']; } } return $receipt; } //把对象转成数组  public function object_toarray($arr) { if(is_object($arr)) { $arr = (array)$arr; } if(is_array($arr)) { foreach($arr as $key=>$value) { $arr[$key] = $this->object_toarray($value); } } return $arr; } /** * 格式化参数格式化成url参数 */ private function params_tourl($arr) { $weipay_key = C('WX_KEY');//微信的key,这个是微信支付给你的key,不要瞎填。  $buff = ""; foreach ($arr as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff.'&key='.$weipay_key; } }
原文链接:https://yq.aliyun.com/articles/680900
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章