1. 程式人生 > >PHP微信APP支付,下單,處理非同步回撥——————微信支付這個坑

PHP微信APP支付,下單,處理非同步回撥——————微信支付這個坑

1.下單

其中陣列轉換xml格式,curl傳送請求,xml格式轉換成陣列可單獨封裝成函式。

    public function index() {

        $order = [

            'appid'=>'123456',

            'mch_id'=>'56789',

            'nonce_str'=>uniqid(md5(time())),

            'body'=>'測試商品',

            'out_trade_no'=>87654321,//商戶唯一訂單號,可包含字母序

            'total_fee'=>100,//訂單金額,單位/分

            'spbill_create_ip'=>'123.12.12.123',//產生訂單號的伺服器IP

            'notify_url'=>'http://www.yoursite.com/wxpay',//接受微信非同步通知地址

            'trade_type'=>'APP'

        ];

        //使用者http_build_query()將資料轉成URL鍵值對形式

        $sign = http_build_query($order);

        //$sign = "appid=123456&mch_id=56789&nonce_str=c6079b98e6aeb4a98f687800c887f6cc58df95d72cd69&body=%E6%B5%8B%E8%AF%95%E5%95%86%E5%93%81&out_trade_no=87654321&total_fee=100&spbill_create_ip=123.12.12.123¬ify_url=http%3A%2F%2Fwww.yoursite.com%2Fwxpay&trade_type=APP";

        //MD5處理,預設支援MD5

        $sign = md5($sign);

        //轉大寫

        $sign = strtoupper($sign);

        $order['sign'] = $sign;

        //轉換成一維XML格式

        $xml = '';

        foreach($order as $k=>$v){

            $xml.='<'.$k.'>';

        }

        $xml.='';

        //CURL會話

        $ch = curl_init();

        // 設定curl允許執行的最長秒數

        curl_setopt($ch, CURLOPT_TIMEOUT, 3);

        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);

        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);

        // 獲取的資訊以檔案流的形式返回,而不是直接輸出。

        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);

        //傳送一個常規的POST請求。

        curl_setopt($ch, CURLOPT_POST, 1);

        curl_setopt($ch, CURLOPT_URL, 'https://api.mch.weixin.qq.com/pay/unifiedorder');

        //要傳送的所有資料

        curl_setopt($ch, CURLOPT_POSTFIELDS, $order);

        // 執行操作

        $response = curl_exec($ch);

        //將xml格式的$response 轉成陣列

        $response = json_decode( json_encode( simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA) ), true );

        //若預下單成功,return_code 和result_code為SUCCESS。

        if ( $response['return_code'] ==='SUCCESS' && $response['result_code'] ==='SUCCESS') {

            //返回trade_type和prepay_id供前端呼叫

            echo json_encode( ['trade_type'=>$response['trade_type'], 'prepay_id'=>$response['prepay_id']] );

        }

    }

2.處理微信回撥

    public function notify()

    {

        $xml = file_get_contents('php://input');

        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

        //使用者http_build_query()將資料轉成URL鍵值對形式

        $sign = http_build_query($arr);

        //md5處理

        $sign = md5($sign);

        //轉大寫

        $sign = strtoupper($sign);

        //驗簽名。預設支援MD5

        if ( $sign === $arr['sign']) {//            校驗返回的訂單金額是否與商戶側的訂單金額一致。修改訂單表中的支付狀態。

        }

        $return = ['return_code'=>'SUCCESS','return_msg'=>'OK'];

        $xml = '';

        foreach($return as $k=>$v){

            $xml.='<'.$k.'>';

        }

        $xml.='';

        echo $xml;

    }

上面的是網上找到的參考程式碼,下面是我寫的;

統一下單:

function WxPay($orderId, $cityCode,$code){

        // 獲取 名稱 、支付金額

        $objPo = new TbPo($cityCode);

        $dataPo = $objPo->getPoInfoById($orderId);

        $actualFee = $dataPo['actual_fee']; //支付金額

        $objPs = new TbPs($cityCode);

        $dataPs = $objPs->getPsById($dataPo['parkspace_id']);

        $parkspaceName = $dataPs['parkspace_name']; //名稱

        $data = $this->getWxLoginInfo($code); // 獲取微信登入資訊

        $data = json_decode($data,true);

        if(empty($data['openid'])){

            return $this->apiNullJson(101);  // code 出錯

        }

        Loader::import('WxpayAPI/lib/WxPay', EXTEND_PATH,'.Data.php');

        $input= new \WxPayUnifiedOrder();    //初始化值物件

        $input->SetBody($parkspaceName);    //文件提及的引數規範:商家名稱-銷售商品類目

        $input->SetOut_trade_no(time());    //生成訂單號

        $input->SetTotal_fee($actualFee*100); //微信支付以分為單位

        $input->SetNotify_url("http://~~~~~/WxPayNotify");//需要自己寫的notify.php  

        $input->SetTrade_type("JSAPI");

        $input->SetOpenid($data['openid']);    //由小程式端傳給後端或者後端自己獲取,寫自己獲取到的,

        $input->SetSpbill_create_ip('~~~~');

        Loader::import('WxpayAPI.lib.WxPay', EXTEND_PATH,'.Api.php');

        $order = \WxPayApi::unifiedOrder($input);    //向微信統一下單,並返回order,它是一個array陣列

        header("Content-Type: application/json");    //json化返回給小程式端

        echo $this->getJsApiParameters($order);

}

    private function getJsApiParameters($UnifiedOrderResult)

    {    //判斷是否統一下單返回了prepay_id

        if(!array_key_exists("appid",$UnifiedOrderResult)||!array_key_exists("prepay_id",$UnifiedOrderResult)|$UnifiedOrderResult['prepay_id'] == "")

{

            return $this->apiNullJson(102);  // 支付出錯

        }

        $jsapi = new \WxPayJsApiPay();

        $jsapi->SetAppid($UnifiedOrderResult["appid"]);

        $timeStamp = time();

        $jsapi->SetTimeStamp("$timeStamp");

        $jsapi->SetNonceStr(\WxPayApi::getNonceStr());

        $jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);

        $jsapi->SetSignType("MD5");

        $jsapi->SetPaySign($jsapi->MakeSign());

        $parameters = json_encode($jsapi->GetValues());

        return $parameters;

}

    function getWxLoginInfo($code)

{

        $url="https://api.weixin.qq.com/sns/jscode2session?appid=~~~~~~~~~~~~&secret=~~~~~~~~~~~~~~&js_code=".$code."&grant_type=authorization_code";

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);

        //引數為1表示傳輸資料,為0表示直接輸出顯示。

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 設定是否輸出結果

        //引數為0表示不帶標頭檔案,為1表示帶標頭檔案

        curl_setopt($ch, CURLOPT_HEADER,false);// 設定是否輸出header

        // 設定是否檢查伺服器端的證書

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        // 使用curl_exec()將CURL返回的結果轉換成正常資料並儲存到一個變數

        $data = curl_exec($ch);

        curl_close($ch);

        return $data;

}

處理微信非同步通知資訊(因為不知道怎麼檢查是否接收成功,只能用一個測試資料檢查是否成功)

    function WxPayNotify(){

        $obj2=new TbPo('0760'); //測試程式碼

        $obj2->updateStatus(1,2); //測試程式碼

        $xml = file_get_contents('php://input');

        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

        //$sign = http_build_query($arr);//使用者http_build_query()將資料轉成URL鍵值對形式

        //$sign = md5($sign);//md5處理

       // $sign = strtoupper($sign);//轉大寫

//參照上面程式碼時,發現簽名不一樣  於是用返回碼來驗證是否成功

        Db::table('tb_po_0760')->where('id',1)->update(['test' => implode("*", $arr)]);  //測試程式碼

        $obj2->updateStatus(1,3); //測試程式碼

            //驗簽名。預設支援MD5

            if ($arr['return_code']=='SUCCESS'&&$arr['result_code']=='SUCCESS') {

                $obj2->updateStatus(1,5);

                //校驗返回的訂單金額是否與商戶側的訂單金額一致。修改訂單表中的支付狀態。

                ~~~~~~~~~~~~

                 ~~~~~~~~~~~~

}

            $return = ['return_code'=>'SUCCESS','return_msg'=>'OK'];

            $xml = '';

            foreach($return as $k=>$v){

                $xml.='<'.$k.'>';

            }

            $xml.='';

            echo $xml;

    }