WxPay.MicroPay.php 3.9 KB

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