/**
* 微信支付驱动
* @author Devil
* @version V_1.0.0
*/
class WeiXinPay
{
private $appid;
private $secret;
private $mch_id;
private $key;
/**
* [__construct 构造方法]
*/
private function __construct($config)
{
$this->appid = isset($config['appid']) ? $config['appid'] : '';
$this->secret = isset($config['secret']) ? $config['secret'] : '';
$this->mch_id = isset($config['mchid']) ? $config['mchid'] : '';
$this->key = isset($config['key']) ? $config['key'] : '';
}
/**
* [Instantiate 静态方法]
* @param [array] $config [微信配置信息]
* @return[object] [当前类对象]
*/
public static function Instantiate($config)
{
$object = null;
if(!is_object($object)) $object = new self($config);
return $object;
}
/**
* [WechatPay 微信支付]
* @param [string] $param['body'] [商品简要描述]
* @param [string] $param['out_trade_no'] [商户订单号]
* @param [int] $param['total_fee'] [订单总金额]
* @param [string] $param['notify_url'] [异步通知地址]
* @param [string] $param['trade_type'] [交易类型(默认JSAPI)JSAPI | APP]
* @param [string] $param['openid'] [openid]
* @param [string] $param['attach'] [原样返回的数据(可选)]
* @return[array] [微信支付数据]
*/
public function WechatPay($param)
{
if(empty($param)) return '';
$data = $this->GetPayParam($param);
$xml = '
'.$this->appid.'
'.$this->mch_id.'
'.$data['data']['nonce_str'].'
'.$data['data']['notify_url'].'
'.$data['data']['openid'].'
'.$data['data']['out_trade_no'].'
'.$data['data']['spbill_create_ip'].'
'.$data['data']['total_fee'].'
'.$data['data']['trade_type'].'
'.$data['data']['attach'].'
'.$data['sign'].'
';
$result = $this->Xml_Array($this->Curl_Post('https://api.mch.weixin.qq.com/pay/unifiedorder', $xml));
if(!empty($result['prepay_id']))
{
// 返回数据
$pay_data = array(
'appid' => $this->appid,
'partnerid' => $this->mch_id,
'prepayid' => $result['prepay_id'],
'package' => 'Sign=WXPay',
'noncestr' => md5(time().rand()),
'timestamp' => time(),
);
$pay_data['sign'] = $this->GetParamSing($pay_data);
return $pay_data;
}
return '';
}
/**
* [Refund 退款接口]
* @param [array] $param [退款的参数]
* @return [boolean] [成功true, 则false]
*/
public function Refund($param)
{
if(empty($param)) return false;
$data = array(
'appid' => $this->appid,
'mch_id' => $this->mch_id,
'nonce_str' => md5(time().rand()),
'transaction_id'=> $param['transaction_id'],
'out_refund_no' => md5($param['transaction_id'].$param['total_fee']),
'total_fee' => $param['total_fee'],
'refund_fee' => $param['refund_fee'],
'op_user_id' => $this->mch_id,
);
$data['sign'] = $this->GetParamSing($data);
$result = $this->Xml_Array($this->Curl_Post('https://api.mch.weixin.qq.com/secapi/pay/refund', $this->GetParamXml($data), true));
return (!empty($result['result_code']) && $result['result_code'] == 'SUCCESS' && !empty($result['return_msg']) && $result['return_msg'] == 'OK');
}
/**
* [GetParamXml xml键值对拼接]
* @param [array] $param [需要拼接xml的数组]
* @return[string] [xml数据]
*/
private function GetParamXml($param)
{
if(empty($param) || !is_array($param)) return '';
$xml = '';
foreach($param as $k=>$v)
{
$xml .= ''.$v.''.$k.'>';
}
return ''.$xml.'';
}
/**
* [Xml_Array xml转数组]
* @param [string] $xml [xml字符串]
* @return[array] [数组]
*/
private function Xml_Array($xml)
{
if(!Xml_Parser($xml)) return '';
return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
}
/**
* [GetPayParam 获取支付参数]
* @param [array] $param [支付的数据]
* @return[array] [支付的字符串和签名]
*/
private function GetPayParam($param)
{
if(empty($param)) return '';
$param['appid'] = $this->appid;
$param['mch_id'] = $this->mch_id;
$param['nonce_str'] = md5(time().rand().$param['out_trade_no']);
$param['spbill_create_ip'] = get_client_ip();
$param['trade_type'] = empty($param['trade_type']) ? 'JSAPI' : $param['trade_type'];
$param['attach'] = empty($param['attach']) ? 'gongfuxiang' : $param['attach'];
return array(
'sign' => $this->GetParamSing($param),
'data' => $param,
);
}
/**
* [GetParamSing 签名生成]
* @param [array] $param [需要参与签名的数据]
* @return[string] [签名]
*/
private function GetParamSing($param)
{
if(empty($param)) return '';
ksort($param);
$sign = '';
foreach($param as $k=>$v)
{
if($k != 'sign') $sign .= "$k=$v&";
}
return strtoupper(md5($sign.'key='.$this->key));
}
/**
* [Curl_Post curl模拟post]
* @param [string] $url [请求地址]
* @param [array] $post [发送的post数据]
* @param [boolean] $use_cert [是否需要使用证书]
*/
private function Curl_Post($url, $post, $use_cert = false)
{
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post,
);
if($use_cert == true)
{
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
$options[CURLOPT_SSLCERTTYPE] = 'PEM';
$options[CURLOPT_SSLCERT] = WEB_ROOT.'cert/wechat_app_apiclient_cert.pem';
$options[CURLOPT_SSLKEYTYPE] = 'PEM';
$options[CURLOPT_SSLKEY] = WEB_ROOT.'cert/wechat_app_apiclient_key.pem';
}
$ch = curl_init($url);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* [Notify 异步回调]
* @return [array] [支付数据]
*/
public function Notify()
{
$result = empty($GLOBALS['HTTP_RAW_POST_DATA']) ? '' : $this->Xml_Array($GLOBALS['HTTP_RAW_POST_DATA']);
if(isset($result['sign']) && $result['sign'] == $this->GetParamSing($result)) return $result;
return '';
}
}
?>