PHP实现APP微信支付的实例讲解


Posted in PHP onFebruary 10, 2018

一、PHP后台后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付!

官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

根据文档拼接微信需要的参数,这里需要几个方法,直接上代码!

传输给微信的参数要组装成xml格式发送,传如参数数组!

public function ToXml($data=array())
 {
 if(!is_array($data) || count($data) <= 0)
 {
  return '数组异常';
 }
 $xml = "<xml>";
 foreach ($data as $key=>$val)
 {
  if (is_numeric($val)){
  $xml.="<".$key.">".$val."</".$key.">";
  }else{
  $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
  }
 }
 $xml.="</xml>";
 return $xml;
 }

2.生成随机字符串,微信所需参数! 这里方法很多,看自己爱好都行!

function rand_code(){
 $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';//62个字符
 $str = str_shuffle($str);
 $str = substr($str,0,32);
 return $str;
}

3.这里是微信比较重要的一步了,这个方法会多次用到!生成签名

private function getSign($params) {
 ksort($params); //将参数数组按照参数名ASCII码从小到大排序
 foreach ($params as $key => $item) {
  if (!empty($item)) {  //剔除参数值为空的参数
  $newArr[] = $key.'='.$item; // 整合新的参数数组
  }
 }
 $stringA = implode("&", $newArr);  //使用 & 符号连接参数
 $stringSignTemp = $stringA."&key="."************************"; //拼接key
 // key是在商户平台API安全里自己设置的
 $stringSignTemp = MD5($stringSignTemp); //将字符串进行MD5加密
 $sign = strtoupper($stringSignTemp); //将所有字符转换为大写
 return $sign;
 }

4.传递参数给微信,生成预支付订单! 接收微信返回的数据,在反给APP端,APP端调用支付接口,完成支付 ! APP端所需参数见微信文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2

public function wx_pay() {
 $nonce_str = $this->rand_code(); //调用随机字符串生成方法获取随机字符串
 $data['appid'] ='wxdbc5dc*******'; //appid
 $data['mch_id'] = '1493*****' ; //商户号
 $data['body'] = "APP支付测试";
 $data['spbill_create_ip'] = $_SERVER['HTTP_HOST']; //ip地址
 $data['total_fee'] = 1;    //金额
 $data['out_trade_no'] = time().mt_rand(10000,99999); //商户订单号,不能重复
 $data['nonce_str'] = $nonce_str;   //随机字符串
 $data['notify_url'] = 'http://xxx.xxx.com/wx_notify'; //回调地址,用户接收支付后的通知,必须为能直接访问的网址,不能跟参数
 $data['trade_type'] = 'APP'; //支付方式
 //将参与签名的数据保存到数组 注意:以上几个参数是追加到$data中的,$data中应该同时包含开发文档中要求必填的剔除sign以外的所有数据
 $data['sign'] = $this->getSign($data); //获取签名
 $xml = $this->ToXml($data);  //数组转xml
 //curl 传递给微信方
 $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
 //header("Content-type:text/xml");
 $ch = curl_init();
 curl_setopt($ch,CURLOPT_URL, $url);
 if(stripos($url,"https://")!==FALSE){
  curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
 } else {
  curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
  curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
 }
 //设置header
 curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
 curl_setopt($ch, CURLOPT_HEADER, FALSE);
 //要求结果为字符串且输出到屏幕上
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
 //设置超时
 curl_setopt($ch, CURLOPT_TIMEOUT, 30);
 curl_setopt($ch, CURLOPT_POST, TRUE);
 //传输文件
 curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
 //运行curl
 $data = curl_exec($ch);
 //返回结果
 if($data){
  curl_close($ch);
  //返回成功,将xml数据转换为数组.
  $re = $this->FromXml($data);
  if($re['return_code'] != 'SUCCESS'){
  json("201",'签名失败');
  }
  else{
  //接收微信返回的数据,传给APP!
  $arr =array(
   'prepayid' =>$re['prepay_id'],
   'appid' => 'wxdbc5dc*****',
   'partnerid' => '14937****',
   'package' => 'Sign=WXPay',
   'noncestr' => $nonce_str,
   'timestamp' =>time(),
  );
  //第二次生成签名
  $sign = $this->getSign($arr);
  $arr['sign'] = $sign;
  json('200','签名成功',$arr);
  }
 } else {
  $error = curl_errno($ch);
  curl_close($ch);
  json('201',"curl出错,错误码:$error");
 }
 }

5.将xml数据转换为数组,接收微信返回数据时用到.

public function FromXml($xml)
 {
 if(!$xml){
  echo "xml数据异常!";
 }
 //将XML转为array
 //禁止引用外部xml实体
 libxml_disable_entity_loader(true);
 $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
 return $data;
 }

二、APP支付成功后,会调用你填写的回调地址.

返回参数详见微信文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7&index=3

// 微信支付回调
 function wx_notify(){
  //接收微信返回的数据数据,返回的xml格式
  $xmlData = file_get_contents('php://input');
  //将xml格式转换为数组
  $data = $this->FromXml($xmlData);
  //用日志记录检查数据是否接受成功,验证成功一次之后,可删除。
  $file = fopen('./log.txt', 'a+');
  fwrite($file,var_export($data,true));
  //为了防止假数据,验证签名是否和返回的一样。
  //记录一下,返回回来的签名,生成签名的时候,必须剔除sign字段。
  $sign = $data['sign'];
  unset($data['sign']);
  if($sign == $this->getSign($data)){
  //签名验证成功后,判断返回微信返回的
  if ($data['result_code'] == 'SUCCESS') {
  //根据返回的订单号做业务逻辑
  $arr = array(
   'pay_status' => 1,
   );
  $re = M('order')->where(['order_sn'=>$data['out_trade_no']])->save($arr);
  //处理完成之后,告诉微信成功结果!
  if($re){
   echo '<xml>
  <return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[OK]]></return_msg>
  </xml>';exit();
  }
  }
  //支付失败,输出错误信息
  else{
  $file = fopen('./log.txt', 'a+');
  fwrite($file,"错误信息:".$data['return_msg'].date("Y-m-d H:i:s"),time()."\r\n"); 
  }
 }
 else{
  $file = fopen('./log.txt', 'a+');
  fwrite($file,"错误信息:签名验证失败".date("Y-m-d H:i:s"),time()."\r\n"); 
  }
}

在这里,微信APP支付流程就成功走完了!谢谢支持!

以上这篇PHP实现APP微信支付的实例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php trim 去除空字符的定义与语法介绍
May 31 PHP
比较时间段一与时间段二是否有交集的php函数
May 31 PHP
解析:使用php mongodb扩展时 需要注意的事项
Jun 18 PHP
执行、获取远程代码返回:file_get_contents 超时处理的问题详解
Jun 25 PHP
php5.5中类级别的常量使用介绍
Oct 02 PHP
PHP和javascript常用正则表达式及用法实例
Jul 01 PHP
PHP中对各种加密算法、Hash算法的速度测试对比代码
Jul 08 PHP
php连接odbc数据源并保存与查询数据的方法
Dec 24 PHP
CodeIgniter配置之config.php用法实例分析
Jan 19 PHP
smarty模板数学运算示例
Dec 11 PHP
记录Yii2框架开发微信公众号遇到的问题及解决方法
Jul 20 PHP
PHP实现支持CURL字符串证书传输的方法
Mar 23 PHP
PHP有序表查找之插值查找算法示例
Feb 10 #PHP
PHP有序表查找之二分查找(折半查找)算法示例
Feb 09 #PHP
php在windows环境下获得cpu内存实时使用率(推荐)
Feb 08 #PHP
PHP基于redis计数器类定义与用法示例
Feb 08 #PHP
php处理抢购类功能的高并发请求
Feb 08 #PHP
php+redis实现商城秒杀功能
Nov 19 #PHP
php+redis消息队列实现抢购功能
Feb 08 #PHP
You might like
在PHP中PDO解决中文乱码问题的一些补充
2010/09/06 PHP
PHP程序中使用adodb连接不同数据库的代码实例
2015/12/19 PHP
PHP设计模式之组合模式定义与应用示例
2020/02/01 PHP
json-lib出现There is a cycle in the hierarchy解决办法
2010/02/24 Javascript
this和执行上下文实现代码
2010/07/01 Javascript
js TextArea的选中区域处理
2010/12/28 Javascript
jquery.boxy弹出框(后隔N秒后自动隐藏/自动跳转)
2013/01/15 Javascript
基于jquery实现的文字淡入淡出效果
2013/11/14 Javascript
javascript使用正则表达式检测IP地址
2014/12/03 Javascript
JavaScript中定义函数的三种方法
2015/03/12 Javascript
EasyUI闪屏EasyUI页面加载提示(原理+代码+效果图)
2016/02/21 Javascript
jQuery的extend方法【三种】
2016/12/14 Javascript
jquery uploadify如何取消已上传成功文件
2017/02/08 Javascript
原生JS实现图片懒加载(lazyload)实例
2017/06/13 Javascript
vue.js项目打包上线的图文教程
2017/11/16 Javascript
Vue-cli Eslint在vscode里代码自动格式化的方法
2018/02/23 Javascript
React 全自动数据表格组件——BodeGrid的实现思路
2019/06/12 Javascript
部署vue+Springboot前后端分离项目的步骤实现
2020/05/31 Javascript
vue swipeCell滑动单元格(仿微信)的实现示例
2020/09/14 Javascript
[03:55]TI9战队采访——TNC Predator
2019/08/22 DOTA
python matplotlib中文显示参数设置解析
2017/12/15 Python
Python分支结构(switch)操作简介
2018/01/17 Python
python利用高阶函数实现剪枝函数
2018/03/20 Python
Pycharm代码无法复制,无法选中删除,无法编辑的解决方法
2018/10/22 Python
Python手绘可视化工具cutecharts使用实例
2019/12/05 Python
通过代码实例了解Python3编程技巧
2020/10/13 Python
英国最大的奢侈珠宝和手表网站:C W Sellors
2017/02/10 全球购物
爱淘宝:淘宝网购物分享平台
2017/04/28 全球购物
方法名是否可以与构造器的名字相同
2012/06/04 面试题
用C#语言写出在本地创建一个UDP接收端口的具体过程
2016/02/22 面试题
餐饮营销方案
2014/02/23 职场文书
2016预备党员培训心得体会
2016/01/08 职场文书
2016年第16个全民国防教育日宣传活动总结
2016/04/05 职场文书
Python图片处理之图片裁剪教程
2021/05/27 Python
Redis如何实现分布式锁
2021/08/23 Redis
漫画「日和酱的要求是绝对的」第3卷封面公开
2022/03/21 日漫