原本項目上有一個提現功能,因原客戶商戶號和流水原因一直沒做。
最近因為剛剛符合條件的原因,今天才開始做。
順便瀏覽下博客,發現原來寫的微信支付有些那個啥了。
因為最近項目前后端分離居多,而且項目也多JSAPI、APP、NATIVE等多種一起居多
所以就將原來的微信支付 重新整合了下
與原來的相比,整合過后的更適用於前后端分離來做
如果沒有前后端分離,還可以借鑒原來的公眾號支付:tp5 -- 微信公眾號支付
不過最好還是自己調整下,畢竟那個代碼比較久了
好了,話不多說,還是直接上代碼吧
因為此支付是自己封裝,同樣還是在 extend/ 文件下 的Wxpay.php
代碼如下:
<?php namespace pay; class Wxpay{ private $config =[ "appid" => "", // 開放平台或商戶平台APPID "mch_id" => "", // 商戶平台 商戶號 "key" => "", // 商戶平台 秘鑰KEY "TOKEN" => "", // 此參數非必傳 有的前端在jsapi 支付時會要求返回signature 參數 此參數即為此准備 ]; public function index($param,$openid="") { $order = [ 'out_trade_no' => $param['out_trade_no'],// 訂單號 'total_fee' => intval($param['total_fee']*100),// 訂單金額 以(分)為單位 'body' => $param['body'],// 商品描述 'notify_url' => $param['notify_url'], //回調地址 'spbill_create_ip' => $param['spbill_create_ip'], //對應IP 'trade_type' => $param['trade_type'] //對應支付類型 ]; #當支付類型為JAPI時 openid 必傳 if($param['trade_type'] == "JSAPI") { $order['openid'] = $openid; } #統一下單 獲取prepay_id $unified_order=$this->unifiedOrder($order); #獲取當前時間戳 $time = time(); #JSAPI if($param['trade_type'] == 'JSAPI') { #組合jssdk需要用到的數據 $data = [ 'appId' => $this->config['appid'], //appid 'timeStamp' => strval($time), //時間戳 'nonceStr' =>$unified_order['nonce_str'],// 隨機字符串 'package' => 'prepay_id='.$unified_order['prepay_id'],// 預支付交易會話標識 'signType' => 'MD5' //加密方式 ]; // 生成簽名 $data['paySign']=$this->makeSign($data); // #有的可能會有需求signature 此參數的在此加密一下即可 // $token = $this->config['token']; // $tmpArr = array($token, strval($time),$unified_order['nonce_str']); // sort($tmpArr, SORT_STRING); // $tmpStr = implode( $tmpArr ); // $tmpStr = sha1($tmpStr); // $data['signature'] = $tmpStr; } #APP elseif($param['trade_type'] == 'APP') { $data = [ 'appid' => $this->config['appid'], 'partnerid' => $this->config['mch_id'], 'prepayid' => $unified_order['prepay_id'], 'package' => 'Sign=WXPay', 'noncestr' => $unified_order['nonce_str'],// 隨機字符串 'timestamp' => strval($time), //時間戳 ]; //生成簽名 $data['sign'] = $this->makeSign($data); } return $data; } /** * 統一下單 * @param array $order 訂單 必須包含支付所需要的參數 body(產品描述)、total_fee(訂單金額)、out_trade_no(訂單號)、product_id(產品id)、trade_type(類型:JSAPI,NATIVE,APP) */ public function unifiedOrder($order) { $config =[ 'appid' => $this->config['appid'], //appid 'mch_id' => $this->config['mch_id'], //商戶號ID 'nonce_str' => $this->getNonceStr() ]; # 合並配置數據和訂單數據 $data=array_merge($order,$config); # 生成簽名 $sign=$this->makeSign($data); $data['sign']=$sign; #轉換成xml $xml=$this->toXml($data); $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //接收xml數據的文件 $header[] = "Content-type: text/xml"; //定義content-type為xml,注意是數組 $ch = curl_init ($url); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 兼容本地沒有指定curl.cainfo路徑的錯誤 curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); $response = curl_exec($ch); if(curl_errno($ch)){ # 顯示報錯信息;終止繼續執行 die(curl_error($ch)); } curl_close($ch); #轉換成數組 $result=$this->toArray($response); #顯示錯誤信息 if ($result['return_code']=='FAIL') { die($result['return_msg']); } $result['sign']=$sign; $result['nonce_str']=$this->getNonceStr(); return $result; } /** * 生成簽名 * @return 簽名,本函數不覆蓋sign成員變量,如要設置簽名需要調用SetSign方法賦值 */ public function makeSign($data) { # 去空 $data=array_filter($data); #簽名步驟一:按字典序排序參數 ksort($data); #將數組轉成url形式 $string_a=http_build_query($data); $string_a=urldecode($string_a); #簽名步驟二:在string后加入KEY $string_sign_temp=$string_a."&key=".$this->config['key']; #簽名步驟三:MD5加密 $sign = md5($string_sign_temp); # 簽名步驟四:所有字符轉為大寫 $result=strtoupper($sign); return $result; } /** * 將xml轉為array * @param string $xml xml字符串 * @return array 轉換得到的數組 */ public function toArray($xml){ #禁止引用外部xml實體 libxml_disable_entity_loader(true); $result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $result; } /** * * 產生隨機字符串,不長於32位 * @param int $length * @return 產生的隨機字符串 */ public function getNonceStr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } /** * 輸出xml字符 * @throws WxPayException **/ public function toXml($data) { if(!is_array($data) || count($data) <= 0) { throw new WxPayException("數組數據異常!"); } $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; } /** * 驗證 * @return array 返回數組格式的notify數據 */ public function notify() { // 獲取xml $xml=file_get_contents('php://input', 'r'); # 轉成php數組 $data=$this->toArray($xml); # 保存原sign $data_sign=$data['sign']; # sign不參與簽名 unset($data['sign']); $sign=$this->makeSign($data); # 判斷簽名是否正確 判斷支付狀態 if ($sign===$data_sign && $data['return_code']=='SUCCESS' && $data['result_code']=='SUCCESS') { $result=$data; }else{ $result=false; } # 返回狀態給微信服務器 if ($result) { $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; }else{ $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[簽名失敗]]></return_msg></xml>'; } return $result; } } ?>
下面就是調用方法超級簡單:
<?php namespace app\index\controller; header("Content-Type: text/html;charset=utf-8"); use think\Controller; use pay\Wxpay; class Buy extends Controller { #新的微信支付類調用 public function newpay() { $pay_sn = date('YmdHis').rand(1000,9999); $total_fee = '0.01'; $body = "商品描述"; $spbill_create_ip = '192.168.0.1'; $notify_url = "你的回調地址"; #根據不同類型回調地址不同 $trade_type = 'APP'; #JSAPI--JSAPI支付(或小程序支付)、 #NATIVE--Native支付、 #APP--app支付, #MWEB--H5支付, #不同trade_type決定了調起支付的方式,請根據支付產品正確上傳 #新的需要參數為六個 # out_trade_no 商戶訂單號 # total_fee 訂單總額 # body 商品描述 # spbill_create_ip 終端IP # notify_url 回調通知地址 # trade_type 交易類型 $wxpay = new Wxpay(); $date = [ 'out_trade_no' => $pay_sn, 'total_fee' => $total_fee, 'body' => $body, 'spbill_create_ip' => getIp(), 'notify_url' => $notify_url, 'trade_type' => $trade_type ]; #根據 trade_type 類型不同,是否傳遞openid #APP 類型支付調用 $res = $wxpay->index($date); #JSAPI 類型支付調用 $res = $wxpay->index($date,$openid); #獲得后將對應內容返回前端即可 return $res; } } ?>
最后就是回調咯:
<?php namespace app\index\controller; header("Content-Type: text/html;charset=utf-8"); use think\Controller; use pay\Wxpay; class Pays extends Controller { public function notify() { $wxpay = new Wxpay(); $result = $wxpay->notify(); #根據拿到的數據 來進行自己的數據邏輯 if($result) { $out_trade_no = $result['out_trade_no']; echo "success";exit; } echo "error"; } } ?>
以上就是本次整合的微信支付咯
感謝各位大大的觀看。
2020年4月17日