本文實例為大家分享了php實現微信企業轉賬的具體代碼,供大家參考,具體內容如下
01 | <?php |
02 | /** |
03 | * 配置賬號信息 |
04 | * 配置要和證書在一起!!!! |
05 | */ |
06 | |
07 | class WxTransfersConfig |
08 | { |
09 | //=======【基本信息設置】============== |
10 | // |
11 | /** |
12 | * TODO: 修改這里配置為您自己申請的商戶信息 |
13 | * 微信公眾號信息配置 |
14 | * |
15 | * APPID:綁定支付的APPID(必須配置,開戶郵件中可查看) |
16 | * |
17 | * MCHID:商戶號(必須配置,開戶郵件中可查看) |
18 | * |
19 | * KEY:商戶支付密鑰,參考開戶郵件設置(必須配置,登錄商戶平臺自行設置) |
21 | * |
22 | */ |
23 | const APPID = '' ; |
24 | const MCHID = '' ; |
25 | const KEY = '' ; |
26 | //=======【證書路徑設置】===================================== |
27 | /** |
28 | * TODO:設置商戶證書路徑 |
29 | * 證書路徑,注意應該填寫絕對路徑,發送紅包和查詢需要,可登錄商戶平臺下載 |
30 | * API證書下載地址:https://pay.weixin.qq.com/index.php/account/api_cert,下載之前需要安裝商戶操作證書) |
31 | * @var path 跟這個文件同一目錄下的cert文件夾放置證書!!!! |
32 | */ |
33 | const SSLCRET12 = 'cert/apiclient_cert.p12' ; |
34 | const SSLCERT_PATH = 'cert/apiclient_cert.pem' ; |
35 | const SSLKEY_PATH = 'cert/apiclient_key.pem' ; |
36 | const SSLROOTCA = 'cert/rootca.pem' ; |
37 | |
38 | //=======【證書路徑設置】===================================== |
39 | /** |
40 | * 獲取文件的路徑,證書需要完整路徑 |
41 | * @return string |
42 | */ |
43 | public static function getRealPath(){ |
44 | return __DIR__. '/' ; |
45 | } |
46 | } |
微信企業轉賬工具類:
001 | <?php |
002 | require_once "WxTransfers.Config.php" ; |
003 | |
004 | /** |
005 | * 微信企業轉賬工具類 |
006 | */ |
007 | class WxTransfers |
008 | { |
009 | // 企業轉賬請求地址 |
010 | const TRANSFERS_URL = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers' ; |
011 | |
012 | //獲取轉賬信息地址 |
013 | const GETINFO_URL= 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo' ; |
014 | |
015 | // 轉賬需要的配置 'wxappid','mch_id','key' |
016 | private $_keys ; |
017 | |
018 | // 轉賬需要的證書文件 'api_cert', 'api_key', 'rootca',請傳入絕對路徑!!! |
019 | private $_cert ; |
020 | |
021 | protected $log_file ; |
022 | |
023 | public $error ; |
024 | |
025 | // 相關配置必備參數 |
026 | protected $_parameters = array (); |
027 | |
028 | // 最后一次生產的訂單號 |
029 | protected $_lastPartnerTradeNo ; |
030 | |
031 | // 記錄最后一次發送請求的結果對象 |
032 | protected $_lastResult ; |
033 | |
034 | // 最后一次隨機數 |
035 | protected $_lastRandNum ; |
036 | |
037 | public function __construct( $config ) |
038 | { |
039 | $keys = array ( |
040 | 'wxappid' , |
041 | 'mch_id' , |
042 | 'key' |
043 | ); |
044 | $files = array ( |
045 | 'api_cert' , |
046 | 'api_key' , |
047 | 'rootca' |
048 | ); |
049 | |
050 | foreach ( $keys as $key ) { |
051 | try { |
052 | $this ->_keys[ $key ] = $config [ $key ]; |
053 | } catch (Exception $e ) { |
054 | throw new Exception( '參數缺失:' . $key ); |
055 | } |
056 | } |
057 | |
058 | foreach ( $files as $file ) { |
059 | try { |
060 | $cret_file = $config [ $file ]; |
061 | if ( is_file ( $cret_file )) { |
062 | $this ->_cert[ $file ] = $cret_file ; |
063 | } |
064 | } catch (Exception $e ) { |
065 | throw new Exception( '證書錯誤' ); |
066 | } |
067 | } |
068 | } |
069 | |
070 | public function transfers( $parameters ){ |
071 | |
072 | $this ->log( $parameters , 'SEND_PARAM' ); |
073 | |
074 | $this ->setParameter( 'mchid' , $this ->_keys[ 'mch_id' ]); |
075 | $this ->setParameter( 'mch_appid' , $this ->_keys[ 'wxappid' ]); |
076 | |
077 | $must = array ( |
078 | 'openid' , |
079 | 'check_name' , |
080 | 're_user_name' , |
081 | 'amount' , |
082 | 'desc' , |
083 | 'spbill_create_ip' , |
084 | ); |
085 | foreach ( $must as $key ) { |
086 | if (isset( $parameters [ $key ]) && $parameters [ $key ]) { |
087 | $this ->setParameter( $key , $parameters [ $key ]); |
088 | } else |
089 | if (! isset( $this ->_parameters[ $key ]) || ! $this ->_parameters[ $key ]) { |
090 | $this ->error = '參數缺損:' . $key ; |
091 | return false; |
092 | } |
093 | } |
094 | if (! isset( $parameters [ 'partner_trade_no' ])) { |
095 | $parameters [ 'partner_trade_no' ] = $this ->getPartnerTradeNo(); |
096 | } |
097 | |
098 | $this ->setParameter( 'partner_trade_no' , $parameters [ 'partner_trade_no' ]); |
099 | |
100 | $this ->setParameter( 'nonce_str' , $this ->getRand(30, 3)); |
101 | |
102 | $postXml = $this ->_createXml(); |
103 | |
104 | if (! $postXml ) { |
105 | return false; |
106 | } |
107 | $this ->log( $postXml , 'SEND_XML' ); |
108 | |
109 | $result = $this ->curl_post_ssl(self::TRANSFERS_URL, $postXml ); |
110 | |
111 | $this ->log( $result , 'RESULT_XML' ); |
112 | |
113 | if (! $result ) { |
114 | return false; |
115 | } |
116 | $resultObj = simplexml_load_string( $result , 'SimpleXMLElement' , LIBXML_NOCDATA); |
117 | |
118 | $this ->_lastResult = $resultObj ; |
119 | |
120 | if ( $resultObj ->return_code == 'SUCCESS' ) { // 成功標識 |
121 | |
122 | if ( $resultObj ->result_code == 'SUCCESS' ) { |
123 | |
124 | return $resultObj ->send_listid; |
125 | } |
126 | |
127 | if ( $resultObj ->return_msg) { |
128 | $this ->error = (string) $resultObj ->return_msg; |
129 | return false; |
130 | } |
131 | |
132 | $this ->error = (string) $resultObj ->err_code_des; |
133 | return false; |
134 | } |
135 | |
136 | if ( $resultObj ->return_code != 'FAIL' ) { |
137 | $this ->error = '返回信息格式異常' ; |
138 | return false; |
139 | } |
140 | |
141 | $this ->error = (string) $resultObj ->return_msg; |
142 | return false; |
143 | } |
144 | |
145 | /** |
146 | * 獲取轉賬信息 |
147 | * @param unknown $partner_trade_no |
148 | * @return boolean|SimpleXMLElement |
149 | */ |
150 | public function getInfo( $partner_trade_no ){ |
151 | $param = array ( |
152 | 'nonce_str' => $this ->getRand(30, 3), |
153 | 'partner_trade_no' => $partner_trade_no , |
154 | 'mch_id' => $this ->_keys[ 'mch_id' ], |
155 | 'appid' => $this ->_keys[ 'wxappid' ], |
156 | ); |
157 | |
158 | ksort( $param ); |
159 | $unSignParaString = $this ->_formatQueryParaMap( $param , false); |
160 | $param [ 'sign' ] = $this ->_sign( $unSignParaString , $this ->_keys[ 'key' ]); |
161 | |
162 | $xml = $this ->arrayToXml( $param ); |
163 | |
164 | $this ->log( $xml , 'GETINFO_XML' ); |
165 | |
166 | $result = $this ->curl_post_ssl(self::GETINFO_URL, $xml ); |
167 | |
168 | if (! $result ){ |
169 | return false ; |
170 | } |
171 | |
172 | $this ->log( $result , 'RESULT_XML' ); |
173 | |
174 | $resultObj = simplexml_load_string( $result , 'SimpleXMLElement' , LIBXML_NOCDATA); |
175 | $this ->_lastResult = $resultObj ; |
176 | if ( $resultObj ->return_code == 'SUCCESS' ){ //成功標識 |
177 | |
178 | if ( $resultObj ->result_code == 'SUCCESS' ){ |
179 | return $resultObj ; |
180 | } |
181 | |
182 | if ( $resultObj ->return_msg){ |
183 | $this ->error = $resultObj ->return_msg ; |
184 | return false ; |
185 | } |
186 | |
187 | $this ->error = $resultObj ->err_code_des ; |
188 | return false ; |
189 | } |
190 | |
191 | if ( $resultObj ->return_code != 'FAIL' ){ |
192 | $this ->error = '返回信息格式異常' ; |
193 | return false ; |
194 | } |
195 | |
196 | $this ->error = $resultObj ->return_msg ; |
197 | return false ; |
198 | } |
199 | /** |
200 | * 設置所需要的參數 |
201 | * @param $parameter 鍵值數組/鍵 |
202 | * @param $value 值 |
203 | * @return WxBonusApi |
204 | */ |
205 | public function setParameter( $parameter , $value = null) |
206 | { |
207 | if (! is_array ( $parameter )) { |
208 | return $this ->setParameter( array ( |
209 | $parameter => $value |
210 | )); |
211 | } |
212 | |
213 | foreach ( $parameter as $key => $value ) { |
214 | $key = trim( $key ); |
215 | $value = trim( $value ); |
216 | $this ->_parameters[ $key ] = $value ; |
217 | } |
218 | return $this ; |
219 | } |
220 | |
221 | /** |
222 | * 獲取參數值 |
223 | * @param $parameter 鍵名 |
224 | * @return multitype: |
225 | */ |
226 | public function getParameter( $parameter ) |
227 | { |
228 | return $this ->_parameters[ $parameter ]; |
229 | } |
230 | |
231 | /** |
232 | * 獲取隨機數 |
233 | * @param number $len 隨機數的位數 |
234 | * @param number $type 取值范圍 1表示數字 2小寫字母 4大寫字母 |
235 | * @return string |
236 | */ |
237 | public function getRand( $len = 30, $type = 0) |
238 | { |
239 | $str = '' ; |
240 | $max = - 1; |
241 | |
242 | if (! $type ) { |
243 | $type = 3; |
244 | } |
245 | |
246 | if ( $type & 1) { |
247 | $str .= '1234567890' ; |
248 | $max += 10; |
249 | } |
250 | |
251 | if ( $type & 2) { |
252 | $str .= 'abcdefghijklmnopqrstuvwxyz' ; |
253 | $max += 26; |
254 | } |
255 | |
256 | if ( $type & 4) { |
257 | $str .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ; |
258 | $max += 26; |
259 | } |
260 | |
261 | $rand = '' ; |
262 | for ( $i = 0; $i < $len ; $i ++) { |
263 | $rand .= $str [rand(0, $max )]; |
264 | } |
265 | |
266 | return $rand ; |
267 | } |
268 | |
269 | /** |
270 | * 生成商戶的訂單號 |
271 | * @return string |
272 | */ |
273 | public function getPartnerTradeNo() |
274 | { |
275 | $this ->_lastPartnerTradeNo = $this ->_parameters[ 'mch_id' ] . date ( 'YmdHis' ) . $this ->getRand(4, 1); // $this->getRandNum(); |
276 | return $this ->_lastPartnerTradeNo; |
277 | } |
278 | |
279 | |
280 | /** |
281 | * 獲取最后一次創建生成的訂單號 |
282 | * @return string |
283 | */ |
284 | public function getLastPartnerTradeNo() |
285 | { |
286 | return $this ->_lastPartnerTradeNo; |
287 | } |
288 | |
289 | |
290 | |
291 | /** |
292 | * 創建XML的方法 |
293 | * @param number $retcode |
294 | * @param string $reterrmsg |
295 | * @return boolean|string |
296 | */ |
297 | private function _createXml() |
298 | { |
299 | try { |
300 | $sign = $this ->_getSign(); |
301 | if (! $sign ) { |
302 | return false; |
303 | } |
304 | $this ->setParameter( 'sign' , $sign ); |
305 | |
306 | return $this ->arrayToXml( $this ->_parameters); |
307 | } catch (Exception $e ) { |
308 | $this ->error = $e ->getMessage(); |
309 | return false; |
310 | } |
311 | } |
312 | |
313 | |
314 | /** |
315 | * 參數轉換成XML |
316 | * @param array $arr 參數數組 |
317 | * @return string |
318 | */ |
319 | public function arrayToXml( $arr ) |
320 | { |
321 | $xml = "<xml>" ; |
322 | foreach ( $arr as $key => $val ) { |
323 | if ( is_numeric ( $val )) { |
324 | $xml .= "<" . $key . ">" . $val . "</" . $key . ">" ; |
325 | } else { |
326 | $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">" ; |
327 | } |
328 | } |
329 | $xml .= "</xml>" ; |
330 | return $xml ; |
331 | } |
332 | |
333 | /** |
334 | * 獲得簽名結果 |
335 | * @return boolean|Ambigous <string, boolean> |
336 | */ |
337 | protected function _getSign() |
338 | { |
339 | try { |
340 | |
341 | if ( $this ->_checkSign() == false) { // 檢查生成簽名參數 |
342 | $this ->error = '生成簽名參數缺失!' ; |
343 | $this ->log(json_encode( $this ->_parameters, JSON_UNESCAPED_UNICODE), 'ERROR_Sign_XML' ); |
344 | return false; |
345 | } |
346 | |
347 | ksort( $this ->_parameters); |
348 | $unSignParaString = $this ->_formatQueryParaMap( $this ->_parameters, false); |
349 | |
350 | return $this ->_sign( $unSignParaString , $this ->_keys[ 'key' ]); |
351 | } catch (Exception $e ) { |
352 | $this ->error = $e ->getMessage(); |
353 | return false; |
354 | } |
355 | } |
356 | |
357 | /** |
358 | * 檢查簽名所需參數是否齊全 |
359 | * @return boolean |
360 | */ |
361 | private function _checkSign() |
362 | { |
363 | // return true; |
364 | if ( $this ->_parameters[ "mch_appid" ] == null || |
365 | $this ->_parameters[ "mchid" ] == null || |
366 | //$this->_parameters["device_info"] == null || 設備id |
367 | $this ->_parameters[ "nonce_str" ] == null || |
368 | $this ->_parameters[ "partner_trade_no" ] == null || |
369 | $this ->_parameters[ "openid" ] == null || |
370 | $this ->_parameters[ "check_name" ] == null || |
371 | $this ->_parameters[ "re_user_name" ] == null || |
372 | $this ->_parameters[ "desc" ] == null || |
373 | $this ->_parameters[ "spbill_create_ip" ] == null) { |
374 | return false; |
375 | } |
376 | return true; |
377 | } |
378 | |
379 | /** |
380 | * |
381 | * @param $paraMap |
382 | * @param $urlencode |
383 | * @return string |
384 | */ |
385 | private function _formatQueryParaMap( $paraMap , $urlencode ) |
386 | { |
387 | $buff = "" ; |
388 | ksort( $paraMap ); |
389 | foreach ( $paraMap as $k => $v ) { |
390 | if (null != $v && "null" != $v && "sign" != $k ) { |
391 | if ( $urlencode ) { |
392 | $v = urlencode( $v ); |
393 | } |
394 | $buff .= $k . "=" . $v . "&" ; |
395 | } |
396 | } |
397 | $reqPar ; |
398 | if ( strlen ( $buff ) > 0) { |
399 | $reqPar = substr ( $buff , 0, strlen ( $buff ) - 1); |
400 | } |
401 | return $reqPar ; |
402 | } |
403 | |
404 | |
405 | /** |
406 | * 簽名 |
407 | * @param $content 簽名的字符串 |
408 | * @param $key 密鑰 |
409 | * @throws Exception |
410 | * @return string|boolean |
411 | */ |
412 | private function _sign( $content , $key ) |
413 | { |
414 | try { |
415 | if (null == $key ) { |
416 | $this ->error = '簽名key不能為空!' ; |
417 | return false; |
418 | } |
419 | if (null == $content ) { |
420 | $this ->error = '簽名內容不能為空' ; |
421 | return false; |
422 | } |
423 | $signStr = $content . "&key=" . $key ; |
424 | |
425 | return strtoupper (md5( $signStr )); |
426 | |
427 | } catch (Exception $e ) { |
428 | $this ->error = $e ->getMessage(); |
429 | return false; |
430 | } |
431 | } |
432 | |
433 | /** |
434 | * cURL抓取 |
435 | * |
436 | * @param $url 鏈接地址 |
437 | * @param $vars 參數 |
438 | * @param |
439 | * $second |
440 | * @param |
441 | * $aHeader |
442 | * @return mixed|boolean |
443 | */ |
444 | function curl_post_ssl( $url , $data , $second = 30, $aHeader = array ()) |
445 | { |
446 | $ch = curl_init(); |
447 | // 超時時間 |
448 | curl_setopt( $ch , CURLOPT_TIMEOUT, $second ); |
449 | curl_setopt( $ch , CURLOPT_RETURNTRANSFER, 1); |
450 | // 這里設置代理,如果有的話 |
451 | curl_setopt( $ch , CURLOPT_URL, $url ); |
452 | curl_setopt( $ch , CURLOPT_SSL_VERIFYPEER, false); |
453 | curl_setopt( $ch , CURLOPT_SSL_VERIFYHOST, false); |
454 | // cert 與 key 分別屬于兩個.pem文件 |
455 | curl_setopt( $ch , CURLOPT_SSLCERT, $this ->_cert[ 'api_cert' ]); |
456 | curl_setopt( $ch , CURLOPT_SSLKEY, $this ->_cert[ 'api_key' ]); |
457 | curl_setopt( $ch , CURLOPT_CAINFO, $this ->_cert[ 'rootca' ]); |
458 | if ( count ( $aHeader ) >= 1) { |
459 | curl_setopt( $ch , CURLOPT_HTTPHEADER, $aHeader ); |
460 | } |
461 | curl_setopt( $ch , CURLOPT_POST, 1); |
462 | curl_setopt( $ch , CURLOPT_POSTFIELDS, $data ); |
463 | $data = curl_exec( $ch ); |
464 | if ( $data ) { |
465 | curl_close( $ch ); |
466 | return $data ; |
467 | } else { |
468 | $this ->log(json_encode( $this ->_cert)); |
469 | $this ->error = 'aa:' .curl_errno( $ch ); |
470 | curl_close( $ch ); |
471 | return false; |
472 | } |
473 | } |
474 | |
475 | /** |
476 | * 獲取服務器ip |
477 | * |
478 | * @return string |
479 | */ |
480 | public function getServerIp() |
481 | { |
482 | $server_ip = '127.0.0.1' ; |
483 | if (isset( $_SERVER )) { |
484 | if (isset( $_SERVER [ 'SERVER_ADDR' ]) && $_SERVER [ 'SERVER_ADDR' ]) { |
485 | $server_ip = $_SERVER [ 'SERVER_ADDR' ]; |
486 | } elseif (isset( $_SERVER [ 'LOCAL_ADDR' ]) && $_SERVER [ 'LOCAL_ADDR' ]) { |
487 | $server_ip = $_SERVER [ 'LOCAL_ADDR' ]; |
488 | } |
489 | } else { |
490 | $server_ip = getenv ( 'SERVER_ADDR' ); |
491 | } |
492 | return $server_ip ; |
493 | } |
494 | |
495 | /** |
496 | * 設置日志目錄文件 |
497 | * |
498 | * @param unknown $file |
499 | */ |
500 | public function setLogFile( $file ) |
501 | { |
502 | $this ->log_file = $file ; |
503 | } |
504 | |
505 | /** |
506 | * 寫日志 |
507 | * |
508 | * @param $msg 寫入的信息 |
509 | * @param $type 日志類型作為查詢標示 |
510 | */ |
511 | public function log( $msg , $type ) |
512 | { |
513 | if ( $this ->log_file) { |
514 | $log = str_replace ( array ( |
515 | "\r\n" , |
516 | "\r" , |
517 | "\n" |
518 | ), array ( |
519 | "" , |
520 | "" , |
521 | "" |
522 | ), $msg ); |
523 | error_log ( $type . ' ' . date ( 'Y-m-d H:i:s' ) . ' ' . json_encode( $log ,JSON_UNESCAPED_UNICODE) . "\r\n" , 3, $this ->log_file); |
524 | } |
525 | } |
526 | |
527 | } |
01 | <?php |
02 |
03 | include 'WxTransfers.Api.php' ; |
04 | class WxTransfers{ |
05 |
06 | /** |
07 | *調用方法即可測試 |
08 | */ |
09 | public function index(){ |
10 | |
11 | $path = WxTransfersConfig::getRealPath(); // 證書文件路徑 |
12 | $config [ 'wxappid' ] = WxTransfersConfig::APPID; |
13 | $config [ 'mch_id' ] = WxTransfersConfig::MCHID; |
14 | $config [ 'key' ] = WxTransfersConfig::KEY; |
15 | $config [ 'PARTNERKEY' ] = WxTransfersConfig::KEY; |
16 | $config [ 'api_cert' ] = $path . WxTransfersConfig::SSLCERT_PATH; |
17 | $config [ 'api_key' ] = $path . WxTransfersConfig::SSLKEY_PATH; |
18 | $config [ 'rootca' ] = $path . WxTransfersConfig::SSLROOTCA; |
19 | |
20 | $wxtran = new WxTransfers( $config ); |
21 | |
22 | $wxtran ->setLogFile( 'D:\\transfers.log' ); //日志地址 |
23 | |
24 | //轉賬 |
25 | $data = array ( |
26 | 'openid' => '' , //openid |
27 | 'check_name' => 'NO_CHECK' , //是否驗證真實姓名參數 |
28 | 're_user_name' => '11' , //姓名 |
29 | 'amount' =>100, //最小1元 也就是100 |
30 | 'desc' => '企業轉賬測試' , //描述 |
31 | 'spbill_create_ip' => $wxtran ->getServerIp(), //服務器IP地址 |
32 | ); |
33 | var_dump(json_encode( $wxtran ->transfers( $data ),JSON_UNESCAPED_UNICODE)); |
34 | var_dump( $wxtran ->error); |
35 | |
36 | //獲取轉賬信息 |
37 | var_dump( $wxtran ->getInfo( '11111111' )); |
38 | var_dump( $wxtran ->error); |
39 | } |
40 | |
41 | } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。