Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/sproduction.datasync/lib/ |
Upload File : |
<?php /** * Rest * * @mail support@s-production.online * @link s-production.online */ namespace SProduction\Datasync; use Bitrix\Main, Bitrix\Main\DB\Exception, Bitrix\Main\Config\Option, SProduction\Datasync\Settings, Bitrix\Main\Application; class Rest { const MODULE_ID = 'sproduction.datasync'; const BATCH_RESP_RESULT = 'result'; const BATCH_RESP_ERRORS = 'result_error'; protected static $MANUAL_RUN = false; protected static $STORE_EVENTS_BGR = true; static $site = false; static $portal = false; static $app_id = false; static $secret = false; /** * Status of running events by asinchronous mode */ public static function disableStoreEventsBgrRun() { self::$STORE_EVENTS_BGR = false; } public static function isStoreEventsBgrRunEnabled() { //FileLog::put('(Rest::isStoreEventsBgrRunEnabled) status ' . (self::$STORE_EVENTS_BGR ? 'true' : 'false')); return self::$STORE_EVENTS_BGR; } /** * Bulk run indicator */ public static function setBulkRun() { self::$MANUAL_RUN = true; } public static function isBulkRun() { return self::$MANUAL_RUN; } /** * Get Bitrix24 application info */ public static function getAppInfo() { $info = false; if (self::$site === false) { self::$site = Settings::get("site"); } if (self::$portal === false) { self::$portal = Settings::get("portal"); } if (self::$app_id === false) { self::$app_id = Settings::get("app_id"); } if (self::$secret === false) { self::$secret = Settings::get("secret"); } if (self::$site && self::$portal && self::$app_id && self::$secret) { $info = [ 'site' => self::$site, 'portal' => self::$portal, 'app_id' => self::$app_id, 'secret' => self::$secret, ]; } return $info; } /** * Save file with auth data * * @param $info * * @return bool|int */ public static function saveAuthInfo($info) { $res = Settings::save("credentials", $info, true); return $res; } /** * Read auth data * * @return bool|mixed */ public static function getAuthInfo() { $info = Settings::get("credentials", true); return $info; } /** * Get link for application authentication * * @return bool|string */ public static function getAuthLink() { $app_info = self::getAppInfo(); if (!$app_info) { return false; } $link = $app_info['portal'].'/oauth/authorize/?client_id='.$app_info['app_id'].'&response_type=code'; return $link; } /** * Get auth token */ public static function restToken($code) { $app_info = self::getAppInfo(); FileLog::put('(Rest::restToken) code ' . $code); if (!$code || !$app_info) { return false; } $query_url = 'https://oauth.bitrix.info/oauth/token/'; $query_data = http_build_query([ 'grant_type' => 'authorization_code', 'client_id' => $app_info['app_id'], 'client_secret' => $app_info['secret'], 'code' => $code, ]); if (Settings::get('log_queries') == 'Y') { FileLog::put('(Rest::restToken) query ' . $query_url . '?' . $query_data, false); } $curl = curl_init(); $curl_opts = [ CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $query_url . '?' . $query_data, ]; $proxy = Proxy::getRandom(); if ($proxy) { $curl_opts[CURLOPT_PROXYTYPE] = 'HTTP'; $curl_opts[CURLOPT_PROXY] = $proxy['ip']; $curl_opts[CURLOPT_PROXYPORT] = $proxy['port']; if ($proxy['login'] && $proxy['password']) { $curl_opts[CURLOPT_PROXYUSERPWD] = $proxy['login'] . ':' . $proxy['password']; } } curl_setopt_array($curl, $curl_opts); $result = curl_exec($curl); curl_close($curl); $cred = json_decode($result, true); FileLog::put('(Rest::restToken) result ' . print_r($cred, true)); if (!$cred['error']) { // Save new auth credentials self::saveAuthInfo($cred); } return $cred; } /** * Refresh access token * * @param array $refresh_token * @return bool|mixed */ public static function refreshToken($refresh_token) { $app_info = self::getAppInfo(); if (!isset($refresh_token) || !$app_info) { return false; } RestLimits::control(); $query_url = 'https://oauth.bitrix.info/oauth/token/'; $query_data = http_build_query([ 'grant_type' => 'refresh_token', 'client_id' => $app_info['app_id'], 'client_secret' => $app_info['secret'], 'refresh_token' => $refresh_token, ]); if (Settings::get('log_queries') == 'Y') { FileLog::put('(Rest::refreshToken) query ' . $query_url . '?' . $query_data, false); } $curl = curl_init(); $curl_opts = [ CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $query_url . '?' . $query_data, ]; $proxy = Proxy::getRandom(); if ($proxy) { $curl_opts[CURLOPT_PROXYTYPE] = 'HTTP'; $curl_opts[CURLOPT_PROXY] = $proxy['ip']; $curl_opts[CURLOPT_PROXYPORT] = $proxy['port']; if ($proxy['login'] && $proxy['password']) { $curl_opts[CURLOPT_PROXYUSERPWD] = $proxy['login'] . ':' . $proxy['password']; } } curl_setopt_array($curl, $curl_opts); $result = curl_exec($curl); curl_close($curl); $resp = json_decode($result, true); if (isset($resp['error'])) { throw new Exception($resp['error_description'], $resp['error']); } return $resp; } /** * Send rest query to Bitrix24. * * @param $method - Rest method, ex: methods * @param array $params - Method params, ex: [] * @param array $cred - Authorize data, ex: Array('domain' => 'https://test.bitrix24.com', 'access_token' => '7inpwszbuu8vnwr5jmabqa467rqur7u6') * @param boolean $auth_refresh - If authorize is expired, refresh token * * @return mixed */ public static function execute($method, array $params = [], $cred = false, $auth_refresh = true, $only_res=true, $err_repeate=true, $force_cache = false) { // Get from cache if (RestCache::hasValue($method, $params, $only_res)) { FileLog::put('(Rest::execute) get method ' . $method . ' cache'); return RestCache::get($method, $params, $only_res); } FileLog::put('(Rest::execute) execute method ' . $method); $app_info = self::getAppInfo(); if (!$app_info) { return false; } if (!$cred) { $cred = self::getAuthInfo(); } RestLimits::control(); // Command to the REST server $access_token = $cred["access_token"] ?? ''; $query_url = $app_info['portal'] . '/rest/' . $method; $query_data = http_build_query(array_merge($params, ['auth' => $access_token])); if (Settings::get('log_queries') == 'Y') { FileLog::put('(Rest::execute) query ' . $query_url . '?' . $query_data, false); } $curl = curl_init(); $curl_opts = [ CURLOPT_POST => true, CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_URL => $query_url, CURLOPT_POSTFIELDS => $query_data, ]; $proxy = Proxy::getRandom(); if ($proxy) { $curl_opts[CURLOPT_PROXYTYPE] = 'HTTP'; $curl_opts[CURLOPT_PROXY] = $proxy['ip']; $curl_opts[CURLOPT_PROXYPORT] = $proxy['port']; if ($proxy['login'] && $proxy['password']) { $curl_opts[CURLOPT_PROXYUSERPWD] = $proxy['login'] . ':' . $proxy['password']; } } curl_setopt_array($curl, $curl_opts); $result = curl_exec($curl); curl_close($curl); $resp = json_decode($result, true); // Error to the log if (isset($resp['error']) || isset($resp['error_description'])) { FileLog::put('(Rest::execute) query "' . $method . '" error: ' . $resp['error_description'] . ' [' . $resp['error'] . ']'); // If token expired then refresh it if (in_array($resp['error'], ['expired_token', 'invalid_token'])) { if ($auth_refresh) { // Try to get new access token $i = 0; do { if ($i > 0) { sleep(1); } try { $cred = self::refreshToken($cred['refresh_token']); } catch (\Exception $e) { FileLog::put('(Rest::execute) query "' . $method . '" refresh token error: ' . $e->getMessage() . ' [' . $e->getCode() . ']'); } $i++; } while (!$cred["access_token"] && $i <= 3); if (is_array($cred)) { foreach ($cred as $k => $value) { $cred_log[$k] = mb_strimwidth($value, 0, 8, '***'); } } FileLog::put('(Rest::execute) query "' . $method . '" repeat result: ' . print_r($cred_log, true)); if ($cred["access_token"]) { // Save new auth credentials self::saveAuthInfo($cred); // Execute again $resp = self::execute($method, $params, $cred, false, false); } } } // Access denied elseif (in_array($resp['error'], ['200040300050'])) {} // Other errors else { // Query limit if (in_array($resp['error'], ['QUERY_LIMIT_EXCEEDED'])) { RestLimits::processQueryLimitError(); } if ($err_repeate) { $i = 0; while ((($resp['error'] ?? false) || ($resp['error_description'] ?? false)) && $i < 2) { usleep(500000); // Execute again try { $resp = self::execute($method, $params, $cred, $auth_refresh, false, false); } catch (\Exception $e) { FileLog::put('(Rest::execute) query "' . $method . '" repeat error: ' . $e->getMessage() . ' [' . $e->getCode() . ']'); } $i++; } } // Return exception if (($resp['error'] ?? false) || ($resp['error_description'] ?? false)) { FileLog::put('(Rest::execute) query "' . $method . '" exception'); throw new Exception($resp['error_description'], $resp['error']); } } } // Get results if ($only_res) { $result = is_array($resp) ? $resp['result'] : false; } else { $result = $resp; } // Save cache if (!isset($resp['error']) && !isset($resp['error_description'])) { RestCache::add($method, $params, $only_res, $result, $force_cache); } // Wakeup DB for long process if (self::isBulkRun()) { self::updateDBConnection(); } return $result; } public static function executeGetFlat($method, array $params = [], $cred = false) { FileLog::put('(Rest::executeGetFlat) method ' . $method); $app_info = self::getAppInfo(); if ( ! $app_info) { return false; } if ( ! $cred) { $cred = self::getAuthInfo(); } // Command to the REST server $query_url = $app_info['portal'] . '/rest/' . $method; $query_data = http_build_query(array_merge($params, ['auth' => $cred["access_token"]])); return $query_url . '?' . $query_data; } /** * Batch request */ public static function batch(array $req_list, $cred = false, $force_cache = false) { $result = []; // Info for log $methods = []; foreach ($req_list as $item) { $methods[] = $item['method']; } FileLog::put('(Rest::batch) methods ' . implode(', ', $methods)); if (!empty($req_list)) { $req_limit = 50; $req_count = ceil(count($req_list) / $req_limit); for ($i = 0; $i < $req_count; $i ++) { $req_list_f = []; $j = 0; foreach ($req_list as $req_code => $req_item) { if ($j >= $i * $req_limit && $j < ($i + 1) * $req_limit) { // Prepare first request $k = $j - $i * $req_limit; if ($i > 0 && $k == 0) { if (isset($req_item['params']) && isset($req_item['params']['filter'])) { foreach ($req_item['params']['filter'] as $key => $value) { $res_value = ''; $matches = []; preg_match('/(\$result)(\[\w*\])+/i', $value, $matches); if (!empty($matches)) { $res_request = $matches[0]; $execute_string = $res_request; $execute_string = str_replace('$result', '$result[result]', $execute_string); $execute_string = '$res_value = ' . preg_replace('/\[(\w*\D\w*)\]/', '["$1"]', $execute_string) . ';'; eval($execute_string); $req_item['params']['filter'][$key] = str_replace($res_request, $res_value, $value); } } } } // Add request to list $params = isset($req_item['params']) ? http_build_query($req_item['params']) : ''; $req_list_f[$req_code] = $req_item['method'] . '?' . $params; } $j++; } if ( ! empty($req_list_f)) { $resp = self::execute('batch', [ "halt" => false, "cmd" => $req_list_f, ], $cred, true, true, true, $force_cache); if (is_array($resp)) { $result = array_merge_recursive($result, $resp ?? []); } } } } return $result; } /** * Universal list */ public static function getList($method, $sub_array='', $params=[], $limit=0) { $list = []; $resp = self::execute($method, $params, false, true, false); $count = $resp['total']; if ($count) { $req_list = []; $req_count = ceil($count / 50); // List without counting if (isset($params['order']['id']) && $params['order']['id'] == 'asc') { $params['start'] = - 1; $params['count_total'] = 'N'; for ($i = 0; $i < $req_count; $i ++) { $last_result = '$result[' . ($i - 1) . ']'; if ($sub_array) { $last_result .= '[' . $sub_array . ']'; } $last_result .= '[49][id]'; $params['filter']['>id'] = $i ? $last_result : 0; $req_list[$i] = [ 'method' => $method, 'params' => $params, ]; } } // List with counting else { for ($i=0; $i < $req_count; $i++) { $next = $i * 50; $params['start'] = $next; $req_list[$i] = [ 'method' => $method, 'params' => $params, ]; } } $resp = self::batch($req_list); foreach ($resp[self::BATCH_RESP_RESULT] as $step_list) { if ($sub_array) { $step_list = $step_list[$sub_array]; } if (is_array($step_list)) { foreach ($step_list as $item) { if ( ! $limit || $i < $limit) { $list[] = $item; $i ++; } } } } } return $list; } public static function getBgrRequestSecret() { $secret = Settings::get('bgr_request_secret'); if (!$secret) { $secret = md5(time()); Settings::save('bgr_request_secret', $secret); } return $secret; } /** * Send request on background */ public static function sendBgrRequest($uri, $data) { $success = false; $data['secret_key'] = self::getBgrRequestSecret(); $data['log_label'] = FileLog::getLabel(); $app_info = self::getAppInfo(); $site = $app_info['site']; $url_info = parse_url($site); $is_https = $url_info['scheme'] == 'https' ? true : false; $server = $url_info['host']; $query_url = ($is_https ? 'https://' : 'http://') . $server . $uri; $query_data = http_build_query($data); // FileLog::put('(Rest::sendBgrRequest) query ' . $query_url . '?' . $query_data); if ($server) { $try_limit = Settings::get('bgr_req_repeat_cnt') ? : 1; for ($i=1; $i<=$try_limit && !$success; $i++) { $curl = curl_init(); $curl_opts = [ CURLOPT_POST => true, CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_URL => $query_url, CURLOPT_POSTFIELDS => $query_data, CURLOPT_FRESH_CONNECT => true, ]; if (self::isStoreEventsBgrRunEnabled()) { $timeout = (int)Settings::get('curl_bgr_timeout') ? : 5; $curl_opts[CURLOPT_TIMEOUT] = $timeout; } curl_setopt_array($curl, $curl_opts); curl_exec($curl); $info = curl_getinfo($curl); $success = ((int)$info['http_code'] < 300) && ($info['request_size'] > 0); FileLog::put('(Rest::sendBgrRequest) response ' . (! $success ? 'failure' : 'success')); if (!$success) { FileLog::put('(Rest::sendBgrRequest) info ' . print_r($info, true)); } curl_close($curl); } } return $success; } public static function checkConnection() { $res = false; if (Rest::getAppInfo() && Rest::getAuthInfo()) { $res = true; } return $res; } public static function updateDBConnection() { $config = Application::getConnection()->getConfiguration(); $link = mysqli_connect($config['host'], $config['login'], $config['password'], $config['database']); if ($link) { mysqli_close($link); } } }