HkScanPayService.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <?php
  2. /**
  3. * Author: 芸众商城 www.yunzshop.com
  4. * Date: 2019/6/3
  5. * Time: 下午3:10
  6. */
  7. namespace app\common\services\wechat;
  8. use app\common\exceptions\AppException;
  9. use app\common\helpers\Url;
  10. use app\common\models\OrderPay;
  11. use app\common\models\PayType;
  12. use app\common\services\Pay;
  13. use app\common\services\wechat\lib\WxPayApi;
  14. use app\common\services\wechat\lib\WxPayConfig;
  15. use app\common\services\wechat\lib\WxPayException;
  16. use app\common\services\wechat\lib\WxPayMicroPay;
  17. use app\framework\Http\Request;
  18. use Illuminate\Support\Facades\DB;
  19. class HkScanPayService extends Pay
  20. {
  21. public $set = null;
  22. public $config = null;
  23. public function __construct()
  24. {
  25. // $this->config = new WxPayConfig();
  26. // $this->set = $set = \Setting::get('shop.wechat_set');
  27. }
  28. /**
  29. * 支付
  30. * @param array $data
  31. * @return mixed|string
  32. * @throws AppException
  33. * @throws \app\common\services\wechat\lib\WxPayException
  34. */
  35. public function doPay($data = [])
  36. {
  37. $op = '微信香港扫码支付'.' 订单号:' . $data['order_no'];
  38. $pay_order_model = $this->log(1, '微信香港扫码支付', $data['amount'] / 100, $op, $data['order_no'], Pay::ORDER_STATUS_NON, \YunShop::app()->getMemberId());
  39. $set = \Setting::get('plugin.hk_pay_set');
  40. $pars['service'] = 'pay.weixin.native.intl';
  41. $pars['mch_id'] = $set['mch_id'];
  42. $pars['out_trade_no'] = $data['order_no'];
  43. $pars['body'] = $data['body'];
  44. $pars['total_fee'] = $data['amount'] * 100;
  45. $pars['mch_create_ip'] = \Request::getClientIp();
  46. $pars['notify_url'] = Url::shopSchemeUrl('payment/hkscan/notifyUrl.php');
  47. $pars['nonce_str'] = $this->getNonceStr();
  48. $pars['attach'] = \YunShop::app()->uniacid;
  49. ksort($pars, SORT_STRING);
  50. $string1 = '';
  51. foreach($pars as $k => $v) {
  52. $string1 .= "{$k}={$v}&";
  53. }
  54. $string1 .= "key={$set['key']}";
  55. $pars['sign'] = strtoupper(md5($string1));
  56. $post = $this->array2xml($pars);
  57. $result = $this->postXmlCurl($post,'https://gateway.wepayez.com/pay/gateway');
  58. $disableEntities = libxml_disable_entity_loader(true);
  59. $data = json_decode(json_encode(simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  60. libxml_disable_entity_loader($disableEntities);
  61. if ($data['status'] == 0 && $data['result_code'] == 0) {
  62. $sign = $data['sign'];
  63. //验签
  64. unset($data['sign']);
  65. $string1 = '';
  66. foreach($data as $k => $v) {
  67. $string1 .= "{$k}={$v}&";
  68. }
  69. $string1 .= "key={$set['key']}";
  70. if ($sign == strtoupper(md5($string1))) {
  71. \Log::debug('验签成功');
  72. return ['qrcode'=>$data['code_img_url']];
  73. }
  74. } else {
  75. \Log::debug('微信港版支付,请求错误',$data);
  76. throw new AppException('获取支付参数失败');
  77. }
  78. }
  79. /**
  80. * 提现
  81. */
  82. public function doWithdraw($member_id, $out_trade_no, $money, $desc, $type)
  83. {
  84. }
  85. /**
  86. * 退款
  87. */
  88. public function doRefund($out_trade_no, $totalmoney, $refundmoney)
  89. {
  90. $out_refund_no = $this->setUniacidNo(\YunShop::app()->uniacid);
  91. $op = '港版微信退款 订单号:' . $out_trade_no . '退款单号:' . $out_refund_no . '退款总金额:' . $totalmoney;
  92. if (empty($out_trade_no)) {
  93. throw new AppException('参数错误');
  94. }
  95. $pay_type_id = OrderPay::get_paysn_by_pay_type_id($out_trade_no);
  96. $pay_type_name = PayType::get_pay_type_name($pay_type_id);
  97. $pay_order_model = $this->refundlog(Pay::PAY_TYPE_REFUND, $pay_type_name, $refundmoney, $op, $out_trade_no, Pay::ORDER_STATUS_NON, 0);
  98. $set = \Setting::get('plugin.hk_pay_set');
  99. $pars['service'] = 'unified.trade.refund';
  100. $pars['mch_id'] = $set['mch_id'];
  101. $pars['out_trade_no'] = $out_trade_no;
  102. $pars['out_refund_no'] = $out_refund_no;
  103. $pars['total_fee'] = $totalmoney * 100;
  104. $pars['refund_fee'] = $refundmoney * 100;
  105. $pars['op_user_id'] = $set['mch_id'];
  106. $pars['nonce_str'] = $this->getNonceStr();
  107. $pars['sign'] = $this->getSign($pars,$set['key']);
  108. $post = $this->array2xml($pars);
  109. $result = $this->postXmlCurl($post,'https://gateway.wepayez.com/pay/gateway');
  110. $disableEntities = libxml_disable_entity_loader(true);
  111. $data = json_decode(json_encode(simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  112. libxml_disable_entity_loader($disableEntities);
  113. $this->payResponseDataLog($out_trade_no, '港版微信退款', json_encode($data));
  114. if ($data['status'] == 0 && $data['result_code'] == 0) {
  115. $sign = $data['sign'];
  116. unset($data['sign']);
  117. //验签
  118. if ($sign == $this->getSign($data,$set['key'])) {
  119. //查询
  120. $json['service'] = 'unified.trade.refundquery';
  121. $json['mch_id'] = $set['mch_id'];
  122. $json['out_trade_no'] = $out_trade_no;
  123. $json['nonce_str'] = $this->getNonceStr();
  124. $json['sign'] = $this->getSign($json,$set['key']);
  125. $post = $this->array2xml($json);
  126. $result = $this->postXmlCurl($post,'https://gateway.wepayez.com/pay/gateway');
  127. $disableEntities = libxml_disable_entity_loader(true);
  128. $data = json_decode(json_encode(simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  129. libxml_disable_entity_loader($disableEntities);
  130. \Log::debug('微信港版支付退款查询',$data);
  131. if ($data['refund_status_0'] == 'PROCESSING' || $data['refund_status_0'] == 'SUCCESS') {
  132. $this->changeOrderStatus($pay_order_model, Pay::ORDER_STATUS_COMPLETE, $data['transaction_id']);
  133. \Log::debug('微信港版支付验签成功,退款');
  134. return true;
  135. } else {
  136. throw new AppException('微信港版支付退款错误');
  137. }
  138. }
  139. } else {
  140. \Log::debug('微信港版支付退款,请求错误',$data);
  141. throw new AppException('微信港版支付退款错误');
  142. }
  143. }
  144. private function changeOrderStatus($model, $status, $trade_no)
  145. {
  146. $model->status = $status;
  147. $model->trade_no = $trade_no;
  148. $model->save();
  149. }
  150. private function getSign($data,$key)
  151. {
  152. ksort($data, SORT_STRING);
  153. $string1 = '';
  154. foreach($data as $k => $v) {
  155. $string1 .= "{$k}={$v}&";
  156. }
  157. $string1 .= "key={$key}";
  158. return strtoupper(md5($string1));
  159. }
  160. /**
  161. * 构造签名
  162. *
  163. * @return mixed
  164. */
  165. function buildRequestSign()
  166. {
  167. // TODO: Implement buildRequestSign() method.
  168. }
  169. /**
  170. *获取带参数的请求URL
  171. */
  172. function getRequestURL() {
  173. $this->buildRequestSign();
  174. $reqPar =json_encode($this->parameters);
  175. \Log::debug('-----请求参数----', $reqPar);
  176. $requestURL = $this->getGateURL() . "?data=".base64_encode($reqPar);
  177. return $requestURL;
  178. }
  179. function setOpenId($data)
  180. {
  181. if (!$this->set['is_independent'] && $this->set['sub_appid'] && $this->set['sub_mchid']) {
  182. $data['openid'] = $data['sub_openid'];
  183. }
  184. return $data;
  185. }
  186. function array2xml($arr, $level = 1) {
  187. $s = $level == 1 ? "<xml>" : '';
  188. foreach ($arr as $tagname => $value) {
  189. if (is_numeric($tagname)) {
  190. $tagname = $value['TagName'];
  191. unset($value['TagName']);
  192. }
  193. if (!is_array($value)) {
  194. $s .= "<{$tagname}>" . (!is_numeric($value) ? '<![CDATA[' : '') . $value . (!is_numeric($value) ? ']]>' : '') . "</{$tagname}>";
  195. } else {
  196. $s .= "<{$tagname}>" . $this->array2xml($value, $level + 1) . "</{$tagname}>";
  197. }
  198. }
  199. $s = preg_replace("/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/", ' ', $s);
  200. return $level == 1 ? $s . "</xml>" : $s;
  201. }
  202. public function getNonceStr($length = 32)
  203. {
  204. $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  205. $str ="";
  206. for ( $i = 0; $i < $length; $i++ ) {
  207. $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
  208. }
  209. return $str;
  210. }
  211. private function postXmlCurl($xml, $url, $useCert = false, $second = 30)
  212. {
  213. $ch = curl_init();
  214. $curlVersion = curl_version();
  215. //设置超时
  216. curl_setopt($ch, CURLOPT_TIMEOUT, $second);
  217. curl_setopt($ch,CURLOPT_URL, $url);
  218. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
  219. curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
  220. //设置header
  221. curl_setopt($ch, CURLOPT_HEADER, FALSE);
  222. //要求结果为字符串且输出到屏幕上
  223. curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  224. //post提交方式
  225. curl_setopt($ch, CURLOPT_POST, TRUE);
  226. curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  227. //运行curl
  228. $data = curl_exec($ch);
  229. //返回结果
  230. if($data){
  231. curl_close($ch);
  232. return $data;
  233. } else {
  234. $error = curl_errno($ch);
  235. curl_close($ch);
  236. throw new WxPayException("curl出错,错误码:$error");
  237. }
  238. }
  239. }