123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- <?php
- /**
- * Wxpay.php UTF-8
- *
- *
- * @date : 2018/5/3 23:07
- *
- * @license 这不是一个自由软件,未经授权不许任何使用和传播。
- * @author : wuyonghong <wyh@huosdk.com>
- * @version : HUOSDK 8.0
- */
- namespace huolib\withdraw\driver;
- use huolib\constant\SettleConst;
- use huolib\withdraw\Driver;
- use WxPayException;
- require_once EXTEND_PATH."pay/wxpay/WxPay.Data.php";
- class Wxpay extends Driver {
- private $config
- = [
- 'app_id' => '', /* 绑定支付的APPID(必须配置,开户邮件中可查看)*/
- 'mch_id' => '', /* 商户号(必须配置,开户邮件中可查看) */
- 'key' => '', /* 商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置) */
- 'app_secret' => '', /* 公众帐号secert */
- 'curl_proxy_host' => '0.0.0.0',
- 'curl_proxy_port' => '0',
- 'report_levenl' => '1',
- 'device_info' => 'WEB', /* 终端设备号(门店号或收银设备ID),默认请传"WEB" */
- 'sslcert_path' => '',
- 'sslkey_path' => '',
- ];
- /**
- * 构造函数
- *
- * @param array $config
- */
- public function __construct(array $config = []) {
- $_config = $config;
- if (empty($config)) {
- $_conf_file = GLOBAL_CONF_PATH.'extra/pay/wxpay/config.php';
- if (file_exists($_conf_file)) {
- $_config = include $_conf_file;
- } else {
- $_config = array();
- }
- $this->config = array_merge($this->config, $_config);
- $this->config['sslcert_path'] = GLOBAL_CONF_PATH.'extra/pay/wxpay/cert/apiclient_cert.pem';
- $this->config['sslkey_path'] = GLOBAL_CONF_PATH.'extra/pay/wxpay/cert/apiclient_key.pem';
- } else {
- $this->config = array_merge($this->config, $_config);
- }
- }
- /**
- * 企业付款
- * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
- *
- * @throws \WxPayException
- */
- public function withDraw() {
- $_re_data = [];
- $_input = new \WxPayTransfers();
- $_input->SetAppid($this->config['app_id']);//商户账号appid
- $_input->SetMch_id($this->config['mch_id']);//商户号
- $_input->setKey($this->config['key']);//商户密钥
- $_input->SetDevice_info($this->config['device_info']);//设备号
- $_input->SetNonce_str(self::getNonceStr());//随机字符串
- $_input->SetOut_trade_no($this->order_id);//商户订单号
- $_input->setOpenId($this->open_id);//用户openid
- $_input->setCheck_name($this->check_name);//校验用户姓名选项 NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
- $_input->setRe_user_name($this->payee_real_name);//收款用户姓名
- $_input->setAmount(intval($this->real_amount * 100));//金额 单位为分
- $_input->setDesc($this->remark);//企业付款描述信息
- $_ip = request()->ip();
- $_input->setSpbill_create_ip($_ip); //Ip地址
- $_url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
- //签名
- $_input->SetSign();
- $_xml = $_input->ToXml();
- $response = self::postXmlCurl($_xml, $_url, true, 6, $this->config);
- $_wx_data_obj = new \WxPayDataBase();
- $_wx_data_obj->FromXml($response);
- $_result = $_wx_data_obj->GetValues();
- $_re_data['result'] = json_encode($_result);
- $_re_data['code'] = $_result['result_code'];
- $_re_data['msg'] = $_result['return_msg'];
- if (!empty($_result['return_code']) && 'SUCCESS' == $_result['return_code']) {
- if (!empty($_result['result_code']) && 'SUCCESS' == $_result['result_code']) { //打款成功
- $_re_data['code'] = SettleConst::SETTLE_SUCCESS;
- } else {
- /*错误处理*/
- switch ($_result['err_code']) {
- case 'SEND_FAILED': //付款错误,请求查询接口 确认结果
- case 'SYSTEMERROR': //微信内部接口调用发生错误,请求查询接口 确认结果
- $_re_data['code'] = $_result['err_code'];
- $_re_data['msg'] = $_result['err_code_des'];
- $_rs = $this->orderQuery($this->order_id);
- $_re_data['query_result'] = $_rs['result'];
- if (isset($_rs['status'])
- && SettleConst::SETTLE_PAY_FAILED != $_rs['status']) { //查询结果不为打款失败,返回状态为成功
- $_re_data['code'] = SettleConst::SETTLE_SUCCESS;
- }
- break;
- default: //其他结果返回错误信息
- $_re_data['code'] = $_result['err_code'];
- $_re_data['msg'] = $_result['err_code_des'];
- }
- }
- }
- return $_re_data;
- }
- /**
- * 查询企业付款
- * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
- *
- * @access public
- *
- * @param string $order_id 商户系统内部订单号
- * @param null $ext 扩展信息
- *
- * @return array
- * @throws WxPayException
- */
- public function orderQuery($order_id, $ext = null) {
- $_input = new \WxPayGetTransfer();
- $_input->SetAppid($this->config['app_id']);//商户账号appid
- $_input->SetMch_id($this->config['mch_id']);//商户号
- $_input->setKey($this->config['key']);//商户密钥
- $_input->SetNonce_str(self::getNonceStr());//随机字符串
- $_input->SetOut_trade_no($this->order_id);//商户订单号
- $_url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo";
- //签名
- $_input->SetSign();
- $_xml = $_input->ToXml();
- $response = self::postXmlCurl($_xml, $_url, true, 6, $this->config);
- $_wx_data_obj = new \WxPayDataBase();
- $_wx_data_obj->FromXml($response);
- $_result = $_wx_data_obj->GetValues();
- $_rdata = [
- 'code' => $_result['return_code'],
- 'msg' => $_result['return_msg'],
- 'result' => json_encode($_result)
- ];
- if (!empty($_result['return_code']) && 'SUCCESS' == $_result['return_code']) {
- $_rdata['code'] = $_result['err_code'];
- $_rdata['msg'] = $_result['err_code_des'];
- if (!empty($_result['result_code']) && 'SUCCESS' == $_result['result_code']) {
- switch ($_rdata['status']) {
- case 'SUCCESS':
- $_rdata['status'] = SettleConst::SETTLE_PAY_SUCCESS;
- break;
- case 'PROCESSING':
- $_rdata['status'] = SettleConst::SETTLE_PAY_PROCESSING;
- break;
- default:
- $_rdata['status'] = SettleConst::SETTLE_PAY_FAILED;
- }
- $_rdata['reason'] = $_result['reason'];
- }
- }
- return $_rdata;
- }
- /**
- *
- * 产生随机字符串,不长于32位
- *
- * @param int $length
- *
- * @return string 产生的随机字符串
- */
- public static 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;
- }
- /**
- * 获取毫秒级别的时间戳
- */
- private static function getMillisecond() {
- //获取毫秒的时间戳
- $time = explode(" ", microtime());
- $time = $time[1].($time[0] * 1000);
- $time2 = explode(".", $time);
- $time = $time2[0];
- return $time;
- }
- /**
- * 以post方式提交xml到对应的接口url
- *
- * @param string $xml 需要post的xml数据
- * @param string $url url
- * @param bool $useCert 是否需要证书,默认不需要
- * @param int $second url执行超时时间,默认30s
- *
- * @param array $config
- *
- * @return mixed
- * @throws WxPayException
- */
- private static function postXmlCurl($xml, $url, $useCert = false, $second = 30, array $config) {
- $ch = curl_init();
- //设置超时
- curl_setopt($ch, CURLOPT_TIMEOUT, $second);
- //如果有配置代理这里就设置代理
- if ($config['curl_proxy_host'] != "0.0.0.0"
- && $config['curl_proxy_port'] != 0
- ) {
- curl_setopt($ch, CURLOPT_PROXY, $config['curl_proxy_host']);
- curl_setopt($ch, CURLOPT_PROXYPORT, $config['curl_proxy_port']);
- }
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);//严格校验
- //设置header
- curl_setopt($ch, CURLOPT_HEADER, false);
- //要求结果为字符串且输出到屏幕上
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- if ($useCert == true) {
- //设置证书
- //使用证书:cert 与 key 分别属于两个.pem文件
- curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
- curl_setopt($ch, CURLOPT_SSLCERT, $config['sslcert_path']);
- curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
- curl_setopt($ch, CURLOPT_SSLKEY, $config['sslkey_path']);
- }
- //post提交方式
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
- //运行curl
- $data = curl_exec($ch);
- //返回结果
- if ($data) {
- curl_close($ch);
- return $data;
- } else {
- $error = curl_errno($ch);
- curl_close($ch);
- throw new WxPayException("curl出错,错误码:$error");
- }
- }
- }
|