WechatPay.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <?php
  2. namespace app\expand\controller;
  3. use app\common\service\HelperService;
  4. use app\common\service\wechat\JsApi_pub;
  5. use app\common\service\wechat\UnifiedOrder_pub;
  6. use app\common\service\wechat\Refund_pub;
  7. use think\Config;
  8. use think\Validate;
  9. use think\Log;
  10. /**
  11. * 微信支付接口
  12. * Class WeChat
  13. * @package app\expand\controller
  14. */
  15. class WechatPay extends BaseAuth
  16. {
  17. private $_Account = null;
  18. private $_APPID = null;
  19. private $_APPSECRET = null;
  20. public function __construct(){
  21. parent::__construct();
  22. $this->getFileContext();
  23. /**
  24. * 当且仅当微信异步回调地址发起请求的的时候,放他通过
  25. */
  26. if($this->_inWhiteList){
  27. return true;
  28. }
  29. $this->_Account = $this->getKey($this->_apiCode);
  30. //验证是否具有访问这个接口的权限
  31. if(!isset($this->_Account['Wechat_pay_appId'])
  32. || !isset($this->_Account['Wechat_pay_appsecret'])
  33. || !isset($this->_Account['Wechat_pay_key'])
  34. || !isset($this->_Account['Wechat_pay_mchId']) ){
  35. HelperService::returnJson(['code'=>400,'msg'=>'WECHAT pay interface unauthorized access','data'=>$this->_Account]);
  36. }
  37. $this->_APPID = $this->_Account['Wechat_pay_appId'];
  38. $this->_APPSECRET = $this->_Account['Wechat_pay_appsecret'];
  39. $WechatPayTip = isset($this->_Account['Wechat_pay_tip'])
  40. ?$this->_Account['Wechat_pay_tip']:"";
  41. $WechatPaySubMchId = isset($this->_Account['Wechat_pay_sub_mchId'])
  42. ?$this->_Account['Wechat_pay_sub_mchId']:"";
  43. Config::set('WECHAT_APPID',$this->_APPID);
  44. Config::set('WECHAT_APPSECRET',$this->_APPSECRET);
  45. Config::set('WECHAT_TIP',$WechatPayTip);
  46. Config::set('WECHAT_MCHID',$this->_Account['Wechat_pay_mchId']);
  47. Config::set('WECHAT_SUB_MCHID',$WechatPaySubMchId);
  48. Config::set('WECHAT_PAY_KEY',$this->_Account['Wechat_pay_key']);
  49. }
  50. /**
  51. * 平台版支付接口
  52. */
  53. public function platformWxPay(){
  54. $param = $this->_sysParams;
  55. $rule = [
  56. 'pay_notify_url|支付通知跳转'=>'max:1000',
  57. 'order_no|订单编号'=>'require',
  58. 'total_price|总金额'=>'require'
  59. ];
  60. // Log::record("platformWxPay:".$param);
  61. $validate = new Validate($rule);
  62. if(!$validate->check($param)){
  63. HelperService::returnJson(['code'=>400,'msg'=>$validate->getError(),'data'=>[]]);
  64. }
  65. session('pay_notify_url',$param['pay_notify_url']);
  66. session('order_no',$param['order_no']);
  67. session('total_price',$param['total_price']);
  68. require_once(APP_PATH.'/common/service/wechat/WxPayPubHelper.php');
  69. //使用jsapi接口
  70. $jsApi = new JsApi_pub();
  71. //通过code获得openid,通知的接口
  72. $httpFix = HelperService::getHttpHeader();
  73. $url = $jsApi->createOauthOpenidForCode("{$httpFix}{$_SERVER['HTTP_HOST']}/v1/getOpenId2Pay/apiCode/".$this->_apiCode, rand(1000,9999));
  74. HelperService::addLog([
  75. 'data'=>$param,
  76. 'url'=>$url,
  77. ]);
  78. header("Location: $url");
  79. exit;
  80. }
  81. /**
  82. * 支付获取openid之后跳转的地址
  83. */
  84. public function getOpenId2Pay(){
  85. //使用jsapi接口
  86. require_once(APP_PATH.'/common/service/wechat/WxPayPubHelper.php');
  87. $jsApi = new JsApi_pub();
  88. $code = $this->_sysParams['code'];
  89. $this->_apiCode = $this->_sysParams['apiCode'];
  90. $account = $this->getKey($this->_apiCode, false);
  91. Config::set('WECHAT_APPID',$account['Wechat_pay_appId']);
  92. Config::set('WECHAT_APPSECRET',$account['Wechat_pay_appsecret']);
  93. Config::set('WECHAT_MCHID',$account['Wechat_pay_mchId']);
  94. Config::set('WECHAT_PAY_KEY',$account['Wechat_pay_key']);
  95. $jsApi->setCode($code);
  96. $openInfo = $jsApi->getOpenidInfo();
  97. HelperService::addLog([
  98. 'openInfo'=>$openInfo,
  99. 'code'=>$code,
  100. ]);
  101. if(!isset($openInfo['openid'])){
  102. $notify_url = base64_decode(session('pay_notify_url'));
  103. header("HTTP/1.1 301 Moved Permanently");
  104. header("Location: $notify_url");
  105. exit;
  106. }
  107. $openid = $openInfo['openid'];
  108. $unifiedOrder = new UnifiedOrder_pub();
  109. $money = intval(session('total_price'));
  110. if($money<=0){
  111. header("HTTP/1.1 500 支付调用失败(支付金额为0)");
  112. exit;
  113. }
  114. //设置统一支付接口参数
  115. $unifiedOrder->setParameter("openid", "$openid"); //商品描述
  116. $unifiedOrder->setParameter("body",Config::get('WECHAT_TIP')."[".date('Y-m-d H:i:s')."]"); //商品描述
  117. //自定义订单号,此处仅作举例
  118. $out_trade_no = $this->_apiCode."_".session('order_no');
  119. $unifiedOrder->setParameter("out_trade_no", $out_trade_no); //商户订单号
  120. $unifiedOrder->setParameter("total_fee", $money); //总金额
  121. $httpFix = HelperService::getHttpHeader();
  122. $unifiedOrder->setParameter("notify_url", "{$httpFix}{$_SERVER['HTTP_HOST']}/v1/platformNotifyUrl.html"); //通知地址
  123. $unifiedOrder->setParameter("trade_type", "JSAPI"); //交易类型
  124. $prepay_id = $unifiedOrder->getPrepayId($out_trade_no."_".time());
  125. $jsApi->setPrepayId($prepay_id);
  126. $jsApiParameters = $jsApi->getParameters();
  127. $notify_url = session('pay_notify_url')?base64_decode(session('pay_notify_url')):"/v1/paySuccess";
  128. HelperService::addLog([
  129. 'data'=>$prepay_id,
  130. 'url'=>$notify_url,
  131. ]);
  132. require_once(APP_PATH.'/expand/view/wechat/wxPlatformPay.php');
  133. }
  134. public function paySuccess(){
  135. return $this->fetch('wechat/paySuccess');
  136. }
  137. /**
  138. * 支付异步通知接口
  139. */
  140. public function platformNotifyUrl(){
  141. $this->getInput();
  142. $param = $this->_oldParams;
  143. $params = HelperService::object2Arr(simplexml_load_string($param, 'SimpleXMLElement', LIBXML_NOCDATA));
  144. if(empty($params)){
  145. HelperService::returnJson(['code' => 400, 'msg' => "参数错误"]);
  146. }
  147. try {
  148. $arr = ['total_fee', 'out_trade_no'];
  149. foreach ($arr as $key=>$value) {
  150. if (!isset($params[$value])) {
  151. HelperService::returnJson(['code' => 400, 'msg' => "参数错误({$key})",'params'=>$params]);
  152. }
  153. }
  154. $tradeNoArr = explode('_', $params['out_trade_no']);
  155. if(count($tradeNoArr)<2){
  156. HelperService::returnJson(['code' => 400, 'msg' => "参数错误(trade)"],$param);
  157. }
  158. $companyCode = $tradeNoArr[0];
  159. $this->_Account = $this->getKey($companyCode,false);
  160. $orderNo = isset($tradeNoArr[1]) ? $tradeNoArr[1] : 0;
  161. //开发分发给不同的支付主体
  162. if(!isset($this->_Account['Wechat_pay_notify_url'])
  163. || empty($this->_Account['Wechat_pay_notify_url'])){
  164. HelperService::returnJson(['code' => 400, 'msg' => "回调地址不存在"],$param);
  165. }
  166. if(!is_array($this->_Account['Wechat_pay_notify_url'])){
  167. HelperService::returnJson(['code' => 400, 'msg' => "回调地址不是数组"],$param);
  168. }
  169. $notifyUrlArr = $this->_Account['Wechat_pay_notify_url'];
  170. foreach($notifyUrlArr as $url){
  171. $is_ssl = strpos($url, 'https://')!==false?true:false;
  172. $data = [
  173. 'order_no'=>$orderNo,
  174. 'total_price'=>"{$params['total_fee']}",
  175. 'out_trade_no'=>"{$params['out_trade_no']}"
  176. ];
  177. $times = 3;
  178. while($times--){
  179. $res = HelperService::httpPost($url,json_encode($data),$is_ssl);
  180. HelperService::addLog(['item'=>$url,'data'=>$data,'result'=>$res]);
  181. if($res != false){
  182. break;
  183. }
  184. }
  185. if($times ==0){
  186. Log::record("支付推送异常=>url:".$url."=>res:". json_encode($res)."=>data:". json_encode($data));
  187. }
  188. }
  189. HelperService::addLog(['ret'=>'success']);
  190. die('success');
  191. }catch (\Exception $ex){
  192. HelperService::addLog(['msg'=>$ex->getMessage(),"file"=>$ex->getFile(),"line"=>$ex->getLine()]);
  193. die('fail');
  194. }
  195. }
  196. /**
  197. * 平台版退款接口
  198. */
  199. public function platformRefund(){
  200. $params = $this->_params;
  201. $rule = [
  202. 'out_trade_no'=>'require',
  203. 'total_fee'=>'require',
  204. 'refund_fee'=>'require',
  205. 'op_user_id'=>'require'
  206. ];
  207. $validate = new Validate($rule);
  208. if(!$validate->check($params)){
  209. HelperService::returnJson(['code'=>400,'msg'=>$validate->getError()],$params);
  210. }
  211. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  212. $Refund = new Refund_pub();
  213. $Refund->setParameter('out_trade_no',$params['out_trade_no']);
  214. $Refund->setParameter('out_refund_no',uniqid());
  215. $Refund->setParameter('total_fee',$params['total_fee']);
  216. $Refund->setParameter('refund_fee',$params['refund_fee']);
  217. $Refund->setParameter('op_user_id',$params['op_user_id']);
  218. $data = $Refund->getResult();
  219. $msg = isset($data['result_code'])?$data['result_code']:'fail';
  220. HelperService::returnJson(['code'=>200,'msg'=>"{$msg}",'data'=>$data]);
  221. }
  222. }