久久免费视频鬼狠狠_久久五月天和激情网_亚洲人成在线播放a偷伦_午夜无码免费视频一区二区

廣豐視角

關(guān)注互聯(lián)網(wǎng),關(guān)注技術(shù)開發(fā),透析與分享移動互聯(lián)網(wǎng)行業(yè)最新動態(tài)

Android通過外部瀏覽器調(diào)用微信H5支付,Android+PHP詳解

時間:2019-02-18 18:26:37    閱讀:30752次 分類:APP開發(fā)
一、and/roid端 and/roid端代碼相對來說比較簡單一些,我這邊直接調(diào)用系統(tǒng)瀏覽器打開h5支付頁面 intent intent = new intent(); intent.setaction("and/roid.intent.action.view"); uri content_url = uri.parse(url); //url里面包含了后端需要用到的參...

一、Android端
Android端代碼相對來說比較簡單一些,我這邊直接調(diào)用系統(tǒng)瀏覽器打開H5支付頁面


 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來加載支付頁面,但是調(diào)試接口的時候發(fā)現(xiàn)一直報如下錯誤:


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


二、PHP端
1.獲取從Android端傳過來的參數(shù)
目前我只想到一種方法,就是通過url攜帶參數(shù)給服務端傳值,OK,獲取方式如下:


//當前頁面的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)一下單API
2.1 具體參數(shù)名稱以及各參數(shù)的用途請查看微信官方文檔 統(tǒng)一下單API
    //配置需要傳遞給微信的參數(shù)
    $input = new WxPayUnifiedOrder();
    $input->SetBody("xxxx-商品購買");
    $input->SetAttach("xxxx");
    $input->SetDevice_info("WEB");
    $input->SetOut_trade_no(WxPayConfig::MCHID . date("YmdHis").$uid);//把UID加在末尾主要用于識別用戶,給對應的用戶充值余額
    $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ù)具體實現(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 成功時返回,其他拋異常
     */
    public static function unifiedOrder($inputObj, $timeOut = 6)
    {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        //檢測必填參數(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未設置,則使用配置文件中的url
        if(!$inputObj->IsNotify_urlSet()){
            $inputObj->SetNotify_url(WxPayConfig::NOTIFY_URL);//異步通知url
        }


        $inputObj->SetAppid(WxPayConfig::APPID);//公眾賬號ID
        $inputObj->SetMch_id(WxPayConfig::MCHID);//商戶號
        $inputObj->SetSpbill_create_ip(self::getIp());//終端ip
        //$inputObj->SetSpbill_create_ip("1.1.1.1");       
        $inputObj->SetNonce_str(self::getNonceStr());//隨機字符串


        //簽名
        $inputObj->SetSign();
        $xml = $inputObj->ToXml();


        $startTimeStamp = self::getMillisecond();//請求開始時間
        $response = self::postXmlCurl($xml, $url, false, $timeOut);
        $result = WxPayResults::Init($response);
        self::reportCostTime($url, $startTimeStamp, $result);//上報請求花費時間


        return $result;
    }

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

這時可以使用以下方式獲取用戶真實IP
//獲取用戶真實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.="<".$key.">".$val."";
            }else{
                $xml.="<".$key.">";
            }
        }
        $xml.="
";
        return $xml; 
    }

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


特別注意以下重要規(guī)則:


◆ 參數(shù)名ASCII碼從小到大排序(字典序);
◆ 如果參數(shù)的值為空不參與簽名;
◆ 參數(shù)名區(qū)分大小寫;
◆ 驗證調(diào)用返回或微信主動通知簽名時,傳送的sign參數(shù)不參與簽名,將生成的簽名與該sign值作校驗。
◆ 微信接口可能增加字段,驗證簽名時必須支持增加的擴展字段

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


key設置路徑:微信商戶平臺(pay.weixin.qq.com)–>賬戶設置–>API安全–>密鑰設置


/**
     * 生成簽名
     * @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)起微信APP
if ($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 " ";
    }

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


正常流程用戶支付完成后會返回至發(fā)起支付的頁面,如需返回至指定頁面,則可以在MWEB_URL后拼接上redirect_url參數(shù),來指定回調(diào)頁面。 
如,您希望用戶支付完成后跳轉(zhuǎn)至https://www.wechatpay.com.cn,則可以做如下處理: 
假設您通過統(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.需對redirect_url進行urlencode處理 
2.由于設置redirect_url后,回跳指定頁面的操作可能發(fā)生在:1,微信支付中間頁調(diào)起微信收銀臺后超過5秒 2,用戶點擊“取消支付“或支付完成后點“完成”按鈕。因此無法保證頁面回跳時,支付流程已結(jié)束,所以商戶設置的redirect_url地址不能自動執(zhí)行查單操作,應讓用戶去點擊按鈕觸發(fā)查單操作,而我后面拼接的$orderId就是用于查單操作的參數(shù)?;靥撁嬲故拘Ч蓞⒖枷聢D


3.處理微信支付結(jié)果通知
支付完成后,微信會把相關(guān)支付結(jié)果和用戶信息發(fā)送給商戶,商戶需要接收處理,并返回應答。 
對后臺通知交互時,如果微信收到商戶的應答不是成功或超時,微信認為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 (通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒) 
注意:同樣的通知可能會多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復的通知。 
推薦的做法是,當收到通知進行處理時,首先檢查對應業(yè)務數(shù)據(jù)的狀態(tài),判斷該通知是否已經(jīng)處理過,如果沒有處理過再進行處理,如果處理過直接返回結(jié)果成功。在對業(yè)務數(shù)據(jù)進行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。 
特別提醒:商戶系統(tǒng)對于支付結(jié)果通知的內(nèi)容一定要做簽名驗證,并校驗返回的訂單金額是否與商戶側(cè)的訂單金額一致,防止數(shù)據(jù)泄漏導致出現(xiàn)“假通知”,造成資金損失。


支付回調(diào)基礎類

/**
 * 
 * 回調(diào)基礎類
 * @author widyhu
 *
 */
class WxPayNotify extends WxPayNotifyReply
{
    /**
     * 
     * 回調(diào)入口
     * @param bool $needSign  是否需要簽名輸出
     */
    final public function Handle($needSign = true)
    {
        $msg = "OK";
        //當返回false的時候,表示notify中調(diào)用NotifyCallBack回調(diào)失敗獲取簽名校驗失敗,此時直接回復失敗
        $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)超時時間為2s,建議用戶使用異步處理流程,確認成功之后立刻回復微信服務器
     * 2、微信服務器在調(diào)用失敗或者接到回包為非確認包的時候,會發(fā)起重試,需確保你的回調(diào)是可以重入
     * @param array $data 回調(diào)解釋出的參數(shù)
     * @param string $msg 如果回調(diào)處理失敗,可以將錯誤信息輸出到該方法
     * @return true回調(diào)出來完成不需要繼續(xù)回調(diào),false回調(diào)處理未完成需要繼續(xù)回調(diào)
     */
    public function NotifyProcess($data, &$msg)
    {
        //TODO 用戶基礎該類之后需要重寫該方法,成功的時候返回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;
    }


    /**
     * 
     * 回復通知
     * @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í)行付款操作的話,是不會觸發(fā)通知的。


當我們接收到的參數(shù)中同時含有return_code,result_code,trade_state并且每個返回值都為SUCCESS的時候,代表用戶付款成功


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)頁面處理
如果在第2.4步驟中MWEB_URL后拼接上了redirect_url參數(shù),用戶支付完成后將返回到這個頁面。 
當用戶點擊界面的已完成按鈕,將觸發(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();
}
?>

三、總結(jié)
微信H5支付的整個流程,大概就是這樣子,以下是流程圖
1. 用戶在商戶側(cè)完成下單,使用微信支付進行支付 
2. 由商戶后臺向微信支付發(fā)起下單請求(調(diào)用統(tǒng)一下單接口)注:交易類型trade_type=MWEB 
3. 統(tǒng)一下單接口返回支付相關(guān)參數(shù)給商戶后臺,如支付跳轉(zhuǎn)url(參數(shù)名“mweb_url”),商戶通過mweb_url調(diào)起微信支付中間頁 
4. 中間頁進行H5權(quán)限的校驗,安全性檢查(此處常見錯誤請見下文) 
5. 如支付成功,商戶后臺會接收到微信側(cè)的異步通知 
6. 用戶在微信支付收銀臺完成支付或取消支付,返回商戶頁面(默認為返回支付發(fā)起頁面) 
7. 商戶在展示頁面,引導用戶主動發(fā)起支付結(jié)果的查詢 
8. 商戶后臺判斷是否接到收微信側(cè)的支付結(jié)果通知,如沒有,后臺調(diào)用我們的訂單查詢接口確認訂單狀態(tài) 
9. 展示最終的訂單支付結(jié)果給用戶


蕪湖廣豐軟件有限公司(原中江網(wǎng)絡),成立于2005年,經(jīng)過10多年定制開發(fā)經(jīng)驗,積累了大量技術(shù)儲備和定制開發(fā)經(jīng)驗,是一家集軟件研發(fā)、互聯(lián)網(wǎng)應用為一體的綜合信息技術(shù)服務提供商。公司擁有核心的策劃團隊和專業(yè)的技術(shù)研發(fā)團隊,致力于采用領(lǐng)先的信息技術(shù),長期為涉及智慧園區(qū)/廠區(qū)/校園領(lǐng)域的各個企業(yè)提供快速、高效、安全的信息技術(shù)支持。公司立足智慧園區(qū)和智慧教育行業(yè),通過軟硬件的研發(fā)和互聯(lián)網(wǎng)應用,疏通各企業(yè)間“端到端”的信息傳輸,靈活滿足智慧園區(qū)和智慧教育企業(yè)間不同用戶的需求,為其提供完善的信息化解決方案。

廣豐軟件,gf-yun.com,安徽軟件開發(fā),Android,PHP
廣豐軟件
智慧園區(qū)系統(tǒng)開發(fā)
最新資訊排行榜