Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

WeChatPay.php 12 KiB

3 år sedan
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. <?php
  2. namespace common\service\pay;
  3. use common\util\CurlInterface;
  4. use common\util\Util;
  5. /**
  6. * Class WxPayService
  7. * 微信交易接口调用核心
  8. * @package Base\Tool
  9. */
  10. class WeChatPay
  11. {
  12. public $unifiedOrderUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//统一下单API
  13. /************************手机浏览器内web支付**************************************/
  14. /**
  15. *
  16. */
  17. public function H5Pay($params)
  18. {
  19. $siteConfig = Util::getSiteConfig();
  20. if (empty($params['notify_url'])) {
  21. $params['notify_url'] = $siteConfig['notify_url'];
  22. }
  23. $data = array(
  24. 'name' => $params['name'],//名称
  25. 'order_id' => (string)$params['order_id'] . '_' . rand(1000, 9999),//支付ID
  26. 'total_fee' => (string)$params['total_fee'] * 100,//总金
  27. 'notify_url' => $params['notify_url'],//支付回调接口
  28. 'trade_type' => 'MWEB',//用户的OPENID
  29. 'scene_info' => [
  30. 'h5_info' => [
  31. 'type' => 'Wap',
  32. 'wap_url' => $siteConfig['host_name'],
  33. 'wap_name' => $siteConfig['web_name']
  34. ]
  35. ]
  36. );
  37. $getpay = $this->unifiedOrderForWeChat($data);//统一下单API
  38. if ($getpay['flag'] == false) {
  39. return $getpay;
  40. }
  41. if (empty($getpay['data']['mweb_url'])) {
  42. return Util::returnArrEr('预支付会话异常!');
  43. }
  44. return Util::returnArrSu('', ['pay_url' => $getpay['data']['mweb_url']]);
  45. }
  46. /************************微信浏览器内web支付**************************************/
  47. /**
  48. * Function Description:去微信下单并获取返回
  49. * Function Name: unifiedOrderByOrderId
  50. * @param $params array
  51. * $order_id string 订单表 订单ID
  52. * $name string 产品名称
  53. * $total_fee int 总金额 单位分
  54. * $openid string 用户opendid
  55. * @return array
  56. *
  57. * @author nzf
  58. */
  59. public function webPay($params)
  60. {
  61. $siteConfig = Util::getSiteConfig();
  62. if (empty($params['notify_url'])) {
  63. $params['notify_url'] = $siteConfig['notify_url'];
  64. }
  65. $data = array(
  66. 'name' => $params['name'],//名称
  67. 'order_id' => (string)$params['order_id'] . '_' . rand(1000, 9999),//支付ID
  68. 'total_fee' => (string)$params['total_fee'] * 100,//总金
  69. 'notify_url' => $params['notify_url'],//支付回调接口
  70. 'openid' => $params['openid']//用户的OPENID
  71. );
  72. $getPrepayId = $this->unifiedOrderForWeChat($data);//统一下单API
  73. if ($getPrepayId['flag'] == false) {
  74. return $getPrepayId;
  75. }
  76. //设置成功返回的结果数
  77. $wxPayConfig = Util::getWeChatConfig();
  78. $return = array(
  79. 'appId' => $wxPayConfig['appid'],//微信�?放平台审核�?�过的应用APPID
  80. 'package' => 'prepay_id=' . $getPrepayId['data']['prepay_id'],//微信返回的支付交易会话ID
  81. 'nonceStr' => self::getNonceStr(),//随机字符�?
  82. 'signType' => 'MD5',
  83. 'timeStamp' => strval(time()),//当前时间�?
  84. );
  85. $return['paySign'] = self::getSign($return);
  86. return Util::returnArrSu('', array('payData' => $return, 'price' => $params['total_fee']));
  87. }
  88. /**
  89. * Function Description:统一下单API
  90. * Function Name: unifiedOrder
  91. * @param $params array
  92. * attach 附加数据,在查询API和支付知中原样返回,该字段主要用于商户携带订单的自定义数
  93. * line_name 线路名称
  94. * order_id 订单ID
  95. * total_fee 总金
  96. * notify_url 回调地址
  97. *
  98. * @return array
  99. *
  100. * @author nzf
  101. */
  102. public function unifiedOrderForWeChat($params)
  103. {
  104. $wxPayConfig = Util::getWeChatConfig();
  105. $data = array(
  106. 'appid' => $wxPayConfig['appid'],//微信开放平台审核过的应用APPID
  107. 'attach' => empty($params['attach']) ? '' : $params['attach'],
  108. 'body' => $params['name'],//产品名称
  109. 'mch_id' => $wxPayConfig['mch_id'],//商户微信支付分配的商户号
  110. 'nonce_str' => $this->getNonceStr(),//随机字符
  111. 'notify_url' => $params['notify_url'],//通知地址
  112. 'out_trade_no' => $params['order_id'],//商户订单ID加上当前时间
  113. 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],//用户端实际ip
  114. 'total_fee' => $params['total_fee'],//订单总金额,单位为分
  115. 'trade_type' => empty($params['trade_type']) ? 'JSAPI' : $params['trade_type'],//交易类型
  116. );
  117. if (empty($params['openid']) == false) {//存在openid
  118. $data['openid'] = $params['openid'];
  119. }
  120. if (isset($params['scene_info'])) {
  121. $data['scene_info'] = json_encode($params['scene_info']);
  122. }
  123. $data['sign'] = $this->getSign($data);//交易签名
  124. $curl = new CurlInterface($data, 2);//函数
  125. $curl->setBaseUrl($this->unifiedOrderUrl);
  126. $result = $curl->execute('', 'POST');
  127. if (empty($result['prepay_id'])) {
  128. return Util::returnArrEr('预支付交易会话异常!');
  129. }
  130. return Util::returnArrSu('', array('prepay_id' => $result['prepay_id'], 'mweb_url' => empty($result['mweb_url']) ? '' : $result['mweb_url']));
  131. }
  132. /************************扫描支付**************************************/
  133. /**
  134. * Function Description:去微信下单并获取返回
  135. * Function Name: unifiedOrderByOrderId
  136. * @param $par
  137. * @return array
  138. *
  139. * @author nzf
  140. */
  141. public function unifiedOrderByOrderIdForSao($par)
  142. {
  143. $siteConfig = Util::getSiteConfig();
  144. $notify_url = $siteConfig['host_name'] . $siteConfig['notify_url'];
  145. $data = array(
  146. 'name' => $par['name'],//线路名称
  147. 'order_id' => (string)$par['order_id'] . '_' . rand(100, 999),//订单ID
  148. 'total_fee' => $par['total_fee'] * 100,//总金
  149. 'notify_url' => $notify_url
  150. );
  151. $codUrl = $this->unifiedOrderForSao($data);//统一下单API
  152. if ($codUrl['flag'] == false) {
  153. return $codUrl;
  154. }
  155. //设置成功返回的结果数�?
  156. $url = $siteConfig['host_name'] . '/fx/?r=weChat/we-chat/q-code&qCode=' . urlencode($codUrl['data']['code_url']) . '&_math=' . rand(100, 999);
  157. return Util::returnArrSu('', array('codUrl' => $url, 'price' => $par['total_fee']));
  158. }
  159. /**
  160. * Function Description:统一下单API
  161. * Function Name: unifiedOrder
  162. * @param $params array
  163. * attach 附加数据,在查询API和支付知中原样返回,该字段主要用于商户携带订单的自定义数
  164. * line_name 线路名称
  165. * order_id 订单ID
  166. * total_fee 总金
  167. * notify_url 回调地址
  168. *
  169. * @return array
  170. *
  171. * @author 倪宗�?
  172. */
  173. public function unifiedOrderForSao($params)
  174. {
  175. $wxPayConfig = Util::getWeChatConfig();
  176. $data = array(
  177. 'appid' => $wxPayConfig['appid'],//微信�?放平台审核�?�过的应用APPID
  178. 'mch_id' => $wxPayConfig['mch_id'],//商户�? 微信支付分配的商户号
  179. 'nonce_str' => $this->getNonceStr(),//随机字符�?
  180. 'body' => $params['name'],//线路名称 �? 上订单ID
  181. 'out_trade_no' => $params['order_id'],//商户订单ID加上当前时间
  182. 'total_fee' => $params['total_fee'],//订单总金额,单位为分
  183. 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],//用户端实际ip
  184. 'notify_url' => $params['notify_url'],//通知地址
  185. 'trade_type' => 'NATIVE',//交易类型
  186. );
  187. $data['sign'] = $this->getSign($data);//交易签名
  188. $curl = new CurlInterface($data, 2);//函数�?
  189. $curl->setBaseUrl($this->unifiedOrderUrl);
  190. $result = $curl->execute('', 'POST');
  191. if (empty($result['prepay_id'])) {
  192. return Util::returnArrEr('预支付交易会话异常!');
  193. }
  194. return Util::returnArrSu('', array('prepay_id' => $result['prepay_id'], 'code_url' => $result['code_url']));
  195. }
  196. /***************************************退款****************************************/
  197. /**
  198. * Des:微信退款接口
  199. * Name: cancelOrder
  200. * @param $params
  201. * @return array
  202. * @author 倪宗锋
  203. */
  204. public static function cancelOrder($params)
  205. {
  206. $config = Util::getWeChatConfig($params['app_id']);
  207. $arr = array(
  208. 'appid' => $config['appid'],
  209. 'mch_id' => $config['mch_id'],
  210. 'nonce_str' => static::getNonceStr(),
  211. 'out_trade_no' => (string)$params['order_id'],//订单ID
  212. 'out_refund_no' => (string)date('YmdHis') . rand(100, 999),//退款ID
  213. 'total_fee' => (string)$params['total_fee'] * 100,//订单总金额 元
  214. 'refund_fee' => (string)$params['refund_fee'] * 100,//退款金额 元
  215. 'op_user_id' => $config['mch_id']
  216. );
  217. $arr['sign'] = static::getSign($arr);
  218. $curl = new CurlInterface($arr, 2);//函数类
  219. $curl->setCert($config);
  220. $curl->setBaseUrl('https://api.mch.weixin.qq.com/secapi/pay/refund');
  221. $result = $curl->execute('', 'POST');
  222. if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
  223. return Util::returnArrSu();
  224. }
  225. $msg = $result['return_msg'];
  226. if ($msg == 'OK') {
  227. $msg = $result['err_code_des'];
  228. }
  229. return Util::returnArrEr('退款失败!' . $msg);
  230. }
  231. /*************************************通用方法**************************************/
  232. /**
  233. * Des:检测是否已经支付
  234. * Name: checkIsPay
  235. * @param $orderId
  236. * @return array
  237. * @author 倪宗锋
  238. */
  239. public static function checkIsPay($orderId)
  240. {
  241. $config = Util::getWeChatConfig();
  242. $arr = array(
  243. 'appid' => $config['appid'],
  244. 'mch_id' => $config['mch_id'],
  245. 'out_trade_no' => (string)$orderId,//订单ID
  246. 'nonce_str' => static::getNonceStr(),
  247. );
  248. $arr['sign'] = static::getSign($arr);
  249. $curl = new CurlInterface($arr, 2);//函数类
  250. $curl->setCert($config);
  251. $curl->setBaseUrl('https://api.mch.weixin.qq.com/pay/orderquery');
  252. $result = $curl->execute('', 'POST');
  253. if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
  254. return Util::returnArrSu('', $result);
  255. }
  256. $msg = $result['return_msg'];
  257. if ($msg == 'OK') {
  258. $msg = $result['err_code_des'];
  259. }
  260. return Util::returnArrEr('退款失败!' . $msg);
  261. }
  262. /**
  263. * Function Description:获取签名
  264. * Function Name: getSign
  265. * @param $params
  266. * @return string
  267. *
  268. * @author nzf
  269. */
  270. public static function getSign($params)
  271. {
  272. if (isset($params['sign'])) {
  273. unset($params['sign']);
  274. }
  275. $config = Util::getWeChatConfig();
  276. //签名步骤按字典序排序参
  277. ksort($params);
  278. $string = self::ToUrlParams($params);
  279. //签名步骤二:在string后加入KEY
  280. $string = $string . "&key=" . $config['key'];
  281. //签名步骤三:MD5加密
  282. $string = md5($string);
  283. //签名步骤四:有字符转为大
  284. $result = strtoupper($string);
  285. return $result;
  286. }
  287. /**
  288. * Function Description:格式化参�? 格式化成url参数
  289. * Function Name: ToUrlParams
  290. * @param $params
  291. *
  292. * @return string
  293. *
  294. * @author 倪宗�?
  295. */
  296. public static function ToUrlParams($params)
  297. {
  298. $buff = "";
  299. foreach ($params as $k => $v) {
  300. if ($k != "sign" && $v != "" && !is_array($v)) {
  301. $buff .= $k . "=" . $v . "&";
  302. }
  303. }
  304. $buff = trim($buff, "&");
  305. return $buff;
  306. }
  307. /**
  308. * Function Description:产生的随机字符串 不长
  309. * Function Name: getNonceStr
  310. * @param int $length
  311. *
  312. * @return string
  313. *
  314. * @author 倪宗�?
  315. */
  316. public static function getNonceStr($length = 32)
  317. {
  318. $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  319. $str = "";
  320. for ($i = 0; $i < $length; $i++) {
  321. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  322. }
  323. return $str;
  324. }
  325. }