Refund.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. namespace addons\service\library;
  3. class Refund
  4. {
  5. protected $userAppid ;
  6. protected $skillAppid;
  7. protected $shopAppid;
  8. protected $mch_id;
  9. protected $key;
  10. protected $cert_client;
  11. protected $cert_key;
  12. protected $reqUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
  13. public function __construct()
  14. {
  15. $payConfig = get_addon_config('epay');
  16. $serviceConfig = \app\api\model\service\ProjectConfigure::getProjectConfig();
  17. $this->userAppid = $payConfig['wechat']['miniapp_id'];
  18. $this->skillAppid = $serviceConfig['skillappid'];
  19. $this->shopAppid = $serviceConfig['shopappid'];
  20. $this->mch_id = $payConfig['wechat']['mch_id'];
  21. $this->key = $payConfig['wechat']['key'];
  22. $this->cert_client = $payConfig['wechat']['cert_client'];
  23. $this->cert_key = $payConfig['wechat']['cert_key'];
  24. }
  25. public function wxRefund($order){
  26. //通过微信api进行退款流程
  27. $params = array(
  28. 'mch_id'=>$this->mch_id,
  29. 'nonce_str'=>$this->createNoncestr(),
  30. 'out_refund_no'=>$order['out_trade_no'],
  31. 'transaction_id'=>$order['transaction_id'],
  32. 'total_fee'=> intval($order['order_price']*100),
  33. 'refund_fee'=> intval($order['refund_price']*100),
  34. );
  35. $params['appid'] = $this->userAppid;
  36. $params['sign'] = $this->getSign($params);
  37. $xmldata = $this->arrayToXml($params);
  38. $xmlresult = $this->postXmlSSLCurl($xmldata,$this->reqUrl);
  39. $result = $this->xmlToArray($xmlresult);
  40. return $result['return_code'];
  41. }
  42. /*
  43. * 对要发送到微信统一下单接口的数据进行签名
  44. */
  45. protected function getSign($Obj){
  46. foreach ($Obj as $k => $v){
  47. $param[$k] = $v;
  48. }
  49. //签名步骤一:按字典序排序参数
  50. ksort($param);
  51. $String = $this->formatBizQueryParaMap($param, false);
  52. //签名步骤二:在string后加入KEY
  53. $wx_key=$this->key; //申请支付后有给予一个商户账号和密码,登陆后自己设置的key
  54. $String = $String."&key=".$wx_key;
  55. //签名步骤三:MD5加密
  56. $String = md5($String);
  57. //签名步骤四:所有字符转为大写
  58. $result_ = strtoupper($String);
  59. // var_dump($result_);
  60. return $result_;
  61. }
  62. /*
  63. *排序并格式化参数方法,签名时需要使用
  64. */
  65. protected function formatBizQueryParaMap($paraMap, $urlencode){
  66. $buff = "";
  67. ksort($paraMap);
  68. foreach ($paraMap as $k => $v){
  69. if($urlencode){
  70. $v = urlencode($v);
  71. }
  72. //$buff .= strtolower($k) . "=" . $v . "&";
  73. $buff .= $k . "=" . $v . "&";
  74. }
  75. $reqPar = "";
  76. if (strlen($buff) > 0){
  77. $reqPar = substr($buff, 0, strlen($buff)-1);
  78. }
  79. return $reqPar;
  80. }
  81. /*
  82. * 生成随机字符串方法
  83. */
  84. protected function createNoncestr($length = 32 ){
  85. $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  86. $str ="";
  87. for ( $i = 0; $i < $length; $i++ ) {
  88. $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
  89. }
  90. return $str;
  91. }
  92. //数组转字符串方法
  93. protected function arrayToXml($arr){
  94. $xml = "<xml>";
  95. foreach ($arr as $key=>$val)
  96. {
  97. if (is_numeric($val)){
  98. $xml.="<".$key.">".$val."</".$key.">";
  99. }else{
  100. $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
  101. }
  102. }
  103. $xml.="</xml>";
  104. return $xml;
  105. }
  106. //将xml字符串转换为数组
  107. protected static function xmlToArray($xml){
  108. $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  109. return $array_data;
  110. }
  111. //需要使用证书的请求
  112. //发送xml请求方法
  113. protected function postXmlSSLCurl($xml, $url, $second = 30)
  114. {
  115. $ch = curl_init();
  116. curl_setopt($ch, CURLOPT_TIMEOUT, $second);
  117. curl_setopt($ch, CURLOPT_URL, $url);
  118. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  119. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  120. curl_setopt($ch, CURLOPT_HEADER, FALSE);
  121. curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  122. curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
  123. curl_setopt($ch, CURLOPT_SSLCERT, ROOT_PATH.$this->cert_client);
  124. curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
  125. curl_setopt($ch, CURLOPT_SSLKEY, ROOT_PATH.$this->cert_key);
  126. curl_setopt($ch, CURLOPT_POST, true);
  127. curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  128. $data = curl_exec($ch);
  129. if ($data) {
  130. curl_close($ch);
  131. return $data;
  132. } else {
  133. $error = curl_errno($ch);
  134. echo "curl出错,错误码:$error" . "<br>";
  135. curl_close($ch);
  136. return false;
  137. }
  138. }
  139. }