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.MVC的模板标签系统(四)
Sep 05 PHP
PHP生成静态页
Nov 25 PHP
php 正确解码javascript中通过escape编码后的字符
Jan 28 PHP
用PHP实现弹出消息提示框的两种方法
Dec 17 PHP
PHP把小数转成整数3种方法
Jun 30 PHP
destoon实现不同会员组公司名称显示不同的颜色的方法
Aug 22 PHP
Laravel 5框架学习之用户认证
Apr 09 PHP
PHP的邮件群发系统phplist配置方法详细总结
Mar 30 PHP
Laravel Memcached缓存驱动的配置与应用方法分析
Oct 08 PHP
PHP实现重载的常用方法实例详解
Oct 18 PHP
php 广告点击统计代码(php+mysql)
Feb 21 PHP
PHP设计模式之策略模式原理与用法实例分析
Apr 04 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
安健A254立体声随身听的分析与打磨
2021/03/02 无线电
ThinkPHP添加更新标签的方法
2014/12/05 PHP
php读取csv数据保存到数组的方法
2015/01/03 PHP
关于IE7 IE8弹出窗口顶上
2008/12/22 Javascript
(jQuery,mootools,dojo)使用适合自己的编程别名命名
2010/09/14 Javascript
javascript 单例/单体模式(Singleton)
2011/04/07 Javascript
js绑定事件this指向发生改变的问题解决方法
2013/04/23 Javascript
使用jQuery快速解决input中placeholder值在ie中无法支持的问题
2014/01/02 Javascript
JavaScript将Web页面内容导出到Word及Excel的方法
2015/02/13 Javascript
jQuery源码分析之Callbacks详解
2015/03/13 Javascript
jQuery.each使用详解
2015/07/07 Javascript
jQuery实现鼠标经过显示动画边框特效
2017/03/24 jQuery
微信小程序实现滚动消息通知
2018/02/02 Javascript
vue elementui form表单验证的实现
2018/11/11 Javascript
微信小程序五子棋游戏AI实现方法【附demo源码下载】
2019/02/20 Javascript
浅析vue插槽和作用域插槽的理解
2019/04/22 Javascript
JS代码优化的8点建议
2020/02/04 Javascript
Vue.extend 登录注册模态框的实现
2020/12/29 Vue.js
python排序方法实例分析
2015/04/30 Python
Python实现大文件排序的方法
2015/07/10 Python
python爬虫之BeautifulSoup 使用select方法详解
2017/10/23 Python
浅谈Django自定义模板标签template_tags的用处
2017/12/20 Python
numpy按列连接两个维数不同的数组方式
2019/12/06 Python
Python命名空间及作用域原理实例解析
2020/08/12 Python
台湾母婴用品限时团购:妈咪爱
2018/08/03 全球购物
美国球迷装备的第一来源:FOCO
2020/07/03 全球购物
2014年应届大学生自我评价
2014/01/09 职场文书
学习党的群众路线教育实践活动心得体会
2014/03/01 职场文书
晚会主持词开场白
2014/03/17 职场文书
孩子教育的心得体会
2014/09/01 职场文书
迟到检讨书范文
2015/01/27 职场文书
装修公司工程部经理岗位职责
2015/04/09 职场文书
2015年大学班主任工作总结
2015/04/30 职场文书
小学运动会通讯稿
2015/07/18 职场文书
2019年七夕情人节浪漫祝福语大全!
2019/08/08 职场文书
解决SpringBoot文件上传临时目录找不到的问题
2021/07/01 Java/Android