微信支付

每個關於支付的文章,都是一篇血淚史,不知到爲何每次接接口總會遇到點問題。還好都走過來了javascript

1.支付測試 (須要完成兩步)php

a.支付調用css

這個微信的demo中有一個測試的例子,直接拿過來用就能夠了,將裏面的參數換成本身真實的參數,這裏我遇到的問題就是,appkey = appSignKey  ,微信產品經理沒有發給咱們,微信後臺又找不到,因此耽擱了一些時間。html

注意事項:前端

          1.必定要將測試代碼放在測試目錄的一級目錄下進行測試 。如,測試目錄是www.xxxx.com/pay/ ,那你的代碼文件wxtest.php 要放在 www.xxxx.com/pay/wxtest.phpjava

          2.必定要在微信中測試,在網頁上測試,點擊按鈕是沒有反映的。將www.xxxx.com/pay/wxtest.php,連接到微信中。jquery

          3.必定要將測試的微信賬號加入白名單(肯定本身已有微信支付)web

代碼以下:json

<!DOCTYPE html>
<html>
    <head>
        <title>公衆號支付測試網頁</title>
        <script language="javascript" src="http://xxx/website/weixin/Paywx/js/jquery.js"></script>
        <script  language="javascript" src="http://xxx/website/weixin/Paywx/js/lazyloadv3.js"></script>
        <script language="javascript" src="http://xxx/website/weixin/Paywx/js/md5.js"></script>
        <script language="javascript" src="http://xxx/website/weixin/Paywx/js/sha1.js"></script>
        <script Language="javascript">

		
            //商家測試請修改此四個參數,並將頁面放在支付受權目錄下,在申請了支付的公衆帳號訪問此頁面,方可調起支付。
            //修改開始
            function getPartnerId()
            {//替換partnerid
                return "xxxxx";
            }
            
            function getPartnerKey()
            {//替換partnerkey
                return "xxxxx";
            }
			
            function getAppId()
            {//替換appid
                return "xxxxx";
            }
            
            function getAppKey()
            {//替換appkey
             return "xxxxx";
            }		
			//修改到此結束
		
            //輔助函數
            function Trim(str,is_global)
            {
                var result;
                result = str.replace(/(^\s+)|(\s+$)/g,"");
                if(is_global.toLowerCase()=="g") result = result.replace(/\s/g,"");
                return result;
            }
            function clearBr(key)
            {
                key = Trim(key,"g");
                key = key.replace(/<\/?.+?>/g,"");
                key = key.replace(/[\r\n]/g, "");
                return key;
            }
            
            //獲取隨機數
            function getANumber()
            {
                var date = new Date();
                var times1970 = date.getTime();
                var times = date.getDate() + "" + date.getHours() + "" + date.getMinutes() + "" + date.getSeconds();
                var encrypt = times * times1970;
                if(arguments.length == 1){
                    return arguments[0] + encrypt;
                }else{
                    return encrypt;
                }
                
            }

            //如下是package組包過程:
            
            var oldPackageString;//記住package,方便最後進行總體簽名時取用
           
            function getPackage()
            {
                var banktype = "WX";
                var body = "江詩丹頓";//商品名稱信息,這裏由測試網頁填入。
                var fee_type = "1";//費用類型,這裏1爲默認的人民幣
                var input_charset = "UTF-8";//字符集,可使用GBK或者UTF-8
                var notify_url = "http://www.qq.com";//支付成功後將通知該地址
                var out_trade_no = ""+getANumber();//訂單號,商戶須要保證該字段對於本商戶的惟一性
                var partner = getPartnerId();//測試商戶號
                var spbill_create_ip = "127.0.0.1";//用戶瀏覽器的ip,這個須要在前端獲取。這裏使用127.0.0.1測試值
                var total_fee = 1;//總金額。
                var partnerKey = getPartnerKey();//這個值和以上其餘值不同是:簽名須要它,而最後組成的傳輸字符串不能含有它。這個key是須要商戶好好保存的。
                
                //首先第一步:對原串進行簽名,注意這裏不要對任何字段進行編碼。這裏是將參數按照key=value進行字典排序後組成下面的字符串,在這個字符串最後拼接上key=XXXX。因爲這裏的字段固定,所以只須要按照這個順序進行排序便可。
                var signString = "bank_type="+banktype+"&body="+body+"&fee_type="+fee_type+"&input_charset="+input_charset+"&notify_url="+notify_url+"&out_trade_no="+out_trade_no+"&partner="+partner+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee+"&key="+partnerKey;
                
                var md5SignValue =  ("" + CryptoJS.MD5(signString)).toUpperCase();
                //而後第二步,對每一個參數進行url轉碼,若是您的程序是用js,那麼須要使用encodeURIComponent函數進行編碼。
                
                
                banktype = encodeURIComponent(banktype);
                body=encodeURIComponent(body);
                fee_type=encodeURIComponent(fee_type);
                input_charset = encodeURIComponent(input_charset);
                notify_url = encodeURIComponent(notify_url);
                out_trade_no = encodeURIComponent(out_trade_no);
                partner = encodeURIComponent(partner);
                spbill_create_ip = encodeURIComponent(spbill_create_ip);
                total_fee = encodeURIComponent(total_fee);
                
                //而後進行最後一步,這裏按照key=value除了sign外進行字典序排序後組成下列的字符串,最後再串接sign=value
                var completeString = "bank_type="+banktype+"&body="+body+"&fee_type="+fee_type+"&input_charset="+input_charset+"&notify_url="+notify_url+"&out_trade_no="+out_trade_no+"&partner="+partner+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee;
                completeString = completeString + "&sign="+md5SignValue;
                
                
                oldPackageString = completeString;//記住package,方便最後進行總體簽名時取用
                
                return completeString;
            }
            
            
            //下面是app進行簽名的操做:
            
            var oldTimeStamp ;//記住timestamp,避免簽名時的timestamp與傳入的timestamp時不一致
            var oldNonceStr ; //記住nonceStr,避免簽名時的nonceStr與傳入的nonceStr不一致
                     
            function getTimeStamp()
            {
                var timestamp=new Date().getTime();
                var timestampstring = timestamp.toString();//必定要轉換字符串
                oldTimeStamp = timestampstring;
                return timestampstring;
            }
            
            function getNonceStr()
            {
                var $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
                var maxPos = $chars.length;
                var noceStr = "";
                for (i = 0; i < 32; i++) {
                    noceStr += $chars.charAt(Math.floor(Math.random() * maxPos));
                }
                oldNonceStr = noceStr;
                return noceStr;
            }
            
            function getSignType()
            {
                return "SHA1";
            }
            
            function getSign()
            {
                var app_id = getAppId().toString();
                var app_key = getAppKey().toString();
                var nonce_str = oldNonceStr;
                var package_string = oldPackageString;
                var time_stamp = oldTimeStamp;
                //第一步,對全部須要傳入的參數加上appkey做一次key=value字典序的排序
                var keyvaluestring = "appid="+app_id+"&appkey="+app_key+"&noncestr="+nonce_str+"&package="+package_string+"&timestamp="+time_stamp;
                sign = CryptoJS.SHA1(keyvaluestring).toString();
                return sign;
            }
            
            
            
            
            </script>
        <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
        <!--<meta id="viewport" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1; user-scalable=no;" />-->
        
        <style>
            
            
            body { margin:0;padding:0;background:#eae9e6; }
            body,p,table,td,th { font-size:14px;font-family:helvetica,Arial,Tahoma; }
            h1 { font-family:Baskerville,HelveticaNeue-Bold,helvetica,Arial,Tahoma; }
            a { text-decoration:none;color:#385487;}
            
            
            .container {  }
            .title { }
            #content {padding:30px 20px 20px;color:#111;box-shadow:0 1px 4px #ccc; background:#f7f2ed;  }
            .seeAlso { padding:15px 20px 30px; }
            
            .headpic div { margin:20px 0 0;}
            .headpic img { display:block;}
            
            .title h1 { font-size:22px;font-weight:bold;padding:0;margin:0;line-height:1.2;color:#1f1f1f; }
            .title p { color:#aaa;font-size:12px;margin:5px 0 0;padding:0;font-weight:bold;}
            .pic { margin:20px 0; }
            .articlecontent img { display:block;clear:both;box-shadow:0px 1px 3px #999; margin:5px auto;}
            .articlecontent p { text-indent: 2em; font-family:Georgia,helvetica,Arial,Tahoma;line-height:1.4; font-size:16px; margin:20px 0;  }
            
            
            .seeAlso h3 { font-size:16px;color:#a5a5a5;}
            .seeAlso ul { margin:0;padding:0; }
            .seeAlso li {  font-size:16px;list-style-type:none;border-top:1px solid #ccc;padding:2px 0;}
            .seeAlso li a { border-bottom:none;display:block;line-height:1.1; padding:13px 0; }
            
            .clr{ clear:both;height:1px;overflow:hidden;}
            
            
            .fontSize1 .title h1 { font-size:20px; }
            .fontSize1 .articlecontent p {  font-size:14px; }
            .fontSize1 .weibo .nickname,.fontSize1 .weibo .comment  { font-size:11px; }
            .fontSize1 .moreOperator { font-size:14px; }
            
            .fontSize2 .title h1 { font-size:22px; }
            .fontSize2 .articlecontent p {  font-size:16px; }
            .fontSize2 .weibo .nickname,.fontSize2 .weibo .comment  { font-size:13px; }
            .fontSize2 .moreOperator { font-size:16px; }
            
            .fontSize3 .title h1 { font-size:24px; }
            .fontSize3 .articlecontent p {  font-size:18px; }
            .fontSize3 .weibo .nickname,.fontSize3 .weibo .comment  { font-size:15px; }
            .fontSize3 .moreOperator { font-size:18px; }
            
            .fontSize4 .title h1 { font-size:26px; }
            .fontSize4 .articlecontent p {  font-size:20px; }
            .fontSize4 .weibo .nickname,.fontSize4 .weibo .comment  { font-size:16px; }
            .fontSize4 .moreOperator { font-size:20px; }
            
            .jumptoorg { display:block;margin:16px 0 16px; }
            .jumptoorg a {  }
            
            .moreOperator a { color:#385487; }
            
            .moreOperator .share{ border-top:1px solid #ddd; }
            
            .moreOperator .share a{ display:block;border:1px solid #ccc;border-radius:4px;margin:20px 0;border-bottom-style:solid;background:#f8f7f1;color:#000; }
            
            .moreOperator .share a span{ display:block;padding:10px 10px;border-radius:4px;text-align:center;border-top:1px solid #eee;border-bottom:1px solid #eae9e3;font-weight:bold; }
            
            .moreOperator .share a:hover,
            .moreOperator .share a:active { background:#efedea; }
            @media only screen and (-webkit-min-device-pixel-ratio: 2) {
            }
            </style>
        <script language="javascript">
            function auto_remove(img){
                div=img.parentNode.parentNode;div.parentNode.removeChild(div);
                img.onerror="";
                return true;
            }
            
            function changefont(fontsize){
                if(fontsize < 1 || fontsize > 4)return;
                $('#content').removeClass().addClass('fontSize' + fontsize);
            }
            
            
            
            
            // 當微信內置瀏覽器完成內部初始化後會觸發WeixinJSBridgeReady事件。
            document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
                                      //公衆號支付
                                      $('#getBrandWCPayRequest').click(function(e){
                                                                             
                                                                             WeixinJSBridge.invoke('getBrandWCPayRequest',{
                                                                                                   "appId" : getAppId(), //公衆號名稱,由商戶傳入
                                                                                                   "timeStamp" : getTimeStamp(), //時間戳
                                                                                                   "nonceStr" : getNonceStr(), //隨機串
                                                                                                   "package" : getPackage(),//擴展包
                                                                                                   "signType" : getSignType(), //微信簽名方式:1.sha1
                                                                                                   "paySign" : getSign() //微信簽名
                                                                                                   },function(res){
                                                                                                   if(res.err_msg == "get_brand_wcpay_request:ok" ) {

alert (res.err_msg);
var paysign = getSign();
timestamp = getTimeStamp();
url= "https://api.weixin.qq.com/pay/delivernotify?access_token=ONmUWirhnDG0UhVvcM3D6amz-XzsMr7hOCb4L59Jqrc5GJ0waRlbPQ7C-JiFbG2KFIN248T_GdmAxiOUuXDxxA";
var str = '{"appid" : getAppId(),"openid" : "oarYcs5sNGIhUn615Gqb8l6GFYmU","transid" : "1219798201201408013230834317","out_trade_no" : "test000001","deliver_timestamp" : "<%=timestamp%>","deliver_status" : "1","deliver_msg" : "ok","app_signature" : "<%=paysign%>","sign_method" : "sha1"}';
/*
WeixinJSBridge.invoke('getBrandWCPayRequest',{
     "appid" : getAppId(), //公衆號名稱,由商戶傳入
     "openid" : "oarYcs5sNGIhUn615Gqb8l6GFYmU",
     "transid" : "1219798201201408013230834317",
     "out_trade_no" : "test000001",
     "deliver_timeStamp" : getTimeStamp(), //時間戳
    "deliver_status" : "1",
    "deliver_msg" : "ok",
     "app_signature" : getSign(), //微信簽名
    "sign_method" : "sha1"
     },function(res){
            if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                alert(res.err_msg);
            }
     }
)
*/
                                                                                                   }else{
jQuery.post(url,str); 
                                                                                                       alert(res.err_msg);
                                                                                                   }
                                                                                                   // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回ok,但並不保證它絕對可靠。
                                                                                                   //所以微信團隊建議,當收到ok返回時,向商戶後臺詢問是否收到交易成功的通知,若收到通知,前端展現交易成功的界面;若此時未收到通知,商戶後臺主動調用查詢訂單接口,查詢訂單的當前狀態,並反饋給前端展現相應的界面。
                                                                                                   
                                                                                                   }); 
                                                                             
                                                                             });
                                      
                                      
                                      
                                      WeixinJSBridge.log('yo~ ready.');
                                      
                                      }, false)
            
            if(jQuery){
                jQuery(function(){
                       
                       var width = jQuery('body').width() * 0.87;
                       jQuery('img').error(function(){
                                           var self = jQuery(this);
                                           var org = self.attr('data-original1');
                                           self.attr("src", org);
                                           self.error(function(){
                                                      auto_remove(this);
                                                      });
                                           });
                       jQuery('img').each(function(){
                                          var self = jQuery(this);
                                          var w = self.css('width');
                                          var h = self.css('height');
                                          w = w.replace('px', '');
                                          h = h.replace('px', '');
                                          if(w <= width){
                                          return;
                                          }
                                          var new_w = width;
                                          var new_h = Math.round(h * width / w);
                                          self.css({'width' : new_w + 'px', 'height' : new_h + 'px'});
                                          self.parents('div.pic').css({'width' : new_w + 'px', 'height' : new_h + 'px'});
                                          });
                       });
            }
            
            </script>
    </head>
    <body>
	
        <div class="WCPay">
            <p>微信支付JSAPI測試頁面a</p>
            <p>請將您申請公衆帳號支付權限的四個參數替換頁面中的參數:partnerid、partnerkey、appid、appkey</p>
            <p>將此頁面放在的支付受權測試目錄下,測試微信號需添加白名單,並在公衆帳號內發起訪問此頁面<p>
			<p>便可檢查公衆帳號支付功能是否正常</p>
            <p></p>
        <a id="getBrandWCPayRequest" href="javascript:void(0);"><h1 class="title">點擊提交測試</h1></a>        </div>
        
       
</body>
</html>

  

測試成功的表現是跳到微信支付輸入密碼的頁面,以下:api

 

js返回一個成功的彈窗。 

提示get_brand_wcpay_request:ok

b.發貨通知

沒有遇到太大困難,代碼以下:

<?php
include_once("/Wxpay/WxPayHelper.php");
$timestamp = strtotime(date("Y-m-d H:i:s"));
$timestamp = time();
$strtoken = "http://www.xxx.cn/token/index.php";     //我是經過這個連接獲取到的個人微信公衆賬號的access_token  ,因我的狀況不一樣
$token = file_get_contents($strtoken);

$obj['appid']               = "xxxxxx";
$obj['appkey']              = "xxxxxxx";
$obj['openid']              = "xxxxxx";   //測試用戶的openId 
$obj['transid']             = "1219798201201408043365444992";
$obj['out_trade_no']        = "test000001";
$obj['deliver_timestamp']   = $timestamp;
$obj['deliver_status']      = "1";
$obj['deliver_msg']         = "ok";


$WxPayHelper = new WxPayHelper();
 //get_biz_sign函數受保護,須要先取消一下,不然會報錯,須要將調用方法的Protect  去掉
$app_signature  = $WxPayHelper->get_biz_sign($obj);

 $jsonmenu = '
 {
     "appid" : "'.$obj['appid'].'",
     "openid" : "'.$obj['openid'].'",
     "transid" : "'.$obj['transid'].'",
     "out_trade_no" : "'.$obj['out_trade_no'].'",
     "deliver_timestamp" : "'.$timestamp.'",
     "deliver_status" : "'.$obj['deliver_status'].'",
     "deliver_msg" : "'.$obj['deliver_msg'].'",
     "app_signature" : "'.$app_signature.'",
     "sign_method" : "sha1"
 }';

$url= "https://api.weixin.qq.com/pay/delivernotify?access_token=".$token;
$result = https_request($url, $jsonmenu);
var_dump($result);

function https_request($url, $data = null){
     $curl = curl_init();
     curl_setopt($curl, CURLOPT_URL, $url);
     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
     curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
     if (!empty($data)){
         curl_setopt($curl, CURLOPT_POST, 1);
         curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
     }
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
     $output = curl_exec($curl);
     curl_close($curl);
     return $output;
 }

?>

這樣去微信後臺支付測試即可以點擊發布,這樣就進入了全網發佈狀態,正式目錄下就能夠進行開發和測試了 

2.正式環境下調用微信支付接口

這裏,我遇到了問題,原本 是調用的微信官方demo中的例子進行的開發,但是遇到了一系列的問題。

a.access_denied,  說明目錄有問題,不過確實咱們申請的域名有問題,而後就一封一封郵件的與微信方溝通,而後把咱們的微信正式目錄修改正確,這樣算是近了一步

b.這裏須要特別提示下,有時候真的不是代碼問題,在咱們改過目錄後,微信中的地址調用能夠了(同事開發的),以前和我報一樣的錯誤,而支付這塊仍是不行,後來仍是與微信e-mail ,不知他們改了什麼,就行了一點

c.接着出現了安卓走通了,可是iphone 提示  get_brand_wcpay_request:fail,估計是參數穿的不正確,可是我是掉的demo的方法,須要本身傳的參數也反覆檢查過,沒有問題,但是就是過不去,後來仍是與微信方面溝通,我傳給微信的全部參數(包括demo中本身獲取的參數)傳給他們的技術支持,他提示我是timestamp 的問題,文檔中強調過一句話,傳給微信的參數必須都是,字符串類型,因此在demo中生成的$tempstamp 兩側加上引號,就ok了,事實證實微信的demo有些問題。固然動手能力強的人經過反覆測試,研究他們的方法,是能夠本身解決的,而我是靠技術支持給我提出

這樣支付接口就算調通了。

代碼日下:

<?php
include_once("Wxpay/WxPayHelper.php");
$commonUtil = new CommonUtil();
$wxPayHelper = new WxPayHelper();
$body = $_GET['ordsubject'];
$trade_no = $_GET['trade_no'];
$total_fee = $_GET['ordtotal_fee'] * 100;
$ordshow_url = $_GET['ordshow_url'];
//$total_fee = "1";
//var_dump($_GET);
$addr_ip = $_SERVER["REMOTE_ADDR"];
$wxPayHelper -> setParameter("bank_type", "WX");
$wxPayHelper -> setParameter("body", $body);
$wxPayHelper -> setParameter("partner", PARTNER);
$wxPayHelper -> setParameter("out_trade_no", $trade_no);
$wxPayHelper -> setParameter("total_fee", $total_fee);
$wxPayHelper -> setParameter("fee_type", "1");
$wxPayHelper -> setParameter("notify_url",NOTIFY_URL);
$wxPayHelper -> setParameter("spbill_create_ip",$addr_ip);
$wxPayHelper -> setParameter("input_charset", "UTF-8");
?>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta content="application/xhtml+xml;charset=UTF-8" http-equiv="Content-Type">
<meta content="no-cache,must-revalidate" http-equiv="Cache-Control">
<meta content="no-cache" http-equiv="pragma">
<meta content="0" http-equiv="expires">
<meta content="telephone=no, address=no" name="format-detection">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />

<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- apple devices fullscreen -->
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<script language="javascript">
function callpay()
{
	WeixinJSBridge.invoke('getBrandWCPayRequest',<?php echo $wxPayHelper -> create_biz_package()  ?>,function(res){
	    WeixinJSBridge.log(res.err_msg);
	    //alert(res.err_code+res.err_desc+res.err_msg);
        if(res.err_msg == "get_brand_wcpay_request:ok"){
            location.href="成功跳轉頁";
        
        }else{
            location.href="失敗跳轉頁";
        
        }
	});
    
        
}

</script>
<body>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<button type="button" onclick="callpay()" style="width:200px;height:200px;">wx pay test</button>
</body>
</html>

  

3.處理回調函數

在支付成功後,微信會返回給當前頁面一個js  alert  "get_brand_wcpay_request:ok",同時會回調,以前提交過的notify_url ,並傳一些參數過去。咱們須要經過這些參數來處理訂單等程序,並在接收到參數後,返回給微信一個字符串 「success」,告訴微信 不用在回調這個連接了,否則微信的補單機制會反覆調用這個連接。

代碼以下:

function  notice(){
if(isset($_GET) && !empty($_GET)){ if($_GET["trade_state"] == "0"){ //寫日誌 foreach($_GET as $k=>$v){ $p .= $k."=".$v."\r\n"; } $post = $GLOBALS["HTTP_RAW_POST_DATA"]; file_put_contents("notice.txt",date("Y-m-d H:i:s")."\r\n".$p."\r\n".$post."\r\n", //寫個日誌文件 $out_trade_no = $_GET["out_trade_no"]; $parameter = array( "out_trade_no" => $out_trade_no, //商戶訂單編號; ); if(!checkorderstatus($out_trade_no)){ //判斷訂單是否處理過,若是處理過就不進行更改狀態 orderhandle($parameter); //進行訂單處理,並傳送從支付寶返回的參數; } echo "success"; } }
}
}

這樣支付和通知接口基本完成了,像發貨通知、訂單查詢、告警通知接口,咱們基本用不到,就沒有接

還有一條須要注意的地方就是,微信不容許使用post、get傳值,我是這樣作的,a頁面經過post向b頁面傳送參數,b頁面接收到參數後,在整合後,調用微信接口,傳給微信。可是遇到的問題是,b頁面能夠接受到參數,可是沒法調用微信接口,點擊按鈕沒有反應。後來我是將post傳值改成header("location:xxxx&id=1");location後面拼接參數的形式來傳參給b頁面,這樣就沒有問題了。

相關文章
相關標籤/搜索