1. 程式人生 > >PHP實現APP微信支付

PHP實現APP微信支付

根據文件拼接微信需要的引數,這裡需要幾個方法,直接上程式碼!

  1. 傳輸給微信的引數要組裝成xml格式傳送,傳如引數陣列!
public function ToXml($data=array())

    {
        if(!is_array($data) || count($data) <= 0)
        {
           return '陣列異常';
        }

        $xml = "<xml>";
        foreach ($data as $key=>$val)
        {
            if
(is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; }

2.生成隨機字串,微信所需引數! 這裡方法很多,看自己愛好都行!

function rand_code(){
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';//62個字元
        $str = str_shuffle($str);
        $str = substr($str,0,32);
        return  $str;
}

3.這裡是微信比較重要的一步了,這個方法會多次用到!生成簽名

private function getSign($params) {
        ksort($params);        //將引數陣列按照引數名ASCII碼從小到大排序
foreach ($params as $key => $item) { if (!empty($item)) { //剔除引數值為空的引數 $newArr[] = $key.'='.$item; // 整合新的引數陣列 } } $stringA = implode("&", $newArr); //使用 & 符號連線引數 $stringSignTemp = $stringA."&key="."************************"; //拼接key // key是在商戶平臺API安全裡自己設定的 $stringSignTemp = MD5($stringSignTemp); //將字串進行MD5加密 $sign = strtoupper($stringSignTemp); //將所有字元轉換為大寫 return $sign; }
public function wx_pay() {

        $nonce_str = $this->rand_code();        //呼叫隨機字串生成方法獲取隨機字串
        $data['appid'] ='wxdbc5dc*******';   //appid
        $data['mch_id'] = '1493*****' ;        //商戶號
        $data['body'] = "APP支付測試";
        $data['spbill_create_ip'] = $_SERVER['HTTP_HOST'];   //ip地址
        $data['total_fee'] = 1;                         //金額
        $data['out_trade_no'] = time().mt_rand(10000,99999);    //商戶訂單號,不能重複
        $data['nonce_str'] = $nonce_str;                   //隨機字串
        $data['notify_url'] = 'http://xxx.xxx.com/wx_notify';   //回撥地址,使用者接收支付後的通知,必須為能直接訪問的網址,不能跟引數
        $data['trade_type'] = 'APP';      //支付方式
        //將參與簽名的資料儲存到陣列  注意:以上幾個引數是追加到$data中的,$data中應該同時包含開發文件中要求必填的剔除sign以外的所有資料
        $data['sign'] = $this->getSign($data);        //獲取簽名
        $xml = $this->ToXml($data);            //陣列轉xml
        //curl 傳遞給微信方
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        //header("Content-type:text/xml");
        $ch = curl_init();
        curl_setopt($ch,CURLOPT_URL, $url);
        if(stripos($url,"https://")!==FALSE){
            curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        }    else    {
            curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
            curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//嚴格校驗
        }
        //設定header
        curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求結果為字串且輸出到螢幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //設定超時
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_POST, TRUE);
        //傳輸檔案
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //執行curl
        $data = curl_exec($ch);
        //返回結果
        if($data){
            curl_close($ch);
            //返回成功,將xml資料轉換為陣列.
            $re = $this->FromXml($data);
            if($re['return_code'] != 'SUCCESS'){
                json("201",'簽名失敗');
            }
            else{
            //接收微信返回的資料,傳給APP!
                $arr =array(
                    'prepayid' =>$re['prepay_id'],
                    'appid' => 'wxdbc5dc*****',
                    'partnerid' => '14937****',
                    'package' => 'Sign=WXPay',
                    'noncestr' => $nonce_str,
                    'timestamp' =>time(),
                );
                //第二次生成簽名
                $sign = $this->getSign($arr);
                $arr['sign'] = $sign;
                json('200','簽名成功',$arr);
            }
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            json('201',"curl出錯,錯誤碼:$error");
        }
    }

5.將xml資料轉換為陣列,接收微信返回資料時用到.

public function FromXml($xml)
    {
        if(!$xml){
            echo "xml資料異常!";
        }
        //將XML轉為array
        //禁止引用外部xml實體
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $data;
    }
// 微信支付回撥
     function wx_notify(){
           //接收微信返回的資料資料,返回的xml格式
           $xmlData = file_get_contents('php://input');
           //將xml格式轉換為陣列
           $data = $this->FromXml($xmlData);
           //用日誌記錄檢查資料是否接受成功,驗證成功一次之後,可刪除。
           $file = fopen('./log.txt', 'a+');
           fwrite($file,var_export($data,true));
           //為了防止假資料,驗證簽名是否和返回的一樣。
           //記錄一下,返回回來的簽名,生成簽名的時候,必須剔除sign欄位。
           $sign = $data['sign'];
           unset($data['sign']);
           if($sign == $this->getSign($data)){
            //簽名驗證成功後,判斷返回微信返回的
            if ($data['result_code'] == 'SUCCESS') {
                //根據返回的訂單號做業務邏輯
                $arr = array(
                       'pay_status' => 1,
                    );
                $re = M('order')->where(['order_sn'=>$data['out_trade_no']])->save($arr);
                //處理完成之後,告訴微信成功結果!
                if($re){
                    echo '<xml>
              <return_code><![CDATA[SUCCESS]]></return_code>
              <return_msg><![CDATA[OK]]></return_msg>
              </xml>';exit();
                }
            }
            //支付失敗,輸出錯誤資訊
            else{
                $file = fopen('./log.txt', 'a+');
           fwrite($file,"錯誤資訊:".$data['return_msg'].date("Y-m-d H:i:s"),time()."\r\n");    
            }
    }
    else{
                $file = fopen('./log.txt', 'a+');
           fwrite($file,"錯誤資訊:簽名驗證失敗".date("Y-m-d H:i:s"),time()."\r\n");    
            }

}

在這裡,微信APP支付流程就成功走完了!謝謝支援!