You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

145 lines
4.8 KiB

  1. <?php
  2. namespace Kuxin\Weixin;
  3. use Kuxin\Config;
  4. use Kuxin\Helper\Http;
  5. use Kuxin\Helper\Json;
  6. use Kuxin\Helper\Xml;
  7. use Kuxin\Request;
  8. class Pay extends Weixin
  9. {
  10. const API_UNIFIED_ORDER = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
  11. const API_ORDER_QUERY = 'https://api.mch.weixin.qq.com/pay/orderquery';
  12. const TRADE_TYPE_JSAPI = 'JSAPI';
  13. const TRADE_TYPE_NATIVE = 'NATIVE';
  14. const TRADE_TYPE_MWEB = 'MWEB';
  15. public function unifiedorder($data, $tradeType = self::TRADE_TYPE_JSAPI)
  16. {
  17. $data = array_merge([
  18. 'appid' => $this->appId,
  19. 'mch_id' => Config::get('weixin.mchid'),
  20. 'nonce_str' => $this->getNonceStr(),
  21. 'notify_url' => Config::get('weixin.notifyurl'),
  22. 'spbill_create_ip' => $tradeType == self::TRADE_TYPE_NATIVE ? Config::get('server_ip', gethostbyname($_SERVER['SERVER_NAME'])) : Request::getIp(),
  23. 'trade_type' => $tradeType,
  24. ], $data);
  25. $data['sign'] = $this->makeSign($data);
  26. $xml = Xml::encode($data);
  27. $res = Http::post(self::API_UNIFIED_ORDER, $xml);
  28. if ($res) {
  29. $res = Xml::decode($res);
  30. if ($res['return_code'] != 'SUCCESS') {
  31. return $res['return_msg'];
  32. }
  33. if (isset($res['result_code']) && $res['result_code'] == 'FAIL') {
  34. return $res['err_code'] . ':' . $res['err_code_des'];
  35. }
  36. return $res;
  37. } else {
  38. return '统一下单请求失败';
  39. }
  40. }
  41. public function notify($data = null)
  42. {
  43. if (!$data) {
  44. $data = file_get_contents('php://input');
  45. }
  46. $data = Xml::decode($data);
  47. if (isset($data['return_code']) && $data['return_code'] == 'SUCCESS') {
  48. if ($data['sign'] == $this->makeSign($data)) {
  49. return [
  50. 'id' => $data['out_trade_no'],
  51. 'is_subscribe' => $data['is_subscribe'],
  52. 'openid' => $data['openid'],
  53. 'attach' => isset($data['attach']) ? $data['attach'] : "",
  54. 'time_end' => strtotime($data['time_end']),
  55. 'transaction_id' => $data['transaction_id'],
  56. 'money' => $data['total_fee'] / 100,
  57. ];
  58. } else {
  59. return '签名验证失败';
  60. }
  61. } else {
  62. return '解析数据失败';
  63. }
  64. }
  65. public function query($orderId)
  66. {
  67. $data = [
  68. 'appid' => $this->appId,
  69. 'mch_id' => Config::get('weixin.mchid'),
  70. 'out_trade_no' => $orderId,
  71. 'nonce_str' => $this->getNonceStr(),
  72. ];
  73. $data['sign'] = $this->makeSign($data);
  74. $xml = Xml::encode($data);
  75. if ($res = Http::post(self::API_ORDER_QUERY, $xml)) {
  76. $res = Xml::decode($res);
  77. if ($res['return_code'] != 'SUCCESS') {
  78. return $res['return_msg'];
  79. }
  80. if (isset($res['result_code']) && $res['result_code'] == 'FAIL') {
  81. return $res['err_code'] . ':' . $res['err_code_des'];
  82. }
  83. return $res;
  84. } else {
  85. return '订单查询请求失败';
  86. }
  87. }
  88. public function jsPayConfig($prepay_id, $json = true)
  89. {
  90. $data = [
  91. 'appId' => $this->appId,
  92. 'timeStamp' => (string)$_SERVER['REQUEST_TIME'],
  93. 'nonceStr' => $this->getNonceStr(),
  94. 'package' => 'prepay_id=' . $prepay_id,
  95. 'signType' => 'MD5',
  96. ];
  97. $data['paySign'] = $this->makeSign($data);
  98. return $json ? Json::encode($data) : $data;
  99. }
  100. /**
  101. * 格式化参数格式化成url参数
  102. */
  103. public function toUrlParams($data)
  104. {
  105. $buff = "";
  106. foreach ($data as $k => $v) {
  107. if ($k != "sign" && $v != "" && !is_array($v)) {
  108. $buff .= $k . "=" . $v . "&";
  109. }
  110. }
  111. $buff = trim($buff, "&");
  112. return $buff;
  113. }
  114. /**
  115. * 生成签名
  116. *
  117. * @return string 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
  118. */
  119. public function makeSign($data)
  120. {
  121. //签名步骤一:按字典序排序参数
  122. ksort($data);
  123. $string = $this->toUrlParams($data);
  124. //签名步骤二:在string后加入KEY
  125. $string = $string . "&key=" . Config::get('weixin.paykey');
  126. //签名步骤三:MD5加密
  127. $string = md5($string);
  128. //签名步骤四:所有字符转为大写
  129. $result = strtoupper($string);
  130. return $result;
  131. }
  132. }