DingService.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. <?php
  2. namespace App\Service;
  3. use App\Model\DDEmployee;
  4. use App\Model\Record;
  5. use App\Model\U8State;
  6. use Illuminate\Support\Facades\Redis;
  7. class DingService extends Service
  8. {
  9. public function getAccessToken($type)
  10. {
  11. $key = DDEmployee::type_redis[$type];
  12. if(empty($key)) return [false, 'token名称未设置'];
  13. $token = Redis::get($key);
  14. if(! empty($token)) return [true, ['access_token' => $token]];
  15. $config = config("dingtalk.{$type}");
  16. if(empty($config)) return [false, '钉钉配置信息不存在'];
  17. $appKey = $config['app_key'] ?? null;
  18. $appSecret = $config['app_secret'] ?? null;
  19. if (!$appKey) return [false, 'AppKey 配置不完整'];
  20. if (!$appSecret) return [false, 'AppSecret 配置不完整'];
  21. $url = "https://api.dingtalk.com/v1.0/oauth2/accessToken";
  22. $resp = $this->curlOpen1($url, [
  23. 'request' => 'post',
  24. 'header' => ['Content-Type: application/json'],
  25. 'json' => [
  26. "appKey" => $appKey,
  27. "appSecret" => $appSecret
  28. ]
  29. ]);
  30. $res = json_decode($resp, true);
  31. $accessToken = $res['accessToken'] ?? "";
  32. $expires_in = $res['expires_in'] ?? 0;
  33. if(empty($accessToken)) return [false, 'AccessToken获取失败'];
  34. Redis::setex($key, $expires_in, $accessToken);
  35. return [true, ['access_token' => $accessToken]];
  36. }
  37. /**
  38. * 根据前端传来的免登 code 获取用户信息
  39. * @param string $code 前端 dd.getAuthCode 获取的 code
  40. * @return array [bool, data] bool 表示成功与否,data 成功返回用户信息,失败返回错误信息
  41. */
  42. public function getUserByCode($data, $LoginType)
  43. {
  44. if(empty($LoginType)) return [false, 'login_type类型不能为空'];
  45. if(! isset(DDEmployee::type[$LoginType])) return [false, 'login_type类型不存在或错误'];
  46. $code = $data['code'] ?? "";
  47. if (empty($code)) return [false, '钉钉授权code不能为空'];
  48. // 1. 获取 access_token
  49. [$success, $tokenData] = $this->getAccessToken($LoginType);
  50. if (! $success) return [false, $tokenData]; // tokenData 是错误信息
  51. $accessToken = $tokenData['access_token'];
  52. // 2. 用 code 换取用户信息(v2 接口)
  53. $url = "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token={$accessToken}";
  54. $resp = $this->curlOpen1($url, [
  55. 'request' => 'post',
  56. 'header' => [
  57. "Content-Type: application/json",
  58. ],
  59. 'json' => [
  60. "code" => $code
  61. ]
  62. ]);
  63. $res = json_decode($resp, true);
  64. if (!isset($res['errcode'])) {
  65. return [false, '接口返回异常: ' . $resp];
  66. }
  67. if ($res['errcode'] !== 0) {
  68. return [false, '获取用户信息失败: ' . $res['errmsg']];
  69. }
  70. if(! empty($res['result'])){
  71. $result = $res['result'];
  72. DDEmployee::updateOrCreate(
  73. ['userid' => $result['userid'], 'login_type' => $LoginType],
  74. ['name' => $result['name'], 'userid' => $result['userid'], 'login_type' => $LoginType, 'u_userid' => $result['unionid']]
  75. );
  76. }
  77. return [true, $res];
  78. }
  79. private function getManDetail($user, $accessToken){
  80. // 3. 根据 userid 获取详细用户信息(包括部门)
  81. $urlDetail = "https://oapi.dingtalk.com/topapi/v2/user/get?access_token={$accessToken}";
  82. $respDetail = $this->curlOpen1($urlDetail, [
  83. 'request' => 'post',
  84. 'header' => ["Content-Type: application/json"],
  85. 'json' => ["userid" => $user['userId']]
  86. ]);
  87. $detail = json_decode($respDetail, true);
  88. if (!isset($detail['errcode'])) return [false, '获取用户详情接口异常: ' . $respDetail];
  89. if ($detail['errcode'] !== 0) return [false, '获取用户详情失败: ' . $detail['errmsg']];
  90. if (empty($detail['result'])) return [false, '获取用户详情失败,结果为空'];
  91. // 返回完整用户信息
  92. return [true, $detail['result']];
  93. }
  94. public function createProcessInstance($data, $user)
  95. {
  96. if(empty($data['type'])) return [false, '单据类型不能为空'];
  97. $type = $data['type'];
  98. if(empty($data['order_number'])) return [false,'单号不能为空'];
  99. [$success, $msg] = $this->checkCreateProcessInstance($data, $user);
  100. if(! $success) return [false, $msg];
  101. //获取模板id
  102. $code = $this->getModelCode($type, $user);
  103. //获取模板数据
  104. [$success, $formData] = $this->getFormData($data, $user);
  105. if(! $success) return [false, $formData];
  106. // 1. 获取 access_token
  107. [$success, $tokenData] = $this->getAccessToken($user['login_type']);
  108. if (!$success) return [false, $tokenData];
  109. $accessToken = $tokenData['access_token'];
  110. $userId = $user['userId'];
  111. [$success, $userDetail] = $this->getManDetail($user, $accessToken);
  112. if(!$success) return [false, $userDetail];
  113. //创建审批
  114. [$success, $msg] = $this->createFlow($accessToken, $code, $userId, $userDetail, $formData);
  115. if(! $success) return [false, $msg];
  116. //记录信息
  117. $this->recordDatabase($data, $user, $msg);
  118. return [true, ''];
  119. }
  120. private function recordDatabase($data, $user, $process_instance_id){
  121. $type = $data['type'];
  122. Record::insert([
  123. 'type' => $type,
  124. 'login_type' => $user['login_type'],
  125. 'database' => $user['zt_database'],
  126. 'order_number'=> $data['order_number'],
  127. 'crt_time' => time(),
  128. 'process_instance_id' => $process_instance_id,
  129. 'state' => Record::state_zero
  130. ]);
  131. //保证
  132. U8State::updateOrCreate(
  133. ['order_number' => $data['order_number'], 'login_type' => $user['login_type'], 'type' => $type],
  134. ['state' => U8State::state_zero]
  135. );
  136. return [true, ''];
  137. }
  138. private function checkCreateProcessInstance($data, $user){
  139. list($status,$msg) = $this->limitingSendRequestBackgExpire($data['order_number'].$data['type'].$user['login_type']);
  140. if(! $status) return [false,$msg];
  141. $type = $data['type'];
  142. $login_type = $user['login_type'];
  143. // // 1. 获取该单号最新的一条记录
  144. // $lastRecord = Record::where('del_time', 0)
  145. // ->where('type', $type)
  146. // ->where('login_type', $login_type)
  147. // ->where('order_number', $data['order_number'])
  148. // ->latest('id') // 按 ID 倒序,取最新
  149. // ->first(['state']); // 只取状态字段
  150. //
  151. // // 2. 逻辑判断
  152. // if ($lastRecord) {
  153. // $text_o = Record::type_name[$type];
  154. // // 如果状态是 0 (待审核) 或 1 (审核通过),拦截
  155. // if (in_array($lastRecord->state, [Record::state_zero, Record::state_one])) {
  156. // $text = Record::state_name[$lastRecord->state];
  157. // return [false, $text_o . ' (' . $data['order_number'] . ') ' . $text . ',操作失败'];
  158. // }
  159. // }
  160. // 1. 获取该单号最新的一条记录
  161. $lastRecord = U8State::where('del_time', 0)
  162. ->where('type', $type)
  163. ->where('login_type', $login_type)
  164. ->where('order_number', $data['order_number'])
  165. ->first(['state']); // 只取状态字段
  166. // 2. 逻辑判断
  167. if ($lastRecord) {
  168. $text_o = U8State::type_name[$type];
  169. // 如果状态是 0 (待审核) 或 1 (审核通过),拦截
  170. if (in_array($lastRecord->state, [U8State::state_zero, U8State::state_one])) {
  171. $text = U8State::state_name[$lastRecord->state];
  172. return [false, $text_o . ' (' . $data['order_number'] . ') 处于' . $text . ',操作失败'];
  173. }
  174. }
  175. return [true, ''];
  176. }
  177. private function createFlow($accessToken, $code, $userId, $userDetail, $formData){
  178. // 2. 请求 URL
  179. $url = "https://oapi.dingtalk.com/topapi/processinstance/create?access_token={$accessToken}";
  180. // 3. 请求体
  181. $payload = [
  182. "process_code" => $code, // 审批模板编码
  183. "originator_user_id" => $userId, // 发起人 userId
  184. "dept_id" => $userDetail['dept_id_list'][0], // 发起人部门 ID
  185. "form_component_values" => $formData, // 表单数据
  186. ];
  187. // 4. 发送请求
  188. $resp = $this->curlOpen1($url, [
  189. 'request' => 'post',
  190. 'header' => [
  191. "Content-Type: application/json",
  192. ],
  193. 'json' => $payload
  194. ]);
  195. $res = json_decode($resp, true);
  196. if (!isset($res['errcode'])) {
  197. return [false, "接口返回异常: " . $resp];
  198. }
  199. if ($res['errcode'] !== 0) {
  200. return [false, "创建审批实例失败: " . $res['errmsg']];
  201. }
  202. return [true, $res['process_instance_id']];
  203. }
  204. /**
  205. * 获取当前用户待审批的实例 ID 列表
  206. * @param string $accessToken
  207. * @param string $userId 钉钉用户的 userId
  208. * @param int $cursor 分页游标,从0开始
  209. * @param int $size 分页大小,最大100
  210. */
  211. public function getTodoProcessList($data, $user)
  212. {
  213. [$success, $tokenData] = $this->getAccessToken($user['login_type']);
  214. if (!$success) return [false, $tokenData];
  215. $accessToken = $tokenData['access_token'];
  216. $cursor = $data['cursor'] ?? 0;
  217. $size = $data['size'] ?? 20;
  218. // 1. 请求 URL
  219. $url = "https://oapi.dingtalk.com/topapi/process/todo/list?access_token={$accessToken}";
  220. // 2. 请求体
  221. $payload = [
  222. "userid" => $user['userid'],
  223. "cursor" => $cursor,
  224. "size" => $size,
  225. ];
  226. // 3. 发送请求
  227. $resp = $this->curlOpen1($url, [
  228. 'request' => 'post',
  229. 'header' => ["Content-Type: application/json"],
  230. 'json' => $payload
  231. ]);
  232. $res = json_decode($resp, true);
  233. if (!isset($res['errcode']) || $res['errcode'] !== 0) return [false, "获取待办列表失败: " . ($res['errmsg'] ?? '未知错误')];
  234. // 4. 提取 process_instance_id
  235. // 返回的结果中包含数据列表,我们需要从中提取所有的实例ID
  236. $list = $res['result']['list'] ?? [];
  237. $instanceIds = array_column($list, 'process_instance_id');
  238. $result = Record::whereIn('process_instance_id', $instanceIds)
  239. ->select('type', 'order_number')
  240. ->get()->toArray();
  241. return [true, [
  242. 'list' => $result, // 所有的待我审核
  243. 'has_more' => $res['result']['has_more'] ?? false, // 是否还有更多
  244. 'next_cursor' => $res['result']['next_cursor'] ?? null // 下一页游标
  245. ]];
  246. }
  247. /**
  248. * 执行审批操作(同意/拒绝)
  249. * @param string $accessToken
  250. * @param string $processInstanceId 审批实例ID
  251. * @param string $action 'agree' 为同意,'refuse' 为拒绝
  252. * @param string $remark 审批意见
  253. * @param string $userId 执行审批操作的人员ID
  254. */
  255. public function executeApproval($data, $user)
  256. {
  257. [$success, $tokenData] = $this->getAccessToken($user['login_type']);
  258. if (!$success) return [false, $tokenData];
  259. $accessToken = $tokenData['access_token'];
  260. $processInstanceId = $data['process_instance_id'] ?? 0;
  261. $action = $data['action'] ?? 'agree';
  262. $remark = $data['remark'] ?? '同意';
  263. // 1. 请求 URL
  264. $url = "https://oapi.dingtalk.com/topapi/process/instance/execute?access_token={$accessToken}";
  265. // 2. 构造请求体
  266. $payload = [
  267. "process_instance_id" => $processInstanceId,
  268. "remark" => $remark,
  269. "result" => $action, // 'agree' 或 'refuse'
  270. "task_id" => $this->getTaskIdByInstanceId($accessToken, $processInstanceId, $user['userid']), // 获取当前人的任务ID
  271. ];
  272. // 3. 发送请求
  273. $resp = $this->curlOpen1($url, [
  274. 'request' => 'post',
  275. 'header' => ["Content-Type: application/json"],
  276. 'json' => $payload
  277. ]);
  278. $res = json_decode($resp, true);
  279. if (!isset($res['errcode']) || $res['errcode'] !== 0) {
  280. return [false, "审批操作失败: " . ($res['errmsg'] ?? '未知错误')];
  281. }
  282. return [true, "操作成功"];
  283. }
  284. /**
  285. * 获取指定实例中属于某个用户的待办任务 ID
  286. */
  287. private function getTaskIdByInstanceId($accessToken, $instanceId, $userId)
  288. {
  289. $url = "https://oapi.dingtalk.com/topapi/processinstance/get?access_token={$accessToken}";
  290. $resp = $this->curlOpen1($url, [
  291. 'request' => 'post',
  292. 'header' => ["Content-Type: application/json"],
  293. 'json' => ["process_instance_id" => $instanceId]
  294. ]);
  295. $res = json_decode($resp, true);
  296. $tasks = $res['process_instance']['tasks'] ?? [];
  297. foreach ($tasks as $task) {
  298. // 状态为 RUNNING (进行中) 且 处理人是当前用户
  299. if ($task['task_status'] === 'RUNNING' && $task['userid'] === $userId) {
  300. return $task['task_id'];
  301. }
  302. }
  303. return null;
  304. }
  305. private function getModelCode($type, $user){
  306. $login_type = $user['login_type'];
  307. if($login_type == DDEmployee::type_one){
  308. //浙江
  309. if($type == 1){
  310. // 采购单
  311. $code = "";
  312. }elseif ($type == 2){
  313. // 请购单
  314. $code = "";
  315. }elseif ($type == 3){
  316. // 采购入库单
  317. $code = "";
  318. }elseif ($type == 4){
  319. // 存货
  320. $code = "";
  321. }elseif ($type == 5){
  322. // 供应商
  323. $code = "";
  324. }
  325. }elseif ($login_type == DDEmployee::type_two){
  326. //杭州
  327. if($type == 1){
  328. // 采购单
  329. $code = "";
  330. }elseif ($type == 2){
  331. // 请购单
  332. $code = "";
  333. }elseif ($type == 3){
  334. // 采购入库单
  335. $code = "";
  336. }elseif ($type == 4){
  337. // 存货
  338. $code = "";
  339. }elseif ($type == 5){
  340. // 供应商
  341. $code = "";
  342. }
  343. }
  344. return $code ?? "";
  345. }
  346. private function getFormData($data, $user){
  347. //cs
  348. // $formData = [ [ "name" => "订单日期", "value" => "2025-09-23" ], [ "name" => "订单编号", "value" => "PO20250923001" ], [ "name" => "业务类型", "value" => "标准采购" ], [ "name" => "供应商", "value" => "XX供应商有限公司" ], [ "name" => "制单人", "value" => "陈庆鹏" ], [ "name" => "表体", "value" => json_encode([ [ [ "name" => "存货名称", "value" => "打印机" ], [ "name" => "数量", "value" => "2" ], [ "name" => "主计量单位", "value" => "台" ], [ "name" => "原币价税合计", "value" => "3000" ] ], [ [ "name" => "存货名称", "value" => "显示器" ], [ "name" => "数量", "value" => "5" ], [ "name" => "主计量单位", "value" => "个" ], [ "name" => "原币价税合计", "value" => "5000" ] ] ], JSON_UNESCAPED_UNICODE) ] ];
  349. // return [true, $formData];
  350. //cs
  351. $service = new U8ServerService($user);
  352. $error = $service->getError();
  353. if(! empty($error)) return [false, $error];
  354. [$success, $order] = $service->getOrderDetails($data, $user);
  355. if(! $success) return [false, $order];
  356. $type = $data['type'];
  357. if($type == 1){
  358. // 采购单
  359. $formData = $this->typeOne($order);
  360. }elseif ($type == 2){
  361. // 采购请购单
  362. $formData = $this->typeTwo($order);
  363. }elseif($type == 3){
  364. // 采购入库单
  365. $formData = $this->typeThree($order);
  366. }elseif($type == 4){
  367. // 存货
  368. $formData = $this->typeThree($order);
  369. }elseif($type == 5){
  370. // 供应商
  371. $formData = $this->typeThree($order);
  372. }
  373. if(empty($formData)) return [false, '审批参数不能为空'];
  374. return [true, $formData];
  375. }
  376. private function typeOne($userOrder){
  377. if (empty($userOrder)) return [];
  378. $formData = [
  379. [
  380. "name" => "订单日期",
  381. "value" => date('Y-m-d', strtotime($userOrder['order_date'] ?? ''))
  382. ],
  383. [
  384. "name" => "订单编号",
  385. "value" => $userOrder['order_number'] ?? ''
  386. ],
  387. [
  388. "name" => "业务类型",
  389. "value" => $userOrder['business_type'] ?? ''
  390. ],
  391. [
  392. "name" => "供应商",
  393. "value" => $userOrder['supplier_title'] ?? ''
  394. ],
  395. [
  396. "name" => "制单人",
  397. "value" => $userOrder['crt_name'] ?? ''
  398. ],
  399. [
  400. "name" => "表体", // 对应 TableField 的 label
  401. "value" => json_encode(
  402. array_map(function($item){
  403. return [
  404. [
  405. "name" => "存货名称",
  406. "value" => $item['product_title'] ?? ''
  407. ],
  408. [
  409. "name" => "数量",
  410. "value" => $item['quantity'] ?? 0
  411. ],
  412. [
  413. "name" => "主计量", // 修改这里,对应模板字段
  414. "value" => $item['unit_title'] ?? ''
  415. ],
  416. [
  417. "name" => "原币价税合计",
  418. "value" => $item['amount'] ?? 0
  419. ]
  420. ];
  421. }, $userOrder['detail'] ?? []),
  422. JSON_UNESCAPED_UNICODE
  423. )
  424. ]
  425. ];
  426. return $formData;
  427. }
  428. private function typeTwo($userOrder){
  429. if (empty($userOrder)) return [];
  430. $formData = [
  431. [
  432. "name" => "单据号",
  433. "value" => $userOrder['order_number'] ?? ''
  434. ],
  435. [
  436. "name" => "日期",
  437. "value" => date('Y-m-d', strtotime($userOrder['order_date'] ?? ''))
  438. ],
  439. [
  440. "name" => "业务类型",
  441. "value" => $userOrder['business_type'] ?? ''
  442. ],
  443. [
  444. "name" => "请购人",
  445. "value" => $userOrder['purchase_name'] ?? ''
  446. ],
  447. [
  448. "name" => "制单人",
  449. "value" => $userOrder['crt_name'] ?? ''
  450. ],
  451. [
  452. "name" => "表体", // 对应 TableField 的 label
  453. "value" => json_encode(
  454. array_map(function($item){
  455. return [
  456. [
  457. "name" => "存货名称",
  458. "value" => $item['product_title'] ?? ''
  459. ],
  460. [
  461. "name" => "数量",
  462. "value" => $item['quantity'] ?? 0
  463. ],
  464. [
  465. "name" => "主计量", // 修改这里,对应模板字段
  466. "value" => $item['unit_title'] ?? ''
  467. ],
  468. [
  469. "name" => "要求到货日期",
  470. "value" => $item['need_arrived_date'] ?? ''
  471. ]
  472. ];
  473. }, $userOrder['detail'] ?? []),
  474. JSON_UNESCAPED_UNICODE
  475. )
  476. ]
  477. ];
  478. return $formData;
  479. }
  480. private function typeThree($userOrder){
  481. if (empty($userOrder)) return [];
  482. $formData = [
  483. [
  484. "name" => "单据编号",
  485. "value" => $userOrder['order_number'] ?? ''
  486. ],
  487. [
  488. "name" => "日期",
  489. "value" => date('Y-m-d', strtotime($userOrder['order_date'] ?? ''))
  490. ],
  491. [
  492. "name" => "供应商",
  493. "value" => $userOrder['supplier_title'] ?? ''
  494. ],
  495. [
  496. "name" => "制单人",
  497. "value" => $userOrder['crt_name'] ?? ''
  498. ],
  499. [
  500. "name" => "总金额",
  501. "value" => $userOrder['total_amount'] ?? 0
  502. ],
  503. [
  504. "name" => "表体", // 对应 TableField 的 label
  505. "value" => json_encode(
  506. array_map(function($item){
  507. return [
  508. [
  509. "name" => "来源",
  510. "value" => $item['source'] ?? ''
  511. ],
  512. [
  513. "name" => "来源单据号",
  514. "value" => $item['source_order_number'] ?? ''
  515. ],
  516. [
  517. "name" => "存货名称",
  518. "value" => $item['product_title'] ?? ''
  519. ],
  520. [
  521. "name" => "数量",
  522. "value" => $item['number'] ?? 0,
  523. ],
  524. [
  525. "name" => "主计量", // 修改这里,对应模板字段
  526. "value" => $item['unit_title'] ?? ''
  527. ],
  528. [
  529. "name" => "申请金额",
  530. "value" => $item['amount'] ?? 0
  531. ]
  532. ];
  533. }, $userOrder['detail'] ?? []),
  534. JSON_UNESCAPED_UNICODE
  535. )
  536. ]
  537. ];
  538. return $formData;
  539. }
  540. public function getTemplateFields($data)
  541. {
  542. $processCode = $data['code'] ?? "";
  543. if (empty($processCode)) {
  544. return [false, '模板编号 process_code 不能为空'];
  545. }
  546. [$ok, $tokenData] = $this->getAccessToken();
  547. if (! $ok) return [false, $tokenData];
  548. $accessToken = $tokenData['access_token'];
  549. // 注意这里是 GET,并且 processCode 是 query 参数
  550. $url = "https://api.dingtalk.com/v1.0/workflow/forms/schemas/processCodes?processCode={$processCode}";
  551. $resp = $this->curlOpen1($url, [
  552. 'request' => 'get',
  553. 'header' => [
  554. "Content-Type: application/json",
  555. "x-acs-dingtalk-access-token: {$accessToken}"
  556. ],
  557. ]);
  558. $res = json_decode($resp, true);
  559. if (isset($res['schemas'])) {
  560. return [true, $res['schemas']];
  561. } else {
  562. return [false, $res];
  563. }
  564. }
  565. protected function curlOpen1($url, $config = [])
  566. {
  567. $default = [
  568. 'post' => false,
  569. 'request' => 'get',
  570. 'header' => [],
  571. 'json' => null,
  572. 'timeout' => 30
  573. ];
  574. $arr = array_merge($default, $config);
  575. $ch = curl_init();
  576. curl_setopt($ch, CURLOPT_URL, $url);
  577. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  578. curl_setopt($ch, CURLOPT_TIMEOUT, $arr['timeout']);
  579. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  580. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  581. if (!empty($arr['header'])) {
  582. curl_setopt($ch, CURLOPT_HTTPHEADER, $arr['header']);
  583. }
  584. if ($arr['post'] || $arr['request'] !== 'get') {
  585. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($arr['request']));
  586. if ($arr['json'] !== null) {
  587. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($arr['json'], JSON_UNESCAPED_UNICODE));
  588. }
  589. }
  590. $result = curl_exec($ch);
  591. if ($result === false) {
  592. $err = curl_error($ch);
  593. curl_close($ch);
  594. return json_encode(['error' => $err]);
  595. }
  596. curl_close($ch);
  597. return $result;
  598. }
  599. }