审查视图

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

		//③、确认支付是否成功
		$queryTimes = 10;
		while($queryTimes > 0)
		{
			$succResult = 0;
			$queryResult = $this->query($out_trade_no, $succResult);
			//如果需要等待1s后继续
			if($succResult == 2){
				sleep(2);
				continue;
			} else if($succResult == 1){//查询成功
				return $queryResult;
			} else {//订单交易失败
				break;
			}
		}
		
		//④、次确认失败,则撤销订单
		if(!$this->cancel($out_trade_no))
		{
			throw new WxpayException("撤销单失败!");
		}

		return false;
	}
	
	/**
	 * 
	 * 查询订单情况
	 * @param string $out_trade_no  商户订单号
	 * @param int $succCode         查询订单结果
	 * @return 0 订单不成功,1表示订单成功,2表示继续等待
	 */
	public function query($out_trade_no, &$succCode)
	{
		$queryOrderInput = new WxPayOrderQuery();
		$queryOrderInput->SetOut_trade_no($out_trade_no);
		$config = new WxPayConfig();
		try{
			$result = WxPayApi::orderQuery($config, $queryOrderInput);
		} catch(Exception $e) {
			Log::ERROR(json_encode($e));
		}
		if($result["return_code"] == "SUCCESS" 
			&& $result["result_code"] == "SUCCESS")
		{
			//支付成功
			if($result["trade_state"] == "SUCCESS"){
				$succCode = 1;
			   	return $result;
			}
			//用户支付中
			else if($result["trade_state"] == "USERPAYING"){
				$succCode = 2;
				return false;
			}
		}
		
		//如果返回错误码为“此交易订单号不存在”则直接认定失败
		if($result["err_code"] == "ORDERNOTEXIST")
		{
			$succCode = 0;
		} else{
			//如果是系统错误,则后续继续
			$succCode = 2;
		}
		return false;
	}
	
	/**
	 * 
	 * 撤销订单,如果失败会重复调用10次
	 * @param string $out_trade_no
	 * @param 调用深度 $depth
	 */
	public function cancel($out_trade_no, $depth = 0)
	{
		try {
			if($depth > 10){
				return false;
			}
			
			$clostOrder = new WxPayReverse();
			$clostOrder->SetOut_trade_no($out_trade_no);

			$config = new WxPayConfig();
			$result = WxPayApi::reverse($config, $clostOrder);

			
			//接口调用失败
			if($result["return_code"] != "SUCCESS"){
				return false;
			}
			
			//如果结果为success且不需要重新调用撤销,则表示撤销成功
			if($result["result_code"] != "SUCCESS" 
				&& $result["recall"] == "N"){
				return true;
			} else if($result["recall"] == "Y") {
				return $this->cancel($out_trade_no, ++$depth);
			}
		} catch(Exception $e) {
			Log::ERROR(json_encode($e));
		}
		return false;
	}
}