文档章节

php版本微信js-sdk支付接口类例子

独孤蝈蝈
 独孤蝈蝈
发布于 2016/11/03 21:01
字数 1548
阅读 102
收藏 1
PHP

本文章来为各位介绍一篇关于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&notify_url=http%3A%2F%2Fwww.demo.com%2Fnotify&out_trade_no=Vf5qsSwtu0hc2loH&partner=wx9998ff5f4dede5b7&spbill_create_ip=127.0.0.1&timestamp=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&notify_url=http%3A%2F%2Fwww.demo.com%2Fnotify&out_trade_no=GDl3what4sALDEAd&partner=wx9998ff5f4dede5b7&spbill_create_ip=127.0.0.1&timestamp=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&timestamp=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;
    }
}

 

本文转载自:

独孤蝈蝈
粉丝 4
博文 59
码字总数 39108
作品 0
朝阳
程序员
私信 提问
微信开放微信内网页开发工具包,助力网页开发

微信公众平台今日面向开发者开放微信内网页开发工具包(微信JS-SDK)。 通过微信JS-SDK提供的11类接口集,开发者不仅能够在网页上使用微信本身的拍照、选图、语音、位置等基本能力,还可以直...

oschina
2015/01/10
26.5K
30
微信开放JS-SDK,助力网页开发[转自微信官方]

微信公众平台今日面向开发者开放微信内网页开发工具包(微信JS-SDK)。 通过微信JS-SDK提供的11类接口集,开发者不仅能够在网页上使用微信本身的拍照、选图、语音、位置等基本能力,还可以直...

明非_
2014/07/26
0
14
分享到朋友圈没有缩略图?微信自定义标题描述及缩略图最简单完美的办法!

首先看看分享到朋友圈没有缩略图的原因 微信为规范自定义分享链接功能在网页上的使用,自2017年4月25日起,JSSDK“分享到朋友圈”及“发送给朋友”接口,自定义的分享链接,其域名或路径必须...

几分野性
04/27
0
0
深究WeixinJSBridge未定义之因

对于Fundebug这样一个没有使用微信JS-SDK的产品来说,我们竟然收到了WeixinJSBridge is not defined 的报错: 去网上一搜,发现很多开发者都遇到类似的问题: 我的微信项目,没有用到微信JS-...

kiwenlau
2017/02/20
0
0
关于微信js分享接口的一些使用心得

虽然微信官方开放了js-sdk,但是在某些老版本的微信上存在兼容性问题,比如在安卓微信6.0.1版本上分享接口就无法使用,官方给出的解决方案就是升级微信。这不坑爹呢!我又不能强制我的用户去...

吾爱
2015/01/21
0
6

没有更多内容

加载失败,请刷新页面

加载更多

Feign输出Info级别日志

背景   spring cloud netfix组件中,feign相关的日志默认是不会输出的,需要自定义配置才能输出,并且Feign只对Debug基本的日志做出响应, 实际业务需要输出Info级别的日志,所以需要做自定...

xiaomin0322
16分钟前
3
0
面向解决问题的java编程,spring boot,mybatis generator和坑-1starter

1、start一个spring boot项目 第一课我们也不能免俗,要从starter开始,spring boot的起始项目脚手架可以从spring boot官方starter生成地址开始:https://start.spring.io/ 这张图列出了一个...

wphmoon
16分钟前
1
0
Linux虚拟化技术—CentOS7.4下KVM虚拟化一 安装配置及基本操作

Linux虚拟化技术—CentOS7.4下KVM虚拟化一 安装配置及基本操作 0行云流水00人评论61017人阅读2018-04-11 19:57:20 KVM的安装配置与基本操作 目录 第一部分 实验环境 第二部分 安装图形界面 ...

linjin200
19分钟前
1
0
php获取网站favicon.ico图标 api源码

 通常情况下,做网站的都会给自己的网站添加一个Icon,浏览器上一长排的标签页,用Icon来区分就显得更加醒目。现在想找一个没有Icon的网站并不好找,可见没有Icon的网站是多么的业余啊。"什...

xiaogg
22分钟前
1
0
双亲委派的认识

首先JVM中有三种类加载器 Bootstrap启动类加载器 Extension扩展类加载器(ExtClassLoader) System系统类加载器(AppClassLoader) 某个特定的类接到加载类的请求时候,首先将加载任务委托给...

最胖的瘦子
27分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部