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/main/classes/general/ |
Upload File : |
<?php use Bitrix\Main\Security\Random; IncludeModuleLangFile(__FILE__); class CControllerClient { public static function IsInCommonKernel() { return file_exists($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/classes/general/update_db_updater.php"); } // Controller's authentication public static function OnExternalLogin(&$arParams) { global $USER, $APPLICATION; $FORMAT_DATE = false; $ar_mem = null; $prefix = COption::GetOptionString("main", "auth_controller_prefix", "controller"); if ( ($prefix != '' && str_starts_with(mb_strtolower($arParams["LOGIN"]), $prefix . '\\')) || ($prefix == '' && !str_contains($arParams["LOGIN"], "\\")) ) { $site = $prefix; if ($prefix == '') { $login = $arParams["LOGIN"]; } else { $login = mb_substr($arParams["LOGIN"], mb_strlen($prefix) + 1); } $password = $arParams["PASSWORD"]; $arVars = ["login" => $login, "password" => $password]; $oRequest = new CControllerClientRequestTo("check_auth", $arVars); $oResponse = $oRequest->SendWithCheck(); if (!$oResponse) { return false; } if (!$oResponse->OK()) { $e = new CApplicationException(GetMessage("MAIN_CMEMBER_ERR1") . ": " . $oResponse->text); $APPLICATION->ThrowException($e); return false; } $arUser = $oResponse->arParameters['USER_INFO']; } elseif ( COption::GetOptionString("main", "auth_controller_sso", "N") == "Y" && mb_strpos($arParams["LOGIN"], "\\") > 0 ) { $site = mb_substr($arParams["LOGIN"], 0, mb_strpos($arParams["LOGIN"], "\\")); $login = mb_substr($arParams["LOGIN"], mb_strpos($arParams["LOGIN"], "\\") + 1); $password = $arParams["PASSWORD"]; $arVars = ["login" => $login, "password" => $password, "site" => $site]; $oRequest = new CControllerClientRequestTo("remote_auth", $arVars); $oResponse = $oRequest->SendWithCheck(); if (!$oResponse) { return false; } if (!$oResponse->OK()) { $e = new CApplicationException(GetMessage("MAIN_CMEMBER_ERR1") . ": " . $oResponse->text); $APPLICATION->ThrowException($e); return false; } $arUser = $oResponse->arParameters['USER_INFO']; } elseif ( COption::GetOptionString("controller", "auth_controller_enabled", "N") === "Y" && mb_strpos($arParams["LOGIN"], "\\") > 0 && CModule::IncludeModule("controller") ) { $site = mb_substr($arParams["LOGIN"], 0, mb_strpos($arParams["LOGIN"], "\\")); $login = mb_substr($arParams["LOGIN"], mb_strpos($arParams["LOGIN"], "\\") + 1); $password = $arParams["PASSWORD"]; $url = mb_strtolower(trim($site, " \t\r\n./")); if (!str_starts_with($url, "http://") && !str_starts_with($url, "https://")) { $url = ["http://" . $url, "https://" . $url]; } $dbr_mem = CControllerMember::GetList( [], [ "=URL" => $url, "=DISCONNECTED" => "N", "=ACTIVE" => "Y", ] ); $ar_mem = $dbr_mem->Fetch(); if (!$ar_mem) { return false; } $res = CControllerMember::CheckUserAuth($ar_mem["ID"], $login, $password); if (!is_array($res)) { return false; } $arUser = $res['USER_INFO']; if (is_array($arUser)) { $arUser["CONTROLLER_ADMIN"] = "N"; } if (isset($res["FORMAT_DATE"])) { $FORMAT_DATE = $res["FORMAT_DATE"]; } } else { return false; } //////////////////////////////////////////////////////// /// сравнивать не просто логин, а полностью\логин ///////////////////////// if (is_array($arUser) && mb_strtolower($arUser['LOGIN']) == mb_strtolower($login)) { //When user did not fill any inforamtion about //we'll use first part of his e-mail like login if ($arUser["NAME"] == '' && $arUser["SECOND_NAME"] == '') { if (preg_match("/^(.+)@/", $arUser["LOGIN"], $match)) { $arUser["NAME"] = $match[1]; } else { $arUser["NAME"] = $arUser["LOGIN"]; } } if ($site != '') { $arUser['LOGIN'] = $site . "\\" . $arUser['LOGIN']; } $USER_ID = CControllerClient::UpdateUser($arUser, $FORMAT_DATE); if ($arUser["CONTROLLER_ADMIN"] == "Y") { AddEventHandler("main", "OnAfterUserLogin", ["CControllerClient", "OnAfterUserLogin"]); $arParams["CONTROLLER_ADMIN"] = "Y"; } $arParams["REMEMBER"] = "N"; if ( $ar_mem && $USER_ID && class_exists("\\Bitrix\\Controller\\AuthLogTable") && \Bitrix\Controller\AuthLogTable::isEnabled() ) { \Bitrix\Controller\AuthLogTable::logSiteToControllerAuth( $ar_mem["ID"], $USER_ID, true, 'CONTROLLER_MEMBER', $arUser['NAME'] . ' ' . $arUser['LAST_NAME'] . ' (' . $arUser['LOGIN'] . ')' )->isSuccess(); } return $USER_ID; } return false; } public static function OnAfterUserLogin($arParams) { global $USER; if ($arParams["CONTROLLER_ADMIN"] === "Y") { $USER->SetControllerAdmin(); } } public static function UpdateUser($arFields = [], $FORMAT_DATE = false) { global $DB; $arFields["ACTIVE"] = "Y"; $arFields["PASSWORD"] = Random::getString(32); $oUser = new CUser; unset($arFields["ID"]); unset($arFields["TIMESTAMP_X"]); unset($arFields["DATE_REGISTER"]); if ( isset($arFields["PERSONAL_BIRTHDAY"]) && $arFields["PERSONAL_BIRTHDAY"] != '' && $FORMAT_DATE !== false ) { $arFields["PERSONAL_BIRTHDAY"] = $DB->FormatDate($arFields["PERSONAL_BIRTHDAY"], $FORMAT_DATE, FORMAT_DATE); } $arFields['EXTERNAL_AUTH_ID'] = "__controller"; $dbr_user = CUser::GetList('', '', [ "LOGIN_EQUAL_EXACT" => $arFields["LOGIN"], "EXTERNAL_AUTH_ID" => "__controller", ]); if ($ar_user = $dbr_user->Fetch()) { $USER_ID = $ar_user["ID"]; if (is_array($arFields["GROUPS_TO_ADD"]) && is_array($arFields["GROUPS_TO_DELETE"])) { $arFields["GROUP_ID"] = CUser::GetUserGroup($USER_ID); foreach ($arFields["GROUPS_TO_DELETE"] as $group_id) { $group_id = CGroup::GetIDByCode($group_id); if ($group_id > 0) { $p = array_search($group_id, $arFields["GROUP_ID"]); if ($p !== false) { unset($arFields["GROUP_ID"][$p]); } } } foreach ($arFields["GROUPS_TO_ADD"] as $group_id) { $group_id = CGroup::GetIDByCode($group_id); if ($group_id > 0) { $arFields["GROUP_ID"][] = $group_id; } } } elseif (is_array($arFields["GROUP_ID"])) { $groups = $arFields["GROUP_ID"]; $arFields["GROUP_ID"] = []; foreach ($groups as $group_id) { $group_id = CGroup::GetIDByCode($group_id); if ($group_id > 0) { $arFields["GROUP_ID"][] = $group_id; } } } if (!$oUser->Update($USER_ID, $arFields)) { return false; } } else { $arFields["LID"] = SITE_ID; if (is_array($arFields["GROUP_ID"])) { $groups = $arFields["GROUP_ID"]; $arFields["GROUP_ID"] = []; foreach ($groups as $group_id) { $group_id = CGroup::GetIDByCode($group_id); if ($group_id > 0) { $arFields["GROUP_ID"][] = $group_id; } } } $USER_ID = $oUser->Add($arFields); } return $USER_ID; } public static function AuthorizeAdmin($arParams = []) { global $USER; if ($arParams["ID"] > 0) { $ADMIN_ID = $arParams["ID"]; } else { unset($arParams["GROUP_ID"]); $ADMIN_ID = CControllerClient::UpdateUser($arParams); } if ($ADMIN_ID > 0) { CUser::SetUserGroup($ADMIN_ID, [1]); $USER->Authorize($ADMIN_ID); $USER->SetControllerAdmin(); return $ADMIN_ID; } return false; } public static function AuthorizeUser($arParams = []) { global $USER; $USER_ID = CControllerClient::UpdateUser($arParams); if ($USER_ID > 0) { $USER->Authorize($USER_ID); return $USER_ID; } return false; } public static function OnExternalAuthList() { $arResult = [ [ "ID" => "__controller", "NAME" => GetMessage("MAIN_CMEMBER_AUTH_TYPE"), ], ]; return $arResult; } public static function PrepareUserInfo($arUser) { $arFields = [ "ID", "LOGIN", "NAME", "LAST_NAME", "EMAIL", "PERSONAL_PROFESSION", "PERSONAL_WWW", "PERSONAL_ICQ", "PERSONAL_GENDER", "PERSONAL_BIRTHDAY", "PERSONAL_PHONE", "PERSONAL_FAX", "PERSONAL_MOBILE", "PERSONAL_PAGER", "PERSONAL_STREET", "PERSONAL_MAILBOX", "PERSONAL_CITY", "PERSONAL_STATE", "PERSONAL_ZIP", "PERSONAL_COUNTRY", "PERSONAL_NOTES", "WORK_COMPANY", "WORK_DEPARTMENT", "WORK_POSITION", "WORK_WWW", "WORK_PHONE", "WORK_FAX", "WORK_PAGER", "WORK_STREET", "WORK_MAILBOX", "WORK_CITY", "WORK_STATE", "WORK_ZIP", "WORK_COUNTRY", "WORK_PROFILE", "WORK_NOTES", ]; $arSaveUser = []; foreach ($arFields as $key) { $arSaveUser[$key] = $arUser[$key]; } return $arSaveUser; } public static function SendMessage($name, $status = 'Y', $description = '') { // send to controller $arVars = [ "NAME" => $name, "STATUS" => $status, "DESCRIPTION" => $description, ]; $oRequest = new CControllerClientRequestTo("log", $arVars); if (!($oResponse = $oRequest->SendWithCheck())) { return false; } if (!$oResponse->OK()) { $e = new CApplicationException(GetMessage("MAIN_CMEMBER_ERR2") . ": " . $oResponse->text); $GLOBALS["APPLICATION"]->ThrowException($e); return false; } return null; } public static function InitTicket($controller_url) { // generating own member_id and temporary ticket $member_id = "m" . Random::getString(31); COption::SetOptionString("main", "controller_member_id", $member_id); $member_secret_id = "m" . Random::getString(31); COption::SetOptionString("main", "controller_member_secret_id", $member_secret_id); $ticket_id = "m" . Random::getString(31); COption::SetOptionString("main", "controller_ticket", time() . "|" . $ticket_id . "|" . $controller_url); COption::SetOptionString("main", "controller_url", $controller_url); return [$member_id, $member_secret_id, $ticket_id]; } public static function JoinToControllerEx($controller_url, $controller_login, $controller_password, $arMemberParams = []) { if (COption::GetOptionString("main", "controller_member", "N") == "Y") { return false; } if ($arMemberParams["URL"] == '') { $arMemberParams["URL"] = $_SERVER['HTTP_HOST']; } [, $member_secret_id, $ticket_id] = CControllerClient::InitTicket($controller_url); // send to controller $arVars = [ "member_secret_id" => $member_secret_id, "ticket_id" => $ticket_id, "admin_login" => $controller_login, "admin_password" => $controller_password, "url" => $arMemberParams["URL"], "name" => $arMemberParams["NAME"], "contact_person" => $arMemberParams["CONTACT_PERSON"], "email" => $arMemberParams["EMAIL"], "shared_kernel" => ($arMemberParams["SHARED_KERNEL"] ? "Y" : "N"), ]; if ($arMemberParams["CONTROLLER_GROUP"] > 0) { $arVars['group_id'] = $arMemberParams["CONTROLLER_GROUP"]; } $oRequest = new CControllerClientRequestTo("join", $arVars); if (!($oResponse = $oRequest->Send())) { return false; } if (!$oResponse->OK()) { $e = new CApplicationException(GetMessage("MAIN_CMEMBER_ERR3") . ": " . $oResponse->text); $GLOBALS["APPLICATION"]->ThrowException($e); return false; } COption::SetOptionString("main", "controller_member", "Y"); global $USER; $USER->Authorize($USER->GetID()); return true; } public static function JoinToController($controller_url, $controller_login, $controller_password, $site_url = false, $controller_group = false, $site_name = false, $bSharedKernel = false) { $arMemberParams = [ "URL" => $site_url, "NAME" => $site_name, "SHARED_KERNEL" => $bSharedKernel, "CONTROLLER_GROUP" => $controller_group, ]; return CControllerClient::JoinToControllerEx($controller_url, $controller_login, $controller_password, $arMemberParams); } public static function RemoveFromController($controller_login, $controller_password) { if (COption::GetOptionString("main", "controller_member", "N") != "Y") { return false; } // send to controller $arVars = [ "admin_login" => $controller_login, "admin_password" => $controller_password, ]; $oRequest = new CControllerClientRequestTo("remove", $arVars); if (!($oResponse = $oRequest->SendWithCheck())) { return false; } if (!$oResponse->OK()) { $e = new CApplicationException(GetMessage("MAIN_CMEMBER_ERR4") . ": " . $oResponse->text); $GLOBALS["APPLICATION"]->ThrowException($e); return false; } COption::SetOptionString("main", "controller_member", "N"); return true; } public static function UpdateCounters() { if (COption::GetOptionString("main", "controller_member", "N") != "Y") { //remove this agent when disconnected from the controller return ""; } else { $oRequest = new CControllerClientRequestTo("update_counters"); $oResponse = $oRequest->SendWithCheck(); if (!$oResponse) { throw new \Bitrix\Main\SystemException("CControllerClient::UpdateCounters: unknown error"); } elseif (!$oResponse->OK()) { throw new \Bitrix\Main\SystemException("CControllerClient::UpdateCounters: " . $oResponse->text); } return "CControllerClient::UpdateCounters();"; } } public static function ExecuteEvent($eventName, $arParams = []) { global $APPLICATION; if (COption::GetOptionString("main", "controller_member", "N") != "Y") { return null; } else { $APPLICATION->ResetException(); $oRequest = new CControllerClientRequestTo("execute_event", [ "event_name" => $eventName, "parameters" => $arParams, ]); $oResponse = $oRequest->SendWithCheck(); if (!$oResponse || !$oResponse->OK()) { $e = $APPLICATION ? $APPLICATION->GetException() : false; $errorMessage = is_object($e) ? ' ' . $e->GetString() : ''; if ($oResponse) { $errorMessage .= ' http headers: [' . $oResponse->httpHeaders . ']'; if ($oResponse->text) { $errorMessage .= ' http body: [' . substr($oResponse->text, 0, 200) . ']'; } } else { $errorMessage .= ' unknown error'; } trigger_error('CControllerClient::ExecuteEvent(' . $eventName . '):' . $errorMessage, E_USER_WARNING); } return $oResponse->arParameters['result']; } } public static function Unlink() { $disconnect_command = COption::GetOptionString("main", "~controller_disconnect_command", ""); if ($disconnect_command <> '') { eval($disconnect_command); } COption::SetOptionString("main", "controller_member", "N"); } public static function GetBackup($bRefresh = false) { static $arCachedData; if (!isset($arCachedData) || $bRefresh) { $arCachedData = unserialize(COption::GetOptionString("main", "~controller_backup", ""), ['allowed_classes' => false]); } return $arCachedData; } public static function SetBackup($arBackup) { COption::SetOptionString("main", "~controller_backup", serialize($arBackup)); CControllerClient::GetBackup(true); } public static function SetOptionString($module_id, $option_id, $value) { $arBackup = CControllerClient::GetBackup(); if (!is_set($arBackup["options"][$module_id], $option_id)) { $arBackup["options"][$module_id][$option_id] = COption::GetOptionString($module_id, $option_id, ""); CControllerClient::SetBackup($arBackup); } COption::SetOptionString($module_id, $option_id, $value); } public static function RestoreOption($module_id, $option_id) { $arBackup = CControllerClient::GetBackup(); if (is_set($arBackup["options"][$module_id], $option_id)) { COption::SetOptionString($module_id, $option_id, $arBackup["options"][$module_id][$option_id]); unset($arBackup["options"][$module_id][$option_id]); CControllerClient::SetBackup($arBackup); return true; } return false; } public static function SetModules($arModules) { $arInstalled = []; $arm = CModule::_GetCache(); foreach ($arm as $module_id => $tr) { $arInstalled[] = $module_id; } $arBackup = CControllerClient::GetBackup(); if (!isset($arBackup["modules"])) { $arBackup["modules"] = $arInstalled; CControllerClient::SetBackup($arBackup); } foreach ($arModules as $module_id => $status) { if (!($oModule = CModule::CreateModuleObject($module_id))) { continue; } if ($status == "Y" && !in_array($module_id, $arInstalled)) { if (!method_exists($oModule, "InstallDB") || $oModule->InstallDB() === false) { $oModule->Add(); } } elseif ($status == "N" && in_array($module_id, $arInstalled)) { $oModule->Remove(); } } return true; } public static function RestoreModules() { $arBackup = CControllerClient::GetBackup(); if (isset($arBackup["modules"])) { $oModule = new CModule(); $arWasInstalled = $arBackup["modules"]; $arNowInstalled = []; $arm = CModule::_GetCache(); foreach ($arm as $module_id => $tr) { $arNowInstalled[] = $module_id; } foreach ($arNowInstalled as $module_id) { if (!in_array($module_id, $arWasInstalled)) { $oModule->MODULE_ID = $module_id; $oModule->Remove(); } else { unset($arWasInstalled[array_search($module_id, $arWasInstalled)]); } } foreach ($arWasInstalled as $module_id) { $oModule->MODULE_ID = $module_id; $oModule->Add(); } unset($arBackup["modules"]); CControllerClient::SetBackup($arBackup); } } public static function RestoreGroupSecurity($group_code, $arModules) { if (($group_id = CGroup::GetIDByCode($group_code)) <= 0) { return false; } $arBackup = CControllerClient::GetBackup(); $old_settings = $arBackup["security"][$group_code]; if (!isset($old_settings)) { return null; } foreach ($old_settings as $module_id => $level) { if (!in_array($module_id, $arModules)) { continue; } CGroup::SetModulePermission($group_id, $module_id, $level); unset($arBackup["security"][$group_code][$module_id]); } CControllerClient::SetBackup($arBackup); return null; } public static function SetTaskSecurity($task_id, $module_id, $arOperations, $letter = '') { $ID = 0; $dbr_task = CTask::GetList([], ['NAME' => $task_id, 'MODULE_ID' => $module_id, "BINDING" => 'module']); if ($ar_task = $dbr_task->Fetch()) { if ($ar_task['SYS'] == 'Y') { return false; } $ID = $ar_task['ID']; } $arFields = [ "NAME" => $task_id, "LETTER" => $letter, "BINDING" => 'module', "MODULE_ID" => $module_id, ]; if ($ID > 0) { $res = CTask::Update($arFields, $ID); } else { $ID = CTask::Add($arFields); $res = ($ID > 0); if ($res) { $arBackup = CControllerClient::GetBackup(); $arBackup['security_task'][] = $ID; CControllerClient::SetBackup($arBackup); } } if ($res) { CTask::SetOperations($ID, $arOperations, true); } return null; } public static function SetGroupSecurity($group_code, $arPermissions, $arSubGroups = false) { if (($group_id = CGroup::GetIDByCode($group_code)) <= 0) { return false; } $arBackup = CControllerClient::GetBackup(); foreach ($arPermissions as $module_id => $level) { if (!is_set($arBackup["security"][$group_code], $module_id)) { $arBackup["security"][$group_code][$module_id] = CGroup::GetModulePermission($group_id, $module_id); } CGroup::SetModulePermission($group_id, $module_id, $level); } if (is_array($arSubGroups)) { $arSubordGroupID = []; foreach ($arSubGroups as $sub_group_id) { $sub_group_id = CGroup::GetIDByCode($sub_group_id); if ($sub_group_id > 0) { $arSubordGroupID[] = $sub_group_id; } } if (!is_set($arBackup["security_subord_groups"], $group_code)) { $arBackup["security_subord_groups"][$group_code] = CGroup::GetSubordinateGroups($group_id); } CGroup::SetSubordinateGroups($group_id, $arSubordGroupID); } CControllerClient::SetBackup($arBackup); return null; } public static function RestoreSecurity($arExcludeGroups = []) { $arBackup = CControllerClient::GetBackup(); if (!is_array($arBackup)) { return true; } if (is_array($arBackup["security"])) { foreach ($arBackup["security"] as $group_code => $perms) { if (in_array($group_code, $arExcludeGroups)) { continue; } if (($group_id = CGroup::GetIDByCode($group_code)) > 0) { foreach ($perms as $module_id => $level) { CGroup::SetModulePermission($group_id, $module_id, $level); } if (isset($arBackup["security_subord_groups"][$group_code])) { CGroup::SetSubordinateGroups($group_id, $arBackup["security_subord_groups"][$group_code]); } } unset($arBackup["security"][$group_code]); unset($arBackup["security_subord_groups"][$group_code]); } if (empty($arBackup["security"])) { unset($arBackup["security"]); } CControllerClient::SetBackup($arBackup); } return true; } public static function RestoreAll() { $arBackup = CControllerClient::GetBackup(); if (!is_array($arBackup)) { return true; } if (is_array($arBackup["options"])) { foreach ($arBackup["options"] as $module_id => $options) { foreach ($options as $option_id => $option_value) { COption::SetOptionString($module_id, $option_id, $option_value); } } } CControllerClient::RestoreModules(); CControllerClient::RestoreSecurity(); if (is_array($arBackup['security_task'])) { foreach ($arBackup['security_task'] as $task_id) { CTask::Delete($task_id); } } CControllerClient::SetBackup([]); return true; } public static function GetInstalledOptions($module_id) { $arOptions = CControllerClient::GetBackup(); $arOptions = $arOptions["options"][$module_id] ?? []; return $arOptions; } public static function RunCommand($command, $oRequest, $oResponse) { global $APPLICATION, $USER, $DB; return eval($command); } } /** * Class __CControllerPacket * * Base class for various types of packets. */ class __CControllerPacket { public $debug_const = ''; public $debug_file_const = ''; var $member_id; var $session_id; var $version; var $strParameters = ""; var $arParameters = []; var $hash; var $secret_id; var $encoding; /** * Returns true if debug is enabled. * * @return boolean */ public function isDebugEnabled() { if ( $this->debug_const && defined($this->debug_const) && constant($this->debug_const) === true ) { return true; } else { return false; } } /** * Returns debug logs directory. * You may define constant CONTROLLER_CLIENT_LOG_DIR. * It's value must end with directory delimiter. * By default, logging will be into /bitrix/controller_logs/ directory * under the DOCUMENT_ROOT. * * @return string */ public function getDebugLogDirectory() { if ($this->debug_file_const && defined($this->debug_file_const)) { return (string)constant($this->debug_file_const); } else { return $_SERVER['DOCUMENT_ROOT'] . '/bitrix/controller_logs/'; } } /** * Returns log file name. * It's equal to session identifier or if there is no session it's randomized. * * @return string */ public function getDebugLogFileName() { if ($this->session_id) { return $this->session_id . ".log"; } else { return "gen_" . Random::getString(32) . ".log"; } } /** * Writes given information into log file. * * @param string|array $sText Text to write to log. * * @return void * @see __CControllerPacket::isDebugEnabled * @see __CControllerPacket::getDebugLogDirectory * @see __CControllerPacket::getDebugLogFileName */ public function Debug($sText) { if (!$this->isDebugEnabled()) { return; } $filename = $this->getDebugLogDirectory() . $this->getDebugLogFileName(); ignore_user_abort(true); CheckDirPath($filename); file_put_contents($filename, date("Y-m-d H:i:s") . " - " . (is_array($sText) ? print_r($sText, true) : $sText) . "\n----------\n", FILE_APPEND | LOCK_EX); ignore_user_abort(false); } /** * Unpacks $parameters and converts it using given $encoding into site charset. * Preserves "file" member of the array. * * @param string $parameters Serialized data. * @param string $encoding Encoding character set identifier. * * @return mixed|null */ protected function unpackParameters($parameters, $encoding = '') { if (CheckSerializedData($parameters)) { $arParameters = unserialize($parameters, ['allowed_classes' => false]); if ($encoding) { if (is_array($arParameters) && array_key_exists("file", $arParameters)) { $file = $arParameters["file"]; unset($arParameters["file"]); $this->_decode($arParameters, $encoding, SITE_CHARSET); $arParameters["file"] = $file; } else { $this->_decode($arParameters, $encoding, SITE_CHARSET); } } return $arParameters; } return null; } /** * Recursively converts arParameter character set. * * @param array &$arParameters Input/Output parameter. * @param string $encodingFrom Encoding character set identifier. * @param string $encodingTo Encoding character set identifier. * * @return void */ protected function _decode(&$arParameters, $encodingFrom, $encodingTo) { $arParameters = \Bitrix\Main\Text\Encoding::convertEncoding($arParameters, $encodingFrom, $encodingTo); } /** * Checks given parameters signature against $hash member. * * @param string $parameter,... Parameter to be checked * * @return boolean */ public function Check() { global $APPLICATION; $hash = implode("|", func_get_args()); $md5hash = md5($hash); if ($md5hash != $this->hash) { if (is_object($APPLICATION)) { $e = new CApplicationException("Hash check failed: hash(" . $hash . ")=" . $md5hash . " != " . $this->hash); $APPLICATION->ThrowException($e); } return false; } return true; } /** * Returns signature for given parameters. * Sets $hash member with calculated value. * * @param string $parameter,... Parameter to be checked * * @return boolean */ function Sign() { $hash = implode("|", func_get_args()); $this->hash = md5($hash); return $this->hash; } } /////////////////////////////////////////////////////////////////////////////////////////// // Базовый класс для классов типа Request: // // Для использования на контроллере: // CControllerServerRequestTo - Класс для отправки запроса клиенту // CControllerServerRequestFrom - Класс для получения запроса от клиента // // Для использования на клиенте: // CControllerClientRequestTo - Класс для отправки запроса на сервер // CControllerClientRequestFrom - Класс для получения запроса от сервера /////////////////////////////////////////////////////////////////////////////////////////// class __CControllerPacketRequest extends __CControllerPacket { public $operation; protected $hostname = ''; /////////////////////////////////// //Для работы в классах получающих результаты (CControllerClientRequestFrom, CControllerServerRequestFrom): /////////////////////////////////// // заполняет объект переменными, пришедшими в $_REQUEST public function InitFromRequest() { $this->member_id = $_REQUEST['member_id']; $this->session_id = $_REQUEST['session_id']; $this->operation = $_REQUEST['operation']; if (isset($_REQUEST['version'])) { $this->version = $_REQUEST['version']; } if (isset($_REQUEST['encoding'])) { $this->encoding = $_REQUEST['encoding']; } if (isset($_REQUEST['parameters'])) { $this->strParameters = base64_decode($_REQUEST['parameters']); $arParameters = $this->unpackParameters($this->strParameters, $_REQUEST['encoding'] ?? ''); if ($arParameters) { $this->arParameters = $arParameters; } } $this->hash = $_REQUEST['hash']; } /** * Checks packet consistency. * * @return boolean * @see __CControllerPacket::Check */ public function Check() { return parent::Check($this->operation, $this->strParameters, $this->secret_id); } /** * Sets $hash member with calculated value. * * @return void */ public function Sign() { parent::Sign($this->operation, serialize($this->arParameters), $this->secret_id); } /** * Check if it was internal call or browser redirect. * * @return boolean **/ public function Internal() { return !empty($_POST); } /////////////////////////////////////// // Для работы в классах отправляющих запросы (CControllerClientRequestTo, CControllerServerRequestTo): /////////////////////////////////////// /** * Returns url encoded and signed string of parameters. * * @return string **/ public function MakeRequestString() { $result = "operation=" . $this->operation . "&version=" . $this->version . "&session_id=" . $this->session_id . "&member_id=" . urlencode($this->member_id) . "&encoding=" . urlencode(SITE_CHARSET); if (is_array($this->arParameters)) { $result .= "¶meters=" . urlencode(base64_encode(serialize($this->arParameters))); } $this->Sign(); $result .= "&hash=" . urlencode($this->hash); return $result; } /** * Asks user browser to do redirect. * And thus make a hit with all needed payload. * * @return void **/ public function RedirectRequest($url) { if (mb_strpos($url, "?") > 0) { $url .= '&'; } else { $url .= '?'; } $url .= $this->MakeRequestString(); if ($this->isDebugEnabled()) { $this->Debug([ __FILE__ . ":" . __LINE__, "Request by redirect", "url" => $url, "Packet" => $this, ]); } LocalRedirect($url, true); } /** * Sends packet. * * @param string $url * @param string $page * @return false | __CControllerPacketResponse */ public function Send($url = "", $page = "") { global $APPLICATION; $server_port = 80; $server_name = mb_strtolower(trim($url, "/ \r\n\t")); if (str_starts_with($server_name, 'http://')) { $server_name = substr($server_name, 7); } elseif (str_starts_with($server_name, 'https://')) { $server_name = substr($server_name, 8); $server_port = 443; } if (preg_match('/.+:([0-9]+)$/', $server_name, $matches)) { $server_port = $matches[1]; $server_name = substr($server_name, 0, 0 - strlen($server_port) - 1); } $proxy_url = CPageOption::GetOptionString("main", "controller_proxy_url"); $proxy_port = CPageOption::GetOptionString("main", "controller_proxy_port"); $bUseProxy = ($proxy_url <> '' && $proxy_port <> ''); if (!$bUseProxy) { $proxy_url = COption::GetOptionString("main", "controller_proxy_url", ""); $proxy_port = COption::GetOptionString("main", "controller_proxy_port", ""); $bUseProxy = ($proxy_url <> '' && $proxy_port <> ''); } // соединяемся с удаленным сервером if ($bUseProxy) { $proxy_port = intval($proxy_port); if ($proxy_port <= 0) { $proxy_port = 80; } $requestIP = $proxy_url; $requestPort = $proxy_port; } elseif ($this->hostname) { $requestIP = $this->hostname; $requestPort = $server_port; } else { $requestIP = $server_name; $requestPort = $server_port; } $conn = @fsockopen(($requestPort == 443 ? 'ssl://' : '') . $requestIP, $requestPort, $errno, $errstr, 30); if (!$conn) { if ($this->isDebugEnabled()) { $this->Debug([ __FILE__ . ":" . __LINE__, "We can't send request to the $server_name:$server_port from member#" . $this->member_id, "errno" => $errno, "errstr" => $errstr, "Packet" => $this, ]); } if (is_object($APPLICATION)) { $strError = GetMessage("MAIN_CMEMBER_ERR5") . $server_name . ":" . $server_port . " (" . $errstr . ")"; $e = new CApplicationException(htmlspecialcharsex($strError)); $APPLICATION->ThrowException($e); } return false; } $strVars = $this->MakeRequestString(); if ($bUseProxy) { $strRequest = "POST http://" . $server_name . ":" . $server_port . $page . " HTTP/1.0\r\n"; $proxy_user = COption::GetOptionString("main", "controller_proxy_user", ""); $proxy_password = COption::GetOptionString("main", "controller_proxy_password", ""); if ($proxy_user <> '') { $strRequest .= "Proxy-Authorization: Basic " . base64_encode($proxy_user . ":" . $proxy_password) . "\r\n"; } } else { $strRequest = "POST " . $page . " HTTP/1.0\r\n"; } $strRequest .= "User-Agent: BitrixControllerMember\r\n"; $strRequest .= "Accept: */*\r\n"; $strRequest .= "Host: " . $server_name . "\r\n"; $strRequest .= "Accept-Language: en\r\n"; $strRequest .= "Content-type: application/x-www-form-urlencoded\r\n"; $strRequest .= "Content-length: " . mb_strlen($strVars) . "\r\n\r\n"; $strRequest .= $strVars . "\r\n"; if ($this->isDebugEnabled()) { $this->Debug([ __FILE__ . ":" . __LINE__, "We send request to the $server_name:$server_port from member#" . $this->member_id, "strVars" => $strVars, "Packet" => $this, ]); } fputs($conn, $strRequest); $header = ''; while (($line = fgets($conn, 4096)) && $line != "\r\n") { $header .= $line; } $result = ''; while ($line = fread($conn, 4096)) { $result .= $line; } fclose($conn); $packet_result = new __CControllerPacketResponse(); $packet_result->httpHeaders = $header; $packet_result->secret_id = $this->secret_id; $packet_result->ParseResult($result); if ($this->isDebugEnabled()) { $this->Debug([ __FILE__ . ":" . __LINE__, "We get response from $server_name:$server_port to member#" . $packet_result->member_id, "secret_id" => $this->secret_id, "result" => $result, "Packet security check" => ($packet_result->Check() ? "passed" : "failed"), "Packet" => $packet_result, ]); } return $packet_result; } } ///////////////////////////////////////////////////////// // Базовый класс для классов типа Response: // // Для использования на контроллере: // CControllerServerResponseFrom - Класс для получения ответа клиента на сервере // CControllerServerResponseTo - Класс для отправки результатов выполнения запроса назад на клиента // // Для использования на клиенте: // CControllerClientResponseFrom - Класс для получения ответа контроллера на клиенте // CControllerClientResponseTo - Класс для отправки результатов выполнения запроса назад на контроллер ////////////////////////////////////////////////////////// class __CControllerPacketResponse extends __CControllerPacket { public $httpHeaders; public $status; public $text; function _InitFromRequest($oPacket, $arExclude = ['operation', 'arParameters']) { if (is_object($oPacket)) { $vars = get_object_vars($oPacket); foreach ($vars as $name => $value) { if (!in_array($name, $arExclude)) { $this->$name = $value; } } } } ////////////////////////////////////////////// // Методы для работы в классах принимающих результат (CControllerServerResponseFrom, CControllerClientResponseFrom): ////////////////////////////////////////////// /** * Checks packet consistency. * * @return boolean * @see __CControllerPacket::Check */ function Check() { return parent::Check($this->status, $this->text, $this->strParameters, $this->secret_id); } /** * Sets $hash member with calculated value. * * @return void */ function Sign() { parent::Sign($this->status, $this->text, serialize($this->arParameters), $this->secret_id); } // Возвращает успешно ли выполнился запрос по статус его ответа function OK() { return (str_starts_with($this->status, "2")); } // Разбирает строку ответа по полям объекта function ParseResult($result) { $ar_result = []; $pairs = explode('&', trim($result, " \n\r\t")); foreach ($pairs as $pair) { [$name, $value] = explode('=', $pair, 2); $ar_result[$name] = $value; } $this->session_id = urldecode($ar_result['session_id']); $this->member_id = urldecode($ar_result['member_id']); $this->hash = urldecode($ar_result['hash']); $this->status = urldecode($ar_result['status']); $this->text = urldecode($ar_result['text']); if (isset($ar_result['encoding'])) { $this->encoding = urldecode($ar_result['encoding']); } $this->strParameters = base64_decode(urldecode($ar_result['parameters'])); $arParameters = $this->unpackParameters($this->strParameters, $_REQUEST['encoding'] ?? ''); if ($arParameters) { $this->arParameters = $arParameters; if (isset($ar_result['encoding'])) { if ($this->text) { $this->text = \Bitrix\Main\Text\Encoding::convertEncoding($this->text, $this->encoding, SITE_CHARSET); } } } $this->version = $ar_result['version']; if ( $this->status == '' && $this->text == '' && $this->member_id == '' ) { $this->status = "479"; $this->text = GetMessage("MAIN_CMEMBER_ERR7") . " " . mb_substr($result, 0, 1000); } } /////////////////////////////////////// // Базовые методы для использования в классах отправляющих результат (CControllerServerResponseTo, CControllerClientResponseTo): /////////////////////////////////////// // возвращает отформатированную строку ответа в формате понятном для приема на сервере, с подписью function GetResponseBody($log = false) { $result = "status=" . urlencode($this->status) . "&text=" . urlencode($this->text) . "&version=" . urlencode($this->version) . "&session_id=" . urlencode($this->session_id) . "&member_id=" . urlencode($this->member_id) . "&encoding=" . urlencode(SITE_CHARSET); $result .= "¶meters=" . urlencode(base64_encode(serialize($this->arParameters))); $this->Sign(); $result .= "&hash=" . urlencode($this->hash); if ($log && $this->isDebugEnabled()) { $this->Debug([ __FILE__ . ":" . __LINE__, "We send errored response back", "result" => $result, "Packet" => $this, ]); } return $result; } // отправляет ответ обратно function Send() { if ($this->isDebugEnabled()) { $this->Debug([ __FILE__ . ":" . __LINE__, "We send response back", "response body" => $this->GetResponseBody(), "Packet" => $this, ]); } echo $this->GetResponseBody(); } } // Класс для отправки запроса на сервер class CControllerClientRequestTo extends __CControllerPacketRequest { var $debug_const = "CONTROLLER_CLIENT_DEBUG"; var $debug_file_const = "CONTROLLER_CLIENT_LOG_DIR"; public function __construct($operation, $arParameters = []) { $this->member_id = COption::GetOptionString("main", "controller_member_id", ""); $this->secret_id = COption::GetOptionString("main", "controller_member_secret_id", ""); $this->operation = $operation; $this->arParameters = $arParameters; $this->session_id = Random::getString(32); } function SendWithCheck($page = "/bitrix/admin/controller_ws.php") { $oResponse = $this->Send("", $page); if ($oResponse === false) { return false; } if (!$oResponse->Check()) { if (is_object($GLOBALS["APPLICATION"])) { $e = new CApplicationException(GetMessage("MAIN_CMEMBER_ERR6")); $GLOBALS["APPLICATION"]->ThrowException($e); } return false; } return $oResponse; } public function Send($url = "", $page = "/bitrix/admin/controller_ws.php") { $this->Sign(); $oResponsePacket = parent::Send(COption::GetOptionString("main", "controller_url", ""), $page); if ($oResponsePacket === false) { return false; } $oResponse = new CControllerClientResponseFrom($oResponsePacket); return $oResponse; } } // Класс получения результата на клиенте (от контроллера) class CControllerClientResponseFrom extends __CControllerPacketResponse { var $debug_const = "CONTROLLER_CLIENT_DEBUG"; var $debug_file_const = "CONTROLLER_CLIENT_LOG_DIR"; public function __construct($oPacket) { $this->_InitFromRequest($oPacket, []); } } class CControllerClientRequestFrom extends __CControllerPacketRequest { var $debug_const = "CONTROLLER_CLIENT_DEBUG"; var $debug_file_const = "CONTROLLER_CLIENT_LOG_DIR"; public function __construct() { $this->InitFromRequest(); $this->Debug([ "Request received from controller", "check" => ($this->Check() ? 'checked' : 'check failed'), "Packet" => $this, ]); } function Check() { $member_id = COption::GetOptionString("main", "controller_member_id", ""); if ($member_id == '' || $member_id != $this->member_id) { $e = new CApplicationException("Bad member_id: ((get)" . $member_id . "!=(own)" . $this->member_id . ")"); $GLOBALS["APPLICATION"]->ThrowException($e); return false; } $member_secret_id = COption::GetOptionString("main", "controller_member_secret_id", ""); $this->secret_id = $member_secret_id; return parent::Check(); } } // Класс для отсылки ответа на сервер class CControllerClientResponseTo extends __CControllerPacketResponse { var $debug_const = "CONTROLLER_CLIENT_DEBUG"; var $debug_file_const = "CONTROLLER_CLIENT_LOG_DIR"; public function __construct($oPacket = false) { $this->_InitFromRequest($oPacket); } } class CControllerTools { public static function PackFileArchive($path) { include_once(__DIR__ . '/tar_gz.php'); if (file_exists($path)) { $path = realpath($path); $arcname = CTempFile::GetFileName(Random::getString(32) . '.tar.gz'); CheckDirPath($arcname); $ob = new CArchiver($arcname); $rem_path = dirname($path); if ($ob->Add([$path], false, $rem_path)) { return $arcname; } } return false; } public static function UnpackFileArchive($strfile, $path_to) { global $APPLICATION; $res = true; $arcname = CTempFile::GetFileName(Random::getString(32) . '.tar.gz'); CheckDirPath($arcname); if (file_put_contents($arcname, $strfile) !== false) { include_once(__DIR__ . '/tar_gz.php'); $ob = new CArchiver($arcname); CheckDirPath($_SERVER['DOCUMENT_ROOT'] . $path_to); $res = $ob->extractFiles($_SERVER['DOCUMENT_ROOT'] . $path_to); if (!$res && is_object($APPLICATION)) { $arErrors = $ob->GetErrors(); if (!empty($arErrors)) { $strError = ""; foreach ($arErrors as $error) { $strError .= $error[1] . "<br>"; } $e = new CApplicationException($strError); $APPLICATION->ThrowException($e); } } } return $res; } }