您好,登錄后才能下訂單哦!
好久沒有更新博客,最近做項目遇到了微信支付,整理一下需求,目的一個活動頁面需要調微信支付!
應用框架THINKPHP5.1
注意:微信支付 需要注意 如果是h6頁面調取支付的話,需要靜默一個登錄狀態(tài)獲取code,這樣才可以保證支付調取的參數(shù)openid正常,這里的坑填了好久,微信內瀏覽器h6用戶輸入完手機號登錄后,頁面存cookie信息,有時候會不更新獲取的openid 導致“下單賬號和支付賬號不一致,請核對”;
微信內瀏覽器刷新頁面用jq執(zhí)行: window.location.href = location.href+'?time='+((new Date()).getTime());
直接上代碼:前端
function get_form(){
var price1 =$(".get_price1").val();
var price2 =$(".get_price2").val();
var price3 =$(".get_price3").val();
var price4 =$(".get_price4").val();
var pid =$(".pid").val();
var username =$(".username").val();
var mobile =$(".mobile").val();
var address =$(".address").val();
if(!username && !mobile && !address){
layer.alert('收貨人信息不能為空');
return false;
}
$.post("home/get_from",//get_from 是后臺請求支付的邏輯
{"price1":price1,"price2":price2,"price3":price3,"price4":price4,"username":username,"mobile":mobile,"address":address,"pid":pid},function(apiConfig){
console.log(apiConfig);
var ua = navigator.userAgent.toLowerCase();//獲取判斷用的對象是微信內還是外部
if (ua.match(/MicroMessenger/i) == "micromessenger") {
//內部
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":apiConfig.appId, //公眾號名稱,由商戶傳入
"timeStamp":apiConfig.timeStamp, //時間戳,自1970年以來的秒數(shù)
"nonceStr":apiConfig.nonceStr, //隨機串
"package":apiConfig.package,
"signType":apiConfig.signType, //微信簽名方式:
"paySign":apiConfig.paySign //微信簽名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ){
window.location.href ="方法路徑"
}
});
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
}else{
//外部
var url="支付成功跳轉";
window.location.href =apiConfig.mweb_url+"&redirect_url="+url;
}
});
}
后端代碼:
靜默登錄 請求頁面的時候通過tp5 redirect重置路由
再進入頁面的方法里 查找有沒有openid
$sa = Cookie::get('kj_phone');
$uid =$sa['id'];//用戶id
$userAgent = $_SERVER['HTTP_USER_AGENT']; // 判斷是 公眾號支付還是外部網址支付
if (strpos($userAgent, 'MicroMessenger')) { // 公眾號支付
$uid =$sa['id'];//用戶id
$open_id= Cache::get($uid);
// print_r($open_id);
if(empty($open_id)){
$this->redirect("https://open.weixin.qq.com/connect/oauth3/authorize?appid=Appid&redirect_uri=頁面進入后先通過get_open方法獲得code獲取openid&response_type=code&scope=snsapi_base&state=1#wechat_redirect");
}
}
get_open方法
public function get_open(){
$code1=empty($_GET['code']) ? '' : $_GET['code'];
$sa =Cookie::get('kj_phone');
// $appId ='appId ';
//$secret ='secret';
$get_token_url = 'https://api.weixin.qq.com/sns/oauth3/access_token?appid=Appid&secret=secre&code=' . $code1 . '&grant_type=authorization_code';
$json_obj = $this->http_request($get_token_url);
$json_obj = json_decode($json_obj,true);
$openid = empty($json_obj['openid']) ? "" : $json_obj['openid'];
$uid =$sa['id'];//用戶id
Cache::set($uid,$openid,3600);
if($code1 == ''){
$this->redirect('重定向到渲染頁面');
}
if(!empty($open_id)){
$this->redirect('重定向到渲染頁面');
}else{
$this->redirect('重定向到渲染頁面');
}
}
get_from:
public function get_from(){
if(request()->isPost()){
$data =input("post.");// 前端傳過來的數(shù)據(jù) 自己寫邏輯吧
$userAgent = $_SERVER['HTTP_USER_AGENT']; // 判斷是 公眾號支付還是外部網址支付
if (strpos($userAgent, 'MicroMessenger')) { // 公眾號支付
$sa = Cookie::get('kj_phone');
$uid =$sa['id'];//用戶id
$open_id= Cache::get($uid);
//print_r($open_id);exit;
$return = $this->weixinapp($open_id,$body,$order_id,$price,$attact);
return $return;
}else{
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$parameters = array(
'appid' => "小程序ID", //小程序ID
'mch_id' => "商戶號", //商戶號
'attach'=>$attact,
'nonce_str' => $this->createNoncestr(), //隨機字符串
'body' =>$body, //商品描述
'out_trade_no' =>$order_id,//商戶訂單號
'total_fee' => $price * 100, //總金額 單位 分
'spbill_create_ip' => '111111', //終端IP
'notify_url' => '回調地址', //通知地址 確保外網能正常訪問
'trade_type' => 'MWEB'//交易類型
);
//統(tǒng)一下單簽名
$parameters['sign'] = $this->getSign($parameters);
$xmlData = $this->arrayToXml($parameters);
$return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60));
return $return;
}
}
}
}
//統(tǒng)一下單接口
private function weixinapp($openid,$body,$orderId,$price,$attact) {
$unifiedorder = $this->unifiedorder($openid,$body,$orderId,$price,$attact);
$parameters = array(
'appId' => "appId", //小程序ID
'timeStamp' => '' . time() . '', //時間戳
'nonceStr' => $this->createNoncestr(), //隨機串
'package' => 'prepay_id=' . $unifiedorder['prepay_id'], //數(shù)據(jù)包
'signType' => 'MD5'//簽名方式
);
//簽名
$parameters['paySign'] = $this->getSign($parameters);
return $parameters;
}
//作用:產生隨機字符串,不長于32位
private function createNoncestr($length = 32) {
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
private function getSign($Obj) {
//halt($Obj);
foreach ($Obj as $k => $v) {
$Parameters[$k] = $v;
}
//簽名步驟一:按字典序排序參數(shù)
ksort($Parameters);
$String = $this->formatBizQueryParaMap($Parameters, false);
//簽名步驟二:在string后加入KEY
$String = $String . "&key=d18e10ad06222c972499296f1cefa481" ;
//簽名步驟三:MD5加密
$String = md5($String);
//簽名步驟四:所有字符轉為大寫
$result_ = strtoupper($String);
return $result_;
}
///作用:格式化參數(shù),簽名過程需要使用
private function formatBizQueryParaMap($paraMap, $urlencode) {
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if ($urlencode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
$reqPar="";
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
//數(shù)組轉換成xml
private function arrayToXml($arr) {
$xml = "<root>";
foreach ($arr as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
} else {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</root>";
return $xml;
}
//xml轉換成數(shù)組
private function xmlToArray($xml) {
//禁止引用外部xml實體
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring), true);
return $val;
}
function http_curl($url){//用curl傳參
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//關閉ssl驗證
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch,CURLOPT_HEADER, 0);
$output = curl_exec($ch);
curl_close($ch);
return json_decode($output, true);
}
private static function postXmlCurl($xml, $url, $second = 30)
{
$ch = curl_init();
//設置超時
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //嚴格校驗
//設置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求結果為字符串且輸出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 40);
set_time_limit(0);
//運行curl
$data = curl_exec($ch);
//返回結果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
throw new WxPayException("curl出錯,錯誤碼:$error");
}
}
//回調
private function unifiedorder($openid,$body,$orderId,$price,$attact) {
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$parameters = array(
'appid' => "appid", //小程序ID
'mch_id' =>"mch_id", //商戶號
'attach'=>$attact,
'nonce_str' => $this->createNoncestr(), //隨機字符串
'body' => $body,
'out_trade_no'=> $orderId,
'total_fee' => $price * 100,
'spbill_create_ip' => '11111111', //終端IP
'notify_url' => 回調, //通知地址 確保外網能正常訪問
'openid' => $openid, //用戶id
'trade_type' => 'JSAPI'//交易類型
);
//統(tǒng)一下單簽名
$parameters['sign'] = $this->getSign($parameters);
$xmlData = $this->arrayToXml($parameters);
$return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60));
return $return;
}
//回調
public function callback(){
$xml = file_get_contents("php://input");
// 將XML 轉換為數(shù)組
$xml = json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA));
$result = json_decode($xml, true);
//如果成功返回
if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
$where['order_id']=$result['out_trade_no'];
$data_e['states']=2;
$ud= db('hc_pr_order')->where($where)->update($data_e);
}
// 給微信的返回值
if ($ud) {
$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
}else{
$str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[簽名失敗]]></return_msg></xml>';
}
return $str;
return $result;
}
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。