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;
}