文件
mashangyoujiu/Application/Pay/Library/WeChat/WxRemitPay.class.php

854 行
38 KiB
PHP
可执行文件

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019-10-21
* Time: 13:53
*/
namespace Pay\Library\WeChat;
//[1.5.22]
/**
* 微信打款支付
* Class WxPay
* @package app\Pay\Library\WeChat
*/
class WxRemitPay
{
private $config; // 微信支付配置
// static private $wxQueryUrl = "https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/gettransferinfo"; // 查询企业付款接口url
// static private $remitPayUrl = "https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/promotion/transfers";// 微信企业付款到零钱接口url
static private $wxQueryUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo"; // 查询企业付款接口url
static private $remitPayUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; // 微信企业付款到零钱接口url
static private $publicKeyUrl = "https://fraud.mch.weixin.qq.com/risk/getpublickey"; // 获取RSA加密公钥API
static private $payBankUrl = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank"; // 企业付款到银行卡API
static private $queryBankUrl = "https://api.mch.weixin.qq.com/mmpaysptrans/query_bank"; // 查询企业付款到银行卡API
static private $payModel = "1";
static private $errmsg = "";
static private $wxReturnData = "";
static private $cancelMsg = "订单超时,并已撤销";
static private $cancelerrMsg = "订单超时,撤销失败,请勿支付,请检查微信支付证书配置";
protected $reTestNum = 0;
/**
* 构造方法
* WxPay constructor.
* @param $config
*/
public function __construct($config)
{
$this->config = $config;
}
/** 企业付款到零钱API接口
* @param $order_no
* @param $code
* @param $total_fee
*/
public function remitPay($order_no, $openid, $total_fee, $body)
{
$url = self::$remitPayUrl;
//创建需要的参数
$params = [
"mch_appid" => $this->config['mch_appid'], // 商户账号appid
"mchid" => $this->config['mch_id'], // 商户号
"nonce_str" => $this->createNoncestr(), // 随机字符串
"partner_trade_no" => $order_no, // 商户订单号
"openid" => $openid, // 用户openid
"check_name" => "NO_CHECK", // NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
"amount" => $total_fee, // 企业付款金额,单位为分
"desc" => $body, // 企业付款备注,必填。注意:备注中的敏感词会被转成字符*
"spbill_create_ip" => $_SERVER['REMOTE_ADDR'], // Ip地址
];
$params["sign"] = $this->makeWxSign($params); // 签名
$result = $this->postXmlCurlCancel($this->toXml($params), $url);
$prepay = $this->fromXml($result);
if (!empty($prepay)) {
// 微信通信标识
if (isset($prepay['return_code']) && $prepay['return_code'] == 'SUCCESS') {
// 业务结果
if (isset($prepay['result_code'])) {
// 业务结果返回成功
if ($prepay['result_code'] == 'SUCCESS') {
self::$wxReturnData = array(
'partner_trade_no' => $prepay['partner_trade_no'],
'payment_no' => $prepay['payment_no'],
'payment_time' => $prepay['payment_time'],
);
return true;
} else {
$this->doLogs($this->toXml($prepay));
if ($prepay['err_code'] == 'SYSTEMERROR') {
// 请务必用原商户订单号重试,或通过查询接口确认此次付款的结果
return $this->getPayState($order_no);// 此处使用的是查询订单接口
} else {
self::$errmsg = isset($prepay['err_code_des']) ? $prepay['err_code_des'] : '付款失败!';
return false;
}
}
} else {
self::$errmsg = '微信api接口返回值已修改';
return false;
}
} else if (isset($prepay['return_code']) && $prepay['return_code'] == 'FAIL') {
$this->doLogs($this->toXml($prepay));
$this->doLogs($this->toXml($this->config));
self::$errmsg = isset($prepay['return_msg']) ? $prepay['return_msg'] : '付款失败。';
return false;
} else {
self::$errmsg = isset($prepay['return_msg']) ? $prepay['return_msg'] : '付款失败';
return false;
}
}
self::$errmsg = "付款失败,微信api接口无任何返回值";
return false;
}
/** 查询订单是否支付
* @param $order_no
*/
public function getPayState($order_no)
{
//暂停一秒查询
$res = $this->searchWxOrder($order_no);
// 微信通信标识
if (isset($res['return_code'])) {
if ($res['return_code'] == "FAIL") {
self::$errmsg = isset($res['return_msg']) ? $res['return_msg'] : "查询微信企业付款订单失败";
return false;
} else {
// 微信通信标识SUCCESS
if (isset($res['result_code']) && $res['result_code'] == 'SUCCESS') {
// 业务结果 SUCCESS
if (isset($res['status'])) {
switch ($res['status']) {
case "SUCCESS":
// 转账成功
self::$wxReturnData = array(
'partner_trade_no' => $res['partner_trade_no'],
'payment_no' => $res['detail_id'],
'payment_time' => $res['payment_time'],
);
return true;
break;
case "FAILED":
// 转账失败
self::$errmsg = isset($res['reason']) ? $res['reason'] : "打款失败";
return false;
break;
case "PROCESSING":
// 处理中
// 继续查询
$time = get_runtime();
if ($time < 20) {
sleep(2);
return $this->getPayState($order_no);
} else {
// 将订单标记为处理中订单(让商家或者客户刷新订单重试)
self::$errmsg = "微信打款处理中,请稍后查询打款结果";
return 0;
}
break;
}
}
} else {
if (isset($res['err_code'])) {
switch ($res['err_code']) {
case "CA_ERROR":
self::$errmsg = "请求未携带证书,或请求携带的证书出错";
return false;
break;
case "SIGN_ERROR":
self::$errmsg = "商户签名错误";
return false;
break;
case "FREQ_LIMIT":
self::$errmsg = "受频率限制";
return false;
break;
case "XML_ERROR":
self::$errmsg = "请求的xml格式错误,或者post的数据为空";
return false;
break;
case "SYSTEMERROR":
$time = get_runtime();
if ($time < 20) {
sleep(2);
return $this->getPayState($order_no);
} else {
// 将订单标记为处理中订单(让商家或者客户刷新订单重试)
self::$errmsg = "微信打款处理中,请稍后查询打款结果";
return 0;
}
break;
case "NOT_FOUND":
self::$errmsg = "1、指定单号数据不存在 2、指定单号数据不存在,单据查询超过有效期";
return false;
break;
}
}
self::$errmsg = isset($res['err_code_des']) ? $res['err_code_des'] : "查询微信企业付款订单失败";
return false;
}
}
}
self::$errmsg = isset($res['err_code_des']) ? $res['err_code_des'] : "查询微信企业付款订单失败";
return false;
}
/**
* @param $out_trade_no
*/
public function searchWxOrder($out_trade_no)
{
$payModel = self::$payModel;
$params = [
"nonce_str" => $this->createNoncestr(),
"partner_trade_no" => $out_trade_no
];
if ($payModel) {
$params['appid'] = $this->config['mch_appid'];
$params['mch_id'] = $this->config['mchid'];
} else {
$params['appid'] = $this->config['xcx_appid'];
$params['mch_id'] = $this->config['xcx_mer_id'];
}
$params['sign'] = $this->makeWxSign($params);
$url = self::$queryBankUrl; // 微信企业付款查询url
$xml = $this->toXml($params);//转换为xml
$response = $this->postXmlCurlCancel($xml, $url, 30);
$response = json_decode(json_encode(simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $response;
}
/**
* 获取微信企业付款到银行卡公钥
* @return bool
*/
public function getWxPublicKey()
{
$url = self::$publicKeyUrl;
//创建需要的参数
$params = [
"mch_id" => $this->config['mchid'], // 商户号
"nonce_str" => $this->createNoncestr(), // 随机字符串
"sign_type" => 'MD5' // 商户订单号
];
$params["sign"] = $this->makeWxSign($params); // 签名
$result = $this->postXmlCurlCancel($this->toXml($params), $url);
$prepay = $this->fromXml($result);
//pre($prepay);
if (!empty($prepay)) {
// 微信通信标识
if (isset($prepay['return_code']) && $prepay['return_code'] == 'SUCCESS') {
// 业务结果
if (isset($prepay['result_code'])) {
// 业务结果返回成功
if ($prepay['result_code'] == 'SUCCESS') {
self::$wxReturnData = array(
'pub_key' => $prepay['pub_key']
);
return true;
} else {
$this->doLogs($this->toXml($prepay));
self::$errmsg = isset($prepay['err_code_des']) ? $prepay['err_code_des'] : '公钥获取失败';
return false;
}
} else {
self::$errmsg = '微信api接口返回值已修改';
return false;
}
} else if (isset($prepay['return_code']) && $prepay['return_code'] == 'FAIL') {
$this->doLogs($this->toXml($prepay));
self::$errmsg = isset($prepay['return_msg']) ? $prepay['return_msg'] : '公钥获取失败。';
return false;
} else {
self::$errmsg = isset($prepay['return_msg']) ? $prepay['return_msg'] : '公钥获取失败';
return false;
}
}
self::$errmsg = "微信企业付款公钥获取失败";
return false;
}
/**
* 调取微信付款到银行卡
* @param $order_no
* @param $userData
* @param $total_fee
* @param $body
* @return bool
*/
public function bankCardPay($order_no, $userData, $total_fee, $body)
{
$url = self::$payBankUrl;
//创建需要的参数
$enc_bank_no = $this->publicEncrypt($userData['enc_bank_no']);
$enc_true_name = $this->publicEncrypt($userData['enc_true_name']);
$bank_code = $userData['bank_code'];
$params = [
"mch_id" => $this->config['mchid'], // 商户号
"nonce_str" => $this->createNoncestr(), // 随机字符串
"partner_trade_no" => $order_no, // 商户订单号
"enc_bank_no" => $enc_bank_no, // 收款方银行卡号(采用标准RSA算法,公钥由微信侧提供)
"enc_true_name" => $enc_true_name, // 收款方用户名(采用标准RSA算法,公钥由微信侧提供)
"bank_code" => $bank_code, // 银行卡所在开户行编号
"amount" => $total_fee, // 企业付款金额,单位为分
"desc" => $body, // 企业付款备注,必填。注意:备注中的敏感词会被转成字符*
];
$params["sign"] = $this->makeWxSign($params); // 签名
$result = $this->postXmlCurlCancel($this->toXml($params), $url);
$prepay = $this->fromXml($result);
return $this->bankCardPayHandle($prepay, $params, $url);
}
/*
* 处理微信付款到银行卡返回值
* */
private function bankCardPayHandle($prepay, $params, $url)
{
$order_no = $params['partner_trade_no'];
if (!empty($prepay)) {
// 微信通信标识
if (isset($prepay['return_code']) && $prepay['return_code'] == 'SUCCESS') {
// 业务结果
if (isset($prepay['result_code'])) {
// 业务结果返回成功
if ($prepay['result_code'] == 'SUCCESS') {
self::$wxReturnData = array(
'partner_trade_no' => $prepay['partner_trade_no'],
'payment_no' => $prepay['payment_no'],
'cmms_amt' => $prepay['cmms_amt'],
);
return true;
} else {
$this->doLogs($this->toXml($prepay));
if (isset($prepay['err_code_des'])) {
$err_code_des = $prepay['err_code_des'] . 'err_code:' . $prepay['err_code'];
} else {
$err_code_des = '';
}
switch ($prepay['err_code']) {
case 'SYSTEMERROR':
// 请务必用原商户订单号重试,或通过查询接口确认此次付款的结果
return $this->getCardPayState($order_no); // 此处使用的是查询订单接口
break;
case 'INVALID_REQUEST':
// 无效的请求,商户系统异常导致,商户权限异常、证书错误、频率限制等
// 使用原单号以及原请求参数重试
if($this->reTestNum>3){
self::$errmsg = $err_code_des ? $err_code_des : '无效的请求!err_code:' . $prepay['err_code'];
return false;
}else{
$this->reTestNum++;
}
return $this->retryBankCardPay($params, $url, 1, 0);
break;
case 'FREQUENCY_LIMITED':
// 超过每分钟600次的频率限制 稍后用原单号重试
return $this->retryBankCardPay($params, $url, 5, 1);
break;
case 'SIGNERROR':
// 签名错误
self::$errmsg = $err_code_des ? $err_code_des : '签名错误!err_code:' . $prepay['err_code'];
return false;
break;
case 'AMOUNT_LIMIT':
// 超额;已达到今日付款金额上限或已达到今日银行卡收款金额上限
self::$errmsg = $err_code_des ? $err_code_des : '超额;已达到今日付款金额上限或已达到今日银行卡收款金额上限!err_code:' . $prepay['err_code'];
return false;
break;
case 'ORDERPAID':
// 超过付款重入有效期
self::$errmsg = $err_code_des ? $err_code_des : '超过付款重入有效期!err_code:' . $prepay['err_code'];
return false;
break;
case 'FATAL_ERROR':
// 已存在该单,并且订单信息不一致;或订单太老
self::$errmsg = $err_code_des ? $err_code_des : '已存在该单,并且订单信息不一致;或订单太老!err_code:' . $prepay['err_code'];
return false;
break;
case 'NOTENOUGH':
// 账号余额不足
self::$errmsg = $err_code_des ? $err_code_des : '账号余额不足!err_code:' . $prepay['err_code'];
return false;
break;
case 'SUCCESS':
// Wx侧受理成功
self::$errmsg = $err_code_des ? $err_code_des : 'Wx侧受理成功!err_code:' . $prepay['err_code'];
return false;
break;
case 'RECV_ACCOUNT_NOT_ALLOWED':
// 收款账户不在收款账户列表
self::$errmsg = $err_code_des ? $err_code_des : '收款账户不在收款账户列表!err_code:' . $prepay['err_code'];
return false;
break;
case 'PAY_CHANNEL_NOT_ALLOWED':
// 本商户号未配置API发起能力
self::$errmsg = $err_code_des ? $err_code_des : '本商户号未配置API发起能力!err_code:' . $prepay['err_code'];
return false;
break;
case 'SENDNUM_LIMIT':
// 已达到付款给此用户次数上限
self::$errmsg = $err_code_des ? $err_code_des : '已达到付款给此用户次数上限!err_code:' . $prepay['err_code'];
return false;
break;
case 'NO_AUTH':
// 此IP地址不允许调用接口
self::$errmsg = $err_code_des ? $err_code_des : '此IP地址不允许调用接口!err_code:' . $prepay['err_code'];
return false;
break;
default:
// 新的错误码
self::$errmsg = $err_code_des ? $err_code_des : '请联系客服确认付款情况!err_code:' . $prepay['err_code'];
return false;
break;
}
}
} else {
self::$errmsg = '微信api接口返回值已修改';
return false;
}
} else if (isset($prepay['return_code']) && $prepay['return_code'] == 'FAIL') {
$this->doLogs($this->toXml($prepay));
$this->doLogs($this->toXml($this->config));
self::$errmsg = isset($prepay['return_msg']) ? $prepay['return_msg'] : '付款失败。';
return false;
} else {
self::$errmsg = isset($prepay['return_msg']) ? $prepay['return_msg'] : '付款失败';
return false;
}
}
self::$errmsg = "付款失败,微信api接口无任何返回值";
return false;
}
// 重试 微信付款到银行卡
private function retryBankCardPay($params, $url, $t, $type)
{
if ($t) {
sleep($t);
}
unset($params["sign"]);
if ($type) {
$params["nonce_str"] = $this->createNoncestr();
}
$params["sign"] = $this->makeWxSign($params); // 签名
$result = $this->postXmlCurlCancel($this->toXml($params), $url);
$prepay = $this->fromXml($result);
return $this->bankCardPayHandle($prepay, $params, $url);
}
/*
* 循环查询微信付款到银行卡
* */
public function getCardPayState($order_no)
{
//暂停一秒查询
$res = $this->searchCardPayOrder($order_no);
// 微信通信标识
if (isset($res['return_code'])) {
if ($res['return_code'] == "FAIL") {
self::$errmsg = isset($res['return_msg']) ? $res['return_msg'] : "查询微信企业付款订单失败";
return false;
} else {
// 微信通信标识SUCCESS
if (isset($res['result_code']) && $res['result_code'] == 'SUCCESS') {
// 业务结果 SUCCESS
if (isset($res['status'])) {
switch ($res['status']) {
case "SUCCESS":
// 付款成功
self::$wxReturnData = array(
'partner_trade_no' => $res['partner_trade_no'],
'payment_no' => $res['payment_no'], // 即为微信内部业务单号
'pay_succ_time' => $res['payment_time'], // 微信侧付款成功时间(依赖银行的处理进度,可能出现延迟返回,甚至被银行退票的情况)
'cmms_amt' => $res['cmms_amt'], // 手续费订单金额 RMB:分
);
return true;
break;
case "FAILED":
// 付款失败,需要替换付款单号重新发起付款
self::$errmsg = isset($res['reason']) ? $res['reason'] : "付款到银行卡失败";
return false;
break;
case "BANK_FAIL":
// 银行退票,订单状态由付款成功流转至退票,退票时付款金额和手续费会自动退还
self::$errmsg = isset($res['reason']) ? $res['reason'] : "付款到银行卡失败,银行退票,订单状态由付款成功流转至退票,退票时付款金额和手续费会自动退还";
return false;
break;
case "PROCESSING":
// 处理中
// 继续查询
$time = get_runtime();
if ($time < 20) {
sleep(2);
return $this->getCardPayState($order_no);
} else {
// 将订单标记为处理中订单(让商家或者客户刷新订单重试)
self::$errmsg = "微信付款到银行卡处理中,请稍后查询打款结果";
return 0;
}
break;
}
}
} else {
if (isset($res['err_code'])) {
switch ($res['err_code']) {
case "INVALID_REQUEST":
// 无效的请求,商户系统异常导致,商户权限异常、证书错误、频率限制等 //使用原单号以及原请求参数重试
self::$errmsg = "无效的请求,商户系统异常导致,商户权限异常、证书错误、频率限制等";
return false;
break;
case "PARAM_ERROR":
// 参数错误 //按照err_msg指定参数错误信息,修改相应参数
self::$errmsg = "参数错误";
return false;
break;
case "SIGNERROR":
// 签名错误 //签名前没有按照要求进行排序。没有使用商户平台设置的密钥进行签名,参数有空格或者进行了encode后进行签名
self::$errmsg = "签名错误";
return false;
break;
case "ORDERNOTEXIST":
// 订单不存在 //确认订单号是否发起过请求
self::$errmsg = "订单不存在";
return false;
break;
case "SYSTEMERROR":
// 系统繁忙,请稍后重试 //使用原单号以及原请求参数重试
self::$errmsg = "系统繁忙,请稍后重试";
return false;
break;
case "SUCCESS":
// Wx侧查询成功 //使用原单号以及原请求参数重试
self::$errmsg = "微信侧查询成功";
return false;
break;
case "NOT_FOUND":
// 1、指定单号数据不存在 2、指定单号数据不存在,单据查询超过有效期
self::$errmsg = "1、指定单号数据不存在 2、指定单号数据不存在,单据查询超过有效期";
return false;
break;
}
}
self::$errmsg = isset($res['err_code_des']) ? $res['err_code_des'] : "查询微信企业付款订单失败";
return false;
}
}
}
self::$errmsg = isset($res['err_code_des']) ? $res['err_code_des'] : "查询微信企业付款订单失败";
return false;
}
/*
* 查询微信付款到银行卡
* */
public function searchCardPayOrder($out_trade_no)
{
$params = [
"nonce_str" => $this->createNoncestr(),
"partner_trade_no" => $out_trade_no,
"mch_id" => $this->config['mchid']
];
$params['sign'] = $this->makeWxSign($params);
$url = self::$wxQueryUrl; // 微信企业付款查询url
$xml = $this->toXml($params);//转换为xml
$response = $this->postXmlCurlCancel($xml, $url, 30);
$response = json_decode(json_encode(simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $response;
}
/**
* @uses 获取公钥
* @return bool|resource
*/
private function _getPublicKey()
{
$publicKeyUrl = $this->config['wx_public_key'];
$public_key = file_get_contents('.' . $publicKeyUrl);
return $public_key;
$GetPublicKey = openssl_pkey_get_public($public_key);
if ($GetPublicKey) {
echo 1;
} else if ($GetPublicKey === false) {
echo 2;
} else {
echo 3;
}
}
function publicEncrypt($source)
{
$pub_key_string = file_get_contents('.' . $this->config['wx_public_key']);
$key_resource = openssl_pkey_get_public($pub_key_string);
$crypttext = '';
openssl_public_encrypt($source, $crypttext, $key_resource,OPENSSL_PKCS1_OAEP_PADDING);
return base64_encode($crypttext);
}
/**
* @return string
*/
public function getMsg()
{
return self::$errmsg;
}
/**
* @return string
*/
public function getReturnData()
{
return self::$wxReturnData;
}
/** 生成签名
* @param $Obj
* @return string
*/
private function makeWxSign($Obj)
{
if (self::$payModel == 1) {
$key = $this->config["wx_secret_key"];
} else {
$key = $this->config["xcx_secret_key"];
}
foreach ($Obj as $k => $v) {
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = $this->formatBizQueryParaMap($Parameters, false);
//echo '【string1】'.$String.'</br>';
//签名步骤二:在string后加入KEY
$String = $String . "&key=" . $key;
//echo "【string2】".$String."</br>";
//签名步骤三:MD5加密
$String = md5($String);
//echo "【string3】 ".$String."</br>";
//签名步骤四:所有字符转为大写
$result_ = strtoupper($String);
//echo "【result】 ".$result_."</br>";
return $result_;
}
/**
* 作用:格式化参数,签名过程需要使用
*/
function formatBizQueryParaMap($paraMap, $urlencode)
{
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if ($urlencode) {
$v = urlencode($v);
}
//$buff .= strtolower($k) . "=" . $v . "&";
$buff .= $k . "=" . $v . "&";
}
$reqPar = "";
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
/**
* 作用:产生随机字符串,不长于32位
*/
public function createNoncestr($length = 32)
{
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
/**
* 写入日志记录
* @param $values
* @return bool|int
*/
private function doLogs($values)
{
$years = date('Y-m');
$url = './Uploads/log/'.$years.'/'.date('Ymd').'remit.txt';
$dir_name = dirname($url);
//目录不存在就创建
if(!file_exists($dir_name)) {
//iconv防止中文名乱码
$res = mkdir(iconv("UTF-8", "GBK", $dir_name),0777,true);
}
$fp = fopen($url, "a");//打开文件资源通道 不存在则自动创建
fwrite($fp,date("Y-m-d H:i:s").var_export($values, true)."\r\n");//写入文件
fclose($fp);//关闭资源通道
// return write_log($values, __DIR__);
// return file_put_contents($values, __DIR__);
}
/**
* 将xml转为array
* @param $xml
* @return mixed
*/
private function fromXml($xml)
{
// 禁止引用外部xml实体
libxml_disable_entity_loader(true);
return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
}
/**
* 以post方式提交xml到对应的接口url
* @param $xml
* @param $url
* @param int $second
* @return mixed
*/
private function postXmlCurl($xml, $url, $second = 30)
{
$ch = curl_init();
// 设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
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);
// post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
// 运行curl
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
//带证书的
private function postXmlCurlCancel($xml, $url, $second = 30)
{
$Domain = $_SERVER['DOCUMENT_ROOT'];
if (self::$payModel == 1) {
// $apiclient_cert = $Domain . "/" . $this->config['apiclient_cert'];
// $apiclient_key = $Domain . "/" . $this->config['apiclient_key'];
$apiclient_cert = $this->config['apiclient_cert'];
$apiclient_key = $this->config['apiclient_key'];
} else {
$apiclient_cert = $Domain . $this->config['xcx_apiclient_cert'];
$apiclient_key = $Domain . $this->config['xcx_apiclient_key'];
}
// $apiclient_cert = "/www/wwwroot/oem.ocean666.top/Uploads/Wx/2020-08-07/5f2d26d741e989.437773624617.pem";
// $apiclient_key ="/www/wwwroot/oem.ocean666.top/Uploads/Wx/2020-08-07/5f2d26db1b3ee1.661954136040.pem";
//初始化curl
$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);
//设置证书
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERT, $apiclient_cert);
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, $apiclient_key);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//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 {
curl_close($ch);
return false;
}
}
/**
* 生成签名
* @param $values
* @return string 本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
*/
private function makeSign($values)
{
//签名步骤一:按字典序排序参数
ksort($values);
$string = $this->toUrlParams($values);
//签名步骤二:在string后加入KEY
$string = $string . '&key=' . $this->config['xcx_secret_key'];
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
/**
* 格式化参数格式化成url参数
* @param $values
* @return string
*/
private function toUrlParams($values)
{
$buff = '';
foreach ($values as $k => $v) {
if ($k != 'sign' && $v != '' && !is_array($v)) {
$buff .= $k . '=' . $v . '&';
}
}
return trim($buff, '&');
}
/**
* 输出xml字符
* @param $values
* @return bool|string
*/
private function toXml($values)
{
if (!is_array($values)
|| count($values) <= 0
) {
return false;
}
$xml = "<xml>";
foreach ($values as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
}