WxPay.MicroPay.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. require_once "../lib/WxPay.Api.php";
  3. /**
  4. *
  5. * 刷卡支付实现类
  6. * 该类实现了一个刷卡支付的流程,流程如下:
  7. * 1、提交刷卡支付
  8. * 2、根据返回结果决定是否需要查询订单,如果查询之后订单还未变则需要返回查询(一般反复查10次)
  9. * 3、如果反复查询10订单依然不变,则发起撤销订单
  10. * 4、撤销订单需要循环撤销,一直撤销成功为止(注意循环次数,建议10次)
  11. *
  12. * 该类是微信支付提供的样例程序,商户可根据自己的需求修改,或者使用lib中的api自行开发,为了防止
  13. * 查询时hold住后台php进程,商户查询和撤销逻辑可在前端调用
  14. *
  15. * @author widy
  16. *
  17. */
  18. class MicroPay
  19. {
  20. /**
  21. *
  22. * 提交刷卡支付,并且确认结果,接口比较慢
  23. * @param WxPayMicroPay $microPayInput
  24. * @throws WxpayException
  25. * @return 返回查询接口的结果
  26. */
  27. public function pay($microPayInput)
  28. {
  29. //①、提交被扫支付
  30. $result = WxPayApi::micropay($microPayInput, 5);
  31. //如果返回成功
  32. if(!array_key_exists("return_code", $result)
  33. || !array_key_exists("out_trade_no", $result)
  34. || !array_key_exists("result_code", $result))
  35. {
  36. echo "接口调用失败,请确认是否输入是否有误!";
  37. throw new WxPayException("接口调用失败!");
  38. }
  39. //签名验证
  40. $out_trade_no = $microPayInput->GetOut_trade_no();
  41. //②、接口调用成功,明确返回调用失败
  42. if($result["return_code"] == "SUCCESS" &&
  43. $result["result_code"] == "FAIL" &&
  44. $result["err_code"] != "USERPAYING" &&
  45. $result["err_code"] != "SYSTEMERROR")
  46. {
  47. return false;
  48. }
  49. //③、确认支付是否成功
  50. $queryTimes = 10;
  51. while($queryTimes > 0)
  52. {
  53. $succResult = 0;
  54. $queryResult = $this->query($out_trade_no, $succResult);
  55. //如果需要等待1s后继续
  56. if($succResult == 2){
  57. sleep(2);
  58. continue;
  59. } else if($succResult == 1){//查询成功
  60. return $queryResult;
  61. } else {//订单交易失败
  62. return false;
  63. }
  64. }
  65. //④、次确认失败,则撤销订单
  66. if(!$this->cancel($out_trade_no))
  67. {
  68. throw new WxpayException("撤销单失败!");
  69. }
  70. return false;
  71. }
  72. /**
  73. *
  74. * 查询订单情况
  75. * @param string $out_trade_no 商户订单号
  76. * @param int $succCode 查询订单结果
  77. * @return 0 订单不成功,1表示订单成功,2表示继续等待
  78. */
  79. public function query($out_trade_no, &$succCode)
  80. {
  81. $queryOrderInput = new WxPayOrderQuery();
  82. $queryOrderInput->SetOut_trade_no($out_trade_no);
  83. $result = WxPayApi::orderQuery($queryOrderInput);
  84. if($result["return_code"] == "SUCCESS"
  85. && $result["result_code"] == "SUCCESS")
  86. {
  87. //支付成功
  88. if($result["trade_state"] == "SUCCESS"){
  89. $succCode = 1;
  90. return $result;
  91. }
  92. //用户支付中
  93. else if($result["trade_state"] == "USERPAYING"){
  94. $succCode = 2;
  95. return false;
  96. }
  97. }
  98. //如果返回错误码为“此交易订单号不存在”则直接认定失败
  99. if($result["err_code"] == "ORDERNOTEXIST")
  100. {
  101. $succCode = 0;
  102. } else{
  103. //如果是系统错误,则后续继续
  104. $succCode = 2;
  105. }
  106. return false;
  107. }
  108. /**
  109. *
  110. * 撤销订单,如果失败会重复调用10次
  111. * @param string $out_trade_no
  112. * @param 调用深度 $depth
  113. */
  114. public function cancel($out_trade_no, $depth = 0)
  115. {
  116. if($depth > 10){
  117. return false;
  118. }
  119. $clostOrder = new WxPayReverse();
  120. $clostOrder->SetOut_trade_no($out_trade_no);
  121. $result = WxPayApi::reverse($clostOrder);
  122. //接口调用失败
  123. if($result["return_code"] != "SUCCESS"){
  124. return false;
  125. }
  126. //如果结果为success且不需要重新调用撤销,则表示撤销成功
  127. if($result["result_code"] != "SUCCESS"
  128. && $result["recall"] == "N"){
  129. return true;
  130. } else if($result["recall"] == "Y") {
  131. return $this->cancel($out_trade_no, ++$depth);
  132. }
  133. return false;
  134. }
  135. }