前面已經(jīng)寫了手機(jī)APP支付寶支付,今天再把手機(jī)APP微信支付補(bǔ)上,前期的準(zhǔn)備工作在這里就不多說了,可以參考微信支付開發(fā)文檔,一定要仔細(xì)閱讀開發(fā)文檔,可以讓你少踩點(diǎn)坑;準(zhǔn)備工作完成后就是配置參數(shù),調(diào)用統(tǒng)一下單接口,支付后異步回調(diào)三部曲啦;
1.我封裝好的一個(gè)支付類文件,多余的東西都去除掉了,并且把配置參數(shù)放到了這個(gè)支付類中,只需要修改Weixinpayandroid方法內(nèi)的幾個(gè)參數(shù)就可以直接復(fù)制使用:
class Wxpayandroid { //參數(shù)配置 public $config = array( 'appid' => "", /*微信開放平臺(tái)上的應(yīng)用id*/ 'mch_id' => "", /*微信申請成功之后郵件中的商戶id*/ 'api_key' => "", /*在微信商戶平臺(tái)上自己設(shè)定的api密鑰 32位*/ ); //服務(wù)器異步通知頁面路徑(必填) public $notify_url = ''; //商戶訂單號(hào)(必填,商戶網(wǎng)站訂單系統(tǒng)中唯一訂單號(hào)) public $out_trade_no = ''; //商品描述(必填,不填則為商品名稱) public $body = ''; //付款金額(必填) public $total_fee = 0; //自定義超時(shí)(選填,支持dhmc) public $time_expire = ''; private $WxPayHelper; public function Weixinpayandroid($total_fee,$tade_no) { $this->total_fee = intval($total_fee * 100);//訂單的金額 1元 $this->out_trade_no = $tade_no;// date('YmdHis') . substr(time(), - 5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));//訂單號(hào) $this->body = 'wxpay';//支付描述信息 $this->time_expire = date('YmdHis', time() + 86400);//訂單支付的過期時(shí)間(eg:一天過期) $this->notify_url = "http://www.ceshi.com/notifyandroid";//異步通知URL(更改支付狀態(tài)) //數(shù)據(jù)以JSON的形式返回給APP $app_response = $this->doPay(); if (isset($app_response['return_code']) && $app_response['return_code'] == 'FAIL') { $errorCode = 100; $errorMsg = $app_response['return_msg']; $this->echoResult($errorCode, $errorMsg); } else { $errorCode = 0; $errorMsg = 'success'; $responseData = array( 'notify_url' => $this->notify_url, 'app_response' => $app_response, ); $this->echoResult($errorCode, $errorMsg, $responseData); } } //接口輸出 function echoResult($errorCode = 0, $errorMsg = 'success', $responseData = array()) { $arr = array( 'errorCode' => $errorCode, 'errorMsg' => $errorMsg, 'responseData' => $responseData, ); exit(json_encode($arr)); //exit可以正常發(fā)送給APP json數(shù)據(jù) // return json_encode($arr); //在TP5中return這個(gè)json數(shù)據(jù),APP接收到的是null,無法正常吊起微信支付 } function getVerifySign($data, $key) { $String = $this->formatParameters($data, false); //簽名步驟二:在string后加入KEY $String = $String . "&key=" . $key; //簽名步驟三:MD5加密 $String = md5($String); //簽名步驟四:所有字符轉(zhuǎn)為大寫 $result = strtoupper($String); return $result; } function formatParameters($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if($k=="sign"){ continue; } if ($urlencode) { $v = urlencode($v); } $buff .= $k . "=" . $v . "&"; } $reqPar; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff) - 1); } return $reqPar; } /** * 得到簽名 * @param object $obj * @param string $api_key * @return string */ function getSign($obj, $api_key) { foreach ($obj as $k => $v) { $Parameters[strtolower($k)] = $v; } //簽名步驟一:按字典序排序參數(shù) ksort($Parameters); $String = $this->formatBizQueryParaMap($Parameters, false); //簽名步驟二:在string后加入KEY $String = $String."&key=".$api_key; //簽名步驟三:MD5加密 $result = strtoupper(md5($String)); return $result; } /** * 獲取指定長度的隨機(jī)字符串 * @param int $length * @return Ambigous <NULL, string> */ function getRandChar($length){ $str = null; $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; $max = strlen($strPol)-1; for($i=0;$i<$length;$i++){ $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max兩個(gè)數(shù)之間的一個(gè)隨機(jī)整數(shù) } return $str; } /** * 數(shù)組轉(zhuǎn)xml * @param array $arr * @return string */ function arrayToXml($arr) { $xml = "<xml>"; foreach ($arr as $key=>$val) { if (is_numeric($val)) { $xml.="<".$key.">".$val."</".$key.">"; } else $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } $xml.="</xml>"; return $xml; } /** * 以post方式提交xml到對(duì)應(yīng)的接口url * * @param string $xml 需要post的xml數(shù)據(jù) * @param string $url url * @param bool $useCert 是否需要證書,默認(rèn)不需要 * @param int $second url執(zhí)行超時(shí)時(shí)間,默認(rèn)30s * @throws WxPayException */ function postXmlCurl($xml, $url, $second=30, $useCert=false, $sslcert_path='', $sslkey_path='') { $ch = curl_init(); //設(shè)置超時(shí) curl_setopt($ch, CURLOPT_TIMEOUT, $second); curl_setopt($ch,CURLOPT_URL, $url); //設(shè)置header curl_setopt($ch, CURLOPT_HEADER, FALSE); //要求結(jié)果為字符串且輸出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); if($useCert == true){ curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//嚴(yán)格校驗(yàn) //設(shè)置證書 //使用證書:cert 與 key 分別屬于兩個(gè).pem文件 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, $sslcert_path); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, $sslkey_path); } //post提交方式 curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); //運(yùn)行curl $data = curl_exec($ch); //返回結(jié)果 if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); curl_close($ch); return false; } } /** * 獲取當(dāng)前服務(wù)器的IP * @return Ambigous <string, unknown> */ function get_client_ip() { if (isset($_SERVER['REMOTE_ADDR'])) { $cip = $_SERVER['REMOTE_ADDR']; } elseif (getenv("REMOTE_ADDR")) { $cip = getenv("REMOTE_ADDR"); } elseif (getenv("HTTP_CLIENT_IP")) { $cip = getenv("HTTP_CLIENT_IP"); } else { $cip = "127.0.0.1"; } return $cip; } /** * 將數(shù)組轉(zhuǎn)成uri字符串 * @param array $paraMap * @param bool $urlencode * @return string */ function formatBizQueryParaMap($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if($urlencode) { $v = urlencode($v); } $buff .= strtolower($k) . "=" . $v . "&"; } $reqPar; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff)-1); } return $reqPar; } /** * XML轉(zhuǎn)數(shù)組 * @param unknown $xml * @return mixed */ function xmlToArray($xml) { //將XML轉(zhuǎn)為array $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $array_data; } public function chkParam() { //用戶網(wǎng)站訂單號(hào) if (empty($this->out_trade_no)) { die('out_trade_no error'); } //商品描述 if (empty($this->body)) { die('body error'); } if (empty($this->time_expire)){ die('time_expire error'); } //檢測支付金額 if (empty($this->total_fee) || !is_numeric($this->total_fee)) { die('total_fee error'); } //異步通知URL if (empty($this->notify_url)) { die('notify_url error'); } if (!preg_match("#^http:\/\/#i", $this->notify_url)) { $this->notify_url = "http://" . $_SERVER['HTTP_HOST'] . $this->notify_url; } return true; } /** * 生成支付(返回給APP) * @return boolean|mixed */ public function doPay() { //檢測構(gòu)造參數(shù) $this->chkParam(); return $this->createAppPara(); } /** * APP統(tǒng)一下單 */ private function createAppPara() { $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; $data["appid"] = $this->config['appid'];//微信開放平臺(tái)審核通過的應(yīng)用APPID $data["body"] = $this->body;//商品或支付單簡要描述 $data["mch_id"] = $this->config['mch_id'];//商戶號(hào) $data["nonce_str"] = $this->getRandChar(32);//隨機(jī)字符串 $data["notify_url"] = $this->notify_url;//通知地址 $data["out_trade_no"] = $this->out_trade_no;//商戶訂單號(hào) $data["spbill_create_ip"] = $this->get_client_ip();//終端IP $data["total_fee"] = $this->total_fee;//總金額 $data["time_expire"] = $this->time_expire;//交易結(jié)束時(shí)間 $data["trade_type"] = "APP";//交易類型 $data["sign"] = $this->getSign($data, $this->config['api_key']);//簽名 $xml = $this->arrayToXml($data); $response = $this->postXmlCurl($xml, $url); //將微信返回的結(jié)果xml轉(zhuǎn)成數(shù)組 $responseArr = $this->xmlToArray($response); if(isset($responseArr["return_code"]) && $responseArr["return_code"]=='SUCCESS'){ return $this->getOrder($responseArr['prepay_id']); } return $responseArr; } /** * 執(zhí)行第二次簽名,才能返回給客戶端使用 * @param int $prepayId:預(yù)支付交易會(huì)話標(biāo)識(shí) * @return array */ public function getOrder($prepayId) { $data["appid"] = $this->config['appid']; $data["noncestr"] = $this->getRandChar(32); $data["package"] = "Sign=WXPay"; $data["partnerid"] = $this->config['mch_id']; $data["prepayid"] = $prepayId; $data["timestamp"] = time(); $data["sign"] = $this->getSign($data, $this->config['api_key']); $data["packagestr"] = "Sign=WXPay"; return $data; } /** * 異步通知信息驗(yàn)證 * @return boolean|mixed */ public function verifyNotify() { $xml = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : ''; if(!$xml){ return false; } $wx_back = $this->xmlToArray($xml); if(empty($wx_back)){ return false; } $checkSign = $this->getVerifySign($wx_back, $this->config['api_key']); if($checkSign=$wx_back['sign']){ return $wx_back; }else{ return false; } } }
2.創(chuàng)建控制器定義統(tǒng)一下單接口和支付后的異步回調(diào)接口:
//異步通知接口 public function notifyandroid() { $wxpayandroid = new \Wxpayandroid; //實(shí)例化微信支付類 $verify_result = $wxpayandroid->verifyNotify(); if ($verify_result['return_code']=='SUCCESS' && $verify_result['result_code']=='SUCCESS') { //商戶訂單號(hào) $out_trade_no = $verify_result['out_trade_no']; //交易號(hào) $trade_no = $verify_result['transaction_id']; //交易狀態(tài) $trade_status = $verify_result['result_code']; //支付金額 $total_fee = $verify_result['total_fee']/100; //支付過期時(shí)間 $pay_date = $verify_result['time_end']; $order = new Order(); $ret = $order->getOrderN2($out_trade_no); //獲取訂單信息 $total_amount=$ret['money']; if ($total_amount==$total_fee) { // 驗(yàn)證成功 修改數(shù)據(jù)庫的訂單狀態(tài)等 $result['out_trade_no']為訂單號(hào) //此處寫自己的邏輯代碼 } exit('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'); }else{ exit('<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>'); } } //調(diào)用統(tǒng)一下單接口生成預(yù)支付訂單并把數(shù)據(jù)返回給APP public function wxpayandroid(Request $request) { $param = $request->param(); //接收值 $tade_no = $param['orderCode']; $order = new Order(); //實(shí)例化訂單 $ret = $order->getOrderN2($tade_no); //查詢訂單信息 $total_fee = $ret['money']; //訂單總金額 $wxpayandroid = new \Wxpayandroid; //實(shí)例化微信支付類 $res = $wxpayandroid->Weixinpayandroid($total_fee,$tade_no); //調(diào)用weixinpay方法 }
封裝一個(gè)支付類文件,并把配置參數(shù)放到支付類內(nèi),再定義控制器創(chuàng)建兩個(gè)方法,這樣兩步就可以把手機(jī)APP微信支付搞定啦。
總結(jié)
以上所述是小編給大家介紹的PHP實(shí)現(xiàn) APP端微信支付功能,希望對(duì)大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)服務(wù)器之家網(wǎng)站的支持!