php实现微信原生支付(扫码支付)功能


Posted in PHP onMay 30, 2018

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

直接运行该文件即可得到一个支付二维码的图片。

需要注意的事项:

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

代码如下:

<?php
header('Content-type:text/html; Charset=utf-8');
$mchid = 'xxxxx';     //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
$appid = 'xxxxx'; //公众号APPID 通过微信支付商户资料审核后邮件发送
$apiKey = 'xxxxx';  //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
$wxPay = new WxpayService($mchid,$appid,$apiKey);
$outTradeNo = uniqid();   //你自己的商品订单号
$payAmount = 0.01;     //付款金额,单位:元
$orderName = '支付测试';  //订单标题
$notifyUrl = 'https://www.xxx.com/wx/';   //付款成功后的回调地址(不要有问号)
$payTime = time();   //付款时间
$arr = $wxPay->createJsBizPackage($payAmount,$outTradeNo,$orderName,$notifyUrl,$payTime);
//生成二维码
$url = 'http://qr.liantu.com/api.php?text='.$arr['code_url'];
echo "<img src='{$url}' style='width:300px;'>";

class WxpayService
{
  protected $mchid;
  protected $appid;
  protected $apiKey;

  public function __construct($mchid, $appid, $key)
  {
    $this->mchid = $mchid;
    $this->appid = $appid;
    $this->apiKey = $key;
  }

  /**
   * 发起订单
   * @param float $totalFee 收款总费用 单位元
   * @param string $outTradeNo 唯一的订单号
   * @param string $orderName 订单名称
   * @param string $notifyUrl 支付结果通知url 不要有问号
   * @param string $timestamp 订单发起时间
   * @return array
   */
  public function createJsBizPackage($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,
      'out_trade_no' => $outTradeNo,
      'spbill_create_ip' => '127.0.0.1',
      'total_fee' => intval($totalFee * 100),    //单位 转为分
      'trade_type' => 'NATIVE',
    );
    $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);
    }
    $codeUrl = (array)($unifiedOrder->code_url);
    if(!$codeUrl[0]) exit('get code_url error');
    $arr = array(
      "appId" => $config['appid'],
      "timeStamp" => $timestamp,
      "nonceStr" => self::createNonceStr(),
      "package" => "prepay_id=" . $unifiedOrder->prepay_id,
      "signType" => 'MD5',
      "code_url" => $codeUrl[0],
    );
    $arr['paySign'] = self::getSign($arr, $config['key']);
    return $arr;
  }


  public function notify()
  {
    $config = array(
      'mch_id' => $this->mchid,
      'appid' => $this->appid,
      'key' => $this->apiKey,
    );
    $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

    $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
    if ($postObj === false) {
      die('parse xml error');
    }
    if ($postObj->return_code != 'SUCCESS') {
      die($postObj->return_msg);
    }
    if ($postObj->result_code != 'SUCCESS') {
      die($postObj->err_code);
    }
    $arr = (array)$postObj;
    unset($arr['sign']);
    if (self::getSign($arr, $config['key']) == $postObj->sign) {
      echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
      return $postObj;
    }
  }

  /**
   * curl get
   *
   * @param string $url
   * @param array $options
   * @return mixed
   */
  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>";
    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下载地址:weixinPay

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

PHP 相关文章推荐
图书管理程序(三)
Oct 09 PHP
Windows下利用Gvim写PHP产生中文乱码问题解决方法
Apr 20 PHP
php入门学习知识点七 PHP函数的基本应用
Jul 14 PHP
php 模拟GMAIL,HOTMAIL(MSN),YAHOO,163,126邮箱登录的详细介绍
Jun 18 PHP
PHP简单实现“相关文章推荐”功能的方法
Jul 19 PHP
php取得字符串首字母的方法
Mar 25 PHP
php实现mysql数据库分表分段备份
Jun 18 PHP
Yii中的relations数据关联查询及统计功能用法详解
Jul 14 PHP
PHP接收App端发送文件流的方法
Sep 23 PHP
Laravel-添加后台模板AdminLte的实现方法
Oct 08 PHP
Yii框架学习笔记之应用组件操作示例
Nov 13 PHP
php计数排序算法的实现代码(附四个实例代码)
Mar 31 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
在Laravel中使用DataTables插件的方法
May 29 #PHP
You might like
php判断用户是否手机访问代码
2015/06/08 PHP
PHP类型约束用法示例
2016/09/28 PHP
PHP反射基础知识回顾
2020/09/10 PHP
通用JS事件写法实现代码
2009/01/07 Javascript
javascript的offset、client、scroll使用方法详解
2012/12/25 Javascript
jquery删除提示框弹出是否删除对话框
2014/01/07 Javascript
浅析jquery的js图表组件highcharts
2014/03/06 Javascript
判断复选框是否被选中的两种方法
2014/06/04 Javascript
jquery checkbox 勾选的bug问题解决方案与分析
2014/11/13 Javascript
node.js中的url.format方法使用说明
2014/12/10 Javascript
jQuery中first()方法用法实例
2015/01/06 Javascript
javascript实现获取服务器时间
2015/05/19 Javascript
js实现兼容IE、Firefox的图片缩放代码
2015/12/08 Javascript
浅谈$_FILES数组为空的原因
2017/02/16 Javascript
JS实现仿UC浏览器前进后退效果的实例代码
2017/07/17 Javascript
Vue 表单控件绑定的实现示例
2017/08/11 Javascript
在AngularJs中设置请求头信息(headers)的方法及不同方法的比较
2018/09/04 Javascript
vue仿element实现分页器效果
2018/09/13 Javascript
vue 项目地址去掉 #的方法
2018/10/20 Javascript
Vue 2.0 中依赖注入 provide/inject组合实战
2019/06/20 Javascript
Javascript前端下载后台传来的文件流代码实例
2020/08/18 Javascript
[01:18:43]2014 DOTA2华西杯精英邀请赛5 24 iG VS DK
2014/05/25 DOTA
在Django中创建URLconf相关的通用视图的方法
2015/07/20 Python
Python使用当前时间、随机数产生一个唯一数字的方法
2017/09/18 Python
Django视图之ORM数据库查询操作API的实例
2017/10/27 Python
Python多进程与服务器并发原理及用法实例分析
2018/08/21 Python
python爬取抖音视频的实例分析
2021/01/19 Python
丹尼尔惠灵顿手表天猫官方旗舰店:Daniel Wellington
2017/08/25 全球购物
Tiqets荷兰:出售欧洲最美丽的景点和博物馆门票
2018/01/09 全球购物
护理学毕业生自荐信
2013/10/02 职场文书
办公室文员工作职责
2014/01/31 职场文书
商场周年庆活动方案
2014/08/19 职场文书
亚布力滑雪场导游词
2015/02/09 职场文书
2015年银行工作总结范文
2015/04/01 职场文书
2015年保险公司个人工作总结
2015/05/22 职场文书
Python 正则模块详情
2021/11/02 Python