WxPay.MicroPay.php 4.5 KB

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