Wechat.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. <?php
  2. namespace app\api\controller;
  3. use app\admin\model\Company;
  4. use app\admin\model\WechatPlan;
  5. use app\admin\model\WechatPlanRecord;
  6. use app\common\model\UserRelation;
  7. use app\common\controller\Api;
  8. use app\common\library\Auth;
  9. use liuniu\WechatService;
  10. use app\common\model\User;
  11. use Overtrue\Socialite\AuthorizeFailedException;
  12. use think\Exception;
  13. use think\Hook;
  14. use think\Request;
  15. class Wechat extends Api
  16. {
  17. protected $noNeedLogin = ['*'];
  18. /**
  19. * 微信公众号服务
  20. * @return \think\Response
  21. */
  22. public function serve()
  23. {
  24. ob_clean();
  25. return WechatService::serve();
  26. }
  27. /**
  28. * 支付异步回调
  29. */
  30. public function notify()
  31. {
  32. ob_clean();
  33. WechatService::handleNotify(input('cid', 0));
  34. }
  35. /**
  36. * 公众号权限配置信息获取
  37. * @param Request $request
  38. * @return mixed
  39. */
  40. public function config(Request $request)
  41. {
  42. return app('json')->success(json_decode(WechatService::jsSdk($request->get('url')), true));
  43. }
  44. /**
  45. * 公众号授权登陆
  46. * @param Request $request
  47. * @return mixed
  48. * @throws \think\db\exception\DataNotFoundException
  49. * @throws \think\db\exception\ModelNotFoundException
  50. * @throws \think\exception\DbException
  51. */
  52. public function auth(Request $request)
  53. {
  54. $spreadId = intval($request->param('spread'));
  55. $login_type = $request->param('login_type', 1);
  56. @file_put_contents("auth.txt", json_encode(input()));
  57. try {
  58. $wechatInfo = WechatService::oauthService($this->cid)->user()->getOriginal();
  59. } catch (\Exception $e) {
  60. $this->error(['message' => $e->getMessage(), 'line' => $e->getLine()]);
  61. }
  62. @file_put_contents("auth.txt", "\r\n" . json_encode($wechatInfo), 8);
  63. try {
  64. if (!isset($wechatInfo['nickname'])) {
  65. try {
  66. $wechatInfo = WechatService::getUserInfo($this->cid, $wechatInfo['openid']);
  67. } catch (\Exception $e) {
  68. $this->error(['message' => $e->getMessage(), 'line' => $e->getLine()]);
  69. }
  70. if (!$wechatInfo['subscribe'] && !isset($wechatInfo['nickname']))
  71. exit(WechatService::oauthService($this->cid)->scopes(['snsapi_userinfo'])
  72. ->redirect($this->request->url(true))->send());
  73. if (isset($wechatInfo['tagid_list']))
  74. $wechatInfo['tagid_list'] = implode(',', $wechatInfo['tagid_list']);
  75. } else {
  76. if (isset($wechatInfo['privilege'])) unset($wechatInfo['privilege']);
  77. if (!UserRelation::where(['openid' => $wechatInfo['openid']])->find())
  78. $wechatInfo['subscribe'] = 0;
  79. }
  80. $openid = $wechatInfo['openid'];
  81. $wechatInfo['cid'] = $this->cid;
  82. $params = [$openid, $wechatInfo, $spreadId, $login_type];
  83. @file_put_contents("auth.txt", "\r\n" . json_encode($params), 8);
  84. Hook::exec("\\app\admin\\behavior\\User", "WechatOauth", $params);
  85. $user = User::where('id', UserRelation::openidToUid($openid, 'openid'))->find();
  86. if (!$user)
  87. $this->error('获取用户失败');
  88. $this->auth->direct($user['id']);
  89. // 设置推广关系
  90. User::setSpread(intval($spreadId), $user->id);
  91. return $this->success('登录成功', $this->auth->getUserinfo());
  92. } catch (Exception $e) {
  93. @file_put_contents("error.txt", $e->getFile() . '-', $e->getLine(), '-' . $e->getMessage());
  94. }
  95. }
  96. /**
  97. * 扣款服务
  98. * @param Request $request
  99. * @return mixed
  100. * @throws \think\db\exception\DataNotFoundException
  101. * @throws \think\db\exception\ModelNotFoundException
  102. * @throws \think\exception\DbException
  103. */
  104. public function signing(Request $request)
  105. {
  106. $price = intval($request->param('price'));
  107. $uid = intval($request->param('uid'));
  108. $cid = intval($request->param('cid'));
  109. $plan_id = WechatPlan::where('price', $price)->value('plan_id');
  110. $p_id = WechatPlan::where('price', $price)->value('id');
  111. // var_dump($plan_id);
  112. // var_dump($p_id);die();
  113. // $plan_id = 11;
  114. // $p_id = 12;
  115. try {
  116. // $notify_url=Request::instance()->domain() . "/api/wechat/notify/" . $cid; //回调接口
  117. // $app_id = 'wx5681205d1ef4d9d3';
  118. $app_id = Company::where('id', $cid)->value('wechat_appid');
  119. // $mch_id = '1623907696';
  120. $mch_id = Company::where('id', $cid)->value('pay_weixin_mchid');
  121. $contract_code = $this->generateRandomString(12);
  122. $notify_url = Request::instance()->domain() . "/api/wechat/notify/" . $cid; //回调接口 $cid 企业id
  123. // $num = time() + mt_rand(10, 999999) . '' . substr($msec, 2, 3);//生成随机数
  124. // $request_serial=$this->generateUniqueSerialNumber();
  125. $request_serial = WechatPlanRecord::where('is_signing', 0)->order('request_serial desc')->value('request_serial');
  126. if (empty($request_serial)) {
  127. $request_serial = 100000;
  128. } else {
  129. $request_serial = $request_serial + 1;
  130. }
  131. $contract_display_account = User::where('id', $uid)->value('nickname');
  132. if (empty($contract_display_account)){
  133. $this->error('用户不存在!');
  134. }
  135. $timestamp = time();
  136. $version = '1.0';
  137. $array = array(
  138. 'appid' => $app_id,
  139. 'mch_id' => $mch_id,
  140. 'plan_id' => $plan_id,
  141. // 'sub_mch_id' => $sub_mch_id,
  142. 'contract_code' => $contract_code,
  143. 'notify_url' => $notify_url,
  144. 'contract_display_account' => $contract_display_account,
  145. 'request_serial' => $request_serial,
  146. 'timestamp' => $timestamp,
  147. 'version' => $version,
  148. );
  149. ksort($array);
  150. $xml = '';
  151. foreach ($array as $key => $value) {
  152. $xml = $xml . $key . '=' . $value . '&';
  153. }
  154. $xml = substr($xml, 0, -1);
  155. @file_put_contents("quanju.txt", json_encode($xml) . "-签约内容\r\n", 8);
  156. $sign = $this->md5_sign($xml, '192006250b4c09247ec02edce69f6a2d');
  157. @file_put_contents("quanju.txt", $sign . "-签名\r\n", 8);
  158. $url = 'https://api.mch.weixin.qq.com/papay/entrustweb?' . $xml . '&sign=' . $sign;
  159. @file_put_contents("quanju.txt", $url . "-链接\r\n", 8);
  160. // var_dump($url);
  161. $response = $this->curl_get($url);
  162. // $url = $this->OfficialAccountSigning($app_id, $mch_id, $plan_id, $contract_code, $request_serial, $contract_display_account, $notify_url, $version, $sign, $timestamp);
  163. @file_put_contents("quanju.txt", $response . '返回链接');
  164. WechatPlanRecord::create([
  165. 'uid' => $uid,
  166. 'plan_id' => $p_id,
  167. 'price' => $price,
  168. 'is_signing' => 0,
  169. 'request_serial' => $request_serial,
  170. 'contract_code' => $contract_code,
  171. 'contract_display_account' => $contract_display_account,
  172. 'createtime' => time(),
  173. 'cid' => 12,
  174. 'wechat_plan_id' => $plan_id,
  175. ]);
  176. // die();
  177. $this->success('获取成功', $response);
  178. // return $response;
  179. } catch (Exception $e) {
  180. // var_dump($e->getMessage());
  181. @file_put_contents("quanju.txt", $e->getMessage() . "-报错信息\r\n", 8);
  182. @file_put_contents("error.txt", $e->getFile() . '-', $e->getLine(), '-' . $e->getMessage());
  183. }
  184. }
  185. /**
  186. * 解约扣款服务
  187. * @param Request $request
  188. * @return mixed
  189. * @throws \think\db\exception\DataNotFoundException
  190. * @throws \think\db\exception\ModelNotFoundException
  191. * @throws \think\exception\DbException
  192. */
  193. public function delete_signing(Request $request)
  194. {
  195. $record_id = intval($request->param('id'));
  196. $uid = intval($request->param('uid'));
  197. $cid = intval($request->param('uid'));
  198. try {
  199. // $notify_url=Request::instance()->domain() . "/api/wechat/notify/" . $cid; //回调接口
  200. $app_id = Company::where('id', $cid)->value('wechat_appid');
  201. $mch_id = Company::where('id', $cid)->value('pay_weixin_mchid');
  202. $contract_code = WechatPlanRecord::where('id', $record_id)->value('contract_code');
  203. $plan_id = WechatPlanRecord::where('id', $record_id)->value('wechat_plan_id');
  204. $contract_termination_remark = '解约备注';
  205. $version = '1.0';
  206. $array = array(
  207. 'appid' => $app_id,
  208. 'mch_id' => $mch_id,
  209. 'plan_id' => $plan_id,
  210. 'contract_code' => $contract_code,
  211. 'contract_termination_remark' => $contract_termination_remark,
  212. 'version' => $version
  213. );
  214. ksort($array);
  215. $xml = '';
  216. foreach ($array as $key => $value) {
  217. $xml = $xml . $key . '=' . $value . '&';
  218. }
  219. $xml = substr($xml, 0, -1);
  220. @file_put_contents("quanju.txt", json_encode($xml) . "-签约内容\r\n", 8);
  221. $sign = $this->md5_sign($xml, '192006250b4c09247ec02edce69f6a2d');
  222. @file_put_contents("quanju.txt", $sign . "-签名\r\n", 8);
  223. $url = 'https://api.mch.weixin.qq.com/papay/deletecontract?' . $xml . '&sign=' . $sign;
  224. @file_put_contents("quanju.txt", $url . "-链接\r\n", 8);
  225. var_dump($url);
  226. // $response = $this->curl_get($url);
  227. // $url=$this->OfficialAccountSigning($app_id,$mch_id,$plan_id,$contract_code,$request_serial,$contract_display_account,$notify_url,$version,$sign,$timestamp);
  228. // @file_put_contents("quanju.txt", $response.'返回链接');
  229. WechatPlanRecord::where('id', $record_id)->update(['is_signing' => 1]);
  230. die();
  231. return 1;
  232. } catch (Exception $e) {
  233. @file_put_contents("error.txt", $e->getFile() . '-', $e->getLine(), '-' . $e->getMessage());
  234. }
  235. }
  236. public function generateRandomString($length)
  237. {
  238. $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  239. $charactersLength = strlen($characters);
  240. $randomString = '';
  241. for ($i = 0; $i < $length; $i++) {
  242. $randomString .= $characters[rand(0, $charactersLength - 1)];
  243. }
  244. return $randomString;
  245. }
  246. // 生成唯一序列号
  247. public function generateUniqueSerialNumber()
  248. {
  249. // 使用uniqid生成一个唯一ID,并去除前缀的'0'
  250. $uniqueId = ltrim(uniqid('', true), '0');
  251. // 确保生成的ID不以0开头且长度不超过19位(int64的最大长度)
  252. while (strlen($uniqueId) > 19 || substr($uniqueId, 0, 1) === '0') {
  253. $uniqueId = ltrim(uniqid('', true), '0');
  254. }
  255. // 将生成的ID转换为纯数字
  256. $serialNumber = preg_replace('/\D/', '', $uniqueId);
  257. // 确保生成的序列号不以0开头
  258. if (substr($serialNumber, 0, 1) === '0') {
  259. $serialNumber = generateUniqueSerialNumber(); // 递归调用以重新生成
  260. }
  261. return $serialNumber;
  262. }
  263. public function curl_post($url = '', $name = array(), $timeout = 100)
  264. {
  265. // var_dump($url);die();
  266. $ch = curl_init();
  267. curl_setopt($ch, CURLOPT_URL, $url);
  268. curl_setopt($ch, CURLOPT_HEADER, false); //是否显示头部
  269. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//是否直接输出到屏幕
  270. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  271. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
  272. curl_setopt($ch, CURLOPT_POST, true); //是否以post方式
  273. //设置post数据
  274. $post_data = json_encode($name);
  275. // curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
  276. curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
  277. $content = curl_exec($ch);
  278. // var_dump($content);die();
  279. curl_close($ch);
  280. $content = json_decode($content, true);
  281. return $content;
  282. }
  283. public function curl_get(string $url, $timeout = 100)
  284. {
  285. // if (!empty($name)) {
  286. // $data = '&';
  287. // foreach ($name as $k => $v) {
  288. // $data = $data . $k . '=' . $v.'&';
  289. // }
  290. // $url = $url . $data;
  291. // }
  292. // $url = substr($url,0,-1);
  293. $ch = curl_init();
  294. curl_setopt($ch, CURLOPT_URL, $url);
  295. curl_setopt($ch, CURLOPT_HEADER, false); //是否显示头部
  296. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//是否直接输出到屏幕
  297. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  298. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
  299. $content = curl_exec($ch);
  300. curl_close($ch);
  301. $content = json_decode($content, true);
  302. // $content = (array)$content;
  303. // var_dump($content);
  304. return $content;
  305. }
  306. public function md5_sign($data, $key)
  307. {
  308. $stringSignTemp = $data . "&key=$key"; //注:key为商户平台设置的密钥key
  309. $sign = MD5($stringSignTemp); //MD5加密
  310. $sign = strtoupper($sign); //大写
  311. return $sign;
  312. }
  313. /**
  314. * 公众号签约
  315. * see:https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_1.shtml
  316. * @param array $data
  317. *
  318. * @return array
  319. * @throws AuthorizeFailedException
  320. */
  321. public function OfficialAccountSigning(string $appid, string $mch_id, string $plan_id, string $contract_code, string $request_serial, string $contract_display_account, string $notify_url, string $version, string $sign, string $timestamp): array
  322. {
  323. $url = 'https://api.mch.weixin.qq.com/papay/entrustweb';
  324. $info = [
  325. 'appid' => $appid, //应用ID
  326. 'mch_id' => $mch_id, //商户号
  327. 'plan_id' => $plan_id, //模板id
  328. // 'sub_mch_id' => $sub_mch_id, //子商户号
  329. 'contract_code' => $contract_code, //签约协议号
  330. 'request_serial' => $request_serial, //请求序列号
  331. 'contract_display_account' => $contract_display_account, //用户账户展示名称
  332. 'notify_url' => $notify_url, //回调通知url
  333. 'version' => $version, //版本号 固定值1.0
  334. 'sign' => $sign, //签名
  335. 'timestamp' => $timestamp
  336. ];
  337. $response = $this->curl_get($url, $info);
  338. return $response;
  339. }
  340. public function test()
  341. {
  342. return '123456';
  343. }
  344. public function signing_plan()
  345. {
  346. $this->success('获取成功', WechatPlan::where('cid', 12)->select());
  347. }
  348. // 用户签约列表
  349. public function user_signing(Request $request)
  350. {
  351. $uid = intval($request->param('uid'));
  352. $this->success('获取成功', WechatPlanRecord::where('uid', $uid)->where('is_signing', 0)->select());
  353. }
  354. }