微信JSAPI支付

阿珏酱發表於2024-05-20

Tips:當你看到這個提示的時候,說明當前的文章是由原emlog部落格系統搬遷至此的,文章釋出時間已過於久遠,編排和內容不一定完整,還請諒解`

微信JSAPI支付

日期:2019-3-30 阿珏 折騰程式碼 瀏覽:1883次 評論:6條

前段時間一直在做微信相關的業務,雖說不是什麼新技術,但之前一直沒有機會接觸到,然後踩了些坑,抽空整理記錄下。
微信支付一共分為7種,分為是:付款碼支付、JSAPI支付、Native支付、APP支付、H5支付、小程式支付、人臉支付。
此次業務中使用到的是微信JSAPI支付:使用者透過微信掃碼、關注公眾號等方式進入商家H5頁面,並在 微信內 呼叫 JSSDK完成支付

文件: https://pay.weixin.qq.com/wiki/doc/api/index.html


SDK: https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1

JSAPI支付需要在微信中的瀏覽器開啟才能喚起微信支付,效果如下圖

微信JSAPI支付
附上介面程式碼
程式碼中使用了模板引擎

html:
<div class="am-modal-bd">
	<img src="{$competition['avatar']}" alt=""><br>
	<span style="font-size: 13px;color: #72c6ef">{$competition['username']}</span><br>
	<span id="tips" style="font-size: 13px"></span>
  <ul class="ul_box">
	<li>
		<div></div>
		<div class="label_box">
			<label>
				<input type="radio" name="price" value="{$prices[0]}" checked="">
				<div class="active"><span class="am-icon-diamond"></span> {$prices[0]}鑽</div>
			</label>
			<label>
				<input type="radio" name="price" value="{$prices[1]}">
				<div><span class="am-icon-diamond"></span> {$prices[1]}鑽</div>
			</label>
			<label>
				<input type="radio" name="price" value="{$prices[2]}">
				<div><span class="am-icon-diamond"></span> {$prices[2]}鑽</div>
			</label>
		</div>
	</li>
	<li>
		<div></div>
		<div class="label_box">
			<label>
				<input type="radio" name="price" value="{$prices[3]}">
				<div><span class="am-icon-diamond"></span> {$prices[3]}鑽</div>
			</label>
			<label>
				<input type="radio" name="price" value="{$prices[4]}">
				<div><span class="am-icon-diamond"></span> {$prices[4]}鑽</div>
			</label>
			<label>
				<input type="number" name="price" id="price" class="input" placeholder="自定義">
			</label>
		</div>
	</li>
  </ul>
  <span style="font-size: 13px">注:1鑽=1元,1鑽={$activity['offset']}票</span><br>
  <button type="button" class="am-btn am-btn-primary  am-radius" onclick="callpay()" style="margin-top: 5px;">立即微信支付</button>
</div>
JavaScript:
// 投票
var offset = {$activity['offset']};
$('#tips').html('正在給{$competition['code']}號贈送{$prices[0]}鑽='+({$prices[0]}*offset)+'票');
$('#vote').click(function(){
	$.post('/index/index/detailed.html?cid={$cid}&aid={$aid}',{
		formhash :'{FORMHASH}',
		submit:'1',
		type:1,
		openid:'{$_G['member']['openid']}'
	},function(res){
		alert(res.msg);
		if (res.code == 0) {
			$('.box-1 span').text(res.data.all);
			$('.box-2 span').text(res.data.rank);
			$('.box-3 span').text(res.data.up + '票');
		}
	});
})
/* jQuery物件級別外掛擴充套件 */
$.fn.extend({
	/* 單選框 */
	hlRadio:function () {
		var radioEl=$(this);
		radioEl.click(function () {
			var price = 0;
			price = $('input:radio:checked').val();
			$('#price').val('');
			$('#tips').html('正在給{$competition['code']}號贈送'+price+'鑽='+(price*offset)+'票');
			radioEl.siblings("div").removeClass("active");
			$(this).siblings("div").addClass("active");
		});
	},
});
$("input[name='price']").hlRadio();
$('#price').bind('input propertychange', function(){
	var price = 0;
	price = $('#price').val();
	$('#tips').html('正在給{$competition['code']}號贈送'+price+'鑽='+(price*offset)+'票');
})
CSS部分
.ul_box {
	margin:0 auto;
	padding:0;
	list-style:none;
	width: 344px;
}
.ul_box>li {
	padding:10px 10px 0 10px;
	overflow:hidden;
	border-bottom:#e5e5e5 solid 1px;
}
.ul_box>li:last-child {
	border-bottom:none;
}
.ul_box>li>div {
	float:left;
}
.ul_box>li>div:nth-child(1) {
	width:100px;
}
.ul_box>li>div:nth-child(2) {
	width:480px;
	overflow:hidden;
}
.label_box>label {
	display:block;
	float:left;
	margin:0 10px 10px 0;
	position:relative;
	overflow:hidden;
}
.label_box>label>input {
	position:absolute;
	top:0;
	left:-20px;
}
.label_box>label>div {
	width:100px;
	text-align:center;
	border:#dddddd solid 1px;
	height:40px;
	line-height:40px;
	color:#666666;
	user-select:none;
	overflow:hidden;
	position:relative;
	height: 75px;
}
.label_box>label>div.active{
	border:#d51917 solid 1px;
	background-color: #fff9f8;
	color:#d51917;
}
.label_box>label>div.active:after {
	content:'';
	display:block;
	width:20px;
	height:20px;
	background-color:#d51917;
	transform:skewY(-45deg);
	position:absolute;
	bottom:-10px;
	right:0;
	z-index:1;
}
.label_box>label>div.active:before {
	content:'';
	display:block;
	width:3px;
	height:8px;
	border-right:#ffffff solid 2px;
	border-bottom:#ffffff solid 2px;
	transform:rotate(35deg);
	position:absolute;
	bottom:2px;
	right:4px;
	z-index:2;
}
.input{
	height: 75px!important;
	border: 1px solid #DDD!important;
	position: initial!important;
	width: 100px!important;
	text-align: center!important;
	padding: 5px!important;
	font-size: 19px!important;
}
.am-modal-bd{
	border-bottom: none;
	margin-top: 20px;
}
.am-modal-bd img{
	width: 50px;
	border-radius: 50px;
}
.am-icon-diamond{
	font-size: 20px;
	display: block;
	text-align: center;
	margin-bottom: -7px;
}
喚起微信支付,此處的js程式碼僅在微信手機瀏覽器中生效
//呼叫微信JS api 支付
function jsApiCall(appId,timeStamp,nonceStr,package,signType,paySign)
{
	WeixinJSBridge.invoke(
		'getBrandWCPayRequest',{
			"appId":appId,     //公眾號名稱,由商戶傳入
			"timeStamp":timeStamp,         //時間戳,自1970年以來的秒數
			"nonceStr":nonceStr, //隨機串
			"package":package,
			"signType":signType,         //微信簽名方式:
			"paySign":paySign //微信簽名
		},
		function(res){
			if(res.err_msg == "get_brand_wcpay_request:ok" ){
				WeixinJSBridge.log(res.err_msg);
				alert('投票成功');
				// window.history.go(-1);
				var url = '/index/index/detailed.html?cid={$cid}&aid={$aid}';
				window.location.href=url;
				// location.reload();
				return false;
			}
			alert('投票失敗');
		}
	);
}
// 支付
function callpay()
{
	var price = '';
	if ($('#price').val()) {
		price = $('#price').val();
	}else if($('input:radio:checked').val()){
		price = $('input:radio:checked').val();
	}else{
		alert('請輸入購買數量');
	}
	if (Number(price) <= 0) {
		alert('請輸入一個大於0的正數');
		$('#price').val('');
		return false
	}
	$.post('/index/index/weixin.html?cid={$cid}&aid={$aid}',{
		formhash :'{FORMHASH}',
		submit:'1',
		type:1,
		pay:1,
		price: price,
		openid:'{$_G['member']['openid']}'
	},function(res){
		if (res.code ==0) {
			jsApiCall(
				res.data.appId,
				res.data.timeStamp,
				res.data.nonceStr,
				res.data.package,
				res.data.signType,
				res.data.paySign,
			);
		}else{
			alert(res.msg);
		}
	});
	// if (typeof WeixinJSBridge == "undefined"){
	// 	if( document.addEventListener ){
	// 		document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
	// 	}else if (document.attachEvent){
	// 		document.attachEvent('WeixinJSBridgeReady', jsApiCall);
	// 		document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
	// 	}
	// }else{
	// }
}
介面基於妹子UI,效果如下圖
微信JSAPI支付
PHP後端,建立本地訂單
//①、獲取使用者openid
$tools = new JsApiPay();
$openid = $tools->Getopenid(); //如果已經有了,可以直接賦值
//②、統一下單
$input = new WxPayUnifiedOrder();
$input->SetBody("購買鑽石票");
$input->SetAttach(json_encode([  //附加引數
	'order' => $order_id,
	'cid' => $cid,
	'uid' => $_G['uid'],
	'aid' => $aid,
	'md5' => $md5
]));
$input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis"));
$input->SetTotal_fee($price);  //價格,單位分,“元記得*100”
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
$input->SetGoods_tag("test");
$input->SetNotify_url(WX_NOTIFY_URL);
$input->SetTrade_type("JSAPI");
$input->Setopenid($openid);
$order = WxPayApi::unifiedOrder($input);
$jsApiParameters = $tools->GetJsApiParameters($order);
//儲存本地訂單
DB::insert('vote_order', [
	'order' => $order_id,
	'time' => time(),
	'price' => intval($_GET['price']),
	'uid' => $_G['uid'],
	'openid' => $openid,
	'ip' => $ip
]);
Json(['code' => 0, 'msg' => '成功','data' => json_decode($jsApiParameters,true)]);
//獲取共享收貨地址js函式引數
// $editAddress = $tools->GetEditAddressParameters();
// debug($jsApiParameters);
//③、在支援成功回撥通知中處理成功之後的事宜,見 notify.php
/**
 * 注意:
 * 1、當你的回撥地址不可訪問的時候,回撥通知會失敗,可以透過查詢訂單來確認支付是否成功
 * 2、jsapi支付時需要填入使用者openid,WxPay.JsApiPay.php中有獲取openid流程 (文件可以參考微信公眾平臺“網頁授權介面”,
 * 參考http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html)
 */
<?php
/**
 *
 * 回撥基礎類
 * @author widyhu
 *
 */
class WxPayNotify extends WxPayNotifyReply {
	/**
	 *
	 * 回撥入口
	 * @param bool $needSign  是否需要簽名輸出
	 */
	final public function Handle($needSign = true) {
		$msg = "OK";
		//當返回false的時候,表示notify中呼叫NotifyCallBack回撥失敗獲取簽名校驗失敗,此時直接回復失敗
		$result = WxpayApi::notify(array($this, 'NotifyCallBack'), $msg);
// 這是一個除錯技巧 
// file_put_contents('a.txt',print_r($msg,true));
		if ($result == false) {
			$this->SetReturn_code("FAIL");
			$this->SetReturn_msg($msg);
			$this->ReplyNotify(false);
			return;
		} else {
			//該分支在成功回撥到NotifyCallBack方法,處理完成之後流程
			$attach = json_decode($msg['attach'], true);
			// file_put_contents('aaaa.txt',print_r($attach,true));
			$cid = $attach['cid'];
			$aid = $attach['aid'];
			$uid = $attach['uid'];
			$order = $attach['order'];
			$md5 = $attach['md5'];
			$vote_order = DB::fetch_first("SELECT * FROM " . DB::table('vote_order') . " WHERE `order`='{$order}' and status = 0");
			if (!$vote_order) {
				$this->SetReturn_code("SUCCESS");
				$this->SetReturn_msg("OK");
			}
			$sign_md5 = md5($vote_order['openid'] . $vote_order['order'] . $vote_order['uid'] );
			if ($sign_md5 == $md5) {
				// 所有活動資訊
				$activity = DB::fetch_first("SELECT * FROM " . DB::table('vote_activity') . " WHERE aid={$aid} ");
				$ip = $vote_order['ip'];
				$jewel_vote = $vote_order['price'] * $activity['offset'];
				// 投票
				DB::query("UPDATE `pre_vote_competition` SET `jewel`=jewel+{$vote_order['price']},jewel_vote=jewel_vote+{$jewel_vote} WHERE (`cid`='{$cid}')");
				// 增加投票記錄
				DB::insert('vote_record',[
					'time' => TIMESTAMP,
					'openid' => $vote_order['openid'],
					'type' => 1,
					'aid' => $aid,
					'cid' => $cid,
					'ip' => $ip,
					'price' => $vote_order['price'],
					'jewel_vote' => $jewel_vote,
					'uid' => $uid,
					'order' => $vote_order['order']
				]);
				// 更新訂單狀態
				DB::query("UPDATE `pre_vote_order` SET `status` = 1 WHERE `order`={$order}");
				// 更新活動總收益
				DB::query("UPDATE `pre_vote_activity` SET `profit`=profit+{$vote_order['price']} WHERE `aid`={$aid}");
			}
			$this->SetReturn_code("SUCCESS");
			$this->SetReturn_msg("OK");
		}
		$this->ReplyNotify($needSign);
	}
	/**
	 *
	 * 回撥方法入口,子類可重寫該方法
	 * 注意:
	 * 1、微信回撥超時時間為2s,建議使用者使用非同步處理流程,確認成功之後立刻回覆微信伺服器
	 * 2、微信伺服器在呼叫失敗或者接到回包為非確認包的時候,會發起重試,需確保你的回撥是可以重入
	 * @param array $data 回撥解釋出的引數
	 * @param string $msg 如果回撥處理失敗,可以將錯誤資訊輸出到該方法
	 * @return true回撥出來完成不需要繼續回撥,false回撥處理未完成需要繼續回撥
	 */
	public function NotifyProcess($data, &$msg) {
		//TODO 使用者基礎該類之後需要重寫該方法,成功的時候返回true,失敗返回false
		return true;
	}
	/**
	 *
	 * notify回撥方法,該方法中需要賦值需要輸出的引數,不可重寫
	 * @param array $data
	 * @return true回撥出來完成不需要繼續回撥,false回撥處理未完成需要繼續回撥
	 */
	final public function NotifyCallBack($data) {
		$msg = "OK";
		$result = $this->NotifyProcess($data, $msg);
		if ($result == true) {
			$this->SetReturn_code("SUCCESS");
			$this->SetReturn_msg("OK");
		} else {
			$this->SetReturn_code("FAIL");
			$this->SetReturn_msg($msg);
		}
		return $result;
	}
	/**
	 *
	 * 回覆通知
	 * @param bool $needSign 是否需要簽名輸出
	 */
	final private function ReplyNotify($needSign = true) {
		//如果需要簽名
		if ($needSign == true &&
			$this->GetReturn_code($return_code) == "SUCCESS") {
			$this->SetSign();
		}
		WxpayApi::replyNotify($this->ToXml());
	}
}
回撥類呼叫
<?php
if(!defined('IN_DISCUZ')) {
	exit('Access Denied');
}
require_once "./source/plugin/vote/class/WxpayAPI_php_v3/lib/WxPay.Api.php";
require_once "./source/plugin/vote/class/WxpayAPI_php_v3/lib/WxPay.Notify.php";
require_once "./source/plugin/vote/class/WxpayAPI_php_v3/example/WxPay.JsApiPay.php";
require_once './source/plugin/vote/class/WxpayAPI_php_v3/example/log.php';
//初始化日誌
// $logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
// $log = Log::Init($logHandler, 15);
// Log::DEBUG("begin notify");
$notify = new WxPayNotify();
$notify->Handle(false);
注意:微信支付需要在後臺配置一個微信支付授權目錄,其中的APPID等引數在微信支付後臺可獲取到。
微信公眾號資訊配置
APPID:繫結支付的APPID(必須配置,開戶郵件中可檢視)
MCHID:商戶號(必須配置,開戶郵件中可檢視)
KEY:商戶支付金鑰,參考開戶郵件設定(必須配置,登入商戶平臺自行設定)
設定地址:https://pay.weixin.qq.com/index.php/account/api_cert
APPSECRET:公眾帳號secert(僅JSAPI支付的時候需要配置, 登入公眾平臺,進入開發者中心可設定),
獲取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
微信JSAPI支付

本部落格所有文章 如無特別註明 均為原創。 作者: 阿珏 複製或轉載請 以超連結形式 註明轉自 阿珏部落格
原文地址《 微信JSAPI支付

網友評論:

蘇寶寶 2年前 (2019-04-06)
這要怎麼複製程式碼呀 我想實戰操作下 求博主給個程式碼的百度雲連結可否

阿珏 2年前 (2019-04-07)
@蘇寶寶:微信官方給的SDK中有呼叫示例,文章中只是基本的html程式碼,複製去你也是沒辦法直接使用的,僅供參考

譯丶淺夏 2年前 (2019-04-03)
表情包怎麼整合的,能不能出個教程大佬

阿珏 2年前 (2019-04-03)
@譯丶淺夏:這個有現成的外掛,可以去搜一下,但是由於每個部落格的模板都不一樣,得花點時間自己整上去

Ricky 2年前 (2019-03-31)
前提是要有個可以開通支付的微信公眾號

楊小杰部落格 2年前 (2019-03-30)
朕已閱

相關文章