PHP 微信支付 以及申请退款(在小程序上实现 原理都差不多)

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 = "";
 foreach ( $data as $key => $val ) {
  if ( is_numeric( $val ) ) {
   $xml .= "<".$key.">".$val."";
  } else {
   $xml .= "<".$key.">";
  }
 }
 $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. 完成

你可能感兴趣的:(支付,退款)