寫這篇文章的目的主要是由於在微信公眾平台提供的SDK中並沒有提供此功能的SDK實現,
其實最后實現還是借助 微信公眾平台開發文檔 和 SDK 。
企業付款的應用場景: 公眾號向已關注用戶付款,比如處理退款、財務結算等
先說一下實現思路:
在SDK中自帶類庫的基礎上擴展WxMchPay組件, 實現企業付款功能的擴展。
話不多說,上代碼, 下面是繼承SDK,實現企業付款的組件:
$parameters參數參考: 企業付款API的文檔
<?php // 引入SDK
import('Common.Util.WxPay'); /** * 微信企業付款操作類 * Author : Max.wen * DateTime: <15/9/16 11:00> */
class WxMchPay extends Wxpay_client_pub { /** * API 參數 * @var array * 'mch_appid' # 公眾號APPID * 'mchid' # 商戶號 * 'device_info' # 設備號 * 'nonce_str' # 隨機字符串 * 'partner_trade_no' # 商戶訂單號 * 'openid' # 收款用戶openid * 'check_name' # 校驗用戶姓名選項 針對實名認證的用戶 * 're_user_name' # 收款用戶姓名 * 'amount' # 付款金額 * 'desc' # 企業付款描述信息 * 'spbill_create_ip' # Ip地址 * 'sign' # 簽名 */
public $parameters = []; public function __construct() { $this->url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'; $this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT; } /** * 生成請求xml數據 * @return string */
public function createXml() { $this->parameters['mch_appid'] = WxPayConf_pub::APPID; $this->parameters['mchid'] = WxPayConf_pub::MCHID; $this->parameters['nonce_str'] = $this->createNoncestr(); $this->parameters['sign'] = $this->getSign($this->parameters); return $this->arrayToXml($this->parameters); } /** * 作用:使用證書,以post方式提交xml到對應的接口url */
function postXmlSSLCurl($xml,$url,$second=30) { $ch = curl_init(); //超時時間
curl_setopt($ch,CURLOPT_TIMEOUT,$second); //這里設置代理,如果有的話 //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8'); //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); //設置header
curl_setopt($ch,CURLOPT_HEADER,FALSE); //要求結果為字符串且輸出到屏幕上
curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE); //設置證書
curl_setopt($ch,CURLOPT_CAINFO, WxPayConf_pub::SSLROOTCA_PATH); //使用證書:cert 與 key 分別屬於兩個.pem文件 //默認格式為PEM,可以注釋
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, WxPayConf_pub::SSLCERT_PATH); //默認格式為PEM,可以注釋
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, WxPayConf_pub::SSLKEY_PATH); //post提交方式
curl_setopt($ch,CURLOPT_POST, true); curl_setopt($ch,CURLOPT_POSTFIELDS,$xml); $data = curl_exec($ch); //返回結果
if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); echo "curl出錯,錯誤碼:$error"."<br>"; echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>錯誤原因查詢</a></br>"; curl_close($ch); return false; } } }
Controller層功能實現:
<?php /** * Author : Max.wen * DateTime: <15/9/20 16:47> */ namespace Home\Controller; class TestController extends CommonController { /** * 企業付款測試 */
public function rebate() { import('Common.Util.WxMchPay'); $mchPay = new \WxMchPay(); // 用戶openid
$mchPay->setParameter('openid', 'oy2lbszXkgvlEKThrzqEziKEBzqU'); // 商戶訂單號
$mchPay->setParameter('partner_trade_no', 'test-'.time()); // 校驗用戶姓名選項
$mchPay->setParameter('check_name', 'NO_CHECK'); // 企業付款金額 單位為分
$mchPay->setParameter('amount', 100); // 企業付款描述信息
$mchPay->setParameter('desc', '開發測試'); // 調用接口的機器IP地址 自定義
$mchPay->setParameter('spbill_create_ip', '127.0.0.1'); # getClientIp() // 收款用戶姓名 // $mchPay->setParameter('re_user_name', 'Max wen'); // 設備信息 // $mchPay->setParameter('device_info', 'dev_server');
$response = $mchPay->postXmlSSL(); if( !empty($response) ) { $data = simplexml_load_string($response, null, LIBXML_NOCDATA); echo json_encode($data); }else{ echo json_encode( array('return_code' => 'FAIL', 'return_msg' => 'transfers_接口出錯', 'return_ext' => array()) ); } } }
完成上述兩部分代碼,基本就可以成功調用企業付款API了。
返回結果的數據結構示例:
{ "return_code": "SUCCESS", "return_msg": { }, "mch_appid": "wx519cae424099ed6b", "mchid": "1228636402", "device_info": { }, "nonce_str": "qjupk84q4iqxkb578hb5h2qiatgcwxwg", "result_code": "SUCCESS", "partner_trade_no": "test-1442801966", "payment_no": "1000018301201509210739170397", "payment_time": "2015-09-21 10:19:26" }
可能遇到的問題:
1、CA證書錯誤
在WxMchPay中大家可以看到,我重寫了SDK中 Wxpay_client_pub 的 postXmlSSLCurl()方法
因為默認在SDK中的這個方法在CURL POST請求的時候沒有附帶CA證書。
相比之下就多了
curl_setopt($ch,CURLOPT_CAINFO, WxPayConf_pub::SSLROOTCA_PATH); 這么一行代碼。
作用就是請求時附帶CA證書。
2、對同一用戶轉賬操作過於頻繁,請稍候重試.
這個錯誤屬於微信服務端的限制,具體限制頻率也沒有找到那里有說明,不過經過實際測試大概在1分鍾左右。
所以在開發的時候還需要多注意。
有任何疑問歡迎共同探討。
P.S. 搬家至博客園的第一篇隨筆, 送給組織的見面禮。希望再次廣交猿友。