Alipay.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. /**
  3. * @note: 支付宝 APP支付、手机网站支付、当面付
  4. * @author: jdzor <895947580@qq.com>
  5. * @date: 2019/3/14
  6. */
  7. namespace payment\alipay;
  8. /**
  9. * 统一支付
  10. * 接口文档:https://docs.open.alipay.com/
  11. * 公共错误码:https://docs.open.alipay.com/common/105806
  12. * 说明:
  13. * 1.当面付不用设置应用网关和授权回调地址,只需要设置应用公钥
  14. *
  15. * 使用方法:
  16. * 1.当面付
  17. * $alipay = new Alipay($config);
  18. * $info = $alipay->placeQrcode($payData);
  19. * $info['code'] != 10000 && json_error((($info['sub_msg'] ?? '') . ' ' . $info['sub_code'] ?? ''), -2);
  20. * $info['code_url'] 通过qrcode生成二维码后,用户扫码即可
  21. * 2.app支付
  22. * $alipay = new Alipay($config);
  23. * $info = $alipay->placeApp($payData);
  24. * 将结果$info传给移动端即可,$info是将参数http_build_query()处理后生成的字符串
  25. * 3.手机网站支付
  26. * $alipay = new Alipay($config);
  27. * $info = $alipay->placeWap($payData);
  28. * $info['html_form'] 将结果通过ajax方式写入html body中即可
  29. * 4.电脑网站支付
  30. * $alipay = new Alipay($config);
  31. * $info = $alipay->placePage($payData);
  32. * $info['html_form'] 将结果通过ajax方式写入html body中即可
  33. *
  34. * Class AlipayQrcode
  35. * @package app\common\extend\alipay
  36. */
  37. class Alipay extends BaseAlipay
  38. {
  39. const PRECREATE_URL = 'alipay.trade.precreate'; //当面付 扫码
  40. const APP_PAY_URL = 'alipay.trade.app.pay'; //App支付
  41. const WAP_PAY_URL = 'alipay.trade.wap.pay'; //手机网站支付
  42. const PAGE_PAY_URL = 'alipay.trade.page.pay'; //电脑网站支付
  43. const CLOSE_URL = 'alipay.trade.close'; //关闭订单
  44. const QUERY_RUL = 'alipay.trade.query'; //查询订单
  45. public function __construct($config)
  46. {
  47. parent::__construct($config);
  48. }
  49. //下单参数检测
  50. private function check($param)
  51. {
  52. isset($param['order_no']) || json_error('缺少参数:order_no');
  53. isset($param['order_price']) || json_error('缺少参数:order_price');
  54. isset($param['subject']) || json_error('缺少参数:subject');
  55. isset($param['notify_url']) || json_error('缺少参数:notify_url');
  56. $this->notifyUrl = $param['notify_url'];
  57. isset($param['return_url']) && $this->returnUrl = $param['return_url'];;
  58. }
  59. //下订单 当面付
  60. public function placeQrcode($param)
  61. {
  62. $this->check($param);
  63. isset($param['expire']) || json_error('缺少参数:expire');
  64. //请求参数
  65. $requestConfig = [
  66. 'out_trade_no' => $param['order_no'], //商户订单号
  67. 'total_amount' => $param['order_price'], //订单总金额,整形,此处单位为元,精确到小数点后2位,不能超过1亿元
  68. 'subject' => $param['subject'], //订单标题,粗略描述用户的支付目的
  69. 'qr_code_timeout_express' => floor($param['expire'] / 60) . 'm', //当面付 二维码过期时间
  70. 'timeout_express' => $this->timeoutExpress //交易创建后才生效
  71. ];
  72. $result = json_decode($this->commonRequest($requestConfig, self::PRECREATE_URL), true);
  73. return $result['alipay_trade_precreate_response'];
  74. }
  75. //下订单 APP支付
  76. public function placeApp($param)
  77. {
  78. $this->check($param);
  79. //请求参数
  80. $requestConfig = [
  81. 'out_trade_no' => $param['order_no'], //商户订单号
  82. 'total_amount' => $param['order_price'], //订单总金额,整形,此处单位为元,精确到小数点后2位,不能超过1亿元
  83. 'subject' => $param['subject'], //订单标题,粗略描述用户的支付目的
  84. 'timeout_express' => $this->timeoutExpress //交易创建后才生效
  85. ];
  86. $result = $this->commonRequest($requestConfig, self::APP_PAY_URL);
  87. return ['alipay' => $result];
  88. }
  89. //下订单 手机网站支付
  90. public function placeWap($param)
  91. {
  92. $this->check($param);
  93. //请求参数
  94. $requestConfig = [
  95. 'out_trade_no' => $param['order_no'], //商户订单号
  96. 'total_amount' => $param['order_price'], //订单总金额,整形,此处单位为元,精确到小数点后2位,不能超过1亿元
  97. 'subject' => $param['subject'], //订单标题,粗略描述用户的支付目的
  98. 'timeout_express' => $this->timeoutExpress, //交易创建后才生效
  99. 'product_code' => 'QUICK_WAP_WAY', //销售产品码,商家和支付宝签约的产品码,如:QUICK_WAP_WAY
  100. ];
  101. $result = $this->commonRequest($requestConfig, self::WAP_PAY_URL);
  102. return $this->buildRequestForm($result);
  103. }
  104. //下订单 电脑网站支付
  105. public function placePage($param)
  106. {
  107. $this->check($param);
  108. //请求参数
  109. $requestConfig = [
  110. 'out_trade_no' => $param['order_no'], //商户订单号
  111. 'total_amount' => $param['order_price'], //订单总金额,整形,此处单位为元,精确到小数点后2位,不能超过1亿元
  112. 'subject' => $param['subject'], //订单标题,粗略描述用户的支付目的
  113. 'timeout_express' => $this->timeoutExpress, //交易创建后才生效
  114. 'product_code' => 'FAST_INSTANT_TRADE_PAY', //销售产品码,商家和支付宝签约的产品码,注:目前仅支持 FAST_INSTANT_TRADE_PAY
  115. ];
  116. $result = $this->commonRequest($requestConfig, self::PAGE_PAY_URL);
  117. return $this->buildRequestForm($result);
  118. }
  119. /**
  120. * 建立请求,以表单HTML形式构造(默认)
  121. * @param array $param 请求参数数组
  122. * @return array 提交表单HTML文本
  123. */
  124. private function buildRequestForm($param)
  125. {
  126. $html = "<form id='alipaysubmit' name='alipaysubmit' action='" . self::GATEWAY_URL
  127. . "?charset=" . $this->charset . "' method='POST'>";
  128. foreach ($param as $key => $val) {
  129. if (false === $this->checkEmpty($val)) {
  130. $val = str_replace("'", "&apos;", $val);
  131. $html .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
  132. }
  133. }
  134. //submit按钮控件请不要含有name属性
  135. $html = $html . "<input type='submit' value='ok' style='display:none;'></form>";
  136. $html = $html . "<script>document.forms['alipaysubmit'].submit();</script>";
  137. return ['html_form' => $html];
  138. }
  139. /**
  140. * 查询订单
  141. * 文档:https://openclub.alipay.com/read.php?tid=5407&fid=72
  142. * 当面付:生成二维码使用支付宝钱包扫码唤起收银台后订单创建,支付宝未扫码前查询显示交易不存在 ACQ.TRADE_NOT_EXIST
  143. * 支付宝钱包支付(手机网站):用户点击支付,唤起支付宝收银台后,输入正确完整的支付密码后订单创建
  144. * 支付宝钱包支付(APP支付):用户点击支付,唤起支付宝收银台后,输入正确完整的支付密码后订单创建
  145. * @param $outTradeNo
  146. * @return mixed
  147. */
  148. public function queryOrder($outTradeNo)
  149. {
  150. //请求参数
  151. $requestConfig = array(
  152. 'out_trade_no' => $outTradeNo //订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 trade_no,out_trade_no 如果同时存在优先取trade_no
  153. );
  154. $result = json_decode($this->commonRequest($requestConfig, self::QUERY_RUL), true);
  155. return $result['alipay_trade_query_response'];
  156. }
  157. /**
  158. * 关闭订单
  159. * 文档:https://openclub.alipay.com/read.php?tid=5407&fid=72
  160. * 当面付:生成二维码使用支付宝钱包扫码唤起收银台后订单创建,支付宝未扫码前查询显示交易不存在 ACQ.TRADE_NOT_EXIST
  161. * 支付宝钱包支付(手机网站):用户点击支付,唤起支付宝收银台后,输入正确完整的支付密码后订单创建
  162. * 支付宝钱包支付(APP支付):用户点击支付,唤起支付宝收银台后,输入正确完整的支付密码后订单创建
  163. * @param $outTradeNo
  164. * @return mixed
  165. */
  166. public function closeOrder($outTradeNo)
  167. {
  168. //请求参数
  169. $requestConfig = array(
  170. 'out_trade_no' => $outTradeNo //订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 trade_no,out_trade_no 如果同时存在优先取trade_no
  171. );
  172. $result = json_decode($this->commonRequest($requestConfig, self::CLOSE_URL), true);
  173. return $result['alipay_trade_close_response'];
  174. }
  175. //异步通知 验签
  176. public function rsaCheck($param)
  177. {
  178. return parent::rsaCheck($param);
  179. }
  180. /**
  181. *程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。
  182. * 一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h)
  183. */
  184. public function replyNotify()
  185. {
  186. echo 'success';
  187. }
  188. }