|
| 1 | +<?php |
| 2 | +/** |
| 3 | + * alipay.trade.refund(统一收单交易退款接口) |
| 4 | + * |
| 5 | + * 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,支付宝将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。 |
| 6 | + */ |
| 7 | +header('Content-type:text/html; Charset=utf-8'); |
| 8 | +/*** 请填写以下配置信息 ***/ |
| 9 | +$appid = 'xxxxx'; //https://open.alipay.com 账户中心->密钥管理->开放平台密钥,填写添加了电脑网站支付的应用的APPID |
| 10 | +$tradeNo = ''; //在支付宝系统中的交易流水号。最短 16 位,最长 64 位。和out_trade_no不能同时为空 |
| 11 | +$outTradeNo = ''; //订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 |
| 12 | +$signType = 'RSA2'; //签名算法类型,支持RSA2和RSA,推荐使用RSA2 |
| 13 | +$refundAmount = 0.01; ////需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数 |
| 14 | +//商户私钥,填写对应签名算法类型的私钥,如何生成密钥参考:https://docs.open.alipay.com/291/105971和https://docs.open.alipay.com/200/105310 |
| 15 | +$rsaPrivateKey=''; |
| 16 | +/*** 配置结束 ***/ |
| 17 | +$aliPay = new AlipayService(); |
| 18 | +$aliPay->setAppid($appid); |
| 19 | +$aliPay->setRsaPrivateKey($rsaPrivateKey); |
| 20 | +$aliPay->setTradeNo($tradeNo); |
| 21 | +$aliPay->setOutTradeNo($outTradeNo); |
| 22 | +$aliPay->setRefundAmount($refundAmount); |
| 23 | +$result = $aliPay->doRefund(); |
| 24 | +$result = $result['alipay_trade_refund_response']; |
| 25 | +if($result['code'] && $result['code']=='10000'){ |
| 26 | + echo '<h1>退款成功</h1>'; |
| 27 | +}else{ |
| 28 | + echo $result['msg'].' : '.$result['sub_msg']; |
| 29 | +} |
| 30 | + |
| 31 | +class AlipayService |
| 32 | +{ |
| 33 | + protected $appId; |
| 34 | + protected $returnUrl; |
| 35 | + protected $notifyUrl; |
| 36 | + protected $charset; |
| 37 | + //私钥值 |
| 38 | + protected $rsaPrivateKey; |
| 39 | + protected $outTradeNo; |
| 40 | + protected $tradeNo; |
| 41 | + protected $refundAmount; |
| 42 | + |
| 43 | + public function __construct() |
| 44 | + { |
| 45 | + $this->charset = 'utf8'; |
| 46 | + } |
| 47 | + public function setAppid($appid) |
| 48 | + { |
| 49 | + $this->appId = $appid; |
| 50 | + } |
| 51 | + public function setRsaPrivateKey($saPrivateKey) |
| 52 | + { |
| 53 | + $this->rsaPrivateKey = $saPrivateKey; |
| 54 | + } |
| 55 | + public function setOutTradeNo($outTradeNo) |
| 56 | + { |
| 57 | + $this->outTradeNo = $outTradeNo; |
| 58 | + } |
| 59 | + public function settradeNo($tradeNo) |
| 60 | + { |
| 61 | + $this->tradeNo = $tradeNo; |
| 62 | + } |
| 63 | + public function setRefundAmount($refundAmount) |
| 64 | + { |
| 65 | + $this->refundAmount = $refundAmount; |
| 66 | + } |
| 67 | + |
| 68 | + /** |
| 69 | + * 退款 |
| 70 | + * @return array |
| 71 | + */ |
| 72 | + public function doRefund() |
| 73 | + { |
| 74 | + //请求参数 |
| 75 | + $requestConfigs = array( |
| 76 | + 'trade_no'=>$this->tradeNo, |
| 77 | + 'out_trade_no'=>$this->outTradeNo, |
| 78 | + 'refund_amount'=>$this->refundAmount, |
| 79 | + ); |
| 80 | + $commonConfigs = array( |
| 81 | + //公共参数 |
| 82 | + 'app_id' => $this->appId, |
| 83 | + 'method' => 'alipay.trade.refund', //接口名称 |
| 84 | + 'format' => 'JSON', |
| 85 | + 'charset'=>$this->charset, |
| 86 | + 'sign_type'=>'RSA2', |
| 87 | + 'timestamp'=>date('Y-m-d H:i:s'), |
| 88 | + 'version'=>'1.0', |
| 89 | + 'biz_content'=>json_encode($requestConfigs), |
| 90 | + ); |
| 91 | + $commonConfigs["sign"] = $this->generateSign($commonConfigs, $commonConfigs['sign_type']); |
| 92 | + $result = $this->curlPost('https://openapi.alipay.com/gateway.do',$commonConfigs); |
| 93 | + $resultArr = json_decode($result,true); |
| 94 | + if(empty($resultArr)){ |
| 95 | + $result = iconv('GBK','UTF-8//IGNORE',$result); |
| 96 | + return json_decode($result,true); |
| 97 | + } |
| 98 | + return $resultArr; |
| 99 | + } |
| 100 | + |
| 101 | + public function generateSign($params, $signType = "RSA") { |
| 102 | + return $this->sign($this->getSignContent($params), $signType); |
| 103 | + } |
| 104 | + |
| 105 | + protected function sign($data, $signType = "RSA") { |
| 106 | + $priKey=$this->rsaPrivateKey; |
| 107 | + $res = "-----BEGIN RSA PRIVATE KEY-----\n" . |
| 108 | + wordwrap($priKey, 64, "\n", true) . |
| 109 | + "\n-----END RSA PRIVATE KEY-----"; |
| 110 | + ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置'); |
| 111 | + if ("RSA2" == $signType) { |
| 112 | + openssl_sign($data, $sign, $res, version_compare(PHP_VERSION,'5.4.0', '<') ? SHA256 : OPENSSL_ALGO_SHA256); //OPENSSL_ALGO_SHA256是php5.4.8以上版本才支持 |
| 113 | + } else { |
| 114 | + openssl_sign($data, $sign, $res); |
| 115 | + } |
| 116 | + $sign = base64_encode($sign); |
| 117 | + return $sign; |
| 118 | + } |
| 119 | + |
| 120 | + /** |
| 121 | + * 校验$value是否非空 |
| 122 | + * if not set ,return true; |
| 123 | + * if is null , return true; |
| 124 | + **/ |
| 125 | + protected function checkEmpty($value) { |
| 126 | + if (!isset($value)) |
| 127 | + return true; |
| 128 | + if ($value === null) |
| 129 | + return true; |
| 130 | + if (trim($value) === "") |
| 131 | + return true; |
| 132 | + |
| 133 | + return false; |
| 134 | + } |
| 135 | + |
| 136 | + public function getSignContent($params) { |
| 137 | + ksort($params); |
| 138 | + $stringToBeSigned = ""; |
| 139 | + $i = 0; |
| 140 | + foreach ($params as $k => $v) { |
| 141 | + if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) { |
| 142 | + // 转换成目标字符集 |
| 143 | + $v = $this->characet($v, $this->charset); |
| 144 | + if ($i == 0) { |
| 145 | + $stringToBeSigned .= "$k" . "=" . "$v"; |
| 146 | + } else { |
| 147 | + $stringToBeSigned .= "&" . "$k" . "=" . "$v"; |
| 148 | + } |
| 149 | + $i++; |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + unset ($k, $v); |
| 154 | + return $stringToBeSigned; |
| 155 | + } |
| 156 | + |
| 157 | + /** |
| 158 | + * 转换字符集编码 |
| 159 | + * @param $data |
| 160 | + * @param $targetCharset |
| 161 | + * @return string |
| 162 | + */ |
| 163 | + function characet($data, $targetCharset) { |
| 164 | + if (!empty($data)) { |
| 165 | + $fileType = $this->charset; |
| 166 | + if (strcasecmp($fileType, $targetCharset) != 0) { |
| 167 | + $data = mb_convert_encoding($data, $targetCharset, $fileType); |
| 168 | + //$data = iconv($fileType, $targetCharset.'//IGNORE', $data); |
| 169 | + } |
| 170 | + } |
| 171 | + return $data; |
| 172 | + } |
| 173 | + |
| 174 | + public function curlPost($url = '', $postData = '', $options = array()) |
| 175 | + { |
| 176 | + if (is_array($postData)) { |
| 177 | + $postData = http_build_query($postData); |
| 178 | + } |
| 179 | + $ch = curl_init(); |
| 180 | + curl_setopt($ch, CURLOPT_URL, $url); |
| 181 | + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
| 182 | + curl_setopt($ch, CURLOPT_POST, 1); |
| 183 | + curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); |
| 184 | + curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数 |
| 185 | + if (!empty($options)) { |
| 186 | + curl_setopt_array($ch, $options); |
| 187 | + } |
| 188 | + //https请求 不验证证书和host |
| 189 | + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); |
| 190 | + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); |
| 191 | + $data = curl_exec($ch); |
| 192 | + curl_close($ch); |
| 193 | + return $data; |
| 194 | + } |
| 195 | +} |
0 commit comments