WechatController.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * Author: 芸众商城 www.yunzshop.com
  5. * Date: 2017/3/28
  6. * Time: 上午6:50
  7. */
  8. namespace app\payment\controllers;
  9. use app\common\facades\EasyWeChat;
  10. use app\common\helpers\Url;
  11. use app\common\models\AccountWechats;
  12. use app\common\models\Order;
  13. use app\common\models\OrderPay;
  14. use app\common\models\PayOrder;
  15. use app\common\modules\wechat\models\WechatPayOrder;
  16. use app\common\services\Pay;
  17. use app\common\services\PayFactory;
  18. use app\payment\PaymentController;
  19. use Yunshop\AuthPayment\services\ManageService;
  20. class WechatController extends PaymentController
  21. {
  22. private $pay_type = ['JSAPI' => '微信', 'APP' => '微信APP'];
  23. private $attach = [];
  24. public function preAction()
  25. {
  26. parent::preAction();
  27. if (empty(\YunShop::app()->uniacid)) {
  28. $post = $this->getResponseResult();
  29. if (\YunShop::request()->attach) {
  30. \Setting::$uniqueAccountId = \YunShop::app()->uniacid = \YunShop::request()->attach;
  31. } else {
  32. $this->attach = explode(':', $post['attach']);
  33. \Setting::$uniqueAccountId = \YunShop::app()->uniacid = $this->attach[0];
  34. }
  35. \Log::debug('---------attach数组--------', \YunShop::app()->uniacid);
  36. AccountWechats::setConfig(AccountWechats::getAccountByUniacid(\YunShop::app()->uniacid));
  37. }
  38. }
  39. public function notifyUrl()
  40. {
  41. $post = $this->getResponseResult();
  42. $this->log($post);
  43. $verify_result = $this->getSignResult($post);
  44. if ($verify_result) {
  45. //区分公众号、小程序、app支付
  46. if ($post['trade_type'] == 'JSAPI') {
  47. $pay_type_id = (isset($this->attach[1]) && $this->attach[1] == 'wechat') ? PayFactory::WECHAT_MIN_PAY : PayFactory::PAY_WEACHAT;
  48. } else {
  49. if (isset($this->attach[2]) && $this->attach[2] == PayFactory::WECHAT_CPS_APP_PAY){
  50. $pay_type_id = PayFactory::WECHAT_CPS_APP_PAY;
  51. }else{
  52. $pay_type_id = PayFactory::PAY_APP_WEACHAT;
  53. }
  54. }
  55. $data = [
  56. 'total_fee' => $post['total_fee'] ,
  57. 'out_trade_no' => $post['out_trade_no'],
  58. 'trade_no' => $post['transaction_id'],
  59. 'unit' => 'fen',
  60. 'pay_type' => $this->pay_type[$post['trade_type']],
  61. 'pay_type_id' => $pay_type_id,
  62. ];
  63. $this->payResutl($data);
  64. echo "success";
  65. } else {
  66. echo "fail";
  67. }
  68. }
  69. public function jsapiNotifyUrl()
  70. {
  71. $post = $this->getResponseResult();
  72. $this->log($post);
  73. //todo 做签名验证
  74. $verify_result = true;
  75. if ($verify_result) {
  76. $data = [
  77. 'total_fee' => $post['total_fee'] ,
  78. 'out_trade_no' => $post['out_trade_no'],
  79. 'trade_no' => $post['transaction_id'],
  80. 'unit' => 'fen',
  81. 'pay_type' => $this->pay_type[$post['trade_type']],
  82. 'pay_type_id' => PayFactory::WECHAT_JSAPI_PAY
  83. ];
  84. $attach = explode(':', $post['attach']);
  85. $WechatPayOrder = [
  86. 'uniacid' => \Yunshop::app()->uniacid,
  87. 'account_id' => $attach[3],
  88. 'pay_sn' => $post['out_trade_no'],
  89. 'transaction_id' => $post['transaction_id'],
  90. 'total_fee' => $post['total_fee'],
  91. 'profit_sharing' => $attach[2] == 'Y' ? 1:0,
  92. ];
  93. $orderPay = OrderPay::where('pay_sn', $data['out_trade_no'])->orderBy('id', 'desc')->first();
  94. if ($orderPay && !$orderPay->orders->isEmpty()) {
  95. $order = $orderPay->orders->first();
  96. $WechatPayOrder['order_id'] = $order->id;
  97. $WechatPayOrder['member_id'] = $order->uid;
  98. } else {
  99. $payOrder = PayOrder::where('out_order_no', $data['out_trade_no'])->first();
  100. $WechatPayOrder['order_id'] = 0;
  101. $WechatPayOrder['member_id'] = $payOrder->member_id;
  102. }
  103. WechatPayOrder::create($WechatPayOrder);
  104. $this->payResutl($data);
  105. echo "success";
  106. } else {
  107. echo "fail";
  108. }
  109. }
  110. /**
  111. * @param $post
  112. * @return mixed
  113. */
  114. public function verifyH5Sign($post)
  115. {
  116. $pay = \Setting::get('shop.pay');
  117. /** @var $app Application */
  118. $payment = $this->getEasyWeChatApp($pay);
  119. try {
  120. $message = (new \EasyWeChat\Payment\Notify\Paid($payment))->getMessage();
  121. return $message;
  122. } catch (\Exception $exception) {
  123. \Log::debug('微信签名验证:'.$exception->getMessage());
  124. return false;
  125. }
  126. }
  127. //微信h5支付
  128. public function notifyH5()
  129. {
  130. $post = $this->getResponseResult();
  131. $this->log($post);
  132. $verify_result = $this->verifyH5Sign($post);
  133. \Log::debug('微信H5支付回调验证结果', $verify_result);
  134. if ($verify_result) {
  135. $data = [
  136. 'total_fee' => $post['total_fee'] ,
  137. 'out_trade_no' => $post['out_trade_no'],
  138. 'trade_no' => $post['transaction_id'],
  139. 'unit' => 'fen',
  140. 'pay_type' => '微信H5',
  141. 'pay_type_id' => PayFactory::WECHAT_H5,
  142. ];
  143. $this->payResutl($data);
  144. echo "success";
  145. } else {
  146. echo "fail";
  147. }
  148. }
  149. //微信NATIVE支付
  150. public function notifyPc()
  151. {
  152. $post = $this->getResponseResult();
  153. $this->log($post);
  154. $verify_result = $this->verifyH5Sign($post);
  155. \Log::debug('微信扫码支付回调验证结果', $verify_result);
  156. if ($verify_result) {
  157. $data = [
  158. 'total_fee' => $post['total_fee'] ,
  159. 'out_trade_no' => $post['out_trade_no'],
  160. 'trade_no' => $post['transaction_id'],
  161. 'unit' => 'fen',
  162. 'pay_type' => '微信扫码支付',
  163. 'pay_type_id' => PayFactory::WECHAT_NATIVE,
  164. ];
  165. $this->payResutl($data);
  166. echo "success";
  167. } else {
  168. echo "fail";
  169. }
  170. }
  171. public function returnUrl()
  172. {
  173. if (\YunShop::request()->outtradeno) {
  174. $orderPay = OrderPay::where('pay_sn', \YunShop::request()->outtradeno)->first();
  175. if (is_null($orderPay)) {
  176. redirect(Url::absoluteApp('home'))->send();
  177. }
  178. //商品免单抽奖
  179. if (app('plugins')->isEnabled('free-lottery')) {
  180. $lotteryOrderCount = \Yunshop\FreeLottery\services\LotteryDrawService::isLotteryOrder($orderPay->order_ids);
  181. if ($lotteryOrderCount > 0) {
  182. $redirect = yzAppFullUrl('FreeLottery',['i' => \YunShop::app()->uniacid,'order_ids'=>implode(",",$orderPay->order_ids)]);
  183. redirect($redirect)->send();
  184. }
  185. }
  186. //优惠卷分享页
  187. $share_bool = \app\frontend\modules\coupon\services\ShareCouponService::showIndex($orderPay->order_ids, $orderPay->uid);
  188. if ($share_bool) {
  189. $ids = rtrim(implode('_', $orderPay->order_ids), '_');
  190. redirect(Url::absoluteApp('coupon/share/'.$ids, ['i' => \YunShop::app()->uniacid, 'mid'=> $orderPay->uid]))->send();
  191. }
  192. //预约商品订单支付成功后跳转预约插件设置的页面
  193. if (app('plugins')->isEnabled('appointment')) {
  194. \Log::debug('pay appointment order outtradeno:'.\YunShop::request()->outtradeno);
  195. $orders = Order::whereIn('id', $orderPay->order_ids)->get();
  196. // 只有一个订单
  197. \Log::debug('pay appointment order $orders:', $orders);
  198. if ($orders->count() == 1) {
  199. $order = $orders[0];
  200. // 是预约商品的订单
  201. if ($order->plugin_id == 101) {
  202. \Log::debug('pay appointment order $order->plugin_id:', $order->plugin_id);
  203. $appointment_redirect = \Yunshop\Appointment\common\service\SetService::getPayReturnUrl();
  204. \Log::debug('pay appointment order $appointment_redirect:', $appointment_redirect);
  205. if ($appointment_redirect) {
  206. redirect($appointment_redirect)->send();
  207. }
  208. }
  209. }
  210. }
  211. }
  212. $trade = \Setting::get('shop.trade');
  213. if (!is_null($trade) && isset($trade['redirect_url']) && !empty($trade['redirect_url'])) {
  214. $redirect = $trade['redirect_url'];
  215. preg_match("/^(http:\/\/)?([^\/]+)/i", $trade['redirect_url'], $matches);
  216. $host = $matches[2];
  217. // 从主机名中取得后面两段
  218. preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
  219. if ($matches){//判断域名是否一致
  220. $redirect = $trade['redirect_url'].'&outtradeno='.\YunShop::request()->outtradeno;
  221. }
  222. redirect($redirect)->send();
  223. }
  224. redirect(Url::absoluteApp('home'))->send();
  225. }
  226. /**
  227. * 签名验证
  228. *
  229. * @return bool
  230. */
  231. public function getSignResult($post)
  232. {
  233. switch ($post['trade_type']) {
  234. case 'JSAPI':
  235. $pay = \Setting::get('shop.pay');
  236. if (isset($this->attach[1]) && $this->attach[1] == 'wechat') {
  237. $min_set = \Setting::get('plugin.min_app');
  238. $pay = [
  239. 'weixin_appid' => $min_set['key'],
  240. 'weixin_secret' => $min_set['secret'],
  241. 'weixin_mchid' => $min_set['mchid'],
  242. 'weixin_apisecret' => $min_set['api_secret'],
  243. 'weixin_cert' => '',
  244. 'weixin_key' => ''
  245. ];
  246. }
  247. break;
  248. case 'APP' :
  249. if (isset($this->attach[2]) && $this->attach[2] == PayFactory::WECHAT_CPS_APP_PAY){
  250. $pay = \Setting::get('plugin.aggregation-cps.pay_info');
  251. }else{
  252. $pay = \Setting::get('shop_app.pay');
  253. }
  254. break;
  255. }
  256. $payment = $this->getEasyWeChatApp($pay);
  257. try {
  258. $message = (new \EasyWeChat\Payment\Notify\Paid($payment))->getMessage();
  259. return $message;
  260. } catch (\Exception $exception) {
  261. \Log::debug('微信签名验证:'.$exception->getMessage());
  262. return false;
  263. }
  264. }
  265. /**
  266. * 创建支付对象
  267. *
  268. * @param $pay
  269. * @return \EasyWeChat\Payment\Payment
  270. */
  271. public function getEasyWeChatApp($pay)
  272. {
  273. $options = [
  274. 'app_id' => $pay['weixin_appid'],
  275. 'secret' => $pay['weixin_secret'],
  276. 'mch_id' => $pay['weixin_mchid'],
  277. 'key' => $pay['weixin_apisecret'],
  278. 'cert_path' => $pay['weixin_cert'],
  279. 'key_path' => $pay['weixin_key']
  280. ];
  281. $app = EasyWeChat::payment($options);
  282. return $app;
  283. }
  284. /**
  285. * 获取回调结果
  286. *
  287. * @return array|mixed|\stdClass
  288. */
  289. public function getResponseResult()
  290. {
  291. $input = file_get_contents('php://input');
  292. if (!empty($input) && empty($_POST['out_trade_no'])) {
  293. //禁止引用外部xml实体
  294. $disableEntities = libxml_disable_entity_loader(true);
  295. $data = json_decode(json_encode(simplexml_load_string($input, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  296. libxml_disable_entity_loader($disableEntities);
  297. if (empty($data)) {
  298. exit('fail');
  299. }
  300. if ($data['result_code'] != 'SUCCESS' || $data['return_code'] != 'SUCCESS') {
  301. exit('fail');
  302. }
  303. $post = $data;
  304. } else {
  305. $post = $_POST;
  306. }
  307. return $post;
  308. }
  309. /**
  310. * 支付日志
  311. *
  312. * @param $post
  313. */
  314. public function log($post)
  315. {
  316. //访问记录
  317. Pay::payAccessLog();
  318. //保存响应数据
  319. Pay::payResponseDataLog($post['out_trade_no'], '微信支付', json_encode($post));
  320. }
  321. public function notifyAuth()
  322. {
  323. $post = $this->getResponseResult();
  324. $verify_result = $this->verifyH5Sign($post);
  325. \Log::debug('微信H5支付回调验证结果', $verify_result);
  326. if ($verify_result) {
  327. $subOrder = \Yunshop\AuthPayment\models\SubOrder::where('sub_pay_sn', $post['out_trade_no'])->first();
  328. if ($subOrder) {
  329. $subOrder->update(['status' => 1]);
  330. $json = [
  331. "data" => [
  332. "pay_sn" => $subOrder->sub_pay_sn,
  333. "uniacid" => $subOrder->belongsToManage->sub_uniacid,
  334. "amount" => $subOrder->amount
  335. ],
  336. "appid" => $subOrder->belongsToManage->appid,
  337. ];
  338. $manageService = new ManageService;
  339. $json['sign'] = $manageService->sign($json, $subOrder->belongsToManage->secret);
  340. // 每三秒循环5次发送通知给子平台 发送通知给子平台 $subOrder->belongsToManage
  341. $count = 3;
  342. for ($x = 0; $x < $count; $x++) {
  343. $result = $subOrder->sendNotify(json_encode($json));
  344. if ($result['result'] == 1) {
  345. break;
  346. }
  347. sleep(3);
  348. }
  349. }
  350. echo "success";
  351. } else {
  352. echo "fail";
  353. }
  354. }
  355. }