php微信支付之公众号支付功能


Posted in PHP onMay 30, 2018

网上的很多PHP微信扫码支付接入教程都颇为复杂,且需要配置和引入较多的文件,本人通过整理后给出一个单文件版的,希望可以给各位想接入微信扫码支付的带来些许帮助和借鉴意义。

将该文件放到你的授权目录下,并在微信里访问这个文件,即可看到演示效果。效果如下:

php微信支付之公众号支付功能 php微信支付之公众号支付功能

需要注意的事项:

1.该文件需放到支付授权目录下,可以在微信支付商户平台->产品中心->开发配置中设置。
2.如提示签名错误可以通过微信支付签名验证工具进行验证:微信公众平台支付接口调试工具

代码如下:

<?php
header('Content-type:text/html; Charset=utf-8');
$mchid = 'xxxxx';   //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
$appid = 'xxxxx'; //微信支付申请对应的公众号的APPID
$appKey = 'xxxxx'; //微信支付申请对应的公众号的APP Key
$apiKey = 'xxxxx'; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥

//①、获取用户openid
$wxPay = new WxpayService($mchid,$appid,$appKey,$apiKey);
$openId = $wxPay->GetOpenid();  //获取openid
if(!$openId) exit('获取openid失败');
//②、统一下单
$outTradeNo = uniqid();  //你自己的商品订单号
$payAmount = 0.01;   //付款金额,单位:元
$orderName = '支付测试'; //订单标题
$notifyUrl = 'https://www.xxx.com/wx/';  //付款成功后的回调地址(不要有问号)
$payTime = time();  //付款时间
$jsApiParameters = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$orderName,$notifyUrl,$payTime);
$jsApiParameters = json_encode($jsApiParameters);
?>
 <html>
 <head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>微信支付样例-支付</title>
  <script type="text/javascript">
   //调用微信JS api 支付
   function jsApiCall()
   {
    WeixinJSBridge.invoke(
     'getBrandWCPayRequest',
     <?php echo $jsApiParameters; ?>,
     function(res){
      WeixinJSBridge.log(res.err_msg);
      alert(res.err_code+res.err_desc+res.err_msg);
     }
    );
   }
   function callpay()
   {
    if (typeof WeixinJSBridge == "undefined"){
     if( document.addEventListener ){
      document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
     }else if (document.attachEvent){
      document.attachEvent('WeixinJSBridgeReady', jsApiCall);
      document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
     }
    }else{
     jsApiCall();
    }
   }
  </script>
 </head>
 <body>
 <br/>
 <font color="#9ACD32"><b>该笔订单支付金额为<span style="color:#f00;font-size:50px"><?php echo $payAmount?>元</span>钱</b></font><br/><br/>
 <div align="center">
  <button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type="button" onclick="callpay()" >立即支付</button>
 </div>
 </body>
 </html>
<?php
class WxpayService
{
 protected $mchid;
 protected $appid;
 protected $appKey;
 protected $apiKey;
 public $data = null;

 public function __construct($mchid, $appid, $appKey,$key)
 {
  $this->mchid = $mchid; //https://pay.weixin.qq.com 产品中心-开发配置-商户号
  $this->appid = $appid; //微信支付申请对应的公众号的APPID
  $this->appKey = $appKey; //微信支付申请对应的公众号的APP Key
  $this->apiKey = $key; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
 }

 /**
  * 通过跳转获取用户的openid,跳转流程如下:
  * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
  * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
  * @return 用户的openid
  */
 public function GetOpenid()
 {
  //通过code获得openid
  if (!isset($_GET['code'])){
   //触发微信返回code码
   $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
   $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
   $url = $this->__CreateOauthUrlForCode($baseUrl);
   Header("Location: $url");
   exit();
  } else {
   //获取code码,以获取openid
   $code = $_GET['code'];
   $openid = $this->getOpenidFromMp($code);
   return $openid;
  }
 }

 /**
  * 通过code从工作平台获取openid机器access_token
  * @param string $code 微信跳转回来带上的code
  * @return openid
  */
 public function GetOpenidFromMp($code)
 {
  $url = $this->__CreateOauthUrlForOpenid($code);
  $res = self::curlGet($url);
  //取出openid
  $data = json_decode($res,true);
  $this->data = $data;
  $openid = $data['openid'];
  return $openid;
 }

 /**
  * 构造获取open和access_toke的url地址
  * @param string $code,微信跳转带回的code
  * @return 请求的url
  */
 private function __CreateOauthUrlForOpenid($code)
 {
  $urlObj["appid"] = $this->appid;
  $urlObj["secret"] = $this->appKey;
  $urlObj["code"] = $code;
  $urlObj["grant_type"] = "authorization_code";
  $bizString = $this->ToUrlParams($urlObj);
  return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
 }

 /**
  * 构造获取code的url连接
  * @param string $redirectUrl 微信服务器回跳的url,需要url编码
  * @return 返回构造好的url
  */
 private function __CreateOauthUrlForCode($redirectUrl)
 {
  $urlObj["appid"] = $this->appid;
  $urlObj["redirect_uri"] = "$redirectUrl";
  $urlObj["response_type"] = "code";
  $urlObj["scope"] = "snsapi_base";
  $urlObj["state"] = "STATE"."#wechat_redirect";
  $bizString = $this->ToUrlParams($urlObj);
  return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
 }

 /**
  * 拼接签名字符串
  * @param array $urlObj
  * @return 返回已经拼接好的字符串
  */
 private function ToUrlParams($urlObj)
 {
  $buff = "";
  foreach ($urlObj as $k => $v)
  {
   if($k != "sign") $buff .= $k . "=" . $v . "&";
  }
  $buff = trim($buff, "&");
  return $buff;
 }

 /**
  * 统一下单
  * @param string $openid 调用【网页授权获取用户信息】接口获取到用户在该公众号下的Openid
  * @param float $totalFee 收款总费用 单位元
  * @param string $outTradeNo 唯一的订单号
  * @param string $orderName 订单名称
  * @param string $notifyUrl 支付结果通知url 不要有问号
  * @param string $timestamp 支付时间
  * @return string
  */
 public function createJsBizPackage($openid, $totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp)
 {
  $config = array(
   'mch_id' => $this->mchid,
   'appid' => $this->appid,
   'key' => $this->apiKey,
  );
  $orderName = iconv('GBK','UTF-8',$orderName);
  $unified = array(
   'appid' => $config['appid'],
   'attach' => 'pay',    //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
   'body' => $orderName,
   'mch_id' => $config['mch_id'],
   'nonce_str' => self::createNonceStr(),
   'notify_url' => $notifyUrl,
   'openid' => $openid,   //rade_type=JSAPI,此参数必传
   'out_trade_no' => $outTradeNo,
   'spbill_create_ip' => '127.0.0.1',
   'total_fee' => intval($totalFee * 100),  //单位 转为分
   'trade_type' => 'JSAPI',
  );
  $unified['sign'] = self::getSign($unified, $config['key']);
  $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', self::arrayToXml($unified));
  $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
  if ($unifiedOrder === false) {
   die('parse xml error');
  }
  if ($unifiedOrder->return_code != 'SUCCESS') {
   die($unifiedOrder->return_msg);
  }
  if ($unifiedOrder->result_code != 'SUCCESS') {
   die($unifiedOrder->err_code);
  }
  $arr = array(
   "appId" => $config['appid'],
   "timeStamp" => "$timestamp",  //这里是字符串的时间戳,不是int,所以需加引号
   "nonceStr" => self::createNonceStr(),
   "package" => "prepay_id=" . $unifiedOrder->prepay_id,
   "signType" => 'MD5',
  );
  $arr['paySign'] = self::getSign($arr, $config['key']);
  return $arr;
 }

 public static function curlGet($url = '', $options = array())
 {
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  if (!empty($options)) {
   curl_setopt_array($ch, $options);
  }
  //https请求 不验证证书和host
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
 }

 public static function curlPost($url = '', $postData = '', $options = array())
 {
  if (is_array($postData)) {
   $postData = http_build_query($postData);
  }
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
  curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
  if (!empty($options)) {
   curl_setopt_array($ch, $options);
  }
  //https请求 不验证证书和host
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
 }

 public static function createNonceStr($length = 16)
 {
  $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $str = '';
  for ($i = 0; $i < $length; $i++) {
   $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  }
  return $str;
 }
 public static function arrayToXml($arr)
 {
  $xml = "<xml>";
  foreach ($arr as $key => $val) {
   if (is_numeric($val)) {
    $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
   } else
    $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
  }
  $xml .= "</xml>";
  file_put_contents('1.txt',$xml);
  return $xml;
 }

 public static function getSign($params, $key)
 {
  ksort($params, SORT_STRING);
  $unSignParaString = self::formatQueryParaMap($params, false);
  $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
  return $signStr;
 }
 protected static function formatQueryParaMap($paraMap, $urlEncode = false)
 {
  $buff = "";
  ksort($paraMap);
  foreach ($paraMap as $k => $v) {
   if (null != $v && "null" != $v) {
    if ($urlEncode) {
     $v = urlencode($v);
    }
    $buff .= $k . "=" . $v . "&";
   }
  }
  $reqPar = '';
  if (strlen($buff) > 0) {
   $reqPar = substr($buff, 0, strlen($buff) - 1);
  }
  return $reqPar;
 }
}
?>

github下载地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
来自PHP.NET的入门教程
Oct 09 PHP
PHP flock 文件锁详细介绍
Dec 29 PHP
用Json实现PHP与JavaScript间数据交换的方法详解
Jun 20 PHP
php中$_POST与php://input的区别实例分析
Jan 07 PHP
thinkPHP使用post方式查询时分页失效的解决方法
Dec 09 PHP
PHP实现163邮箱自动发送邮件
Mar 29 PHP
php日期操作技巧小结
Jun 25 PHP
php实现登录tplink WR882N获取IP和重启的方法
Jul 20 PHP
php fseek函数读取大文件两种方法
Oct 12 PHP
使用laravel的Eloquent模型如何获取数据库的指定列
Oct 17 PHP
laravel admin实现分类树/模型树的示例代码
Jun 10 PHP
PHP后门隐藏的一些技巧总结
Nov 04 PHP
php实现微信原生支付(扫码支付)功能
May 30 #PHP
php实现支付宝当面付(扫码支付)功能
May 30 #PHP
PHP ADODB生成HTML表格函数rs2html功能【附错误处理函数用法】
May 29 #PHP
PHP ADODB生成下拉列表框功能示例
May 29 #PHP
Laravel实现短信注册的示例代码
May 29 #PHP
PHP abstract 抽象类定义与用法示例
May 29 #PHP
thinkPHP中U方法加密传递参数功能示例
May 29 #PHP
You might like
《逃离塔科夫》——“萌新劝退,老手自嗨”的硬核FPS游戏
2020/04/03 其他游戏
PHP+MySQL5.0中文乱码解决方法
2006/11/20 PHP
深入PHP5中的魔术方法详解
2013/06/17 PHP
PHP+Ajax检测用户名或邮件注册时是否已经存在实例教程
2014/08/23 PHP
很酷的javascript loading效果代码
2008/06/18 Javascript
jQuery EasyUI API 中文文档 - ValidateBox验证框
2011/10/06 Javascript
js异步加载的三种解决方案
2013/03/04 Javascript
JavaScript中的console.group()函数详细介绍
2014/12/29 Javascript
JavaScript获取网页表单提交方式的方法
2015/04/02 Javascript
javascript编写贪吃蛇游戏
2015/07/07 Javascript
jQuery使用$.each遍历json数组的简单实现方法
2016/04/18 Javascript
Wireshark基本介绍和学习TCP三次握手
2016/08/15 Javascript
详解基于Vue,Nginx的前后端不分离部署教程
2018/12/04 Javascript
JS获取月的第几周和年的第几周实例代码
2018/12/05 Javascript
微信小程序转发事件实现解析
2019/10/22 Javascript
vue项目强制清除页面缓存的例子
2019/11/06 Javascript
Python中使用Tkinter模块创建GUI程序实例
2015/01/14 Python
python通过get,post方式发送http请求和接收http响应的方法
2015/05/26 Python
Python基于pillow判断图片完整性的方法
2016/09/18 Python
python numpy和list查询其中某个数的个数及定位方法
2018/06/27 Python
Python简单计算给定某一年的某一天是星期几示例
2018/06/27 Python
Python3获取拉勾网招聘信息的方法实例
2019/04/03 Python
Python统计时间内的并发数代码实例
2019/12/28 Python
解决python DataFrame 打印结果不换行问题
2020/04/09 Python
Python flask框架实现查询数据库并显示数据
2020/06/04 Python
虚拟机下载python是否需要联网
2020/07/27 Python
10分钟入门CSS3 Animation
2018/12/25 HTML / CSS
全球性的在线婚纱礼服工厂:27dress.com
2019/03/21 全球购物
广告设计专业自荐信范文
2013/11/14 职场文书
工作自我评价怎么写
2014/01/29 职场文书
运输企业安全生产责任书
2014/07/28 职场文书
优秀校长事迹材料
2014/12/24 职场文书
毕业设计答辩开场白
2015/05/29 职场文书
2015年度环卫处工作总结
2015/07/24 职场文书
spring cloud eureka 服务启动失败的原因分析及解决方法
2022/03/17 Java/Android
详解Python中*args和**kwargs的使用
2022/04/07 Python