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 相关文章推荐
php 正则匹配函数体
Aug 25 PHP
php面向对象全攻略 (十七) 自动加载类
Sep 30 PHP
三个类概括PHP的五种设计模式
Sep 05 PHP
php笔记之:文章中图片处理的使用
Apr 26 PHP
Codeigniter中禁止A Database Error Occurred错误提示的方法
Jun 12 PHP
ThinkPHP应用模式扩展详解
Jul 16 PHP
浅析get与post的一些特殊情况
Jul 28 PHP
基于JQuery+PHP编写砸金蛋中奖程序
Sep 08 PHP
php 计算两个时间相差的天数、小时数、分钟数、秒数详解及实例代码
Nov 09 PHP
thinkPHP微信分享接口JSSDK用法实例
Jul 07 PHP
PHP微信PC二维码登陆的实现思路
Jul 13 PHP
Laravel修改验证提示信息为中文的示例
Oct 23 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错误和异长常处理总结
2014/03/06 PHP
laravel 4安装及入门图文教程
2014/10/29 PHP
php使用strip_tags()去除html标签仍有空白的解决方法
2016/07/28 PHP
IE8 兼容性问题(属性名区分大小写)
2009/06/04 Javascript
js使用函数绑定技术改变事件处理程序的作用域
2011/12/26 Javascript
在父页面调用子页面的JS方法
2013/09/29 Javascript
jQuery插件实现控制网页元素动态居中显示
2015/03/24 Javascript
jQuery制作效果超棒的手风琴折叠菜单
2015/04/03 Javascript
JavaScript编程的单例设计模讲解
2015/11/10 Javascript
jQuery进行组件开发完整实例
2015/12/15 Javascript
javascript检测移动设备横竖屏
2016/05/21 Javascript
jquery pagination插件动态分页实例(Bootstrap分页)
2016/12/23 Javascript
详解Vuejs2.0之异步跨域请求
2017/04/20 Javascript
浅谈ECMAScript6新特性之let、const
2017/08/02 Javascript
基于jQuery对象和DOM对象和字符串之间的转化实例
2017/08/08 jQuery
原生JS上传大文件显示进度条 php上传文件代码
2020/03/27 Javascript
详解vuex commit保存数据技巧
2018/12/25 Javascript
package.json配置文件构成详解
2019/08/27 Javascript
在vue项目中promise解决回调地狱和并发请求的问题
2020/11/09 Javascript
python访问sqlserver示例
2014/02/10 Python
为Python程序添加图形化界面的教程
2015/04/29 Python
Python的math模块中的常用数学函数整理
2016/02/04 Python
python 排序算法总结及实例详解
2016/09/28 Python
Python 描述符(Descriptor)入门
2016/11/20 Python
Python实现简单的多任务mysql转xml的方法
2017/02/08 Python
python中模块查找的原理与方法详解
2017/08/11 Python
python 实时得到cpu和内存的使用情况方法
2018/06/11 Python
python将pandas datarame保存为txt文件的实例
2019/02/12 Python
使用Python实现跳一跳自动跳跃功能
2019/07/10 Python
pycharm激活码有效到2020年11月底
2020/09/18 Python
马来西亚综合购物网站:Lazada马来西亚
2018/06/05 全球购物
求职信需要的五点内容
2014/02/01 职场文书
《油菜花开了》教学反思
2014/02/22 职场文书
2015年社区计生工作总结
2015/04/21 职场文书
劳务派遣管理制度(样本)
2019/08/23 职场文书
mysql 生成连续日期及变量赋值
2022/03/20 MySQL