日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

php根据浏览器调用支付_Android通过外部浏览器调用微信H5支付,Android+PHP详解

發(fā)布時(shí)間:2023/12/20 php 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php根据浏览器调用支付_Android通过外部浏览器调用微信H5支付,Android+PHP详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

看了好多關(guān)于講解微信H5支付開發(fā)的文章,大多數(shù)都是通過微信內(nèi)部瀏覽器來調(diào)用支付接口(其實(shí)就是公眾號(hào)支付),可能是因?yàn)镠5支付接口剛開放不久吧。

微信官方體驗(yàn)鏈接:http://wxpay.wxutil.com/mch/pay/h5.v2.php,請(qǐng)?jiān)谖⑿磐鉃g覽器打開。

看了上面的體驗(yàn)鏈接,如果感興趣,可以接著往下看,希望對(duì)你有所幫助。

一、Android端

Android端代碼相對(duì)來說比較簡(jiǎn)單一些,我這邊直接調(diào)用系統(tǒng)瀏覽器打開H5支付頁(yè)面Intent?intent?=?new?Intent();

intent.setAction("android.intent.action.VIEW");

Uri?content_url?=?Uri.parse(url);?//url里面包含了后端需要用到的參數(shù),例如金額,用戶ID

intent.setData(content_url);

startActivity(intent);

剛開始考慮過使用webview來加載支付頁(yè)面,但是調(diào)試接口的時(shí)候發(fā)現(xiàn)一直報(bào)如下錯(cuò)誤:

微信官方報(bào)錯(cuò)示例圖

根據(jù)微信官方的報(bào)錯(cuò)示例可以看出,應(yīng)該是webview中沒有設(shè)置referer導(dǎo)致的。于是,我按照說明加上了referer,然鵝,并沒有什么卵用,依然報(bào)錯(cuò)。我只好放棄使用webview改用系統(tǒng)瀏覽器。使用系統(tǒng)瀏覽器的弊端還是挺明顯的,客戶端和后臺(tái)傳值不好處理(正在看文章的你,如果用webview調(diào)用成功了,還請(qǐng)賜教)

二、PHP端

1.獲取從Android端傳過來的參數(shù)

目前我只想到一種方法,就是通過url攜帶參數(shù)給服務(wù)端傳值,OK,獲取方式如下://當(dāng)前頁(yè)面的URL地址為:http://www.XXXXX.com/wechatpay/h5Pay.php?money=100&uid=337828932$string?=?$_SERVER['QUERY_STRING'];//通過$_SERVER['QUERY_STRING']函數(shù)獲取url地址?后面的值$androidData?=?convertUrlQuery($string);//將字符串$string轉(zhuǎn)化為數(shù)組$money?=?$androidData['money?'];//獲取money值?100$uid?=?$androidData['uid'];//獲取用戶ID?337828932

上面用到的convertUrlQuery函數(shù)代碼//將字符串參數(shù)變?yōu)閿?shù)組function?convertUrlQuery($query){

$queryParts?=?explode('&',?$query);

$params?=?array();????foreach?($queryParts?as?$param)?{

$item?=?explode('=',?$param);

$params[$item[0]]?=?$item[1];

}????return?$params;

}

2.調(diào)用微信統(tǒng)一下單API2.1 具體參數(shù)名稱以及各參數(shù)的用途請(qǐng)查看微信官方文檔 統(tǒng)一下單API//配置需要傳遞給微信的參數(shù)

$input?=?new?WxPayUnifiedOrder();

$input->SetBody("xxxx-商品購(gòu)買");

$input->SetAttach("xxxx");

$input->SetDevice_info("WEB");

$input->SetOut_trade_no(WxPayConfig::MCHID?.?date("YmdHis").$uid);//把UID加在末尾主要用于識(shí)別用戶,給對(duì)應(yīng)的用戶充值余額

$input->SetTotal_fee($money);

$input->SetTime_start(date("YmdHis"));

$input->SetTime_expire(date("YmdHis",?time()?+?600));

$input->SetGoods_tag("t");

$input->SetNotify_url("http://www.xxxxx.com/wechatpay/notify.php");//用于接收微信下發(fā)的支付結(jié)果通知

$input->SetTrade_type("MWEB");

$input->SetOpenid($openId);

$input->SetScene_info("{\"h5_info\":?\"h5_info\"{\"type\":?\"Wap\",\"wap_url\":?\"http://www.xxxxx.com/shop\",\"wap_name\":?\"xxx\"}}");2.2 接下來通過$order = WxPayApi::unifiedOrder($input);獲取微信返回的參數(shù),unifiedOrder函數(shù)具體實(shí)現(xiàn)如下/**

*

*?統(tǒng)一下單,WxPayUnifiedOrder中out_trade_no、body、total_fee、trade_type必填

*?appid、mchid、spbill_create_ip、nonce_str不需要填入

*?@param?WxPayUnifiedOrder?$inputObj

*?@param?int?$timeOut

*?@throws?WxPayException

*?@return?成功時(shí)返回,其他拋異常

*/

public?static?function?unifiedOrder($inputObj,?$timeOut?=?6)

{

$url?=?"https://api.mch.weixin.qq.com/pay/unifiedorder";????????//檢測(cè)必填參數(shù)

if(!$inputObj->IsOut_trade_noSet())?{????????????throw?new?WxPayException("缺少統(tǒng)一支付接口必填參數(shù)out_trade_no!");

}else?if(!$inputObj->IsBodySet()){????????????throw?new?WxPayException("缺少統(tǒng)一支付接口必填參數(shù)body!");

}else?if(!$inputObj->IsTotal_feeSet())?{????????????throw?new?WxPayException("缺少統(tǒng)一支付接口必填參數(shù)total_fee!");

}else?if(!$inputObj->IsTrade_typeSet())?{????????????throw?new?WxPayException("缺少統(tǒng)一支付接口必填參數(shù)trade_type!");

}

//異步通知url未設(shè)置,則使用配置文件中的url

if(!$inputObj->IsNotify_urlSet()){

$inputObj->SetNotify_url(WxPayConfig::NOTIFY_URL);//異步通知url

}

$inputObj->SetAppid(WxPayConfig::APPID);//公眾賬號(hào)ID

$inputObj->SetMch_id(WxPayConfig::MCHID);//商戶號(hào)

$inputObj->SetSpbill_create_ip(self::getIp());//終端ip

//$inputObj->SetSpbill_create_ip("1.1.1.1");

$inputObj->SetNonce_str(self::getNonceStr());//隨機(jī)字符串

//簽名

$inputObj->SetSign();

$xml?=?$inputObj->ToXml();

$startTimeStamp?=?self::getMillisecond();//請(qǐng)求開始時(shí)間

$response?=?self::postXmlCurl($xml,?$url,?false,?$timeOut);

$result?=?WxPayResults::Init($response);????????self::reportCostTime($url,?$startTimeStamp,?$result);//上報(bào)請(qǐng)求花費(fèi)時(shí)間

return?$result;

}2.3 上面代碼中需要注意的有以下3點(diǎn)獲取客服端的真實(shí)IP地址使用REMOTE_ADDR只能獲取訪問者本地連接中設(shè)置的IP。經(jīng)本人粗略測(cè)試,使用UC瀏覽的時(shí)候?qū)o法直接獲取真實(shí)IP,這是如果把這個(gè)IP傳過去,微信將會(huì)返回 網(wǎng)絡(luò)環(huán)境未能通過安全驗(yàn)證,請(qǐng)稍后再試 的錯(cuò)誤

這時(shí)可以使用以下方式獲取用戶真實(shí)IP//獲取用戶真實(shí)IP

public?static?function?getIp(){

$ip?=?'';????????if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){

$ip?=?$_SERVER['HTTP_X_FORWARDED_FOR'];

}elseif(isset($_SERVER['HTTP_CLIENT_IP'])){

$ip?=?$_SERVER['HTTP_CLIENT_IP'];

}else{

$ip?=?$_SERVER['REMOTE_ADDR'];

}

$ip_arr?=?explode(',',?$ip);????????return?$ip_arr[0];

}把參數(shù)轉(zhuǎn)換成XML格式在這JSON橫行的年代,還使用XML格式傳遞數(shù)據(jù),也許這是微信的高端操作,也許是他們以前的框架就是那樣,這我們就不管了。直接上代碼/**

*?輸出xml字符

*?@throws?WxPayException

**/

public?function?ToXml()

{????????if(!is_array($this->values)

||?count($this->values)?<=?0)

{????????????throw?new?WxPayException("數(shù)組數(shù)據(jù)異常!");

}

$xml?=?"";????????foreach?($this->values?as?$key=>$val)

{????????????if?(is_numeric($val)){

$xml.="".$val."".$key.">";

}else{

$xml.="".$key.">";

}

}

$xml.="";????????return?$xml;

}簽名方法

簽名生成的通用步驟如下:

第一步,設(shè)所有發(fā)送或者接收到的數(shù)據(jù)為集合M,將集合M內(nèi)非空參數(shù)值的參數(shù)按照參數(shù)名ASCII碼從小到大排序(字典序),使用URL鍵值對(duì)的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特別注意以下重要規(guī)則:參數(shù)名ASCII碼從小到大排序(字典序);

如果參數(shù)的值為空不參與簽名;

參數(shù)名區(qū)分大小寫;

驗(yàn)證調(diào)用返回或微信主動(dòng)通知簽名時(shí),傳送的sign參數(shù)不參與簽名,將生成的簽名與該sign值作校驗(yàn)。

微信接口可能增加字段,驗(yàn)證簽名時(shí)必須支持增加的擴(kuò)展字段

第二步,在stringA最后拼接上key得到stringSignTemp字符串,并對(duì)stringSignTemp進(jìn)行MD5運(yùn)算,再將得到的字符串所有字符轉(zhuǎn)換為大寫,得到sign值signValue。

key設(shè)置路徑:微信商戶平臺(tái)(pay.weixin.qq.com)-->賬戶設(shè)置-->API安全-->密鑰設(shè)置/**

*?生成簽名

*?@return?簽名

*/

public?function?MakeSign()

{????????//簽名步驟一:按字典序排序參數(shù)

ksort($this->values);

$string?=?$this->ToUrlParams();????????//簽名步驟二:在string后加入KEY

$string?=?$string?.?"&key=".WxPayConfig::KEY;????????//簽名步驟三:MD5加密

$string?=?md5($string);????????//簽名步驟四:所有字符轉(zhuǎn)為大寫

$result?=?strtoupper($string);????????return?$result;

}????/**

*?格式化參數(shù)??--格式化成url參數(shù)

*/

public?function?ToUrlParams()

{

$buff?=?"";????????foreach?($this->values?as?$k?=>?$v)

{????????????if($k?!=?"sign"?&&?$v?!=?""?&&?!is_array($v)){

$buff?.=?$k?.?"="?.?$v?.?"&";

}

}

$buff?=?trim($buff,?"&");????????return?$buff;

}2.4 通過返回的mweb_url參數(shù)調(diào)起微信APPif?($order['mweb_url'])?{

$orderId?=?$input->GetOut_trade_no();

$payUrl?=?$order['mweb_url']."&redirect_url=http%3A%2F%2Fwww.xxxx.com%2Fwechatpay%2Forderquery.php%3Ftransaction_id%3D".$orderId;

Log::DEBUG($payUrl);????????//通過JS打開鏈接,調(diào)起微信APP支付

echo?"";

}這里詳細(xì)解釋一下payUrl中redirect_url參數(shù)的含義

正常流程用戶支付完成后會(huì)返回至發(fā)起支付的頁(yè)面,如需返回至指定頁(yè)面,則可以在MWEB_URL后拼接上redirect_url參數(shù),來指定回調(diào)頁(yè)面。

如,您希望用戶支付完成后跳轉(zhuǎn)至https://www.wechatpay.com.cn,則可以做如下處理:

假設(shè)您通過統(tǒng)一下單接口獲到的MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096

則拼接后的地址為MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cn

注意:

1.需對(duì)redirect_url進(jìn)行urlencode處理

2.由于設(shè)置redirect_url后,回跳指定頁(yè)面的操作可能發(fā)生在:1,微信支付中間頁(yè)調(diào)起微信收銀臺(tái)后超過5秒 2,用戶點(diǎn)擊“取消支付“或支付完成后點(diǎn)“完成”按鈕。因此無法保證頁(yè)面回跳時(shí),支付流程已結(jié)束,所以商戶設(shè)置的redirect_url地址不能自動(dòng)執(zhí)行查單操作,應(yīng)讓用戶去點(diǎn)擊按鈕觸發(fā)查單操作,而我后面拼接的$orderId就是用于查單操作的參數(shù)。回跳頁(yè)面展示效果可參考下圖

回調(diào)頁(yè)面示例圖.png

3.處理微信支付結(jié)果通知支付完成后,微信會(huì)把相關(guān)支付結(jié)果和用戶信息發(fā)送給商戶,商戶需要接收處理,并返回應(yīng)答。

對(duì)后臺(tái)通知交互時(shí),如果微信收到商戶的應(yīng)答不是成功或超時(shí),微信認(rèn)為通知失敗,微信會(huì)通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 (通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒)

注意:同樣的通知可能會(huì)多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。

推薦的做法是,當(dāng)收到通知進(jìn)行處理時(shí),首先檢查對(duì)應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),判斷該通知是否已經(jīng)處理過,如果沒有處理過再進(jìn)行處理,如果處理過直接返回結(jié)果成功。在對(duì)業(yè)務(wù)數(shù)據(jù)進(jìn)行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進(jìn)行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。

特別提醒:商戶系統(tǒng)對(duì)于支付結(jié)果通知的內(nèi)容一定要做簽名驗(yàn)證,并校驗(yàn)返回的訂單金額是否與商戶側(cè)的訂單金額一致,防止數(shù)據(jù)泄漏導(dǎo)致出現(xiàn)“假通知”,造成資金損失。

支付回調(diào)基礎(chǔ)類/**

*

*?回調(diào)基礎(chǔ)類

*?@author?widyhu

*

*/class?WxPayNotify?extends?WxPayNotifyReply{????/**

*

*?回調(diào)入口

*?@param?bool?$needSign??是否需要簽名輸出

*/

final?public?function?Handle($needSign?=?true)

{

$msg?=?"OK";????????//當(dāng)返回false的時(shí)候,表示notify中調(diào)用NotifyCallBack回調(diào)失敗獲取簽名校驗(yàn)失敗,此時(shí)直接回復(fù)失敗

$result?=?WxpayApi::notify(array($this,?'NotifyCallBack'),?$msg);????????if($result?==?false){????????????$this->SetReturn_code("FAIL");????????????$this->SetReturn_msg($msg);????????????$this->ReplyNotify(false);????????????return;

}?else?{????????????//該分支在成功回調(diào)到NotifyCallBack方法,處理完成之后流程

$this->SetReturn_code("SUCCESS");????????????$this->SetReturn_msg("OK");

}????????$this->ReplyNotify($needSign);

}

/**

*

*?回調(diào)方法入口,子類可重寫該方法

*?注意:

*?1、微信回調(diào)超時(shí)時(shí)間為2s,建議用戶使用異步處理流程,確認(rèn)成功之后立刻回復(fù)微信服務(wù)器

*?2、微信服務(wù)器在調(diào)用失敗或者接到回包為非確認(rèn)包的時(shí)候,會(huì)發(fā)起重試,需確保你的回調(diào)是可以重入

*?@param?array?$data?回調(diào)解釋出的參數(shù)

*?@param?string?$msg?如果回調(diào)處理失敗,可以將錯(cuò)誤信息輸出到該方法

*?@return?true回調(diào)出來完成不需要繼續(xù)回調(diào),false回調(diào)處理未完成需要繼續(xù)回調(diào)

*/

public?function?NotifyProcess($data,?&$msg)

{????????//TODO?用戶基礎(chǔ)該類之后需要重寫該方法,成功的時(shí)候返回true,失敗返回false

return?true;

}

/**

*

*?notify回調(diào)方法,該方法中需要賦值需要輸出的參數(shù),不可重寫

*?@param?array?$data

*?@return?true回調(diào)出來完成不需要繼續(xù)回調(diào),false回調(diào)處理未完成需要繼續(xù)回調(diào)

*/

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;

}

/**

*

*?回復(fù)通知

*?@param?bool?$needSign?是否需要簽名輸出

*/

final?private?function?ReplyNotify($needSign?=?true)

{????????//如果需要簽名

if($needSign?==?true?&&

$this->GetReturn_code($return_code)?==?"SUCCESS")

{????????????$this->SetSign();

}

WxpayApi::replyNotify($this->ToXml());

}

}需要注意的是,如果用戶只是打開付款界面,而沒有執(zhí)行付款操作的話,是不會(huì)觸發(fā)通知的。

當(dāng)我們接收到的參數(shù)中同時(shí)含有return_code,result_code,trade_state并且每個(gè)返回值都為SUCCESS的時(shí)候,代表用戶付款成功if(array_key_exists("return_code",?$result)

&&?array_key_exists("result_code",?$result)

&&array_key_exists("trade_state",?$resultData)

&&?$resultData["trade_state"]?==?"SUCCESS"

&&?$result["return_code"]?==?"SUCCESS"

&&?$result["result_code"]?==?"SUCCESS")

{????????????//這里執(zhí)行給用戶充值余額的操作

}

4.redirect_url回調(diào)頁(yè)面處理

如果在第2.4步驟中MWEB_URL后拼接上了redirect_url參數(shù),用戶支付完成后將返回到這個(gè)頁(yè)面。

當(dāng)用戶點(diǎn)擊界面的已完成按鈕,將觸發(fā)查單操作

微信查單操作API

查單操作相關(guān)代碼如下//查詢訂單

public?function?Queryorder($transaction_id)

{

$input?=?new?WxPayOrderQuery();

$input->SetTransaction_id($transaction_id);

$result?=?WxPayApi::orderQuery($input);

Log::DEBUG("query:"?.?json_encode($result));????????if(array_key_exists("return_code",?$result)

&&?array_key_exists("result_code",?$result)

&&?$result["return_code"]?==?"SUCCESS"

&&?$result["result_code"]?==?"SUCCESS")

{????????????return?$result;

}????????return?false;

}

界面布局以及相關(guān)的邏輯處理:if(isset($_REQUEST["out_trade_no"])?&&?$_REQUEST["out_trade_no"]?!=?""){

$out_trade_no?=?$_REQUEST["out_trade_no"];

$input?=?new?WxPayOrderQuery();

$input->SetOut_trade_no($out_trade_no);

Log::DEBUG("out_trade_no".$out_trade_no);//??printf_info(WxPayApi::orderQuery($input));

$result=WxPayApi::orderQuery($input);????if(array_key_exists("return_code",?$result)

&&?array_key_exists("result_code",?$result)

&&?array_key_exists("trade_state",?$result)

&&?$result["trade_state"]?==?"SUCCESS"

&&?$result["return_code"]?==?"SUCCESS"

&&?$result["result_code"]?==?"SUCCESS"){

$successUrl="success.html";????????echo?"";

}else{

$failUrl="fail.html";????????echo?"";

}????exit();

}?>

window.=function?()?{????????var?Request=new?UrlSearch();?//實(shí)例化

document.getElementById("out_trade_no").value=Request.transaction_id;

document.getElementById("transaction_id").style.height?=?0;

document.getElementById("out_trade_no").style.height?=?0;

document.getElementById("btn").style.height?=?0;

$.DialogByZ.Confirm({Title:?"",?Content:?"請(qǐng)確認(rèn)微信支付是否已完成",FunL:confirmL,FunR:Immediate})

}????///

function?confirmL(){

$.DialogByZ.Close();

document.getElementById('btn').click();

}????function?Immediate(){????????//location.href="http://sc.chinaz.com/jiaoben/"

window.location.href="nonglegou://data/?state=fail";

}????function?UrlSearch()

{????????var?name,value;????????var?str=location.href;?//取得整個(gè)地址欄

var?num=str.indexOf("?")

str=str.substr(num+1);?//取得所有參數(shù)???stringvar.substr(start?[,?length?]

var?arr=str.split("&");?//各個(gè)參數(shù)放到數(shù)組里

for(var?i=0;i?<?arr.length;i++){

num=arr[i].indexOf("=");????????????if(num>0){

name=arr[i].substring(0,num);

value=arr[i].substr(num+1);

this[name]=value;

}

}

}

三、總結(jié)

微信H5支付的整個(gè)流程,大概就是這樣子,以下是流程圖

接口流程圖用戶在商戶側(cè)完成下單,使用微信支付進(jìn)行支付

由商戶后臺(tái)向微信支付發(fā)起下單請(qǐng)求(調(diào)用統(tǒng)一下單接口)注:交易類型trade_type=MWEB

統(tǒng)一下單接口返回支付相關(guān)參數(shù)給商戶后臺(tái),如支付跳轉(zhuǎn)url(參數(shù)名“mweb_url”),商戶通過mweb_url調(diào)起微信支付中間頁(yè)

中間頁(yè)進(jìn)行H5權(quán)限的校驗(yàn),安全性檢查(此處常見錯(cuò)誤請(qǐng)見下文)

如支付成功,商戶后臺(tái)會(huì)接收到微信側(cè)的異步通知

用戶在微信支付收銀臺(tái)完成支付或取消支付,返回商戶頁(yè)面(默認(rèn)為返回支付發(fā)起頁(yè)面)

商戶在展示頁(yè)面,引導(dǎo)用戶主動(dòng)發(fā)起支付結(jié)果的查詢

商戶后臺(tái)判斷是否接到收微信側(cè)的支付結(jié)果通知,如沒有,后臺(tái)調(diào)用我們的訂單查詢接口確認(rèn)訂單狀態(tài)

展示最終的訂單支付結(jié)果給用戶

總結(jié)

以上是生活随笔為你收集整理的php根据浏览器调用支付_Android通过外部浏览器调用微信H5支付,Android+PHP详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。