微信支付
namespace WxPay;
/**
微信支付
*/
class wxpay{
private $pay_url = ‘https://api.mch.weixin.qq.com/pay/unifiedorder‘; // 统一支付地址
private $h5_pay_url = ‘https://api.mch.weixin.qq.com/pay/unifiedorder‘; // H5支付地址
private $h5_order = ‘https://api.mch.weixin.qq.com/pay/orderquery‘; // H5支付订单查询地址
private $refund_url = ‘https://api.mch.weixin.qq.com/secapi/pay/refund‘; // 退款地址
private $transfers = ‘https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers‘; // 企业付款到零钱 需支付证书
// 证书文件放在与入口文件同级的cert目录下
private $SSLCERT_PATH = ‘cert/apiclient_cert.pem‘; // api证书路径
private $SSLKEY_PATH = ‘cert/apiclient_key.pem‘; // 密钥证书路径/**
- H5网页支付
- [web_pay description]
- @Author 念天地之悠悠
- @DateTime 2019-05-28
- @param [type] $appid [description] 微信分配的公众账号ID(企业号corpid即为此appId)
- @param [type] $mch_id [description] 微信支付分配的商户号
- @param [type] $body [description] 商品描述 如 购买商品
- @param [type] $out_trade_no [description] 商户系统内部的订单号
- @param [type] $total_fee [description] 订单金额 金额 单位分
- @param [type] $notify_url [description] 异步回调地址
- @param [type] $scene_info [description] 场景信息
- @param [type] $wx_key [description] 微信支付秘钥
- @return [type] [description]
*/
public function web_pay($appid,$mch_id,$body,$out_trade_no,$total_fee,$notify_url,$scene_info,$wx_key){
$nonce_str = $this->nonce_str(); // 随机字符串
$spbill_create_ip = request()->ip(); // 终端ip
$trade_type = ‘MWEB‘; // 交易类型
$device_info = ‘WEB‘; // 设备号
$attach = "yidun"; // 附加数据
$post[‘appid‘] = $appid;
$post[‘attach‘] = $attach;
$post[‘body‘] = $body;
$post[‘device_info‘] = $device_info;
$post[‘mch_id‘] = $mch_id;
$post[‘nonce_str‘] = $nonce_str;
$post[‘notify_url‘] = $notify_url;
$post[‘out_trade_no‘] = $out_trade_no;
$post[‘scene_info‘] = $scene_info;
$post[‘spbill_create_ip‘] = $spbill_create_ip;
$post[‘total_fee‘] = $total_fee;
$post[‘trade_type‘] = $trade_type;
$sign = $this->sign($post,$wx_key);
$post_xml = ‘<xml>
<appid>‘.$appid.‘</appid>
<attach>‘.$attach.‘</attach>
<body>‘.$body.‘</body>
<device_info>‘.$device_info.‘</device_info>
<mch_id>‘.$mch_id.‘</mch_id>
<nonce_str>‘.$nonce_str.‘</nonce_str>
<notify_url>‘.$notify_url.‘</notify_url>
<out_trade_no>‘.$out_trade_no.‘</out_trade_no>
<spbill_create_ip>‘.$spbill_create_ip.‘</spbill_create_ip>
<total_fee>‘.$total_fee.‘</total_fee>
<trade_type>‘.$trade_type.‘</trade_type>
<scene_info>‘.$scene_info.‘</scene_info>
<sign>‘.$sign.‘</sign>
</xml>‘;
$xml = $this->http_request($this->h5_pay_url,$post_xml);
// 将xml转数组
$arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
$xmljson = json_encode($arr);
$array = json_decode($xmljson,true);
if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘return_msg‘] == ‘OK‘ && $array[‘result_code‘] == ‘SUCCESS‘) {
// $data[‘return_code‘] = 1;
// $data[‘mweb_url‘] = $array[‘mweb_url‘];
$ret = [‘code‘=>1,‘data‘=>$array[‘mweb_url‘],‘msg‘=>‘调用成功!‘];
}else{
// $data[‘return_code‘] = 0;
// $data[‘return_msg‘] = $array[‘err_code_des‘];
$ret = [‘code‘=>0,‘data‘=>‘‘,‘msg‘=>$array[‘err_code_des‘]];
}
return $ret;
}
/** - APP支付
- [app_pay description]
- @Author 念天地之悠悠
- @DateTime 2019-05-28
- @param [type] $appid [description] 微信开放平台审核通过的应用APPID
- @param [type] $mch_id [description] 微信支付分配的商户号
- @param [type] $body [description] 商品描述 如 购买商品
- @param [type] $out_trade_no [description] 商户系统内部的订单号
- @param [type] $total_fee [description] 订单金额 单位分
- @param [type] $notify_url [description] 异步回调地址
- @param [type] $wx_key [description] 微信支付秘钥
- @return [type] [description]
*/
public function app_pay($appid,$mch_id,$body,$out_trade_no,$total_fee,$notify_url,$wx_key){
$nonce_str = $this->nonce_str(); // 随机字符串
$spbill_create_ip = request()->ip(); // 终端ip
$trade_type = ‘APP‘; // 交易类型
$post[‘appid‘] = $appid;
$post[‘body‘] = $body;
$post[‘mch_id‘] = $mch_id;
$post[‘nonce_str‘] = $nonce_str;
$post[‘notify_url‘] = $notify_url;
$post[‘out_trade_no‘] = $out_trade_no;
$post[‘spbill_create_ip‘] = $spbill_create_ip;
$post[‘total_fee‘] = $total_fee;
$post[‘trade_type‘] = $trade_type;
$sign = $this->sign($post,$wx_key);
$post_xml = ‘<xml>
<appid>‘.$appid.‘</appid>
<body>‘.$body.‘</body>
<mch_id>‘.$mch_id.‘</mch_id>
<nonce_str>‘.$nonce_str.‘</nonce_str>
<notify_url>‘.$notify_url.‘</notify_url>
<out_trade_no>‘.$out_trade_no.‘</out_trade_no>
<spbill_create_ip>‘.$spbill_create_ip.‘</spbill_create_ip>
<total_fee>‘.$total_fee.‘</total_fee>
<trade_type>‘.$trade_type.‘</trade_type>
<sign>‘.$sign.‘</sign>
</xml>‘;
$xml = $this->http_request($this->pay_url,$post_xml);
// 将xml转数组
$arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
$xmljson = json_encode($arr);
$array = json_decode($xmljson,true);
if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘result_code‘] == ‘SUCCESS‘) {
// 进行二签
$data[‘appid‘] = $appid; // appid
$data[‘noncestr‘] = $this->nonce_str(); // 随机字符串
$data[‘package‘] = ‘Sign=WXPay‘; // 固定值
$data[‘partnerid‘] = $mch_id; // 商户号
$data[‘prepayid‘] = $array[‘prepay_id‘]; // 支付交易会话ID
$data[‘timestamp‘] = (string)time(); // 时间戳
$data[‘sign‘] = $this->sign($data,$wx_key); // 签名
$ret = [‘code‘=>1,‘data‘=>$data,‘msg‘=>‘调用成功!‘];
}else{
$ret = [‘code‘=>0,‘data‘=>‘‘,‘msg‘=>$array[‘return_msg‘]];
// $data[‘return_code‘] = 0;
// $data[‘return_msg‘] = $array[‘return_msg‘];
}
return $ret;
}
/** - H5支付订单查询
- [get_H5_order description]
- @Author 念天地之悠悠
- @DateTime 2019-06-04
- @param [type] $appid [description] 微信支付分配的公众账号ID(企业号corpid即为此appId)
- @param [type] $mch_id [description] 商户号
- @param [type] $out_trade_no [description] 自定义单号
- @param [type] $wx_key [description] 支付秘钥
- @return [type] [description]
*/
public function get_H5_order($appid,$mch_id,$out_trade_no,$wx_key){
$nonce_str = $this->nonce_str(); // 随机字符串
$post[‘appid‘] = $appid;
$post[‘mch_id‘] = $mch_id;
$post[‘nonce_str‘] = $nonce_str;
$post[‘out_trade_no‘] = $out_trade_no;
$sign = $this->sign($post,$wx_key);
$post_xml = ‘<xml>
<appid>‘.$appid.‘</appid>
<mch_id>‘.$mch_id.‘</mch_id>
<nonce_str>‘.$nonce_str.‘</nonce_str>
<out_trade_no>‘.$out_trade_no.‘</out_trade_no>
<sign>‘.$sign.‘</sign>
</xml>‘;
$xml = $this->http_request($this->h5_order,$post_xml);
// 将xml转数组
$arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
$xmljson = json_encode($arr);
$array = json_decode($xmljson,true);
$data = [];
if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘result_code‘] == ‘SUCCESS‘ && $array[‘trade_state‘] == ‘SUCCESS‘) {
$data[‘code‘] = 1;
$data[‘transaction_id‘] = $array[‘transaction_id‘];
}else{
$data[‘code‘] = 0;
}
return $data;
}
/** - 微信小程序支付
- [pay description]
- @Author 念天地之悠悠
- @DateTime 2019-03-11
- @param [type] $appid [description] 小程序APPid
- @param [type] $body [description] 商品描述
- @param [type] $mch_id [description] 商户id
- @param [type] $notify_url [description] 异步通知地址
- @param [type] $openid [description] 微信用户唯一标识符
- @param [type] $order_no [description] 商户自定义订单号
- @param [type] $total_fee [description] 总金额 单位分
- @param [type] $trade_type [description] 交易类型
- @param [type] $spbill_create_ip [description] 终端的ip地址
- @param [type] $wx_key [description] 申请支付后设置的key
@return [type] [description]
*/
public function pay($appid,$body,$mch_id,$notify_url,$openid,$order_no,$total_fee,$trade_type,$spbill_create_ip,$wx_key){
$post = [];
$nonce_str = $this->nonce_str();
//这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
$post[‘appid‘] = $appid; // 小程序APPid
$post[‘body‘] = $body; // 商品描述
$post[‘mch_id‘] = $mch_id; // 商户id
$post[‘nonce_str‘] = $nonce_str; // 随机字符串
$post[‘notify_url‘] = $notify_url; // 异步通知地址
$post[‘openid‘] = $openid; // 微信用户唯一标识符
$post[‘out_trade_no‘] = $order_no; // 商户自定义订单号
$post[‘spbill_create_ip‘] = $spbill_create_ip; // 终端的ip
$post[‘total_fee‘] = (int)$total_fee; // 总金额
$post[‘trade_type‘] = $trade_type; // 交易类型
$sign = $this->sign($post,$wx_key); //签名
$post_xml = ‘<xml>
<appid>‘.$appid.‘</appid>
<body>‘.$post[‘body‘].‘</body>
<mch_id>‘.$mch_id.‘</mch_id>
<nonce_str>‘.$nonce_str.‘</nonce_str>
<notify_url>‘.$notify_url.‘</notify_url>
<openid>‘.$openid.‘</openid>
<out_trade_no>‘.$order_no.‘</out_trade_no>
<spbill_create_ip>‘.$spbill_create_ip.‘</spbill_create_ip>
<total_fee>‘.(int)$total_fee.‘</total_fee>
<trade_type>‘.$trade_type.‘</trade_type>
<sign>‘.$sign.‘</sign>
</xml> ‘;
$xml = $this->http_request($this->pay_url,$post_xml);
// 将xml转数组
$arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
$xmljson = json_encode($arr);
$array = json_decode($xmljson,true);
if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘result_code‘] == ‘SUCCESS‘) {
$time = time();
$tmp = ‘‘;//临时数组用于签名
$tmp[‘appId‘] = $appid;
$tmp[‘nonceStr‘] = $nonce_str;
$tmp[‘package‘] = ‘prepay_id=‘.$array[‘prepay_id‘];
$tmp[‘signType‘] = ‘MD5‘;
$tmp[‘timeStamp‘] = "$time";$data[‘code‘] = 1; $data[‘msg‘] = ‘成功!‘; $data[‘data‘][‘timeStamp‘] = "$time"; // 时间戳 $data[‘data‘][‘nonceStr‘] = $nonce_str; // 随机字符串 $data[‘data‘][‘signType‘] = ‘MD5‘; // 签名算法,暂支持 MD5 $data[‘data‘][‘package‘] = ‘prepay_id=‘.$array[‘prepay_id‘]; // 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=* $data[‘data‘][‘paySign‘] = $this->sign($tmp,$wx_key); // 签名,具体签名方案参见微信公众号支付帮助文档; $data[‘data‘][‘out_trade_no‘] = $order_no;
}else{
$data[‘code‘] = 0;
$data[‘msg‘] = $array[‘err_code_des‘];
$data[‘data‘][‘return_code‘] = $array[‘return_code‘]; // 微信支付返回码
$data[‘data‘][‘return_msg‘] = $array[‘err_code_des‘]; // 微信支付返回消息
}
return $data;
}
/**- 微信退款
- [wx_refund description]
- @Author 念天地之悠悠
- @DateTime 2019-03-11
- @param [type] $appid [description] APPID
- @param [type] $mch_id [description] 商户号
- @param [type] $order_no [description] 商户退款单号
- @param [type] $notify_url [description] 异步通知地址
- @param [type] $total_fee [description] 订单金额
- @param [type] $refund_fee [description] 退款金额 单位分
- @param [type] $transaction_id [description] 微信单号
- @param [type] $wx_key [description] 申请支付后设置的key
- @return [type] [description]
*/
public function wx_refund($appid,$mch_id,$order_no,$notify_url,$total_fee,$refund_fee,$transaction_id,$wx_key){
$post_data = [];
$nonce_str = $this->nonce_str();
$post_data[‘appid‘] = $appid; // APPID
$post_data[‘mch_id‘] = $mch_id; // 商户号
$post_data[‘nonce_str‘] = $nonce_str; // 随机码
$post_data[‘out_refund_no‘] = $order_no; // 商户退款单号
$post_data[‘refund_fee‘] = (int)$refund_fee; // 退款金额
$post_data[‘total_fee‘] = (int)$total_fee; // 订单金额
$post_data[‘transaction_id‘] = $transaction_id; // 微信单号
$sign = $this->sign($post_data,$wx_key); // 签名
$post_xml = ‘<xml>
<appid>‘.$appid.‘</appid>
<mch_id>‘.$mch_id.‘</mch_id>
<nonce_str>‘.$nonce_str.‘</nonce_str>
<out_refund_no>‘.$order_no.‘</out_refund_no>
<refund_fee>‘.$refund_fee.‘</refund_fee>
<total_fee>‘.$total_fee.‘</total_fee>
<transaction_id>‘.$transaction_id.‘</transaction_id>
<sign>‘.$sign.‘</sign>
</xml>‘;
$xml = $this->postXmlSSLCurl($this->refund_url,$post_xml);
// 将xml转数组
$arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
$xmljson = json_encode($arr);
$array = json_decode($xmljson,true);
$data = [];
if ($array[‘return_code‘] == ‘SUCCESS‘ && $array[‘result_code‘] == ‘SUCCESS‘) {
$data[‘code‘] = 1;
$data[‘data‘] = ‘‘;
$data[‘msg‘] = ‘调用成功!‘;
}else{
$data[‘code‘] = 0;
$data[‘data‘] = ‘‘;
$data[‘msg‘] = $array[‘err_code_des‘];
}
return $data;
}
/** - 企业向微信用户个人付款(用作提现) 需要支付证书 付款到零钱包
- 使用条件
- 1、商户号(或同主体其他非服务商商户号)已入驻90日
- 2、截止今日回推30天,商户号(或同主体其他非服务商商户号)连续不间断保持有交易
- 3、登录微信支付商户平台-产品中心,开通企业付款。
- [wx_transfers description]
- @Author 念天地之悠悠
- @DateTime 2019-07-09
- @param [type] $mch_appid [description] 申请商户号的appid或商户号绑定的appid
- @param [type] $mchid [description] 微信支付分配的商户号
- @param [type] $partner_trade_no [description] 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有其他字符)
- @param [type] $openid [description] 商户appid下,某用户的openid
- @param string $check_name [description] NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
- @param [type] $amount [description] 企业付款金额,单位为分
- @param string $desc [description] 企业付款备注,必填。
- @param [type] $wx_key [description] 支付秘钥
- @return [type] [description]
*/
public function wx_transfers($mch_appid,$mchid,$partner_trade_no,$openid,$check_name=‘NO_CHECK‘,$amount,$desc=‘提现‘,$wx_key){
$nonce_str = $this->nonce_str(); // 32位随机字符串
$spbill_create_ip = request()->ip(); // 终端ip
$post_data[‘amount‘] = $amount;
$post_data[‘check_name‘] = $check_name;
$post_data[‘desc‘] = $desc;
$post_data[‘mch_appid‘] = $mch_appid;
$post_data[‘mchid‘] = $mchid;
$post_data[‘nonce_str‘] = $nonce_str;
$post_data[‘openid‘] = $openid;
$post_data[‘partner_trade_no‘] = $partner_trade_no;
$post_data[‘spbill_create_ip‘] = $spbill_create_ip;
$sign = $this->sign($post_data,$wx_key);
$post_xml = ‘<xml>
<mch_appid>‘.$mch_appid.‘</mch_appid>
<mchid>‘.$mchid.‘</mchid>
<nonce_str>‘.$nonce_str.‘</nonce_str>
<partner_trade_no>‘.$partner_trade_no.‘</partner_trade_no>
<openid>‘.$openid.‘</openid>
<check_name>‘.$check_name.‘</check_name>
<amount>‘.$amount.‘</amount>
<desc>‘.$desc.‘</desc>
<spbill_create_ip>‘.$spbill_create_ip.‘</spbill_create_ip>
<sign>‘.$sign.‘</sign>
</xml>‘;
$xml = $this->postXmlSSLCurl($this->transfers,$post_xml);
// 将xml转数组
$arr = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA);
$xmljson = json_encode($arr);
$arr = json_decode($xmljson,true);
return $arr;
}
/** - 签名
- [sign description]
- @Author 念天地之悠悠
- @DateTime 2019-03-11
- @param [type] $data [description] 数据集
- @param [type] $wx_key [description] 微信支付key
- @return [type] [description]
*/
private function sign($data,$wx_key = ‘‘){
$stringA = ‘‘;
foreach ($data as $key => $value) {
if (!$value) continue;
if ($stringA) $stringA .= ‘&‘.$key."=".$value;
else $stringA = $key."=".$value;
}
if ($wx_key == ‘‘) {
$stringSignTemp = $stringA;
}else{
$stringSignTemp = $stringA.‘&key=‘.$wx_key;
}
return strtoupper(md5($stringSignTemp));
}
/** - 随机32位字符串
- [nonce_str description]
- @Author 念天地之悠悠
- @DateTime 2019-02-21
- @return [type] [description]
*/
private function nonce_str(){
$result = ‘‘;
$str = ‘QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz‘;
for ($i = 0; $i < 32; $i++) {
$result .= $str[rand(0,48)];
}
return $result;
}
/** - curl请求
- [http_request description]
- @Author 念天地之悠悠
- @DateTime 2019-02-21
- @param [type] $url [description]
- @param [type] $data [description]
- @param array $headers [description]
- @return [type] [description]
*/
public function http_request($url,$data = null,$headers=array()){
$curl = curl_init();
if( count($headers) >= 1 ){
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
/** - 需要证书的curl请求
- [postXmlSSLCurl description]
- @Author 念天地之悠悠
- @DateTime 2019-03-12
- @param [type] $url [description] 访问地址
- @param [type] $xml [description] mxl数据体
- @param integer $second [description] 超时时间
- @return [type] [description]
*/
public function postXmlSSLCurl($url,$xml,$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);
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLCERTTYPE,‘PEM‘);
curl_setopt($ch,CURLOPT_SSLCERT, $this->SSLCERT_PATH);
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLKEYTYPE,‘PEM‘);
curl_setopt($ch,CURLOPT_SSLKEY, $this->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>";
curl_close($ch);
return false;
}
}
}