php版微信js-sdk支付接口类用法示例


Posted in PHP onOctober 12, 2016

本文实例讲述了php版微信js-sdk支付接口类用法。分享给大家供大家参考,具体如下:

这个支付类是根据官方的文档修改而来!主要实现生成JS API 、Native的package签名包和Native响应的XML格式数据。注释都标上了各方法的用意。由于package包签名,略复杂,这个要自己多花时间去对应去看和log出文件来一一对比!当然只要你用上教程的类,设置好对应的参数就可以正确的生成package参数等

<?php
if (isset($argc) && $argc >= 1 && $argv[0] == __FILE__) {
  //初始化pay的必要信息
  $pay = new WechatPay(array(
    WechatPay::APPID => 'wx99dabzpiuq83985b8',
    WechatPay::APPSERCER => 'ac12e7e4abaer63hkoa0cc36a9663fa',
    WechatPay::PARTNERKEY => 'bae4sfa3562rsfaq23s2045',
    WechatPay::PARTNERID => '1268969802',
    WechatPay::PAYSIGNKEY => '9Fqsxb3PK4IVOCEc4yCquy5zecS9LeeMjF2Nn4B4YKoOxPwaQdFwMezKT8oNlBYaWcuT',
    WechatPay::SIGNTYPE => 'sha1',
  ));
  //设置package 必要的参数 jsapi native都通用
  $pay->setParams(WechatPay::BANK_TYPE, "WX");
  $pay->setParams(WechatPay::BODY, "test");
  $pay->setParams(WechatPay::PARTNER, $pay->partnerid);
  $pay->setParams(WechatPay::OUT_TRADE_NO, commonUtil::createNoncestr());
  $pay->setParams(WechatPay::TOTAL_FEE, "1");
  $pay->setParams(WechatPay::FEE_TYPE, "1");
  $pay->setParams(WechatPay::TIMESTAMP, time());
  $pay->setParams(WechatPay::NOTIFY_URL, "http://www.demo.com/notify");
  $pay->setParams(WechatPay::SPBILL_CREATE_IP, "127.0.0.1");
  $pay->setParams(WechatPay::INPUT_CHARSET, "UTF-8");
  //JSAPI的签名json
  print_r($pay->createJsApiPackage());
  //生成native XML
  print_r($pay->createNativePackage());
  //生成native URL
  print_r($pay->createNativeUrl("9701"));
}

JS API生成的package签名包参数:

{
  "appId":"wx9998ff5f4dede5b7",
  "package":"bank_type=WX&body=test&fee_type=1&input_charset=UTF-8¬ify_url=http%3A%2F%2Fwww.demo.com%2Fnotify&out_trade_no=Vf5qsSwtu0hc2loH&partner=wx9998ff5f4dede5b7&spbill_create_ip=127.0.0.1×tamp=1409295711&total_fee=1&sign=FEE0167BD0D89A88BF6850590EA889B6",
  "timeStamp":1409295711,
  "nonceStr":"Vf5qsSwtu0hc2loH",
  "paySign":"f816264c750923863c370a1739640244b0c2d39c",
  "signType":"sha1"
}

Native 响应的XML格式:

<xml>
  <AppId><![CDATA[wx9998ff5f4dede5b7]]></AppId>
  <Package>
    <![CDATA[bank_type=WX&body=test&fee_type=1&input_charset=UTF-8¬ify_url=http%3A%2F%2Fwww.demo.com%2Fnotify&out_trade_no=GDl3what4sALDEAd&partner=wx9998ff5f4dede5b7&spbill_create_ip=127.0.0.1×tamp=1409296124&total_fee=1&sign=BF949B85570644B939B369FD44B0C4A9]]>
  </Package>
  <TimeStamp>1409296124</TimeStamp>
  <NonceStr><![CDATA[GDl3what4sALDEAd]]></NonceStr>
  <RetCode>0</RetCode>
  <RetErrMsg><![CDATA[ok]]></RetErrMsg>
  <AppSignature><![CDATA[ca4a2467b817a62c38a9801fcf451f51692027bf]]></AppSignature>
  <SignMethod><![CDATA[sha1]]></SignMethod>
</xml>

Native的URL链接:

weixin://wxpay/bizpayurl?appid=wx9998ff5f4dede5b7&noncestr=VY7cVA6mtVrc1BVq&productid=9701&sign=43508b65b50e1d7e1089be66d55a709469155d73×tamp=1409296323

无论哪一种方式,我们都要通过setParams来设置必要初始化参数和商品价格和状态等!

WechatPay class:

<?php
class WechatPay {
  const
    BANK_TYPE = 'bank_type',
    BODY = 'body',
    PARTNER = 'partner',
    OUT_TRADE_NO = 'out_trade_no',
    TIMESTAMP = 'timestamp',
    TOTAL_FEE = 'total_fee',
    FEE_TYPE = 'fee_type',
    NOTIFY_URL = 'notify_url',
    SPBILL_CREATE_IP = 'spbill_create_ip',
    INPUT_CHARSET = 'input_charset',
    APPID = 'appid',
    APPSERCER = 'appsercer',
    PAYSIGNKEY = 'appkey',
    PARTNERID = 'partnerid',
    PARTNERKEY = 'partnerkey',
    SIGNTYPE = 'signtype';
  public
    $params = array(), $partnerid = '';
  static protected
    $_instance;
  protected
    $_appid, $_appkey, $_signtype, $_partnerkey, $_appsercer;
  static public function getInstance(array $options = array()) {
    if (empty(self::$_instance)) {
      self::$_instance = new self ($options);
    }
    return self::$_instance;
  }
  public function __construct(array $options = array()){
    $this->_appid = $options[self::APPID];
    $this->_appkey = $options[self::PAYSIGNKEY];
    $this->_signtype = $options[self::SIGNTYPE];
    $this->_partnerkey = $options[self::PARTNERKEY];
    $this->_appsercer = $options[self::APPSERCER];
    $this->partnerid = $options[self::APPID];
  }
  public function setParams($param, $paramValue) {
    $this->params[CommonUtil::trimString($param)] = CommonUtil::trimString($paramValue);
  }
  public function getParams($param) {
    return $this->params[$param];
  }
  protected 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 function checkParams(){
    //必要的9个参与签名的参数
    if($this->params[self::BANK_TYPE] == null || $this->params[self::BODY] == null || $this->params[self::PARTNER] == null ||
      $this->params[self::OUT_TRADE_NO] == null || $this->params[self::TOTAL_FEE] == null || $this->params[self::FEE_TYPE] == null ||
      $this->params[self::NOTIFY_URL] == null || $this->params[self::SPBILL_CREATE_IP] == null || $this->params[self::INPUT_CHARSET] == null
    ) {
      return false;
    }
    return true;
  }
  /*
   * 生成package包
   * @params 初始化类时用setParams方法定义必要的9个参数
   * 排序后格式化url query形式 再md5SignUtil类签名,再给合URL
   */
  protected function getPackageSign(){
    try {
      if (null == $this->_partnerkey || "" == $this->_partnerkey ) {
        throw new Exception("密钥不能为空!" . "<br>");
      }
      $commonUtil = new CommonUtil();
      ksort($this->params);
      $unSignParaString = $commonUtil->formatUrlQuery($this->params, false);
      $paraString = $commonUtil->formatUrlQuery($this->params, true);
      $md5SignUtil = new MD5SignUtil();
      return $paraString . "&sign=" . $md5SignUtil->sign($unSignParaString,commonUtil::trimString($this->_partnerkey));
    } catch (Exception $e) {
      echo ($e->getMessage());
    }
  }
  /*
   * 生成签名方法
   * @params appid appkey package timestamp noncestr 等参数而native事例代码中加上retcode reterrmsg两个参数
   */
  public function getPaySign($signObj){
    foreach ($signObj as $k => $v){
      $signParams[strtolower($k)] = $v;
    }
    try {
      if ($this->_appkey == "") {
        throw new Exception("APPKEY为空!" . "<br>");
      }
      $signParams["appkey"] = $this->_appkey;
      ksort($signParams, SORT_STRING);
      $commonUtil = new CommonUtil();
      $signString = $commonUtil->formatPayUrlQuery($signParams, false);
      return sha1($signString);
    } catch (Exception $e) {
      echo ($e->getMessage());
    }
  }
  //JS API 签名 其中nonceStr是作为订单号 灌穿整个支付流程
  public function createJsApiPackage(){
    try {
      if($this->checkParams() == false) {
        throw new Exception("生成package参数缺失!" . "<br>");
      }
      $payObj["appId"] = $this->_appid;
      $payObj["package"] = $this->getPackageSign();
      $payObj["timeStamp"] = $this->getParams(self::TIMESTAMP);
      $payObj["nonceStr"] = $this->getParams(self::OUT_TRADE_NO);
      $payObj["paySign"] = $this->getPaySign($payObj);
      $payObj["signType"] = $this->_signtype;
      return json_encode($payObj);
    } catch (Exception $e) {
      die($e->getMessage());
    }
  }
  /*
   * 构建发货状态数组 主要三个参数openid transid orderid
   */
  public function createDeliverPost(Array $params) {
    $deliver = array();
    $deliver['appid'] = $this->_appid;
    $deliver['openid'] = $params['openid'];
    $deliver['transid'] = $params['transid'];
    $deliver['out_trade_no'] = $params['out_trade_no'];
    $deliver['deliver_timestamp'] = current_time('timestamp');
    $deliver['deliver_status'] = 1;
    $deliver['deliver_msg'] = 'OK';
    $deliver['app_signature'] = $this->getPaySign($deliver);
    $deliver['sign_method'] = 'sha1';
    return $deliver;
  }
  /*
   * 生成扫描或者点击原生URL后,响应的XML格式
   * @params $retcode $reterrmsg 定义该商品的状态
   */
  public function createNativePackage($retcode = 0, $reterrmsg = "ok") {
    try {
      if ($this->checkParams() == false && $retcode == 0) {  //如果是正常的返回, 检查财付通的参数
        throw new Exception("生成package参数缺失!" . "<br>");
      }
      $nativeObj["AppId"] = $this->_appid;
      $nativeObj["Package"] = $this->getPackageSign();
      $nativeObj["TimeStamp"] = $this->getParams(self::TIMESTAMP);
      $nativeObj["NonceStr"] = $this->getParams(self::OUT_TRADE_NO);
      $nativeObj["RetCode"] = $retcode;
      $nativeObj["RetErrMsg"] = $reterrmsg;
      $nativeObj["AppSignature"] = $this->getPaySign($nativeObj);
      $nativeObj["SignMethod"] = $this->_signtype;
      $commonUtil = new CommonUtil();
      $xml = $commonUtil->arrayToXml($nativeObj);
      exit($xml);
    }catch (Exception $e) {
      echo ($e->getMessage());
    }
  }
  /*
   * 生成原生URL 以订单号为参数 这是灌穿整个支付流程
   */
  public function createNativeUrl($productid) {
    $commonUtil = new CommonUtil();
    $nativeObj["appid"] = $this->_appid;
    $nativeObj["productid"] = urlencode($productid);
    $nativeObj["timestamp"] = time();
    $nativeObj["nonceStr"] = commonUtil::createNoncestr();
    $nativeObj["sign"] = $this->getPaySign($nativeObj);
    $nativeString = $commonUtil->formatPayUrlQuery($nativeObj, false);
    return "weixin://wxpay/bizpayurl?".$nativeString;
  }
  /*
   * 取IP地址
   */
  public function getIp(){
    switch(true) {
      case !empty($_SERVER["HTTP_CLIENT_IP"]):
        $ip = $_SERVER["HTTP_CLIENT_IP"];
        break;
      case !empty($_SERVER["HTTP_X_FORWARDED_FOR"]):
        $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        break;
      case !empty($_SERVER["REMOTE_ADDR"]):
        $ip = $_SERVER["REMOTE_ADDR"];
        break;
      default:
        $ip = "127.0.0.1";
    }
    return $ip;
  }
}
class MD5SignUtil {
  public function sign($content, $key) {
    try {
      if (null == $key) {
        throw new Exception("财付通签名key不能为空!" . "<br>");
      }
      if (null == $content) {
        throw new Exception("财付通签名内容不能为空" . "<br>");
      }
      $signStr = $content . "&key=" . $key;
      return strtoupper(md5($signStr));
    } catch (Exception $e) {
      echo ($e->getMessage());
    }
  }
  public static function verifySignature($content, $sign, $md5Key) {
    $signStr = $content . "&key=" . $md5Key;
    $calculateSign = strtolower(md5($signStr));
    $tenpaySign = strtolower($sign);
    return $calculateSign == $tenpaySign;
  }
}
class CommonUtil {
  public function genAllUrl($toURL, $paras) {
    $allUrl = null;
    if (null == $toURL) {
      die("toURL is null");
    }
    if (strripos($toURL,"?") =="") {
      $allUrl = $toURL . "?" . $paras;
    } else {
      $allUrl = $toURL . "&" . $paras;
    }
    return $allUrl;
  }
  //订单号,可根据实际自定义
  static public function createOrderNo() {
    $nonce = CommonUtil::createNoncestr(4);
    return strtoupper(date('ymds').substr(microtime(),2,4).$nonce);
  }
  //随机字符串
  static public 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 function splitParaStr($src, $token) {
    $resMap = array();
    $items = explode($token,$src);
    foreach ($items as $item){
      $paraAndValue = explode("=",$item);
      if ($paraAndValue != "") {
        $resMap[$paraAndValue[0]] = $paraAndValue[1];
      }
    }
    return $resMap;
  }
  static function trimString($value) {
    $ret = null;
    if (null != $value) {
      $ret = $value;
      if (strlen($ret) == 0) {
        $ret = null;
      }
    }
    return $ret;
  }
  public function formatUrlQuery($paraMap, $urlencode) {
    $buff = "";
    ksort($paraMap, SORT_STRING);
    foreach ($paraMap as $k => $v) {
      if (null != $v && "null" != $v && "sign" != $k) {
        if($urlencode) {
          $v = urlencode($v);
        }
        $buff .= $k . "=" . $v . "&";
      }
    }
    $reqPar = '';
    if (strlen($buff) > 0) {
      $reqPar = substr($buff, 0, strlen($buff)-1);
    }
    return $reqPar;
  }
  public function formatPayUrlQuery($paraMap, $urlencode) {
    $buff = "";
    ksort($paraMap, SORT_STRING);
    foreach ($paraMap as $k => $v) {
      if($urlencode){
        $v = urlencode($v);
      }
      $buff .= strtolower($k) . "=" . $v . "&";
    }
    $reqPar = '';
    if (strlen($buff) > 0) {
      $reqPar = substr($buff, 0, strlen($buff)-1);
    }
    return $reqPar;
  }
  /*
   * 输出一级数组的xml格式
   */
  public function arrayToXml($arr) {
    $xml = "<xml>";
    foreach ($arr as $key=>$val) {
      if ($key == 'TimeStamp' || $key == 'RetCode') {
        $xml.="<".$key.">".$val."</".$key.">";
      } else
        $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
    }
    $xml .= "</xml>";
    return $xml;
  }
}

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
Apache, PHP在Windows 9x/NT下的安装与配置 (一)
Oct 09 PHP
文件系统基本操作类
Nov 23 PHP
php 数组使用详解 推荐
Jun 02 PHP
Linux中为php配置伪静态
Dec 17 PHP
PHP对象链式操作实现原理分析
Oct 09 PHP
php中array_slice和array_splice函数解析
Oct 18 PHP
php自定义时间转换函数示例
Dec 07 PHP
PHP实现广度优先搜索算法(BFS,Broad First Search)详解
Sep 16 PHP
PHP实现用session来实现记录用户登陆信息
Oct 15 PHP
Laravel框架定时任务2种实现方式示例
Dec 08 PHP
PHP中ltrim()函数的用法与实例讲解
Mar 28 PHP
Aliyun Linux 编译安装 php7.3 tengine2.3.2 mysql8.0 redis5的过程详解
Oct 20 PHP
php版微信支付api.mch.weixin.qq.com域名解析慢原因与解决方法
Oct 12 #PHP
如何使用php等比例缩放图片
Oct 12 #PHP
php与python实现的线程池多线程爬虫功能示例
Oct 12 #PHP
php实现的SSO单点登录系统接入功能示例分析
Oct 12 #PHP
php用户密码加密算法分析【Discuz加密算法】
Oct 12 #PHP
基于php实现的php代码加密解密类完整实例
Oct 12 #PHP
php fseek函数读取大文件两种方法
Oct 12 #PHP
You might like
php checkbox复选框值的获取与checkbox默认值输出方法
2010/05/15 PHP
php安装dblib扩展,连接mssql的具体步骤
2017/03/02 PHP
yii2实现Ueditor百度编辑器的示例代码
2018/11/02 PHP
JavaScript 获取用户客户端操作系统版本
2009/08/25 Javascript
javascript 实现键盘上下左右功能的小例子
2013/09/15 Javascript
js日期对象兼容性的处理方法
2014/01/28 Javascript
javascript实现简单的贪吃蛇游戏
2015/03/31 Javascript
jquery实现多条件筛选特效代码分享
2015/08/28 Javascript
AngularJS实现Model缓存的方式
2016/02/03 Javascript
百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
2016/02/19 Javascript
JavaScript+CSS实现的可折叠二级菜单实例
2016/02/29 Javascript
EasyUI中在表单提交之前进行验证
2016/07/19 Javascript
js实现常用排序算法
2016/08/09 Javascript
BootStrap实现手机端轮播图左右滑动事件
2016/10/13 Javascript
解决vue router使用 history 模式刷新后404问题
2017/07/19 Javascript
详解Vue用自定义指令完成一个下拉菜单(select组件)
2017/10/31 Javascript
基于Vue开发数字输入框组件
2017/12/19 Javascript
在vue中封装可复用的组件方法
2018/03/01 Javascript
vue使用nprogress实现进度条
2019/12/09 Javascript
[14:57]DOTA2 HEROS教学视频教你分分钟做大人-幽鬼
2014/06/13 DOTA
[51:36]EG vs VP 2018国际邀请赛淘汰赛BO3 第一场 8.24
2018/08/25 DOTA
python私有属性和方法实例分析
2015/01/15 Python
使用graphics.py实现2048小游戏
2015/03/10 Python
Linux 发邮件磁盘空间监控(python)
2016/04/23 Python
对python读取CT医学图像的实例详解
2019/01/24 Python
Python单链表原理与实现方法详解
2020/02/22 Python
JetBrains PyCharm(Community版本)的下载、安装和初步使用图文教程详解
2020/03/19 Python
Pytest测试框架基本使用方法详解
2020/11/25 Python
最新PyCharm 2020.2.3永久激活码(亲测有效)
2020/11/26 Python
Clarks英国官方网站:全球领军鞋履品牌
2016/11/26 全球购物
澳大利亚吉他在线:Artist Guitars
2017/03/30 全球购物
马来西亚户外装备商店:PTT Outdoor
2019/07/13 全球购物
网络技术专业求职信
2014/07/13 职场文书
2015毕业生实习期工作总结
2015/04/09 职场文书
《莫泊桑拜师》教学反思
2016/02/22 职场文书
Python制作春联的示例代码
2022/01/22 Python