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版(1)
Oct 09 PHP
如何在PHP中使用Oracle数据库(2)
Oct 09 PHP
使用数据库保存session的方法
Oct 09 PHP
function.inc.php超越php
Dec 09 PHP
php处理restful请求的路由类分享
Feb 27 PHP
php绘制圆形的方法
Jan 24 PHP
YiiFramework入门知识点总结(图文教程)
Dec 28 PHP
PHP常用字符串操作函数实例总结(trim、nl2br、addcslashes、uudecode、md5等)
Jan 09 PHP
ThinkPHP 3.2.2实现事务操作的方法
May 05 PHP
php判断电子邮件是否正确方法
Dec 04 PHP
PHP设计模式之模板方法模式实例浅析
Dec 20 PHP
smarty模板的使用方法实例分析
Sep 18 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
用PHP中的 == 运算符进行字符串比较
2006/11/26 PHP
php 进度条实现代码
2009/03/10 PHP
PHP实现的字符串匹配算法示例【sunday算法】
2017/12/19 PHP
PHP命名空间简单用法示例
2018/12/28 PHP
可以文本显示的公告栏的js代码
2007/03/11 Javascript
javascript 面向对象全新理练之数据的封装
2009/12/03 Javascript
Dom操作之兼容技巧分享
2011/09/20 Javascript
javascript图像处理—仿射变换深度理解
2013/01/16 Javascript
子页向父页传值示例
2013/11/27 Javascript
jQuery中click事件用法实例
2014/12/26 Javascript
浅谈JavaScript对象与继承
2016/07/10 Javascript
浅谈Angularjs link和compile的使用区别
2016/10/21 Javascript
简单理解Vue条件渲染
2016/12/03 Javascript
BootStrap selectpicker后台动态绑定数据
2017/06/01 Javascript
vue结合Echarts实现点击高亮效果的示例
2018/03/17 Javascript
Nodejs实现的操作MongoDB数据库功能完整示例
2019/02/02 NodeJs
JS大坑之19位数的Number型精度丢失问题详解
2019/04/22 Javascript
浅谈Vue.js之初始化el以及数据的绑定说明
2019/11/14 Javascript
序列化模块json代码实例详解
2020/03/03 Javascript
[01:59]深扒TI7聊天轮盘语音出处 1
2017/05/11 DOTA
Python获取任意xml节点值的方法
2015/05/05 Python
Python字典及字典基本操作方法详解
2018/01/30 Python
Python提取频域特征知识点浅析
2019/03/04 Python
pyqt5 lineEdit设置密码隐藏,删除lineEdit已输入的内容等属性方法
2019/06/24 Python
解决Jupyter notebook中.py与.ipynb文件的import问题
2020/04/21 Python
Python基于xlrd模块处理合并单元格
2020/07/28 Python
Python制作简单的剪刀石头布游戏
2020/12/10 Python
中外合拍动画首获奥斯卡提名,“上海出品”《飞奔去月球》能否拿下最终大奖?
2021/03/16 国漫
HTML5+Canvas+CSS3实现齐天大圣孙悟空腾云驾雾效果
2016/04/26 HTML / CSS
StubHub新加坡:购买和出售全球活动门票
2017/03/10 全球购物
2013年学期结束动员演讲稿
2014/01/07 职场文书
实习指导老师评语
2014/04/26 职场文书
公证委托书
2014/08/01 职场文书
婚礼女方父母答谢词
2015/01/04 职场文书
岗位聘任协议书
2015/09/21 职场文书
写一个Python脚本自动爬取Bilibili小视频
2021/04/24 Python