<?php /** * 微信支付驱动 * @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 = '<xml> <appid>'.$this->appid.'</appid> <body>'.$data['data']['body'].'</body> <mch_id>'.$this->mch_id.'</mch_id> <nonce_str>'.$data['data']['nonce_str'].'</nonce_str> <notify_url>'.$data['data']['notify_url'].'</notify_url> <openid>'.$data['data']['openid'].'</openid> <out_trade_no>'.$data['data']['out_trade_no'].'</out_trade_no> <spbill_create_ip>'.$data['data']['spbill_create_ip'].'</spbill_create_ip> <total_fee>'.$data['data']['total_fee'].'</total_fee> <trade_type>'.$data['data']['trade_type'].'</trade_type> <attach>'.$data['data']['attach'].'</attach> <sign>'.$data['sign'].'</sign> </xml>'; $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 .= '<'.$k.'>'.$v.'</'.$k.'>'; } return '<xml>'.$xml.'</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 ''; } } ?>
发表评论: