1. 接通微信商户
2.需要用到的值
'wx_appid' => 'wx16840b25284915bb' , //小程序appid 'wx_appsecret' => '5e5cfcc51e7114465856d9fd421282f3' , //小程序秘钥 'mch_id' => '1599147911', //微信商户id 'appKey' => 'xmzhzgxcxsxaqtwljsyxgszz20200612', //微信商户秘钥
3. 微信支付需要生成预支付订单(里面有个二次签名)
//生成预支付订单 public function wechatGeneratesPrepaid( Request $request ) { //随机字符串 $str = self::genRandomString(); $data['appid'] = config( 'myconfig.config.wx_appid' ); //appid $data['mch_id'] = config( 'myconfig.config.mch_id' ); //商户ID $data['nonce_str'] = $str; //随机字符串 这个随便一个字符串算法就可以 $data['body'] = $request->input( 'name' ); // 商品描述 $data['out_trade_no'] = $request->input( 'out_trade_no' ); //商户订单号,不能重复 $data['total_fee'] = $request->input( 'real_price' ); //金额 $data['spbill_create_ip'] = $_SERVER['SERVER_ADDR']; //ip地址 $data['openid'] = $request->input( 'openid' ); //用户唯一标识openid $data['notify_url'] = 'http://192.168.1.183/peihuchuang/public/unified/callback'; //回调地址,用户接收支付后的通知,必须为能直接访问的网址,不能跟参数 $data['trade_type'] = 'JSAPI'; //支付方式 $data['sign'] = self::getSign( $data ); //获取签名 $xml = self::ToXml( $data ); $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; $data = self::curl( $url , $xml , [] ); // 请求微信生成预支付订单 //返回结果 if ( $data ) { //返回成功,将xml数据转换为数组. $re = self::FromXml( $data ); if ( $re['result_code'] != 'SUCCESS' ) { $msg = isset( $re['err_code_des'] ) ? $re['err_code_des'] : '签名失败'; return [ 'code' => FALSE."1" , 'msg' => $msg ]; } else { //接收微信返回的数据,传给小程序! $arr = array ( // 用返回的数据 'appId' => config( 'myconfig.config.wx_appid' ) , 'timeStamp' => time() , 'nonceStr' => $str , 'package' => 'prepay_id='.$re['prepay_id'] , 'signType' => 'MD5' , ); //第二次生成签名 $sign = $this->getSign( $arr ); $arr['sign'] = $sign; return [ 'code' => TRUE , 'msg' => '生成预支付订单成功' , 'data' => $arr , ]; } } else { return [ 'code' => FALSE."2" , 'msg' => '签名数据为空' ]; } }
//数组转XML public function ToXml( $data = array () ) { if ( !is_array( $data ) || count( $data ) <= 0 ) { return '数组异常'; } $xml = "<xml>"; foreach ( $data as $key => $val ) { if ( is_numeric( $val ) ) { $xml .= "<".$key.">".$val."</".$key.">"; } else { $xml .= "<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml .= "</xml>"; return $xml; } //XML转数组 public function FromXml( $xml ) { if ( !$xml ) { echo "xml数据异常!"; } //将XML转为array //禁止引用外部xml实体 libxml_disable_entity_loader( TRUE ); $data = json_decode( json_encode( simplexml_load_string( $xml , 'SimpleXMLElement' , LIBXML_NOCDATA ) ) , TRUE ); return $data; } //获取签名 public function getSign( $params ) { ksort( $params ); //将参数数组按照参数名ASCII码从小到大排序 foreach ( $params as $key => $item ) { if ( !empty( $item ) ) { //剔除参数值为空的参数 $newArr[] = $key.'='.$item; // 整合新的参数数组 } } $stringA = implode( "&" , $newArr ); //使用 & 符号连接参数 $stringSignTemp = $stringA."&key=".config( 'myconfig.config.appKey' ); //微信商户的key // key是在商户平台API安全里自己设置的 $stringSignTemp = MD5( $stringSignTemp ); //将字符串进行MD5加密 $sign = strtoupper( $stringSignTemp ); //将所有字符转换为大写 return $sign; } //生成不重复的随机字符串 public function genRandomString() { $length = 32; $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str = ""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr( $chars , mt_rand( 0 , strlen( $chars ) - 1 ) , 1 ); } return $str; }
//CURL请求没有携带证书 public function curl( $url = '' , $request = [] , $header = [] , $method = 'POST' ) { $header[] = 'Accept-Encoding: gzip, deflate';//gzip解压内容 $ch = curl_init(); //1.初始化 curl_setopt( $ch , CURLOPT_URL , $url ); //2.请求地址 curl_setopt( $ch , CURLOPT_CUSTOMREQUEST , $method );//3.请求方式 //4.参数如下 curl_setopt( $ch , CURLOPT_SSL_VERIFYPEER , FALSE );//https curl_setopt( $ch , CURLOPT_SSL_VERIFYHOST , FALSE ); curl_setopt( $ch , CURLOPT_USERAGENT , 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)' );//模拟浏览器 curl_setopt( $ch , CURLOPT_FOLLOWLOCATION , 1 ); curl_setopt( $ch , CURLOPT_AUTOREFERER , 1 ); curl_setopt( $ch , CURLOPT_HTTPHEADER , $header ); curl_setopt( $ch , CURLOPT_ENCODING , 'gzip,deflate' ); if ( $method == "POST" ) {//5.post方式的时候添加数据 curl_setopt( $ch , CURLOPT_POSTFIELDS , $request ); } curl_setopt( $ch , CURLOPT_RETURNTRANSFER , TRUE ); $tmpInfo = curl_exec( $ch );//6.执行 if ( curl_errno( $ch ) ) {//7.如果出错 return curl_error( $ch ); } curl_close( $ch );//8.关闭 return $tmpInfo; } //CURL请求携带证书 public function curl_z( $url = '' , $request = [] , $header = [] , $method = 'POST' ) { $cert = "C:\phpStudy\PHPTutorial\WWW\peihuchuang\public\cert\apiclient_cert.pem"; //证书路径为绝对路径 $key = "C:\phpStudy\PHPTutorial\WWW\peihuchuang\public\cert\apiclient_key.pem"; //证书路径为绝对路径 $header[] = 'Accept-Encoding: gzip, deflate';//gzip解压内容 $ch = curl_init(); //1.初始化 curl_setopt( $ch , CURLOPT_URL , $url ); //2.请求地址 curl_setopt( $ch , CURLOPT_CUSTOMREQUEST , $method );//3.请求方式 //4.参数如下 curl_setopt( $ch , CURLOPT_SSL_VERIFYPEER , FALSE );//https curl_setopt( $ch , CURLOPT_SSL_VERIFYHOST , FALSE ); curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem'); curl_setopt($ch,CURLOPT_SSLCERT,$cert); curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem'); curl_setopt($ch,CURLOPT_SSLKEY,$key); curl_setopt( $ch , CURLOPT_USERAGENT , 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)' );//模拟浏览器 curl_setopt( $ch , CURLOPT_FOLLOWLOCATION , 1 ); curl_setopt( $ch , CURLOPT_AUTOREFERER , 1 ); curl_setopt( $ch , CURLOPT_HTTPHEADER , $header ); curl_setopt( $ch , CURLOPT_ENCODING , 'gzip,deflate' ); if ( $method == "POST" ) {//5.post方式的时候添加数据 curl_setopt( $ch , CURLOPT_POSTFIELDS , $request ); } curl_setopt( $ch , CURLOPT_RETURNTRANSFER , TRUE ); $tmpInfo = curl_exec( $ch );//6.执行 if ( curl_errno( $ch ) ) {//7.如果出错 return curl_error( $ch ); } curl_close( $ch );//8.关闭 return $tmpInfo; }
//微信申请退款接口
public function wechatRefund( Request $request ) { $str = self::genRandomString(); $data['appid'] = (string)config( 'myconfig.config.wx_appid' ); $data['mch_id'] = (string)config( 'myconfig.config.mch_id' ); $data['nonce_str'] = (string)$str; $data['out_trade_no'] = (string)$request->input( 'out_trade_no' ); //商户订单号 $data['out_refund_no'] = 'ph'.time(); //商户退款单号 $data['total_fee'] = (int)$request->input( 'total_fee' ); // $data['refund_fee'] = (int)$request->input( 'refund_fee' ); $data['sign'] = self::getSign( $data ); $url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; $xml = self::ToXml( $data ); $data = self::curl_z( $url , $xml , [] ); if ( $data ) { //返回成功,将xml数据转换为数组. $re = self::FromXml( $data ); if($re['result_code'] == 'SUCCESS' && $re['return_code'] == 'SUCCESS'){ return [ 'code' => 101, 'msg' => '退款成功' ]; } } else { return [ 'code' => FALSE."2" , 'msg' => '签名数据为空' ]; } }
4. 完成