以前一直使用v2,格式是xml格式,但是微信最新推出v3之后,只有以前的老用戶才能用v2,而新用戶只能用v3。閱讀了一下文檔,發現v3采用的是json格式和以前的xml大有不同。官方的demo又不清不白,用的是guzzle(關鍵我不會啊,研究又要太久時間,項目趕,沒辦法只有自己編寫一個demo了,希望可以幫助大家)
首先創建一個文件和類,如WxPayv3.php,請勿直接復制,因為可以看到這個類繼承了另一個類,功能有請求,加密,解密,我的環境為Tp6.0+,所以3.2的用戶需要做下小小的修改。
WxPayv3.php如下
<?php namespace wx; use wx\WxExtend; class WxPayv3 extends WxExtend{ /** * # +======================================================================== * # | - @name 執行 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2021-01-20 * # +======================================================================== */ public function execute($url,$body = null,$http_method = 'POST') { # 轉化大寫 $http_method = strtoupper($http_method); if($http_method == 'POST') { $body = json_encode($body); }else{ $url = $url . '?' . http_build_query($body); $body = null; } # 分割符號 $sign = $this -> getV3Sign($url,$http_method,$body); $header[] = 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'; $header[] = 'Accept: application/json'; $header[] = 'Content-Type: application/json;'; $header[] = 'Authorization: WECHATPAY2-SHA256-RSA2048 '.$sign; $exc = $this -> Curl($url,$body,$http_method,$header); return $exc; } /** * # +======================================================================== * # | - @name 調起小程序支付的簽名 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2021-01-20 * # +======================================================================== */ function getWechartSign($data){ if(!isset($data['appid']) || $data['appid'] == '') {echo 'appid 不能為空';die;} if(!isset($data['timeStamp']) || $data['timeStamp'] == '') {echo 'timeStamp 不能為空';die;} if(!isset($data['package']) || $data['package'] == '') {echo 'package 不能為空';die;} if(!isset($data['nonceStr']) || $data['nonceStr'] == '') {echo 'nonceStr 不能為空';die;} $str = $data['appid']."\n".$data['timeStamp']."\n".$data['nonceStr']."\n".$data['package']."\n"; $str = $this -> getSha256WithRSA($str); return $str; } /** * # +======================================================================== * # | - @name 計算簽名 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2021-01-20 * # +======================================================================== */ function getSha256WithRSA($content){ $privateKey = file_get_contents($this -> SSLKEY_PATH); $binary_signature = ""; $algo = "SHA256"; openssl_sign($content, $binary_signature, $privateKey, $algo); $sign = base64_encode($binary_signature); return $sign; } /** * # +======================================================================== * # | - @name 請求 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2021-01-20 * # +======================================================================== */ public function Curl($url, $data, $http_method,$header = array(), $timeout = 30) { $opts = array( CURLOPT_TIMEOUT => $timeout, CURLOPT_RETURNTRANSFER => 1, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_HTTPHEADER => $header, CURLOPT_URL => $url, CURLOPT_HEADER => 1 , ); # 根據請求類型設置特定參數 if($http_method == 'POST') { # 判斷是否傳輸文件 $opts[CURLOPT_POST] = 1; $opts[CURLOPT_POSTFIELDS] = $data; } # 初始化並執行curl請求 $ch = curl_init(); curl_setopt_array($ch, $opts); $data = curl_exec($ch); $error = curl_error($ch); $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE); curl_close($ch); if($error) throw new Exception('請求發生錯誤:' . $error); list($headers, $body) = explode("\r\n\r\n", $data, 2); $result['data'] = json_decode($body,true); $result['httpcode'] = $httpCode; $result['headers'] = explode("\r\n", $headers); return $result; } /** * # +======================================================================== * # | - @name 簽名 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2021-01-20 * # +======================================================================== */ public function getV3Sign($url,$http_method,$body) { # 商戶號 $merchant_id = $this -> MCHID; # 隨機字符串 $nonce = strtoupper($this -> getNoncestr()); # 商戶序列號 $serial_no = $this -> merchantSerialNumber; # 時間搓 $timestamp = time(); # url $url_parts = parse_url($url); # 獲取絕對路徑 $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : "")); # 密鑰key $private_key = $this -> getPrivateKey($this -> SSLKEY_PATH); # 拼接參數 $message = $http_method."\n". $canonical_url."\n". $timestamp."\n". $nonce."\n". $body."\n"; # 獲取簽名 openssl_sign($message, $raw_sign, $private_key, 'sha256WithRSAEncryption'); $sign = base64_encode($raw_sign); $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $merchant_id, $nonce, $timestamp, $serial_no, $sign); return $token; } /** * # +======================================================================== * # | - @name 獲取私鑰 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2019-12-26 * # +======================================================================== */ public function getPrivateKey($filepath) { return openssl_get_privatekey(file_get_contents($filepath)); } /** * # +======================================================================== * # | - @name 獲取隨機數 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2021-01-20 * # +======================================================================== */ 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; } /** * # +======================================================================== * # | - @name 解密 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2021-01-20 * # +======================================================================== */ public function decryptToString($associatedData, $nonceStr, $ciphertext) { $aesKey = $this -> v3key; $ciphertext = \base64_decode($ciphertext , true); if (strlen($ciphertext) <= 16) { return false; } // ext-sodium (default installed on >= PHP 7.2) if(function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available() ){ return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey); } // ext-libsodium (need install libsodium-php 1.x via pecl) if(function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available()){ return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey); } // PHP >= 7.1 if(PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods()) ){ $ctext = substr($ciphertext, 0, -16); $authTag = substr($ciphertext, -16); return \openssl_decrypt($ctext, 'aes-256-gcm', $aesKey, \OPENSSL_RAW_DATA, $nonceStr,$authTag, $associatedData); } throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安裝libsodium-php'); } }
WxExtend.php如下
<?php namespace wx; class WxExtend { //=======【基本信息設置】===================================== //微信公眾號身份的唯一標識。審核通過后,在微信發送的郵件中查看 public $APPID; //受理商ID,身份標識 public $MCHID; //商戶支付密鑰Key。審核通過后,在微信發送的郵件中查看 public $KEY; //微信v3 public $v3key; //JSAPI接口中獲取openid,審核后在公眾平台開啟開發模式后可查看 public $APPSECRET; //=======【證書路徑設置】===================================== //證書路徑,注意應該填寫絕對路徑 public $SSLCERT_PATH; public $SSLKEY_PATH; //商戶API證書序列號 public $merchantSerialNumber; //小程序appid public $appletappid; //小程序密鑰 public $appletsecret; //=======【curl超時設置】=================================== //本例程通過curl使用HTTP POST方法,此處可修改其超時時間,默認為30秒 public $CURL_TIMEOUT = 30; //服務service_id,微信分特有 public $service_id; function __construct() { //小程序appid $this->appletappid ='000000'; //小程序密鑰 $this->appletsecret ='000'; //微信公眾號身份的唯一標識。審核通過后,在微信發送的郵件中查看 $this->APPID = '000' ; //JSAPI接口中獲取openid,審核后在公眾平台開啟開發模式后可查看 $this->APPSECRET = '000' ; //受理商ID,身份標識 $this->MCHID = '000' ; //商戶支付密鑰Key。審核通過后,在微信發送的郵件中查看 $this->KEY = '000'; $this->v3key = '000'; //商戶API證書序列號 $this->merchantSerialNumber = '000'; //服務service_id,微信分特有 $this->service_id = '000'; //=======【證書路徑設置】===================================== //證書路徑,注意應該填寫絕對路徑 $this->SSLCERT_PATH = app()->getRootPath().'extend/wx/cacert/apiclient_cert.pem' ; $this->SSLKEY_PATH = app()->getRootPath().'extend/wx/cacert/apiclient_key.pem'; } }
然后再new再調用就完事了
/** * # +======================================================================== * # | - @name 查詢用戶 * # | - @author cq <just_leaf@foxmail.com> * # | - @copyright zmtek 2020-11-24 * # +------------------------------------------------------------------------ * # | - 1.msg * # +======================================================================== */ public function permissions_openid(WxPayv3 $WxPayv3,WxExtend $WxExtend) { $url = 'https://api.mch.weixin.qq.com/v3/payscore/permissions/openid/xxxx'; $authorization_code = $WxPayv3 -> getNoncestr(); $data = array( 'appid' => $WxExtend -> appletappid , 'service_id' => $WxExtend -> service_id, ); $result = $WxPayv3 -> execute($url,$data,'GET'); pf($result); // $data = json_decode($result['data'],true); // return $this -> success($data); }
好,我們來看調用結果

啊呀,好家伙,是不是我這個方法有問題呢?結果趕緊看下官方文檔,原來是微信那邊掛了。不信?看下圖

好啦,之后就可以愉快的調用任何接口了。
