当前位置:首页 > CMS教程 > Thinkphp > 列表

基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作

发布:smiling 来源: PHP粉丝网  添加日期:2022-03-22 09:22:25 浏览: 评论:0 

这篇文章主要介绍了基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下。

微信小程序或微信支付相关操作支付退款订单查询退款查询支付成功,进行回调退款成功 进行回调用到的方法

支付

  1. /** 
  2.  * 预支付请求接口(POST) 
  3.  * @param string $openid openid 
  4.  * @param string $body 商品简单描述 
  5.  * @param string $order_sn 订单编号 
  6.  * @param string $total_fee 金额 
  7.  * @return json的数据 
  8.  */ 
  9.  public function prepay() 
  10.  { 
  11.  tp_log('预支付请求数据===>' . json_encode($_POST), 'prepay', request()->controller()); 
  12.  $goods_user = db('tf_goods_user')->where(array('order_no' => $_POST['order_no']))->find(); 
  13.  $goods = db('tf_goods')->where(array('id' => $goods_user['goods_id']))->find(); 
  14.  //判断产品的数量 
  15.  if (($goods['sales_initial'] - $goods['sales_actual']) <= 0) { 
  16.  $return['status'] = 0; 
  17.  $return['info'] = '此产品已售完'
  18.  exit(json_encode($return)); 
  19.  } 
  20.  
  21.  $order_no = $_POST['order_no']; //订单号 
  22.  $is_sale = $_POST['is_sale']; 
  23.  $openid = $_POST['openid']; 
  24.  $goods_name = $_POST['goods_name']; 
  25.  $pay_price = $_POST['price']; 
  26.  $attach['is_sale'] = $_POST['is_sale']; 
  27.  $attach['sale_id'] = $_POST['sale_id']; 
  28.  $nonce_str = $this->nonce_str();//随机字符串 
  29.  
  30.  
  31.  $order_no_ssh = $this->get_orderssh(); //商户订单号 
  32.  //组装支付数据 
  33.  $data = [ 
  34.  'appid' => config('pay.APPID'), 
  35.  'mch_id' => config('pay.MCHID'), 
  36.  'nonce_str' => $nonce_str
  37.  'body' => $goods_name//商品名称组合 
  38.  'attach' => json_encode($attach), 
  39.  'out_trade_no' => $order_no_ssh,//$order_no, //订单号 商户订单号 
  40.  'total_fee' => intval($pay_price * 100), 
  41.  'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], 
  42.  'notify_url' => config('pay.NOTIFY_URL'), 
  43.  'trade_type' => 'JSAPI'
  44.  'openid' => $openid 
  45.  ]; 
  46.  
  47.  //订单支付表创建订单支付数据 
  48.  $p_o_data['createtime'] = time(); 
  49.  $p_o_data['order_no'] = $order_no
  50.  $p_o_data['order_no_ssh'] = $order_no_ssh
  51.  $p_o_data['ready'] = json_encode($data); 
  52.  $p_o_return = db('tf_pay_order')->insert($p_o_data); 
  53.  if(!$p_o_return){ 
  54.  //失败 
  55.  $return['status'] = -1; 
  56.  $return['info'] = $p_o_data
  57.  exit(json_encode($return)); 
  58.  } 
  59.  
  60.  // 获取签名 
  61.  $sign = $this->makeSign($data); 
  62.  $data['sign'] = $sign
  63.  $xml = $this->toXml($data); 
  64.  $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //发起支付接口链接 
  65.  //发起预支付请求 
  66.  $prepay_return_reslut_xml = $this->http_request($url$xml); 
  67.  $xml_to_arr = $this->fromXml($prepay_return_reslut_xml); 
  68.  $return_result = json_encode($xml_to_arr, true); 
  69.  tp_log('预支付请求返回数据array===>' .$return_result , 'prepay', request()->controller()); 
  70.  //记录预支付返回信息 
  71.  db('tf_goods_order')->where(array('order_no' => $order_no)) 
  72.  ->update(array
  73.  'go_pay' => $return_result
  74.  'updatetime' => time(), 
  75.  'updateuser' => $openid 
  76.  )); 
  77.  if($xml_to_arr['return_code'] == 'SUCCESS' && $xml_to_arr['result_code'] == 'SUCCESS'){ 
  78.  //成功 
  79.  
  80.  $time = time(); 
  81.  //临时数组用于签名 
  82.  $tmp = [ 
  83.  'appId' => config('pay.APPID'), 
  84.  'nonceStr' => $nonce_str
  85.  'package' => 'prepay_id='.$xml_to_arr['prepay_id'], 
  86.  'signType' => 'MD5'
  87.  'timeStamp' => "$time"
  88.  ]; 
  89.  $data['timeStamp'] = "$time";//时间戳 
  90.  $data['nonceStr'] = $nonce_str;//随机字符串 
  91.  $data['signType'] = 'MD5';//签名算法,暂支持 MD5 
  92.  $data['package'] = 'prepay_id='.$xml_to_arr['prepay_id'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=* 
  93.  $data['paySign'] = $this->makeSign($tmp);//签名,具体签名方案参见微信公众号支付帮助文档;$data['out_trade_no'] = $out_trade_no; 
  94.  
  95.  
  96.  $return['status'] = 1; 
  97.  $return['info'] = $data
  98.  }else
  99.  //失败 
  100.  $return['status'] = -1; 
  101.  $return['info'] = $xml_to_arr
  102.  } 
  103.  exit(json_encode($return)); 
  104.  } 
  105.  
  106.  //curl请求 
  107.  public function http_request($url$data = null, $headers = array()) 
  108.  { 
  109.  $curl = curl_init(); 
  110.  if (count($headers) >= 1) { 
  111.  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); 
  112.  } 
  113.  curl_setopt($curl, CURLOPT_URL, $url); 
  114.  
  115.  
  116.  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); 
  117.  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); 
  118.  
  119.  
  120.  if (!emptyempty($data)) { 
  121.  curl_setopt($curl, CURLOPT_POST, 1); 
  122.  curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 
  123.  } 
  124.  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 
  125.  $output = curl_exec($curl); 
  126.  curl_close($curl); 
  127.  return $output
  128.  } 

退款

  1. /** 
  2.  * 申请退款API 
  3.  * @param $transaction_id 
  4.  * @param double $total_fee 账单总金额 
  5.  * @param double $refund_fee 退款金额 
  6.  * @return bool 
  7.  * @throws BaseException 
  8.  */ 
  9.  public function refund() 
  10.  { 
  11.  
  12.  $transaction_id = '4200000712202007274705432240'
  13.  $total_fee = '0.01'
  14.  $refund_fee = '0.01'
  15.  // 当前时间 
  16.  $time = time(); 
  17.  // 生成随机字符串 
  18.  $nonceStr = md5($time . $transaction_id . $total_fee . $refund_fee); 
  19.  // API参数 
  20.  $params = [ 
  21.  'appid' => config('pay.APPID'), 
  22.  'mch_id' => config('pay.MCHID'), 
  23.  'nonce_str' => $nonceStr
  24.  'transaction_id' => $transaction_id
  25.  'out_refund_no' => $time
  26.  'total_fee' => $total_fee * 100, 
  27.  'refund_fee' => $refund_fee * 100, 
  28.  'notify_url' => config('pay.NOTIFY_URL_REFUND'),//退款回调地址 
  29.  ]; 
  30.  // 生成签名 
  31.  $params['sign'] = $this->makeSign($params); 
  32.  
  33.  tp_log('退款请求数据===>' . json_encode($params), 'refund', request()->controller()); 
  34.  
  35.  // 请求API 
  36.  $url = 'https://api.mch.weixin.qq.com/secapi/pay/refund'
  37.  $result = $this->post($url$this->toXml($params), true, $this->getCertPem()); 
  38.  $prepay = $this->fromXml($result); 
  39.  // 请求失败 
  40.  if (emptyempty($result)) { 
  41.  throw new BaseException(['msg' => '微信退款api请求失败']); 
  42.  } 
  43.  // 格式化返回结果 
  44.  $prepay = $this->fromXml($result); 
  45.  tp_log('退款返回数据===>' . json_encode($prepay), 'refund', request()->controller()); 
  46.  // 请求失败 
  47. // if ($prepay['return_code'] === 'FAIL') { 
  48. // throw new BaseException(['msg' => 'return_msg: ' . $prepay['return_msg']]); 
  49. // } 
  50. // if ($prepay['result_code'] === 'FAIL') { 
  51. // throw new BaseException(['msg' => 'err_code_des: ' . $prepay['err_code_des']]); 
  52. // } 
  53.  return true; 
  54.  } 
  55.  /** 
  56.  * 模拟POST请求 
  57.  * @param $url 
  58.  * @param array $data 
  59.  * @param bool $useCert 
  60.  * @param array $sslCert 
  61.  * @return mixed 
  62.  */ 
  63.  public function post($url$data = [], $useCert = false, $sslCert = []) 
  64.  { 
  65.  $header = [ 
  66.  'Content-type: application/json;' 
  67.  ]; 
  68.  $curl = curl_init(); 
  69.  //如果有配置代理这里就设置代理 
  70. // if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0" 
  71. // && WxPayConfig::CURL_PROXY_PORT != 0){ 
  72. // curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST); 
  73. // curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT); 
  74. // } 
  75.  
  76.  curl_setopt($curl, CURLOPT_URL, $url); 
  77.  curl_setopt($curl, CURLOPT_HTTPHEADER, $header); 
  78.  curl_setopt($curl, CURLOPT_HEADER, false); 
  79.  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 
  80.  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); 
  81.  curl_setopt($curl, CURLOPT_POST, TRUE); 
  82.  curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 
  83.  if ($useCert == true) { 
  84.  // 设置证书:cert 与 key 分别属于两个.pem文件 
  85.  curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM'); 
  86.  curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']); 
  87.  curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM'); 
  88.  curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']); 
  89.  } 
  90.  $result = curl_exec($curl); 
  91.  curl_close($curl); 
  92.  return $result
  93.  } 

订单查询

  1. /** 
  2.  * 订单查询 
  3.  * @param $out_trade_no 
  4.  * @return mixed 
  5.  * @throws BaseException 
  6.  */ 
  7.  public function orderquery() 
  8.  { 
  9.  $transaction_id = '4200000712202007274705432240';//微信订单号 
  10.  // 当前时间 
  11.  $time = time(); 
  12.  // 生成随机字符串 
  13.  $nonce_str = md5($time . mt_rand(00000,99999)); 
  14.  //API参数 
  15.  $params = [ 
  16.  'appid' => config('pay.APPID'), //公众号ID 
  17.  'mch_id' => config('pay.MCHID'), //商户号 
  18.  'transaction_id' => $transaction_id//商户订单号 
  19.  'nonce_str' => $nonce_str// 随机字符串 
  20.  ]; 
  21.  //生成签名 
  22.  $params['sign'] = $this->makeSign($params); 
  23.  //请求API 
  24.  $url = 'https://api.mch.weixin.qq.com/pay/orderquery'
  25.  $result = $this->post($url$this->toXml($params)); 
  26.  $prepay = $this->fromXml($result); 
  27.  // 请求失败 
  28.  if ($prepay['return_code'] === 'FAIL') { 
  29.  throw new BaseException(['msg' => $prepay['return_msg'], 'code' => 0]); 
  30.  } 
  31.  if ($prepay['result_code'] === 'FAIL') { 
  32.  throw new BaseException(['msg' => $prepay['err_code_des'], 'code' => 0]); 
  33.  } 
  34.  return $prepay
  35.  } 

退款查询

  1. /** 
  2.  * 退款查询 
  3.  * @param $out_trade_no 
  4.  * @return mixed 
  5.  * @throws BaseException 
  6.  */ 
  7.  public function refundquery() 
  8.  { 
  9.  $transaction_id = '4200000712202007274705432240';//微信订单号 
  10.  // 当前时间 
  11.  $time = time(); 
  12.  // 生成随机字符串 
  13.  $nonce_str = md5($time . mt_rand(00000,99999)); 
  14.  //API参数 
  15.  $params = [ 
  16.  'appid' => config('pay.APPID'), //公众号ID 
  17.  'mch_id' => config('pay.MCHID'), //商户号 
  18.  'transaction_id' => $transaction_id//商户订单号 
  19.  'nonce_str' => $nonce_str// 随机字符串 
  20.  ]; 
  21.  //生成签名 
  22.  $params['sign'] = $this->makeSign($params); 
  23.  //请求API 
  24.  $url = 'https://api.mch.weixin.qq.com/pay/refundquery'
  25.  $result = $this->post($url$this->toXml($params)); 
  26.  $prepay = $this->fromXml($result); 
  27.  dump($prepay);die
  28.  // 请求失败 
  29.  if ($prepay['return_code'] === 'FAIL') { 
  30.  throw new BaseException(['msg' => $prepay['return_msg'], 'code' => 0]); 
  31.  } 
  32.  if ($prepay['result_code'] === 'FAIL') { 
  33.  throw new BaseException(['msg' => $prepay['err_code_des'], 'code' => 0]); 
  34.  } 
  35.  return $prepay
  36.  } 

支付成功,进行回调

  1. public function index() 
  2.  { 
  3.  $data = file_get_contents('php://input'); 
  4.  $data = $this->FromXml($data); 
  5.  tp_log('支付回调数据===>' . json_encode($data), 'index', request()->controller()); 
  6.  // 保存微信服务器返回的签名sign 
  7.  $data_sign = $data['sign']; 
  8.  // sign不参与签名算法 
  9.  unset($data['sign']); 
  10.  $sign = $this->makeSign($data);//回调验证签名 
  11.  
  12.  $str_success = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'
  13.  $str_error = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>'
  14.  
  15.  if (($sign === $data_sign) && ($data['return_code'] == 'SUCCESS') && ($data['result_code'] == 'SUCCESS')) { 
  16.  // 支付成功 进行你的逻辑处理 
  17.  } 
  18. echo $str_success;//str_error 告知微信 你已的逻辑处理完毕 不用再推送或再次推送你结果 
  19.  } 

退款成功 进行回调

  1. /* 
  2.  * 小程序 退款结果通知 
  3.  */ 
  4.  public function refund(){ 
  5.  
  6.  $data = file_get_contents('php://input'); 
  7.  $data = $this->FromXml($data); 
  8.  tp_log('退款回调数据===>' . json_encode($data), 'refund', request()->controller()); 
  9.  
  10.  //对加密的字符串解密 
  11.  $req_info_xml = openssl_decrypt(base64_decode($data['req_info']), 'aes-256-ecb', md5(config('pay.KEY')),OPENSSL_RAW_DATA); 
  12.  $req_info = $this->FromXml($req_info_xml); 
  13.  
  14. // // 保存微信服务器返回的签名sign 
  15. // $data_sign = $data['sign']; 
  16. // // sign不参与签名算法 
  17. // unset($data['sign']); 
  18. // $sign = $this->makeSign($data);//回调验证签名 
  19. // 
  20. // $str_success = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; 
  21. // $str_error = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>'; 
  22. // 
  23. // 
  24. // 
  25. // if (($sign === $data_sign) && ($data['return_code'] == 'SUCCESS') && ($data['result_code'] == 'SUCCESS')) { 
  26. // tp_log('退款成功===>', 'refund', request()->controller()); 
  27. // //去修改订单的状态 和支付回调的一样 修改成功 告知微信 不在推送 
  28. // } 
  29.  } 

用到的方法

  1. /** 
  2.  * 生成签名 
  3.  * @param $values 
  4.  * @return string 本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值 
  5.  */ 
  6.  private function makeSign($values
  7.  { 
  8.  //签名步骤一:按字典序排序参数 
  9.  ksort($values); 
  10.  $string = $this->toUrlParams($values); 
  11.  //签名步骤二:在string后加入KEY 
  12.  $string = $string . '&key=' . config('pay.KEY'); 
  13.  //签名步骤三:MD5加密 
  14.  $string = md5($string); 
  15.  //签名步骤四:所有字符转为大写 
  16.  $result = strtoupper($string); 
  17.  return $result
  18.  } 
  19.  private function ToUrlParams($array
  20.  { 
  21.  $buff = ""
  22.  foreach ($array as $k => $v) { 
  23.  if ($k != "sign" && $v != "" && !is_array($v)) { 
  24.  $buff .= $k . "=" . $v . "&"
  25.  } 
  26.  } 
  27.  $buff = trim($buff"&"); 
  28.  return $buff
  29.  } 
  30.  
  31.  /** 
  32.  * 输出xml字符 
  33.  * @param $values 
  34.  * @return bool|string 
  35.  */ 
  36.  private function toXml($values
  37.  { 
  38.  if (!is_array($values
  39.  || count($values) <= 0 
  40.  ) { 
  41.  return false; 
  42.  } 
  43.  $xml = "<xml>"
  44.  foreach ($values as $key => $val) { 
  45.  if (is_numeric($val)) { 
  46.  $xml .= "<" . $key . ">" . $val . "</" . $key . ">"
  47.  } else { 
  48.  $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">"
  49.  } 
  50.  } 
  51.  $xml .= "</xml>"
  52.  return $xml
  53.  } 
  54.  
  55.  /** 
  56.  * 将xml转为array 
  57.  * @param $xml 
  58.  * @return mixed 
  59.  */ 
  60.  private function fromXml($xml
  61.  { 
  62.  // 禁止引用外部xml实体 
  63.  libxml_disable_entity_loader(true); 
  64.  return json_decode(json_encode(simplexml_load_string($xml'SimpleXMLElement', LIBXML_NOCDATA)), true); 
  65.  } 
  66.  
  67.  /** 
  68.  * 获取cert证书文件 
  69.  * @return array 
  70.  * @throws BaseException 
  71.  */ 
  72.  private function getCertPem() 
  73.  { 
  74. // if (empty($this->config['cert_pem']) || empty($this->config['key_pem'])) { 
  75. // throw new BaseException(['msg' => '请先到后台小程序设置填写微信支付证书文件']); 
  76. // } 
  77.  // cert目录 
  78.  $filePath = EXTEND_PATH.'wxpay/cert/'
  79.  return [ 
  80.  'certPem' => $filePath . 'apiclient_cert.pem'
  81.  'keyPem' => $filePath . 'apiclient_key.pem' 
  82.  ]; 
  83.  } 
  84. /** 
  85.  * 生成商户订单号 
  86.  */ 
  87.  public function get_orderssh() 
  88.  { 
  89.  return date("YmdHis") . mt_rand(10000000, 99999999); 
  90.  } 

证书路径

基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作

config配置

基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作

Tags: thinkphp5微信小程序支付

分享到: