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
使用XDebug调试及单元测试覆盖率分析
Jan 27 PHP
php在多维数组中根据键名快速查询其父键以及父键值的代码
May 07 PHP
PHP的preg_match匹配字符串长度问题解决方法
May 03 PHP
php判断当前用户已在别处登录的方法
Jan 06 PHP
php上传中文文件名乱码问题处理方案
Feb 03 PHP
php实现数组中索引关联数据转换成json对象的方法
Jul 08 PHP
CentOS下与Apache连接的PHP多版本共存方案实现详解
Dec 19 PHP
在Laravel中使用DataTables插件的方法
May 29 PHP
浅谈laravel aliases别名的原理
Oct 24 PHP
thinkphp框架无限级栏目的排序功能实现方法示例
Mar 29 PHP
PHP 技巧 * SVG 保存为图片(分享图生成)
Apr 02 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
rrmdir php中递归删除目录及目录下的文件
2011/05/15 PHP
基于wordpress主题制作的具体实现步骤
2013/05/10 PHP
php通过array_merge()函数合并两个数组的方法
2015/03/18 PHP
thinkPHP5.0框架配置格式、加载解析与读取方法
2017/03/17 PHP
PHP利用Socket获取网站的SSL证书与公钥
2017/06/18 PHP
PHP实现的基于单向链表解决约瑟夫环问题示例
2017/09/30 PHP
php实现的mongoDB单例模式操作类
2018/01/20 PHP
原生javascript图片自动或手动切换示例附演示源码
2013/09/04 Javascript
基于jquery实现一个滚动的分步注册向导-附源码
2015/08/26 Javascript
Bootstrap组件系列之福利篇几款好用的组件(推荐二)
2016/07/12 Javascript
Javascript动画效果(2)
2016/10/11 Javascript
详解nodejs 文本操作模块-fs模块(三)
2016/12/22 NodeJs
JS常见算法详解
2017/02/28 Javascript
ES5学习教程之Array对象
2017/04/01 Javascript
Node.js Buffer用法解读
2018/05/18 Javascript
Babel 入门教程学习笔记
2018/06/13 Javascript
vuex如何重置所有state(可定制)
2019/01/17 Javascript
微信小程序云开发之使用云函数
2019/05/17 Javascript
在 Vue 应用中使用 Netlify 表单功能的方法详解
2019/06/03 Javascript
解决vue打包后vendor.js文件过大问题
2019/07/03 Javascript
Javascript查看大图功能代码实现
2020/05/07 Javascript
Python字符串处理实例详解
2017/05/18 Python
Python解析命令行读取参数--argparse模块使用方法
2018/01/23 Python
Pycharm无法使用已经安装Selenium的解决方法
2018/10/13 Python
Python TKinter如何自动关闭主窗口
2020/02/26 Python
天巡全球:Skyscanner Global
2017/06/20 全球购物
MyBag中文网:英国著名的时尚包袋电商零售网站
2020/07/31 全球购物
房地产项目建议书
2014/03/12 职场文书
媒矿安全生产承诺书
2014/05/23 职场文书
优秀党支部书记事迹材料
2014/05/29 职场文书
2013年最新自荐信范文
2014/06/23 职场文书
校本教研活动总结
2014/07/01 职场文书
关于感恩的演讲稿400字
2014/08/26 职场文书
争先创优活动总结
2014/08/27 职场文书
护士节活动总结
2014/08/29 职场文书
golang switch语句的灵活写法介绍
2021/05/06 Golang