Weixin.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <?php
  2. namespace app\api\controller\v1;
  3. use app\BaseController;
  4. use app\model\api\Member;
  5. use app\model\api\Order;
  6. use app\model\api\OrderInfo;
  7. use app\model\api\Product;
  8. use app\model\api\Recharge;
  9. use app\Request;
  10. use EasyWeChat\Factory;
  11. use library\lib\weixina;
  12. use library\services\UtilService;
  13. use library\services\MiniProgramService;
  14. use think\db\exception\DbException;
  15. use think\db\exception\PDOException;
  16. use think\Exception;
  17. use think\facade\Db;
  18. class Weixin extends BaseController
  19. {
  20. public function jssdk(Request $request){
  21. $config = [
  22. 'app_id' => config('weixin')['APPID'],
  23. 'secret' => config('weixin')['APPSECRET'],
  24. // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
  25. 'response_type' => 'array'
  26. ];
  27. $app = Factory::officialAccount($config);
  28. $apiList = ['openAddress','updateAppMessageShareData','updateTimelineShareData','onMenuShareAppMessage','onMenuShareTimeline'];
  29. $jssdk = $app->jssdk->buildConfig($apiList, $debug = false, $beta = false, $json = false, [], $url = $request->get('url'));
  30. return app('json')->success($jssdk);
  31. }
  32. /**
  33. * 公众号获取微信信息
  34. */
  35. public function getInfo(Request $request)
  36. {
  37. $code = trim($request->get('code'));
  38. $weixinA = new weixina;
  39. $token = $weixinA->oauth_reuslt($code);
  40. if (!empty($token['access_token'])) {
  41. $userInfo = $weixinA->userinfo($token['access_token']);
  42. $member = (new Member)->where('uid',$request->user['uid'])->find();
  43. if($member['routine_openid']){
  44. (new Member)->where('uid',$request->user['uid'])->save(['openid' => $userInfo['openid']]);
  45. }else{
  46. $data['openid'] = $userInfo['openid'];
  47. $data['nickname'] = $userInfo['nickname'];
  48. $data['sex'] = $userInfo['sex'];
  49. $data['language'] = $userInfo['language'];
  50. $data['city'] = $userInfo['city'];
  51. $data['province'] = $userInfo['province'];
  52. $data['country'] = $userInfo['country'];
  53. $data['avatar'] = $userInfo['headimgurl'];
  54. (new Member)->where('uid',$request->user['uid'])->save($data);
  55. }
  56. return app('json')->success([
  57. 'nickname' => $data['nickname'],
  58. 'avatar' => $data['avatar']
  59. ]);
  60. }
  61. }
  62. /**
  63. * 小程序获取手机号
  64. */
  65. public function getPhone(Request $request)
  66. {
  67. $post = UtilService::getMore([
  68. ['code', '', 'empty', '参数错误'],
  69. ['iv', ''],
  70. ['encryptedData', '']
  71. ]);
  72. $mini = Factory::miniProgram(config('weixin')['mini_program']);
  73. $new_mini = $mini->auth->session($post['code']);
  74. $decryptData = $mini->encryptor->decryptData($new_mini['session_key'], $post['iv'], $post['encryptedData']);
  75. return app('json')->success($decryptData['phoneNumber']);
  76. }
  77. /**
  78. * 小程序授权登录
  79. * @param Request $request
  80. * @return mixed
  81. * @throws \Psr\SimpleCache\InvalidArgumentException
  82. * @throws \think\db\exception\DataNotFoundException
  83. * @throws \think\db\exception\ModelNotFoundException
  84. * @throws \think\exception\DbException
  85. */
  86. public function mp_auth(Request $request){
  87. $post = UtilService::getMore([
  88. ['code', '', 'empty', '参数错误'],
  89. ['iv', ''],
  90. ['encryptedData', '']
  91. ]);
  92. try {
  93. $mini = Factory::miniProgram(config('weixin')['mini_program']);
  94. $new_mini = $mini->auth->session($post['code']);
  95. $member = (new Member)->where('uid',$request->user['uid'])->find();
  96. if($member['openid']){
  97. (new Member)->where('uid',$request->user['uid'])->save(['routine_openid' => $new_mini['openid']]);
  98. }else{
  99. $userInfo = $mini->encryptor->decryptData($new_mini['session_key'], $post['iv'], $post['encryptedData']);
  100. $data['routine_openid'] = $new_mini['openid'];
  101. $data['nickname'] = $userInfo['nickName'];
  102. $data['sex'] = $userInfo['gender'];
  103. $data['language'] = $userInfo['language'];
  104. $data['city'] = $userInfo['city'];
  105. $data['province'] = $userInfo['province'];
  106. $data['country'] = $userInfo['country'];
  107. $data['avatar'] = $userInfo['avatarUrl'];
  108. (new Member)->where('uid',$request->user['uid'])->save($data);
  109. return app('json')->success([
  110. 'nickname' => $data['nickname'],
  111. 'avatar' => $data['avatar']
  112. ]);
  113. }
  114. } catch (\Exception $e) {
  115. return app('json')->fail('获取session_key失败', ['line' => $e->getLine(), 'message' => $e->getMessage()]);
  116. }
  117. }
  118. /**
  119. * @param Request $request
  120. */
  121. public function result(Request $request)
  122. {
  123. $state = trim($request->get('state'));
  124. $code = trim($request->get('code'));
  125. if (empty($state)) {
  126. exit('error');
  127. }
  128. $weixinA = new weixina;
  129. $data = $weixinA->oauth_reuslt($code);
  130. if (!empty($data['access_token'])) {
  131. $userInfo = $weixinA->userinfo($data['access_token']);
  132. $userInfo['access_token'] = $data['access_token'];
  133. $userInfo['expires_in'] = $data['expires_in'];
  134. $userInfo['time'] = time();
  135. cookie("weix_userinfo", serialize($userInfo));
  136. $url = setParam(cookie('w_url'), ['data' => json_encode($userInfo, \JSON_UNESCAPED_UNICODE)]);
  137. redirect($url)->send();
  138. } else {
  139. exit('微信授权登录失败,关闭页面重新,重新扫描!');
  140. }
  141. }
  142. public function pay(Request $request)
  143. {
  144. [$orderId, $from] = UtilService::getMore([
  145. ['order_id', '', 'empty', '参数错误'],
  146. ['from', '', 'empty', '参数错误'],
  147. ], $request, true);
  148. $order = Order::where('order_id', $orderId)->find();
  149. if (empty($order)) {
  150. return app('json')->fail('找不到订单信息');
  151. }
  152. //订单已付款
  153. if (!empty($order['is_pay'])) {
  154. return app('json')->fail('订单已经支付成功');
  155. }
  156. $data['out_trade_no'] = $order['order_id'];
  157. $data['money'] = $order['all_price'];
  158. $data['type'] = 'order';
  159. $data['time'] = time();
  160. Db::name('wx_notify')->insert($data);
  161. if ($from == 'weixin') {
  162. $app = Factory::payment(config('weixin')['wxPay']);
  163. $result = $app->order->unify([
  164. 'body' => '支付订单',
  165. 'out_trade_no' => $order['order_id'],
  166. 'total_fee' => $order['all_price'] * 100,
  167. 'notify_url' => 'https://www.boofly.cn/api/weixin/notify', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  168. 'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
  169. 'openid' => $request->user['openid']
  170. ]);
  171. $jssdk = $app->jssdk;
  172. $jsConfig = $jssdk->bridgeConfig($result['prepay_id'], false);
  173. $json['result'] = $jsConfig;
  174. $json['type'] = 'WECHAT_PAY';
  175. }
  176. if ($from == 'h5') {
  177. $app = Factory::payment(config('weixin')['wxPay']);
  178. $result = $app->order->unify([
  179. 'body' => '支付订单',
  180. 'out_trade_no' => $order['order_id'],
  181. 'total_fee' => $order['all_price'] * 100,
  182. 'notify_url' => 'https://www.boofly.cn/api/weixin/notify', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  183. 'trade_type' => 'MWEB' // 请对应换成你的支付方式对应的值类型
  184. ]);
  185. $jssdk = $app->jssdk;
  186. $jsConfig = $jssdk->bridgeConfig($result['prepay_id'], false);
  187. $json['result'] = $jsConfig;
  188. $json['type'] = 'WECHAT_H5_PAY';
  189. }
  190. if ($from == 'routine') {
  191. $app = Factory::payment(config('weixin')['routinePay']);
  192. $result = $app->order->unify([
  193. 'body' => '支付订单',
  194. 'out_trade_no' => $order['order_id'],
  195. 'total_fee' => $order['all_price'] * 100,
  196. 'notify_url' => 'https://www.boofly.cn/api/weixin/notify', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  197. 'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
  198. 'openid' => $request->user['routine_openid']
  199. ]);
  200. $jssdk = $app->jssdk;
  201. $jsConfig = $jssdk->bridgeConfig($result['prepay_id'], false);
  202. $json['result'] = $jsConfig;
  203. $json['type'] = 'ROUTINE_PAY';
  204. }
  205. return app('json')->success($json);
  206. }
  207. public function recharge(Request $request)
  208. {
  209. [$money, $from] = UtilService::getMore([
  210. ['money', '', 'empty', '请选择充值金额'],
  211. ['from', '', 'empty', '参数错误']
  212. ], $request, true);
  213. try {
  214. Recharge::beginTrans();
  215. $recharge = new Recharge();
  216. $d = [];
  217. $d['order_id'] = 'RE' . time() . sprintf('%04d', rand(0, 1000)) . $request->user['uid'];
  218. $d['v'] = $money;
  219. $d['time'] = time();
  220. $d['uid'] = $request->user['uid'];
  221. $recharge->insert($d);
  222. //生成支付凭证
  223. $data['out_trade_no'] = $d['order_id'];
  224. $data['money'] = $money;
  225. $data['type'] = 'recharge';
  226. $data['time'] = time();
  227. Db::name('wx_notify')->insert($data);
  228. Recharge::commitTrans();
  229. $app = Factory::payment(config('weixin')['wxPay']);
  230. if ($from == 'weixin') {
  231. $result = $app->order->unify([
  232. 'body' => '充值余额',
  233. 'out_trade_no' => $d['order_id'],
  234. 'total_fee' => $money * 100,
  235. 'notify_url' => 'https://www.boofly.cn/api/weixin/notify', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  236. 'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
  237. 'openid' => $request->user['openid'],
  238. ]);
  239. $jssdk = $app->jssdk;
  240. $jsConfig = $jssdk->bridgeConfig($result['prepay_id'], false);
  241. $json['result'] = $jsConfig;
  242. $json['type'] = 'WECHAT_PAY';
  243. } else {
  244. $result = $app->order->unify([
  245. 'body' => '充值余额',
  246. 'out_trade_no' => $d['order_id'],
  247. 'total_fee' => $money * 100,
  248. 'notify_url' => 'https://www.boofly.cn/api/weixin/notify', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  249. 'trade_type' => 'MWEB' // 请对应换成你的支付方式对应的值类型
  250. ]);
  251. $json['result'] = $result;
  252. $json['type'] = 'WECHAT_H5_PAY';
  253. }
  254. return app('json')->success($json);
  255. } catch (DbException $db) {
  256. Recharge::rollbackTrans();
  257. return app('json')->fail("充值失败,请联系客服人员");
  258. }
  259. }
  260. /**
  261. * @throws \Exception
  262. */
  263. public function notify()
  264. {
  265. // 获取微信回调的数据
  266. $notifiedData = file_get_contents('php://input');
  267. //XML格式转换
  268. $xmlObj = simplexml_load_string($notifiedData, 'SimpleXMLElement', LIBXML_NOCDATA);
  269. $xmlObj = json_decode(json_encode($xmlObj), true);
  270. // 当支付通知返回支付成功时
  271. if ($xmlObj['return_code'] == "SUCCESS" && $xmlObj['result_code'] == "SUCCESS") {
  272. try {
  273. $data['appid'] = $xmlObj['appid'];
  274. $data['bank_type'] = $xmlObj['bank_type'];
  275. $data['cash_fee'] = $xmlObj['cash_fee'];
  276. $data['fee_type'] = $xmlObj['fee_type'];
  277. $data['is_subscribe'] = $xmlObj['is_subscribe'];
  278. $data['mch_id'] = $xmlObj['mch_id'];
  279. $data['nonce_str'] = $xmlObj['nonce_str'];
  280. $data['openid'] = $xmlObj['openid'];
  281. $data['result_code'] = $xmlObj['result_code'];
  282. $data['return_code'] = $xmlObj['return_code'];
  283. $data['sign'] = $xmlObj['sign'];
  284. $data['time_end'] = $xmlObj['time_end'];
  285. $data['total_fee'] = $xmlObj['total_fee'];
  286. $data['trade_type'] = $xmlObj['trade_type'];
  287. $data['transaction_id'] = $xmlObj['transaction_id'];
  288. $data2 = Db::name('wx_notify')->where('out_trade_no', $xmlObj['out_trade_no'])->find();
  289. if (empty($data2)) {
  290. echo 'SUCCESS';
  291. exit;
  292. }
  293. $res = Db::name('wx_notify')->where('out_trade_no',$xmlObj['out_trade_no'])->save($data);
  294. if($res){
  295. if ($data2['type'] == 'order') {
  296. $order = Order::where('order_id', $xmlObj['out_trade_no'])->find();
  297. //减库存加销量
  298. Product::where('id', $order['pro_id'])->dec('stock', $order['num'])->inc('sales', $order['num'])->update();
  299. Db::name('ProductAttrValue')->where('product_id', $order['pro_id'])->where('unique', $order['unique'])->dec('stock', $order['num'])->inc('sales', $order['num'])->update();
  300. //改订单状态
  301. Order::where('order_id', $xmlObj['out_trade_no'])->save([
  302. 'status' => 1,
  303. 'is_pay' => 1,
  304. 'pay_type' => 'weixin',
  305. 'pay_time' => time()
  306. ]);
  307. //改子订单状态
  308. OrderInfo::where('o_id', $order['id'])->save(['status' => 1,]);
  309. Member::where('uid', $order['uid'])->save(['last_con_time' => time()]);
  310. }
  311. if ($data2['type'] == 'recharge') {
  312. $recharge = new Recharge();
  313. $recharge->rechargeSuccess($xmlObj['out_trade_no']);
  314. }
  315. echo 'SUCCESS';
  316. exit;
  317. }
  318. } catch (Exception $e) {
  319. @file_put_contents('error.txt', '[' . date('Y-m-d') . ']Exception:' . json_encode(['Msg' => $e->getMessage(), 'File' => $e->getFile(), 'Line' => $e->getLine(), 'Trance' => $e->getTrace()]) . PHP_EOL, FILE_APPEND);
  320. } catch (DbException $e) {
  321. @file_put_contents('error.txt', '[' . date('Y-m-d') . ']DbException:' . json_encode(['Msg' => $e->getMessage(), 'File' => $e->getFile(), 'Line' => $e->getLine(), 'Trance' => $e->getTrace()]) . PHP_EOL, FILE_APPEND);
  322. } catch (\Exception $e) {
  323. @file_put_contents('error.txt', '[' . date('Y-m-d') . ']\Exception:' . json_encode(['Msg' => $e->getMessage(), 'File' => $e->getFile(), 'Line' => $e->getLine(), 'Trance' => $e->getTrace()]) . PHP_EOL, FILE_APPEND);
  324. }
  325. }
  326. }
  327. }