Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/classes/general/ |
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/classes/general/site_checker.php |
<?php use Bitrix\Main\Application; class CSiteCheckerTest { const MIN_PHP_VER = '8.0.0'; public $arTestVars; public $percent; public $last_function; public $strCurrentTestName; public $strNextTestName; public $result; public $LogResourse; public $LogResult; public $group_name; public $group_desc; public $test_percent = 0; public $strError = ''; public $timeout = 10; // sec for one step public $strResult = ''; public $step; public $fix_mode; public $cafile; public $force_repair; public $host; public $ssl; public $port; public $arTest = []; public $function; public $LogFile; public function __construct($step = 0, $fast = 0, $fix_mode = 0) { $this->step = intval($step); if (!$this->step) { $this->arTestVars['site_checker_success'] = 'Y'; } $this->fix_mode = intval($fix_mode); $this->cafile = $_SERVER['DOCUMENT_ROOT'] . '/bitrix/tmp/cacert.pem'; $this->force_repair = defined('SITE_CHECKER_FORCE_REPAIR') && SITE_CHECKER_FORCE_REPAIR === true; $this->host = isset($_REQUEST['HTTP_HOST']) && $_REQUEST['HTTP_HOST'] ? $_REQUEST['HTTP_HOST'] : 'localhost'; if (!$fix_mode) // no need to know the host in fix mode { if (!preg_match('/^[a-z0-9.\-]+$/i', $this->host)) // cyrillic domain hack { $host = $this->host; $host0 = \Bitrix\Main\Text\Encoding::convertEncoding($host, 'utf8', 'cp1251'); if (preg_match("/[\xC0-\xFF]/", $host0)) { // utf-8; if (!defined('BX_UTF') || BX_UTF !== true) { $host = $host0; } } elseif (preg_match("/[\xC0-\xFF]/", $host)) { // windows-1251 if (defined('BX_UTF') && BX_UTF === true) { $host = \Bitrix\Main\Text\Encoding::convertEncoding($host, 'cp1251', 'utf8'); } } $converter = new CBXPunycode(); $host = $converter->Encode($host); $this->host = $host; } } $this->ssl = isset($_REQUEST['HTTPS']) && $_REQUEST['HTTPS'] == 'on'; $this->port = isset($_REQUEST['SERVER_PORT']) && $_REQUEST['SERVER_PORT'] ? $_REQUEST['SERVER_PORT'] : ($this->ssl ? 443 : 80); $arTestGroup = []; $arGroupName = []; $arGroupName[1] = IsModuleInstalled('intranet') ? GetMessage("MAIN_SC_GENERAL") : GetMessage("MAIN_SC_GENERAL_SITE"); $arGroupDesc[1] = GetMessage("MAIN_SC_REQUIRED_MODS_DESC"); $arTestGroup[1] = [ ['check_php_modules' => GetMessage('SC_T_MODULES')], ['check_php_settings' => GetMessage('SC_T_PHP')], ['check_security' => GetMessage('SC_T_APACHE')], ['check_server_vars' => GetMessage('SC_T_SERVER')], ['check_session' => GetMessage('SC_T_SESS')], ['check_mbstring' => GetMessage('SC_T_MBSTRING')], ['check_install_scripts' => GetMessage('SC_T_INSTALL_SCRIPTS')], ['check_socket' => GetMessage('SC_T_SOCK')], ['check_bx_crontab' => GetMessage("MAIN_SC_AGENTS_CRON")], ]; $arGroupName[2] = GetMessage("MAIN_SC_BUSINESS"); $arGroupDesc[2] = GetMessage("MAIN_SC_CORRECT_DESC"); $arTestGroup[2] = [ ['check_pull_stream' => GetMessage("MAIN_SC_TEST_PUSH_SERVER")], ['check_pull_comments' => GetMessage("MAIN_SC_TEST_COMMENTS")], ['check_turn' => GetMessage("MAIN_SC_TEST_VIDEO")], ['check_access_mobile' => GetMessage("MAIN_SC_TEST_MOBILE")], ['check_push_bitrix' => GetMessage("MAIN_SC_TEST_PUSH")], ['check_access_docs' => GetMessage("MAIN_SC_TEST_DOCS")], ['check_fast_download' => GetMessage("MAIN_SC_TEST_FAST_FILES_MSGVER_1")], ['check_search' => GetMessage("MAIN_SC_TEST_SEARCH_CONTENTS")], ['check_mail' => GetMessage("MAIN_SC_MAIL_TEST")], ['check_ca_file' => GetMessage("MAIN_SC_CLOUD_TEST")], ['check_connect_mail' => GetMessage("MAIN_SC_TEST_MAIL_INTEGRATION")], ['check_socnet' => GetMessage("MAIN_SC_TEST_SOCNET_INTEGRATION")], ['check_rest' => GetMessage("MAIN_SC_TEST_REST")], ['check_mail_push' => GetMessage("MAIN_SC_TEST_MAIL_PUSH")], ]; if (IsModuleInstalled('extranet')) { $arTestGroup[2][] = ['check_extranet' => GetMessage("MAIN_SC_EXTRANET_ACCESS")]; } $arGroupName[4] = GetMessage("MAIN_SC_WINDOWS_ENV"); $arGroupDesc[4] = ''; $arTestGroup[4] = [ ['check_webdav' => GetMessage("MAIN_SC_DOCS_EDIT_MS_OFFICE")], ['check_socket_ssl' => GetMessage("MAIN_SC_EXTERNAL_APPS_TEST")], ['check_ad' => GetMessage("MAIN_SC_TEST_LDAP")], ['check_ntlm' => GetMessage("MAIN_SC_TEST_NTLM")], ]; $arGroupName[8] = GetMessage("MAIN_SC_PERFORM"); $arGroupDesc[8] = ''; $arTestGroup[8] = [ ['check_perf' => GetMessage("MAIN_SC_PERF_TEST")], ['check_compression' => GetMessage("MAIN_SC_COMPRESSION_TEST")], ]; $arGroupName[16] = GetMessage('SC_GR_EXTENDED'); $arTestGroup[16] = [ ['check_dbconn_settings' => GetMessage('SC_T_DBCONN_SETTINGS')], ['check_dbconn' => GetMessage('SC_T_DBCONN')], ['check_session_ua' => GetMessage('SC_T_SESS_UA')], ['check_sites' => GetMessage('SC_T_SITES')], ['check_pcre_recursion' => GetMessage('SC_T_RECURSION')], ['check_upload' => GetMessage('SC_T_UPLOAD')], ['check_upload_big' => GetMessage('SC_T_UPLOAD_BIG')], ['check_upload_raw' => GetMessage('SC_T_UPLOAD_RAW')], ['check_post' => GetMessage('SC_T_POST')], ['check_mail' => GetMessage('SC_T_MAIL')], ['check_mail_big' => GetMessage('SC_T_MAIL_BIG')], ['check_mail_b_event' => GetMessage('SC_T_MAIL_B_EVENT')], ['check_localredirect' => GetMessage('SC_T_REDIRECT')], ['check_memory_limit' => GetMessage('SC_T_MEMORY')], ['check_cache' => GetMessage('SC_T_CACHE')], ['check_update' => GetMessage('SC_UPDATE_ACCESS')], ['check_http_auth' => GetMessage('SC_T_AUTH')], ['check_exec' => GetMessage('SC_T_EXEC')], ['check_getimagesize' => GetMessage('SC_T_GETIMAGESIZE')], ]; $arGroupName[32] = GetMessage('SC_GR_MYSQL'); $arTestGroup[32] = [ ['check_mysql_bug_version' => GetMessage('SC_T_MYSQL_VER')], ['check_mysql_time' => GetMessage('SC_T_TIME')], ['check_mysql_mode' => GetMessage('SC_T_SQL_MODE')], ['check_mysql_connection_charset' => GetMessage('SC_CONNECTION_CHARSET')], ['check_mysql_db_charset' => GetMessage('SC_DB_CHARSET')], ['check_mysql_table_format' => GetMessage('SC_T_FORMAT')], ['check_mysql_table_charset' => GetMessage('SC_T_CHARSET')], ['check_mysql_table_structure' => GetMessage('SC_T_STRUCTURE')], ]; $arGroupName[64] = GetMessage('SC_GR_MYSQL'); $arTestGroup[64] = [ ['check_pgsql_version' => GetMessage('SC_T_PGSQL_VER')], ['check_mysql_time' => GetMessage('SC_T_TIME')], ['check_pgsql_db_charset' => GetMessage('SC_DB_CHARSET')], ['check_pgsql_connection_charset' => GetMessage('SC_CONNECTION_CHARSET')], ]; if ($this->fix_mode) { switch ($this->fix_mode) { case 1: $this->arTest = [ ['check_mysql_table_status' => GetMessage('SC_T_CHECK')], ]; break; case 2: $this->arTest = [ ['check_mysql_connection_charset' => GetMessage('SC_CONNECTION_CHARSET')], ['check_mysql_db_charset' => GetMessage('SC_DB_CHARSET')], ['check_mysql_table_format' => GetMessage('SC_T_FORMAT')], ['check_mysql_table_charset' => GetMessage('SC_T_CHARSET')], ['check_mysql_table_structure' => GetMessage('SC_T_STRUCTURE')], ]; break; case 3: $this->arTest = [ ['check_mysql_table_structure' => GetMessage('SC_T_STRUCTURE')], ]; break; case 4: $this->arTest = [ ['check_mbstring' => GetMessage('SC_T_MBSTRING')], ]; break; default: $this->arTest = [ ['check_server_vars' => GetMessage('SC_T_SERVER')], ]; break; } } else { $profile = 1; if ($fast) { if (IsModuleInstalled('intranet')) { $profile |= 2; $profile |= 4; $profile |= 8; } } else { $profile |= 16; switch (\Bitrix\Main\Application::getConnection()->getType()) { case 'mysql': $profile |= 32; break; case 'pgsql': $profile |= 64; break; } } $this->arTest = []; $step0 = $step; foreach ($arTestGroup as $i => $ar) { if ($i & $profile) { if (!$this->group_name) { $c = count($ar); if ($step0 >= $c) { $step0 -= $c; } else { $this->group_name = $arGroupName[$i] ?? ''; $this->group_desc = $arGroupDesc[$i] ?? ''; } } $this->arTest = array_merge($this->arTest, $ar); } } } $this->function = key($this->arTest[$this->step]); $this->strCurrentTestName = current($this->arTest[$this->step]); $this->strNextTestName = $this->strCurrentTestName; $LICENSE_KEY = ''; if (file_exists($file = $_SERVER['DOCUMENT_ROOT'] . '/bitrix' . '/license_key.php')) { include($file); } if ($LICENSE_KEY == '') { $LICENSE_KEY = 'DEMO'; } if (!defined('LICENSE_HASH')) { define('LICENSE_HASH', md5('CONNECTION_TEST')); } $this->LogFile = '/bitrix' . '/site_checker_' . md5('SITE_CHECKER' . $LICENSE_KEY) . '.log'; } public static function GetTestList() { $ar = []; foreach (get_class_methods('CSiteCheckerTest') as $method) { if (str_starts_with($method, 'check_')) { $ar[] = $method; } } return $ar; } function Start() { $this->test_percent = 100; // by default ob_start(); try { if ($this->fix_mode && (!isset($this->arTestVars['start_function']) || $this->arTestVars['start_function'] != $this->function)) { // dummy hit to display zero progress $this->arTestVars['start_function'] = $this->function; $this->test_percent = 0; $this->result = true; } else { $this->result = call_user_func([$this, $this->function]); } } catch (Exception $e) { $this->Result(null, GetMessage("MAIN_SC_TEST_IS_INCORRECT")); echo $e->getMessage(); } $this->strError = ob_get_clean(); if (!$this->strResult) { $this->Result($this->result); } if (!$this->fix_mode) { // write to log if (@$this->OpenLog()) { $text = date('Y-M-d H:i:s') . ' ' . $this->strCurrentTestName . ' (' . $this->function . "): " . $this->LogResult . "\n"; if ($this->test_percent < 100) { $text .= $this->test_percent . '% done' . "\n"; } if ($this->strError) { $text .= str_replace('<br>', "\n", $this->strError) . "\n"; } if ($this->test_percent >= 100) // test finished { $text .= preg_replace('#<[^<>]+>#', '', $this->strResult) . "\n"; } $text = htmlspecialchars_decode($text); fwrite($this->LogResourse, $text); } } $this->last_function = $this->function; $this->percent = floor(($this->step + $this->test_percent / 100) / count($this->arTest) * 100); if ($this->test_percent >= 100) // test finished { if ($this->step + 1 < count($this->arTest)) { $this->step++; $this->test_percent = 0; $this->arTestVars['last_value'] = ''; $this->function = key($this->arTest[$this->step]); $this->strNextTestName = current($this->arTest[$this->step]); } else // finish { if (!$this->fix_mode) // if we have a kernel { COption::SetOptionString('main', 'site_checker_success', $this->arTestVars['site_checker_success'] ?? ''); if (isset($this->arTestVars['site_checker_success']) && $this->arTestVars['site_checker_success'] == 'Y') { CAdminNotify::DeleteByTag('SITE_CHECKER'); } } } } elseif ($this->result === true) { $this->strResult = ''; } // in case of temporary result on this step if ($this->result === false) { $this->arTestVars['site_checker_success'] = 'N'; } } function Result($result, $text = '') { if ($result === true) { $this->LogResult = 'Ok'; } elseif ($result === null) { $this->LogResult = 'Warning'; } else { $this->LogResult = 'Fail'; } if ($result === false) { $text = GetMessage('SC_ERROR0') . ' ' . ($text ?: GetMessage('SC_ERROR1')); } elseif ($result === null) { $text = GetMessage("MAIN_SC_SOME_WARNING") . '. ' . ($text ?: GetMessage('SC_WARN')); } else { $text = $text ?: GetMessage('SC_TEST_SUCCESS'); } $this->strResult = $text; return $result; } function OpenLog() { $continue = $this->step > 0; if (!$this->LogResourse = fopen($_SERVER['DOCUMENT_ROOT'] . $this->LogFile, $continue ? 'ab' : 'wb')) { $this->arTestVars['site_checker_success'] = 'N'; } return $this->LogResourse; } function ConnectToHost($host = false, $port = false, $ssl = false) { if (!$host) { if (!empty($this->arTestVars['check_socket_fail'])) { return $this->Result(null, GetMessage('SC_SOCK_NA')); } $host = $this->host; $port = $this->port; $ssl = $this->ssl ? 'ssl://' : ''; } echo "Connection to $ssl$host:$port "; $res = false; try { $res = fsockopen($ssl . $host, $port, $errno, $errstr, 5); } catch (Exception) { } if (!$res) { echo "Fail\n"; echo "Socket error [$errno]: $errstr" . "\n"; return $this->Result(false); } echo "Success\n"; return $res; } function Unformat($str) { $str = strtolower($str); $res = intval($str); $suffix = substr($str, -1); if ($suffix == "k") { $res *= 1024; } elseif ($suffix == "m") { $res *= 1048576; } elseif ($suffix == "g") { $res *= 1048576 * 1024; } elseif ($suffix == "b") { $res = self::Unformat(substr($str, 0, -1)); } return $res; } function TableFieldCanBeAltered($f, $f_tmp) { if ($f['Type'] == str_replace(['long', 'medium'], '', $f_tmp['Type']) || $this->force_repair) { return true; } if ( preg_match('#^([a-z]+)\(([0-9]+)\)(.*)$#i', $f['Type'], $regs) && preg_match('#^([a-z]+)\(([0-9]+)\)(.*)$#i', $f_tmp['Type'], $regs_tmp) && str_replace('varchar', 'char', strtolower($regs[1])) == str_replace('varchar', 'char', strtolower($regs_tmp[1])) && $regs[2] <= $regs_tmp[2] && $regs[3] == $regs_tmp[3] // signed || unsigned ) { return true; } return false; } ###### TESTS ####### # { # function check_php_modules() { $arMods = [ 'fsockopen' => GetMessage("SC_SOCKET_F"), 'xml_parser_create' => GetMessage("SC_MOD_XML"), 'preg_match' => GetMessage("SC_MOD_PERL_REG"), 'imagettftext' => "Free Type Text", 'gzcompress' => "Zlib", 'imagecreatetruecolor' => GetMessage("SC_MOD_GD"), 'imagecreatefromjpeg' => GetMessage("SC_MOD_GD_JPEG"), 'json_encode' => GetMessage("SC_MOD_JSON"), 'hash' => 'Hash', 'highlight_file' => 'PHP Syntax Highlight', ]; $strError = ''; foreach ($arMods as $func => $desc) { if (!function_exists($func)) { $strError .= $desc . "<br>"; } } if (!function_exists('openssl_encrypt')) { $strError .= GetMessage("MAIN_SC_MCRYPT") . ' OpenSSL'; } if (!function_exists('mb_substr')) { $strError .= GetMessage("SC_MOD_MBSTRING") . "<br>"; } if (!in_array('ssl', stream_get_transports())) { $strError .= GetMessage('ERR_NO_SSL') . '<br>'; } if ($strError) { return $this->Result(false, GetMessage('ERR_NO_MODS') . "<br>" . $strError); } if (IsModuleInstalled('intranet')) { if (!class_exists('DOMDocument') || !class_exists('ZipArchive')) { return $this->Result(null, GetMessage('ERR_NO_MODS_DOC_GENERATOR')); } } return $this->Result(true, GetMessage("MAIN_SC_ALL_MODULES")); } function check_php_settings() { $strError = ''; if (version_compare($v = phpversion(), self::MIN_PHP_VER, '<')) { $strError = GetMessage('SC_VER_ERR', ['#CUR#' => $v, '#REQ#' => self::MIN_PHP_VER]) . "<br>"; } $arRequiredParams = [ 'safe_mode' => 0, 'file_uploads' => 1, 'wincache.chkinterval' => 0, 'session.auto_start' => 0, 'magic_quotes_runtime' => 0, 'magic_quotes_sybase' => 0, 'magic_quotes_gpc' => 0, 'arg_separator.output' => '&', 'register_globals' => 0, 'zend.multibyte' => 0, ]; if (extension_loaded('xcache')) { $arRequiredParams['xcache.cacher'] = 0; $arRequiredParams['xcache.stat'] = 1; } foreach ($arRequiredParams as $param => $val) { $cur = ini_get($param); if (strtolower($cur) == 'on') { $cur = 1; } elseif (strtolower($cur) == 'off') { $cur = 0; } if ($cur != $val) { $strError .= GetMessage('SC_ERR_PHP_PARAM', ['#PARAM#' => $param, '#CUR#' => $cur ? htmlspecialcharsbx($cur) : 'off', '#REQ#' => $val ? 'on' : 'off']) . "<br>"; } } $param = 'opcache.revalidate_freq'; if (($cur = ini_get($param)) <> 0) { $strError .= GetMessage('SC_ERR_PHP_PARAM', ['#PARAM#' => $param, '#CUR#' => htmlspecialcharsbx($cur), '#REQ#' => '0']) . "<br>"; } $param = 'default_socket_timeout'; if (($cur = ini_get($param)) < 60) { $strError .= GetMessage('SC_ERR_PHP_PARAM', ['#PARAM#' => $param, '#CUR#' => htmlspecialcharsbx($cur), '#REQ#' => '60']) . "<br>"; } if (($m = ini_get('max_input_vars')) && $m < 10000) { $strError .= GetMessage('ERR_MAX_INPUT_VARS', ['#MIN#' => 10000, '#CURRENT#' => $m]) . "<br>"; } if (IsModuleInstalled('intranet')) { $vm = getenv('BITRIX_VA_VER'); if (!$vm) { $strError .= GetMessage('ERR_NO_VM') . "<br>"; } else { $last_version = '7.3.0'; $tmp = $_SERVER['DOCUMENT_ROOT'] . '/bitrix/tmp/bitrix-env.version'; if (!file_exists($tmp) || time() - filemtime($tmp) > 86400) { $ob = new CHTTP(); $ob->http_timeout = 5; $ob->Download('http://repos.1c-bitrix.ru/yum/bitrix-env.version', $tmp); } if (file_exists($tmp)) { $last_version_remote = str_replace('-', '.', file_get_contents($tmp)); if (version_compare($last_version_remote, $last_version, '>')) { $last_version = $last_version_remote; } } if (version_compare($vm, $last_version, '<')) { $strError .= GetMessage('ERR_OLD_VM', ['#CURRENT#' => $vm, '#LAST_VERSION#' => $last_version]) . "<br>"; } } } // check_divider $locale_info = localeconv(); $delimiter = $locale_info['decimal_point']; if ($delimiter != '.') { $strError .= GetMessage('SC_DELIMITER_ERR', ['#VAL#' => $delimiter]) . '<br>'; } // check_precision if (1234567891 != (string)doubleval(1234567891)) { $strError .= GetMessage("MAIN_SC_ERROR_PRECISION") . '<br>'; } // check_suhosin if (in_array('suhosin', get_loaded_extensions()) && !ini_get('suhosin.simulation')) { $strError .= GetMessage('SC_WARN_SUHOSIN', ['#VAL#' => ini_get('suhosin.simulation') ? 1 : 0]) . '<br>'; } // check_backtrack_limit $param = 'pcre.backtrack_limit'; $cur = self::Unformat(ini_get($param)); ini_set($param, $cur + 1); $new = ini_get($param); if ($new != $cur + 1) { $strError .= GetMessage("MAIN_SC_CANT_CHANGE") . '<br>'; } if ($strError) { return $this->Result(false, $strError); } return $this->Result(true, GetMessage("MAIN_SC_CORRECT_SETTINGS")); } function check_server_vars() { $strError = ''; [$host,] = explode(':', $_SERVER['HTTP_HOST'] ?? ''); if ($host != 'localhost' && !preg_match('#^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$#', $host)) { if (!preg_match('#^[a-z0-9\-.]{1,192}\.(xn--)?[a-z0-9]{2,63}$#i', $host)) { $strError .= GetMessage("SC_TEST_DOMAIN_VALID", ['#VAL#' => htmlspecialcharsbx($_SERVER['HTTP_HOST'] ?? '')]) . "<br>"; } } if ($strError) { return $this->Result(false, $strError); } return $this->Result(true, GetMessage("MAIN_IS_CORRECT")); } function check_mail($big = false) { $body = "Test message.\nDelete it."; if ($big) { $str = file_get_contents(__FILE__); if (!$str) { return $this->Result(false, GetMessage('SC_CHECK_FILES')); } $body = str_repeat($str, 2); } $startTime = microtime(true); if ($big) { $eol = \Bitrix\Main\Mail\Mail::getMailEol(); $val = mail("hosting_test@bitrixsoft.com", "Bitrix site checker" . $eol . "\tmultiline subject", $body, 'BCC: noreply@bitrixsoft.com'); } else { $val = mail("hosting_test@bitrixsoft.com", "Bitrix site checker", $body); } $endTime = microtime(true); $time = round($endTime - $startTime, 2); if ($val) { if ($time > 1) { return $this->Result($this->arTestVars['check_bx_crontab'] ? null : false, GetMessage('SC_SENT') . ' ' . $time . ' ' . GetMessage('SC_SEC')); } } else { return false; } return true; } function check_mail_big() { return $this->check_mail(true); } function check_mail_b_event() { global $DB, $CACHE_MANAGER; $res = $DB->Query("SELECT COUNT(1) AS A FROM b_event WHERE SUCCESS_EXEC = 'N'"); $f = $res->Fetch(); if ($f['A'] > 0) { $info = defined('BX_CRONTAB_SUPPORT') && BX_CRONTAB_SUPPORT ? '<br> ' . GetMessage('SC_CRON_WARN') : ''; if (CACHED_b_event !== false && $CACHE_MANAGER->Read(CACHED_b_event, "events")) { $info .= "<br> " . GetMessage('SC_CACHED_EVENT_WARN'); } return $this->Result(false, GetMessage('SC_T_MAIL_B_EVENT_ERR') . ' ' . $f['A'] . $info); } return true; } function check_connect_mail() { if (!CModule::IncludeModule('mail')) { return $this->Result(null, GetMessage("MAIN_SC_MAIL_IS_NOT_INSTALLED")); } $rs = CMailBox::GetList([], ['SERVER_TYPE' => 'imap']); if ($rs->Fetch()) { return true; } return $this->Result(null, GetMessage("MAIN_SC_MAIL_INTEGRATION")); } function check_socnet() { if (!CModule::IncludeModule('socialservices')) { return $this->Result(null, GetMessage("MAIN_SC_NO_SOCIAL_MODULE")); } $oAuthManager = new CSocServAuthManager(); $arActiveSocServ = $oAuthManager->GetActiveAuthServices([]); if (!empty($arActiveSocServ)) { if (is_array($arActiveSocServ['Bitrix24Net'])) { return true; } return $this->Result(null, GetMessage("MAIN_SC_NO_SOCIAL_SERVICES_24NET")); } return $this->Result(null, GetMessage("MAIN_SC_NO_SOCIAL_SERVICES")); } function check_rest() { if (!CModule::IncludeModule('rest')) { return $this->Result(null, GetMessage("MAIN_SC_NO_REST_MODULE")); } return true; } function check_mail_push() { $site = \Bitrix\Main\SiteTable::getList([ 'select' => ['LID', 'NAME', 'SERVER_NAME'], 'order' => ['DEF' => 'DESC', 'SORT' => 'ASC'], ])->fetch(); $domain = $site['SERVER_NAME'] ?: COption::getOptionString('main', 'server_name', ''); if (preg_match('/^(?<domain>.+):(?<port>\d+)$/', $domain, $matches)) { $domain = $matches['domain']; } if (!getmxrr($domain, $mxhosts) || !count($mxhosts)) { return $this->Result(null, GetMessage('SC_ERR_DNS', ['#DOMAIN#' => $domain])); } foreach ($mxhosts as $mx) { if ($mx != 'mail-001.bitrix24.com') { print_r($mxhosts); return $this->Result(null, GetMessage('SC_ERR_DNS_WRONG', ['#DOMAIN#' => $mx])); } } if (!$res = $this->ConnectToHost('mail-001.bitrix24.com', 25)) { return $this->Result(null, GetMessage('SC_ERR_CONNECT_MAIL001')); } echo fgets($res); fwrite($res, "HELO " . $domain . "\r\n"); echo fgets($res); fwrite($res, "MAIL FROM: sitecheckerfrom@" . $domain . "\r\n"); echo fgets($res); fwrite($res, "RCPT TO: rplsitecheckerto@" . $domain . "\r\n"); echo fgets($res); fwrite($res, "DATA\r\n"); echo fgets($res); fwrite($res, "From: sitecheckerfrom@" . $domain . "\r\n" . "To: rplsitecheckerto@" . $domain . "\r\n" . "Subject: Site checker mail test\r\n" . "Content-type: text/plain\r\n" . "MIME-Version: 1.0\r\n" . "\r\n" . ".\r\n"); echo($str = fgets($res)); fclose($res); if (preg_match('#\(Bad Request 400\)#i', $str)) { echo "Success\n"; return true; } return $this->Result(null, GetMessage('SC_ERR_TEST_MAIL_PUSH', ['#DOMAIN#' => $domain])); } function check_socket() { $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=socket_test&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; $retVal = false; if ($res = $this->ConnectToHost()) { $retVal = IsHttpResponseSuccess($res, $strRequest); } if (!$retVal) { $this->arTestVars['check_socket_fail'] = 1; } return $retVal; } function check_compression() { $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=compression&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "Accept-Encoding: gzip, deflate\r\n"; $strRequest .= "\r\n"; if (!$res = $this->ConnectToHost()) { return false; } $strRes = GetHttpResponse($res, $strRequest, $strHeaders); if (preg_match('#gzip|deflate#mi', $strHeaders) && strlen($strRes) < 64 * 1024) // comression not supported by server { return $this->Result(true, GetMessage("MAIN_SC_ENABLED_MOD")); } else { return $this->Result(false, GetMessage("MAIN_SC_COMP_DISABLED_MOD")); } } function check_socket_ssl() { if (!file_exists($this->cafile) || filesize($this->cafile) == 0) { return $this->Result(null, GetMessage("MAIN_SC_TEST_SSL1")); } if (!$context = stream_context_create( [ 'ssl' => [ 'verify_peer' => true, 'allow_self_signed' => false, 'cafile' => $this->cafile, ], ] )) { return false; } echo "Connection to ssl://{$this->host}:443 (certificate check enabled) "; if ($res = stream_socket_client('ssl://' . $this->host . ':443', $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $context)) { echo "Success\n"; fclose($res); return true; } echo "Fail\n"; if (!$context = stream_context_create( [ 'ssl' => [ 'verify_peer' => false, 'allow_self_signed' => true, 'cafile' => $this->cafile, ], ] )) { return false; } echo "Connection to ssl://{$this->host}:443 "; if ($res = stream_socket_client('ssl://' . $this->host . ':443', $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $context)) { echo "Success\n"; fclose($res); return $this->Result(null, GetMessage("MAIN_SC_SSL_NOT_VALID")); } echo "Fail\n"; return $this->Result(null, GetMessage("MAIN_SC_NO_CONNECTTO", ['#HOST#' => 'https://' . $this->host])); } function check_ad() { if (!CModule::IncludeModule('ldap')) { return $this->Result(null, GetMessage("MAIN_SC_NO_LDAP_MODULE")); } $rs = CLdapServer::GetList(); if (!$rs->Fetch()) { return $this->Result(null, GetMessage("MAIN_SC_NO_LDAP_INTEGRATION")); } return true; } function check_ntlm() { if (!CModule::IncludeModule('ldap')) { return $this->Result(null, GetMessage("MAIN_SC_NO_LDAP_MODULE")); } if (COption::GetOptionString('ldap', 'use_ntlm', 'N') != 'Y') { return $this->Result(null, GetMessage("MAIN_SC_OPTION_SWITCHED_OFF")); } if (COption::GetOptionString('ldap', 'bitrixvm_auth_support', 'N') == 'Y') { return true; } if (($ntlm_varname = COption::GetOptionString('ldap', 'ntlm_varname', 'REMOTE_USER')) && ($user = trim($_SERVER[$ntlm_varname]))) { return $this->Result(true, GetMessage("MAIN_SC_NTLM_SUCCESS") . $user); } return $this->Result(null, GetMessage("MAIN_SC_NO_NTLM")); } function check_ca_file() { if (file_exists($this->cafile)) { unlink($this->cafile); } CheckDirPath($this->cafile); $region = Application::getInstance()->getLicense()->getRegion(); if (in_array($region, ['ru', 'by', 'kz'])) { $url = 'https://www.1c-bitrix.ru/upload/lib/cafile.pem'; } else { $url = 'https://www.bitrixsoft.com/upload/lib/cafile.pem'; } $ob = new CHTTP(); $ob->http_timeout = 5; if ($ob->Download($url, $this->cafile) && is_file($this->cafile) && filesize($this->cafile) > 0) { return true; } return $this->Result(null, GetMessage("MAIN_SC_NO_ACCESS") . '"'); } function check_dbconn() { $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=dbconn_test&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; $retVal = false; $file = ''; if (IsModuleInstalled('security')) { $file = COption::GetOptionString("security", "ipcheck_disable_file", ""); COption::SetOptionString("security", "ipcheck_disable_file", $this->LogFile); } if ($res = $this->ConnectToHost()) { $retVal = IsHttpResponseSuccess($res, $strRequest); } if (IsModuleInstalled('security')) { COption::SetOptionString("security", "ipcheck_disable_file", $file); } return $retVal; } function check_dbconn_settings() { global $DB; $conn = Bitrix\Main\Application::getInstance()->getConnectionPool()->getConnection(); if ($DB->DBHost == $conn->getHost() && $DB->DBLogin == $conn->getLogin() && $DB->DBName == $conn->getDatabase()) { return true; } echo "/bitrix/php_interface/dbconn.php\n" . '$DBHost = "' . $DB->DBHost . "\"\n" . '$DBLogin = "' . $DB->DBLogin . "\"\n" . '$DBName = "' . $DB->DBName . "\"\n" . "\n" . "/bitrix/.settings.php\n" . 'host = "' . $conn->getHost() . "\"\n" . 'login = "' . $conn->getLogin() . "\"\n" . 'database = "' . $conn->getDatabase() . "\"\n"; return $this->Result(false, GetMessage('SC_ERR_CONN_DIFFER')); } function check_upload($big = false, $raw = false) { if (($sp = ini_get("upload_tmp_dir"))) { if (!file_exists($sp)) { return $this->Result(false, GetMessage('SC_NO_TMP_FOLDER') . ' <i>(' . htmlspecialcharsbx($sp) . ')</i>'); } elseif (!is_writable($sp)) { return $this->Result(false, GetMessage('SC_TMP_FOLDER_PERMS') . ' <i>(' . htmlspecialcharsbx($sp) . ')</i>'); } } if (defined('BX_TEMPORARY_FILES_DIRECTORY')) { $sp = BX_TEMPORARY_FILES_DIRECTORY; if (!file_exists($sp)) { return $this->Result(false, GetMessage('SC_NO_TMP_FOLDER') . ' <i>(BX_TEMPORARY_FILES_DIRECTORY: ' . htmlspecialcharsbx($sp) . ')</i>'); } elseif (!is_writable($sp)) { return $this->Result(false, GetMessage('SC_TMP_FOLDER_PERMS') . ' <i>(BX_TEMPORARY_FILES_DIRECTORY: ' . htmlspecialcharsbx($sp) . ')</i>'); } } $binaryData = ''; for ($i = 40; $i < 240; $i++) { $binaryData .= chr($i); } if ($big) { $binaryData = str_repeat($binaryData, 21000); } if ($raw) { $POST = $binaryData; } else { $boundary = '--------' . md5(checker_get_unique_id()); $POST = "--$boundary\r\n"; $POST .= 'Content-Disposition: form-data; name="test_file"; filename="site_checker.bin' . "\r\n"; $POST .= 'Content-Type: image/gif' . "\r\n"; $POST .= "\r\n"; $POST .= $binaryData . "\r\n"; $POST .= "--$boundary\r\n"; } $strRequest = "POST " . "/bitrix/admin/site_checker.php?test_type=upload_test&unique_id=" . checker_get_unique_id() . "&big=" . ($big ? 1 : 0) . "&raw=" . ($raw ? 1 : 0) . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; if (!$raw) { $strRequest .= "Content-Type: multipart/form-data; boundary=$boundary\r\n"; } $strRequest .= "Content-Length: " . strlen($POST) . "\r\n"; $strRequest .= "\r\n"; $strRequest .= $POST; if ($res = $this->ConnectToHost()) { return IsHttpResponseSuccess($res, $strRequest); } return false; } function check_upload_big() { return $this->check_upload(true); } function check_upload_raw() { return $this->check_upload(false, true); } function check_post() { $POST = ''; for ($i = 0; $i < 201; $i++) { $POST .= 'i' . $i . '=' . md5($i) . '&'; } $strRequest = "POST " . "/bitrix/admin/site_checker.php?test_type=post_test&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "Content-Length: " . strlen($POST) . "\r\n"; $strRequest .= "Content-Type: application/x-www-form-urlencoded\r\n"; $strRequest .= "\r\n"; $strRequest .= $POST; if ($res = $this->ConnectToHost()) { return IsHttpResponseSuccess($res, $strRequest); } return false; } function check_memory_limit() { $total_steps = 5; if (!$this->arTestVars['last_value']) { $last_success = 0; $max = 16; $step = 1; } else { if (!CheckSerializedData($this->arTestVars['last_value'])) { return false; } [$last_success, $max, $step] = unserialize($this->arTestVars['last_value'], ['allowed_classes' => false]); } $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=memory_test&unique_id=" . checker_get_unique_id() . "&max=" . ($max - 1) . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; if (!$res = $this->ConnectToHost()) { return false; } if (IsHttpResponseSuccess($res, $strRequest)) { $last_success = $max; $max *= 2; } else { $max = floor(($last_success + $max) / 2); } if ($max < 16) { return false; } if ($step < $total_steps) { $this->test_percent = floor(100 / $total_steps * $step); $step++; $this->arTestVars['last_value'] = serialize([$last_success, $max, $step]); return true; } $ok = false; $res = GetMessage('SC_NOT_LESS', ['#VAL#' => $last_success]); $last_success = (int)$last_success; if ($last_success > 32) { $ok = true; $cur = \Bitrix\Main\Config\Ini::getInt('memory_limit'); if ($cur > 0 && $cur < $last_success * 1024 * 1024) { $res .= '<br> ' . GetMessage('SC_MEMORY_CHANGED', ['#VAL0#' => ini_get('memory_limit'), '#VAL1#' => '512M']); $ok = null; } } return $this->Result($ok, $res); } function check_session() { if (!$this->arTestVars['last_value']) { $_SESSION['CHECKER_CHECK_SESSION'] = 'SUCCESS'; $this->test_percent = 50; $this->arTestVars['last_value'] = 'Y'; } else { if ($_SESSION['CHECKER_CHECK_SESSION'] != 'SUCCESS') { return false; } unset($_SESSION['CHECKER_CHECK_SESSION']); } return true; } function check_session_ua() { $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=session_test&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; if ($this->arTestVars['last_value']) // second step: put session id { $strRequest .= "Cookie: " . $this->arTestVars['last_value'] . "\r\n"; } $strRequest .= "\r\n"; if (!$res = $this->ConnectToHost()) { return false; } if (!$this->arTestVars['last_value']) // first step: read session id { $strRes = GetHttpResponse($res, $strRequest, $strHeaders); if (!preg_match('#Set-Cookie: (' . session_name() . '=[a-z0-9\-_]+?);#i', $strHeaders, $regs)) { PrintHTTP($strRequest, $strHeaders, $strRes); return false; } $this->arTestVars['last_value'] = $regs[1]; $this->test_percent = 50; return true; } else { return IsHttpResponseSuccess($res, $strRequest); } } function check_mbstring() { $file = $_SERVER['DOCUMENT_ROOT'] . '/bitrix/.settings.php'; if ($this->fix_mode) { if (!file_exists($file)) { \Bitrix\Main\Config\Configuration::wnc(); Application::resetAccelerator(); } return $this->Result(file_exists($file)); } if (!file_exists($file)) { $this->arTestVars['check_mbstring_fail'] = true; $mode = 4; $link = ' <a href="javascript:show_popup(\'' . GetMessageJS('SC_FIX_MBSTRING') . '\', \'?fix_mode=' . $mode . '\', \'' . GetMessageJS('SC_FIX_MBSTRING_CONFIRM') . '\')">' . GetMessage('SC_FIX') . '</a>'; return $this->Result(false, GetMessage('SC_ERR_NO_SETTINGS') . $link); } if (\Bitrix\Main\Config\Configuration::getValue("utf_mode") !== (defined('BX_UTF') && BX_UTF === true)) { return $this->Result(false, GetMessage('MAIN_SC_MBSTRING_SETTIGNS_DIFFER')); } $encoding = strtolower(ini_get('mbstring.internal_encoding')); $default = strtolower(ini_get('default_charset')); if ($default == "") { return $this->Result(false, GetMessage("MAIN_SC_DEFAULT_CHARSET")); } if ($encoding <> '' && $encoding <> $default) { return $this->Result(false, GetMessage("MAIN_SC_ENC_EQUAL")); } if (ini_get('mbstring.func_overload') > 0) { //should be non-existent return $this->Result(false, GetMessage("MAIN_SC_FUNC_OVERLOAD")); } $retVal = true; $bUtf = false; $rs = CSite::GetList('', '', ['ACTIVE' => 'Y']); while ($f = $rs->Fetch()) { if (str_contains(strtolower($f['CHARSET']), 'utf')) { $bUtf = true; break; } } if ($bUtf) { $text = GetMessage('SC_MB_UTF'); if ($default <> "utf-8") { $retVal = false; $text .= '<br>' . GetMessage("MAIN_SC_ENC_UTF"); $this->arTestVars['check_mbstring_fail'] = true; } if (!defined('BX_UTF') || BX_UTF !== true) { $retVal = false; $text .= '<br>' . GetMessage('SC_BX_UTF'); $this->arTestVars['check_mbstring_fail'] = true; } } else { $text = GetMessage('SC_MB_NOT_UTF'); if ($default == "utf-8") { $retVal = false; $text .= '<br>' . GetMessage("MAIN_SC_ENC_NON_UTF"); $this->arTestVars['check_mbstring_fail'] = true; } if (defined('BX_UTF')) { $retVal = false; $text .= '<br>' . GetMessage('SC_BX_UTF_DISABLE'); $this->arTestVars['check_mbstring_fail'] = true; } } if ($retVal) { $retVal = (strlen("\xd0\xa2") == 2); if (!$retVal) { $text = GetMessage('SC_STRLEN_FAIL_PHP56'); } } return $this->Result($retVal, ($retVal ? GetMessage("MAIN_SC_CORRECT") . '. ' : '') . $text); } function check_http_auth() { $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=auth_test&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "Authorization: Basic dGVzdF91c2VyOnRlc3RfcGFzc3dvcmQ=\r\n"; $strRequest .= "\r\n"; if ($res = $this->ConnectToHost()) { return IsHttpResponseSuccess($res, $strRequest); } return false; } function check_update() { $ServerIP = COption::GetOptionString("main", "update_site", "www.bitrixsoft.com"); $ServerPort = 80; $proxyAddr = COption::GetOptionString("main", "update_site_proxy_addr", ""); $proxyPort = COption::GetOptionString("main", "update_site_proxy_port", ""); $proxyUserName = COption::GetOptionString("main", "update_site_proxy_user", ""); $proxyPassword = COption::GetOptionString("main", "update_site_proxy_pass", ""); $bUseProxy = !$this->arTestVars['last_value'] && $proxyAddr <> '' && $proxyPort <> ''; if ($bUseProxy) { $proxyPort = intval($proxyPort); if ($proxyPort <= 0) { $proxyPort = 80; } $requestIP = $proxyAddr; $requestPort = $proxyPort; } else { $requestIP = $ServerIP; $requestPort = $ServerPort; } $strRequest = ""; $page = "us_updater_list.php"; if ($bUseProxy) { $strRequest .= "POST http://" . $ServerIP . "/bitrix/updates/" . $page . " HTTP/1.0\r\n"; if ($proxyUserName <> '') { $strRequest .= "Proxy-Authorization: Basic " . base64_encode($proxyUserName . ":" . $proxyPassword) . "\r\n"; } } else { $strRequest .= "POST /bitrix/updates/" . $page . " HTTP/1.0\r\n"; } $strRequest .= "User-Agent: BitrixSMUpdater\r\n"; $strRequest .= "Accept: */*\r\n"; $strRequest .= "Host: " . $ServerIP . "\r\n"; $strRequest .= "Accept-Language: en\r\n"; $strRequest .= "Content-type: application/x-www-form-urlencoded\r\n"; $strRequest .= "Content-length: 7\r\n\r\n"; $strRequest .= "lang=en"; $strRequest .= "\r\n"; $res = false; try { $res = fsockopen($requestIP, $requestPort, $errno, $errstr, 5); } catch (Exception $e) { echo $e->getMessage() . "\n"; } if (!$res) { if ($bUseProxy) { return $this->Result(false, GetMessage('SC_NO_PROXY') . ' (' . $errstr . ')'); } else { return $this->Result(false, GetMessage('SC_UPDATE_ERROR') . ' (' . $errstr . ')'); } } else { if (\Bitrix\Main\Config\Option::get("updateserverlight", "is_turned_on", "N") === "Y") { return true; } $strRes = GetHttpResponse($res, $strRequest, $strHeaders); if ((str_contains($strRes, "EMPTY_LICENSE_KEY")) || (str_contains($strRes, "LICENSE_KEY_REQUIRED"))) { return true; } else { $strRes = mb_strtolower(strip_tags($strRes)); PrintHTTP($strRequest, $strHeaders, $strRes); if ($bUseProxy) { return $this->Result(false, GetMessage('SC_PROXY_ERR_RESP')); } else { return $this->Result(false, GetMessage('SC_UPDATE_ERR_RESP')); } } } } function check_pull_stream() { if (CModule::IncludeModule('pull')) { $text = md5(mt_rand(100000, 999999)); $channelId = md5($text); $id = CPullChannel::SignChannel($channelId); if (CPullOptions::GetQueueServerStatus()) { $isServerShared = CPullOptions::IsServerShared(); if ($isServerShared && !\Bitrix\Pull\SharedServer\Config::isRegistered()) { $this->arTestVars['push_stream_fail'] = true; return $this->Result(false, GetMessage("MAIN_SC_PULL_NOT_REGISTERED")); } else { if (CPullOptions::GetQueueServerVersion() < 4) { $this->arTestVars['push_stream_warn'] = true; return $this->Result(null, GetMessage("MAIN_SC_PULL_UNSUPPORTED_VERSION")); } else { if (!$ar = parse_url(str_replace('#DOMAIN#', $this->host, \Bitrix\Pull\Config::getPublishUrl($id)))) { return $this->Result(false, GetMessage("MAIN_SC_PATH_PUB")); } $pub_domain = $ar['host']; $pub_host = ($ar['scheme'] == 'https' ? 'ssl://' : '') . $pub_domain; $pub = $ar['path'] . '?' . $ar['query']; $pub_port = $ar['port']; if (!$pub_port) { $pub_port = $ar['scheme'] == 'https' ? 443 : 80; } if ($isServerShared) { $listenUrl = \Bitrix\Pull\SharedServer\Config::getLongPollingUrl(); $listenUrl .= "?CHANNEL_ID=" . $id . "&clientId=" . \Bitrix\Pull\SharedServer\Client::getPublicLicenseCode(); } else { $listenUrl = $this->ssl ? CPullOptions::GetListenSecureUrl($id) : CPullOptions::GetListenUrl($id); } if (!$ar = parse_url(str_replace('#DOMAIN#', $this->host, $listenUrl))) { return $this->Result(false, GetMessage("MAIN_SC_PATH_SUB")); } $sub_domain = $ar['host']; $sub_host = ($ar['scheme'] == 'https' ? 'ssl://' : '') . $sub_domain; $sub = $ar['path'] . '?' . $ar['query']; $sub_port = $ar['port']; if (!$sub_port) { $sub_port = $ar['scheme'] == 'https' ? 443 : 80; } } } } else { $this->arTestVars['push_stream_fail'] = true; return $this->Result(false, GetMessage("MAIN_SC_STREAM_DISABLED_2")); } } else { $this->arTestVars['push_stream_fail'] = true; return $this->Result(false, GetMessage("MAIN_NO_PULL")); } $ver = CPullOptions::GetQueueServerVersion(); $bNodeJS = $ver > 2; echo 'Server version: ' . $ver . ($bNodeJS ? ' (Bitrix Push server)' : ' (nginx-push-stream-module)') . "\n"; $strRequest0 = 'POST ' . $pub . ' HTTP/1.0' . "\r\n" . 'Host: ' . $pub_domain . "\r\n" . 'Content-Length: ' . strlen($text) . "\r\n" . "\r\n" . $text . "\r\n"; $strRequest1 = 'GET ' . $sub . ' HTTP/1.0' . "\r\n" . 'If-Modified-Since: ' . date('r', time() - 86400) . "\r\n" . 'Host: ' . $sub_domain . "\r\n\r\n"; $strRequest2 = 'DELETE ' . $pub . ' HTTP/1.0' . "\r\n" . 'Host: ' . $sub_domain . "\r\n\r\n"; if (!$bNodeJS) { // POST - to create a channel if (!$res0 = $this->ConnectToHost($pub_host, $pub_port)) { $this->arTestVars['push_stream_fail'] = true; return $this->Result(false, GetMessage("MAIN_SC_NO_PUSH_STREAM_CONNECTION")); } fwrite($res0, $strRequest0); fclose($res0); } // GET - connection if (!$res1 = $this->ConnectToHost($sub_host, $sub_port)) { $this->arTestVars['push_stream_fail'] = true; return $this->Result(false, GetMessage("MAIN_SC_NO_SUB_CONNECTION_2")); } fwrite($res1, $strRequest1); sleep(1); // we need some time to create channel // POST - message $postResult = CPullChannel::Send($channelId, $text, ['dont_wait_answer' => false]); if (!$postResult) { $this->arTestVars['push_stream_fail'] = true; return $this->Result(false, GetMessage("MAIN_SC_NO_PUSH_STREAM_CONNECTION")); } // GET - message $strRes1 = fread($res1, 4096); $retVal = true; if (!str_contains($strRes1, $text)) { PrintHTTP($strRequest1, '', $strRes1); $this->arTestVars['push_stream_fail'] = true; $retVal = $this->Result(false, GetMessage("MAIN_SC_PUSH_INCORRECT", ['#MODULE#' => $bNodeJS ? 'Bitrix Push server' : 'nginx-push-stream-module'])); } // DELETE if (!$res2 = $this->ConnectToHost($pub_host, $pub_port)) { $this->arTestVars['push_stream_fail'] = true; return $this->Result(false, GetMessage("MAIN_SC_NO_PUSH_STREAM_CONNECTION_2")); } fwrite($res2, $strRequest2); fclose($res2); if ($retVal && COption::GetOptionString('main', 'session_expand', 'Y') <> 'N' && (!defined("BX_SKIP_SESSION_EXPAND") || BX_SKIP_SESSION_EXPAND === false)) { return $this->Result(null, GetMessage('MAIN_SC_WARN_EXPAND_SESSION')); } return $retVal; } function check_pull_comments() { if ($this->arTestVars['push_stream_warn']) { return $this->Result(null, GetMessage("MAIN_SC_NO_PUSH_STREAM_2")); } else { if ($this->arTestVars['push_stream_fail']) { return $this->Result(false, GetMessage("MAIN_SC_NO_PUSH_STREAM_2")); } } return true; } function check_turn() { if (!IsModuleInstalled('im')) { return $this->Result(null, GetMessage("MAIN_SC_NO_IM")); } if ($this->arTestVars['push_stream_warn']) { return $this->Result(null, GetMessage("MAIN_SC_NO_PUSH_STREAM_VIDEO_2")); } else { if ($this->arTestVars['push_stream_fail']) { return $this->Result(false, GetMessage("MAIN_SC_NO_PUSH_STREAM_VIDEO_2")); } } if (COption::GetOptionString("im", "turn_server_self") == 'Y') { $host = COption::GetOptionString("im", "turn_server"); } else { $host = 'turn.calls.bitrix24.com'; } $port = 3478; if (!($res = $this->ConnectToHost($host, $port))) { $res = $this->ConnectToHost('udp://' . $host, $port); } if ($res) { fclose($res); return $this->Result(true, GetMessage("MAIN_SC_AVAIL")); } return $this->Result(null, GetMessage("MAIN_SC_NOT_AVAIL")); } function check_push_bitrix() { if (!CModule::IncludeModule('pull')) { return $this->Result(null, GetMessage("MAIN_NO_PULL_MODULE")); } if (!CPullOptions::GetPushStatus()) { return $this->Result(null, GetMessage("MAIN_NO_OPTION_PULL")); } if ($this->arTestVars['check_access_fail']) { return $this->Result(false, GetMessage("MAIN_SC_NO_EXTERNAL_ACCESS_MOB")); } $host = 'cloud-messaging.bitrix24.com'; $POST = 'Action=SendMessage&MessageBody=batch'; $strRequest = "POST /send/?key=" . md5('key') . " HTTP/1.1\r\n"; $strRequest .= "User-Agent: BitrixCloud SiteChecker\r\n"; $strRequest .= "Host: " . $host . "\r\n"; $strRequest .= "Content-type: application/x-www-form-urlencoded\r\n"; $strRequest .= "Content-length: " . strlen($POST) . "\r\n"; $strRequest .= "\r\n" . $POST . "\r\n"; if (!$res = $this->ConnectToHost('ssl://' . $host, 443)) { return false; } $strRes = mb_strtolower(GetHttpResponse($res, $strRequest, $strHeaders)); if (str_contains($strRes, 'xml version=')) { return true; } PrintHTTP($strRequest, $strHeaders, $strRes); return $this->Result(false, GetMessage("MAIN_WRONG_ANSWER_PULL")); } function check_access_docs() { if ($this->arTestVars['check_access_fail']) { return $this->Result(null, GetMessage("MAIN_SC_NO_EXTERNAL_ACCESS_")); } return true; } function check_extranet() { if ($this->arTestVars['check_access_fail']) { return $this->Result(false, GetMessage("MAIN_SC_NO_EXTRANET_CONNECT")); } return true; } function check_webdav() { if (!CModule::IncludeModule('webdav') && !CModule::IncludeModule('disk')) { return $this->Result(false, GetMessage("MAIN_SC_NO_WEBDAV_MODULE")); } if ($this->arTestVars['check_socket_fail']) { return $this->Result(null, GetMessage('SC_SOCK_NA')); } $allow = [ "PUT" => ["rights" => "U", "min_rights" => "U"], "LOCK" => ["rights" => "U", "min_rights" => "U"], "MOVE" => ["rights" => "W", "min_rights" => "U"], "MKCOL" => ["rights" => "W", "min_rights" => "W"], "PROPFIND" => ["rights" => "R", "min_rights" => "R"], ]; foreach ($allow as $method => $ar) { $strRequest = $method . " /bitrix/admin/site_checker.php?test_type=webdav_test&method=$method&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; if (!$res = $this->ConnectToHost()) { return null; } $strRes = GetHttpResponse($res, $strRequest, $strHeaders); if (trim($strRes) != 'SUCCESS') { PrintHTTP($strRequest, $strHeaders, $strRes); return $this->Result(null, str_replace('#METHOD#', $method, GetMessage("MAIN_SC_METHOD_NOT_SUP"))); } } return true; } function check_search() { if (!CModule::IncludeModule('intranet')) { return null; } $tmp = $_SERVER['DOCUMENT_ROOT'] . '/bitrix/tmp/success.doc'; if (!CheckDirPath($tmp) || !file_put_contents($tmp, 'SUCCESS')) { return $this->Result(false, GetMessage("MAIN_TMP_FILE_ERROR")); } $res = CIntranetSearchConverters::OnSearchGetFileContent($tmp); unlink($tmp); if (is_array($res) && str_contains($res['CONTENT'], 'SUCCESS')) { return true; } $strError = GetMessage("MAIN_SC_SEARCH_INCORRECT") . "<br>\n"; if ($res === false && function_exists('exec')) { exec('catdoc -V', $output, $return_var); if ($return_var === 0) { $version = $output[0]; if (str_contains($version, '0.94.4') || str_contains($version, '0.94.3')) { $strError .= GetMessage('MAIN_CATDOC_WARN', ['#VERSION#' => $version]); } } } return $this->Result(false, $strError); } function check_fast_download() { $tmp = $_SERVER['DOCUMENT_ROOT'] . '/bitrix/tmp/success.txt'; if (!CheckDirPath($tmp) || !file_put_contents($tmp, 'SUCCESS')) { return $this->Result(false, GetMessage("MAIN_TMP_FILE_ERROR")); } $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=fast_download&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; if (!$res = $this->ConnectToHost()) { return false; } if (IsHttpResponseSuccess($res, $strRequest)) { $retVal = COption::GetOptionString('main', 'bx_fast_download', 'N') == 'Y' ? true : $this->Result(false, GetMessage("MAIN_FAST_DOWNLOAD_SUPPORT")); } else { $retVal = COption::GetOptionString('main', 'bx_fast_download', 'N') == 'N' ? $this->Result(false, GetMessage("MAIN_SC_NOT_SUPPORTED")) : $this->Result(false, GetMessage("MAIN_FAST_DOWNLOAD_ERROR")); } unlink($tmp); return $retVal; } function check_access_mobile() { $checker = 'checker.internal.bitrix24.com'; $retVal = null; $strRes = ''; if (preg_match('#^(127|10|172\.16|192\.168)\.#', $this->host)) { $status = 0; } else { $strRequest = 'GET /check/?license_hash=' . LICENSE_HASH . '&host=' . urlencode($this->host) . '&port=' . urlencode($this->port) . '&https=' . ($this->ssl ? 'Y' : 'N') . ' HTTP/1.1' . "\r\n" . 'host: ' . $checker . "\r\n" . "\r\n"; if (!$res = $this->ConnectToHost($checker, 80)) { $this->arTestVars['check_access_fail'] = true; return $this->Result($retVal, GetMessage("MAIN_SC_NO_CONNECTTO", ['#HOST#' => $checker])); } $strRes = GetHttpResponse($res, $strRequest, $strHeaders); PrintHTTP($strRequest, $strHeaders, $strRes); if (!preg_match('#^Status: (.+)$#m', $strRes, $regs)) { $this->arTestVars['check_access_fail'] = true; return $this->Result($retVal, GetMessage("MAIN_SC_UNKNOWN_ANSWER", ['#HOST#' => $checker])); } $status = intval($regs[1]); } if (!$status) { $this->arTestVars['check_access_fail'] = true; return $this->Result($retVal, GetMessage("MAIN_SC_NO_EXTERNAL_CONNECT_WARN")); } if ($status != 200 && $status != 401) { $this->arTestVars['check_access_fail'] = true; echo $strRes; return $this->Result($retVal, GetMessage("MAIN_SC_EXTERNAL_ANSWER_INCORRECT")); } if (!CModule::IncludeModule('pull')) { return $this->Result(null, GetMessage("MAIN_NO_PULL_MODULE")); } if (!CPullOptions::GetPushStatus()) { return $this->Result(null, GetMessage("MAIN_NO_OPTION_PULL")); } if (!$ar = parse_url(str_replace('#DOMAIN#', $this->host, COption::GetOptionString('pull', 'path_to_mobile_listener' . ($this->ssl ? '_secure' : ''))))) { return $this->Result(false, GetMessage("MAIN_SC_PATH_SUB")); } $sub_port = $ar['port']; if (!$sub_port) { $sub_port = 80; } if ($sub_port != $this->port) { $strRequest = 'GET /check/?license_hash=' . LICENSE_HASH . '&host=' . urlencode($this->host) . '&port=' . urlencode($sub_port) . '&https=' . ($ar['scheme'] == 'https' ? 'Y' : 'N') . ' HTTP/1.1' . "\r\n" . 'host: ' . $checker . "\r\n" . "\r\n"; if (!$res = $this->ConnectToHost($checker, 80)) { return $this->Result($retVal, GetMessage("MAIN_SC_NO_CONNECTTO", ['#HOST#' => $checker])); } $strRes = GetHttpResponse($res, $strRequest, $strHeaders); PrintHTTP($strRequest, $strHeaders, $strRes); if (!preg_match('#^Status: (.+)$#m', $strRes, $regs)) { return $this->Result($retVal, GetMessage("MAIN_SC_UNKNOWN_ANSWER", ['#HOST#' => $checker])); } $status = intval($regs[1]); if (!$status) { return $this->Result($retVal, GetMessage("MAIN_SC_NO_PULL_EXTERNAL_2")); } } return true; } function check_perf() { $arTime = []; $count = 3; for ($i = 0; $i < $count; $i++) { if (!$res = $this->ConnectToHost()) { return false; } $file = ''; if (IsModuleInstalled('security')) { $file = COption::GetOptionString("security", "ipcheck_disable_file", ""); COption::SetOptionString("security", "ipcheck_disable_file", $this->LogFile); } $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=perf&unique_id=" . checker_get_unique_id() . "&i=" . $i . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; $strRes = GetHttpResponse($res, $strRequest, $strHeaders); if (IsModuleInstalled('security')) { COption::SetOptionString("security", "ipcheck_disable_file", $file); } if (!is_numeric($strRes)) { PrintHTTP($strRequest, $strHeaders, $strRes); return $this->Result(false, GetMessage('SC_TEST_FAIL')); } $arTime[] = doubleval($strRes); } $r = doubleval($count) / array_sum($arTime); if ($r < 10) { $strResult = GetMessage("MAIN_PERF_VERY_LOW"); } elseif ($r < 15) { $strResult = GetMessage("MAIN_PERF_LOW"); } elseif ($r < 30) { $strResult = GetMessage("MAIN_PERF_MID"); } else { $strResult = GetMessage("MAIN_PERF_HIGH"); } return $this->Result($r >= 10, $strResult . ' (' . number_format($r, 2, ".", " ") . ' ' . GetMessage("MAIN_PAGES_PER_SECOND") . ')'); } function check_cache() { $dir = $_SERVER["DOCUMENT_ROOT"] . BX_PERSONAL_ROOT . "/cache"; $file0 = $dir . "/" . md5(mt_rand()); $file1 = $file0 . ".tmp"; $file2 = $file0 . ".php"; if (!file_exists($dir)) { mkdir($dir, BX_DIR_PERMISSIONS); } return ($f = fopen($file1, 'wb')) && (fclose($f)) && (rename($file1, $file2)) && (unlink($file2)); } function check_exec() { $path = '/bitrix' . '/site_check_exec.php'; if (!($f = fopen($_SERVER['DOCUMENT_ROOT'] . $path, 'wb'))) { return $this->Result(false, GetMessage('SC_CHECK_FILES')); } chmod($_SERVER['DOCUMENT_ROOT'] . $path, BX_FILE_PERMISSIONS); fwrite($f, '<' . '? echo "SUCCESS"; ?' . '>'); fclose($f); $strRequest = "GET " . $path . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; if ($res = $this->ConnectToHost()) { $retVal = IsHttpResponseSuccess($res, $strRequest); } else { $retVal = false; } unlink($_SERVER['DOCUMENT_ROOT'] . $path); return $retVal; } function check_security() { $strError = ''; if (function_exists('apache_get_modules')) { $arLoaded = apache_get_modules(); if (in_array('mod_security', $arLoaded)) { $strError .= GetMessage('SC_WARN_SECURITY') . "<br>"; } if (in_array('mod_dav', $arLoaded) || in_array('mod_dav_fs', $arLoaded)) { $strError .= GetMessage('SC_WARN_DAV') . "<br>"; } } if ($strError) { return $this->Result(null, $strError); } return $this->Result(true, GetMessage("MAIN_SC_NO_CONFLICT")); } function check_install_scripts() { $strError = ''; foreach ([ 'restore.php', 'bitrix_server_test.php', 'bitrixsetup.php', 'bitrix_install.php', 'bitrix_setup.php', 'bitrix6setup.php', 'bitrix7setup.php', 'bitrix8setup.php', 'export_file.csv', '1c_bx_import.php', ] as $file) { if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/' . $file)) { $strError .= GetMessage('SC_FILE_EXISTS') . ' ' . $file . "\n<br>"; } if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/bitrix/' . $file)) { $strError .= GetMessage('SC_FILE_EXISTS') . ' /bitrix/' . $file . "\n<br>"; } if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/upload/' . $file)) { $strError .= GetMessage('SC_FILE_EXISTS') . ' /upload/' . $file . "\n<br>"; } } if ($strError) { return $this->Result(false, $strError); } return $this->Result(true, GetMessage("MAIN_SC_ABSENT_ALL")); } function check_getimagesize() { $file = $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/fileman/install/components/bitrix/player/mediaplayer/player'; if (!file_exists($file)) { return $this->Result(null, "File not found: " . $file); } if (false === getimagesize($file)) { return $this->Result(null, GetMessage('SC_SWF_WARN')); } return true; } function check_localredirect() { $strSERVER = ''; foreach (['SERVER_PORT', 'HTTPS', 'FCGI_ROLE', 'HTTP_HOST', 'SERVER_PROTOCOL'] as $var) { $strSERVER .= '&' . $var . '=' . urlencode($_SERVER[$var] ?? ''); } if (!$this->arTestVars['last_value']) { $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=redirect_test&unique_id=" . checker_get_unique_id() . $strSERVER . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; if (!$res = $this->ConnectToHost()) { return false; } $strRes = GetHttpResponse($res, $strRequest, $strHeaders); if (preg_match('#Location: (.+)#i', $strHeaders, $regs)) { $url = trim($regs[1]); if (!$url) { PrintHTTP($strRequest, $strHeaders, $strRes); return false; } $this->arTestVars['last_value'] = $url; $this->test_percent = 50; return true; } PrintHTTP($strRequest, $strHeaders, $strRes); return false; } else { $url = $this->arTestVars['last_value']; if (!$url) { return false; } $ar = parse_url($url); $host = $ar['host']; $ssl = $ar['scheme'] == 'https' ? 'ssl://' : ''; $port = intval($ar['port']) ?: ($ssl ? 443 : 80); $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=redirect_test&unique_id=" . checker_get_unique_id() . $strSERVER . "&done=Y HTTP/1.1\r\n"; $strRequest .= "Host: " . $host . "\r\n"; $strRequest .= "\r\n"; if ($res = $this->ConnectToHost($host, $port, $ssl)) { return IsHttpResponseSuccess($res, $strRequest); } return false; } } function check_sites() { $strError = ''; $bUtf = false; $bChar = false; $arDocRoot = []; $rs = CSite::GetList('', '', ['ACTIVE' => 'Y']); while ($f = $rs->Fetch()) { $arDocRoot[] = trim($f['DOC_ROOT']); $bFound = str_contains(strtolower($f['CHARSET']), 'utf'); $bUtf = $bUtf || $bFound; $bChar = $bChar || !$bFound; } if (count($arDocRoot) == 1) { if ($root = $arDocRoot[0]) { $strError = GetMessage('SC_PATH_FAIL_SET') . ' <i>' . htmlspecialcharsbx($root) . '</i><br>'; } } else { foreach ($arDocRoot as $root) { if ($root) { if (!is_readable($root . '/bitrix')) { $strError .= GetMessage('SC_NO_ROOT_ACCESS') . ' <i>' . htmlspecialcharsbx($root) . '/bitrix</i><br>'; } } } } if ($bUtf && $bChar) { $strError .= GetMessage("SC_SITE_CHARSET_FAIL"); } if ($strError) { return $this->Result(false, $strError); } return $this->Result(true, GetMessage("MAIN_SC_CORRECT")); } function check_pcre_recursion() { $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=pcre_recursion_test&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; if ($res = $this->ConnectToHost()) { if ('SUCCESS' == $strRes = GetHttpResponse($res, $strRequest, $strHeaders)) { return true; } if ($strRes == 'CLEAN') { return $this->Result(null, GetMessage('SC_PCRE_CLEAN')); } } return false; } function check_method_exists() { $strRequest = "GET " . "/bitrix/admin/site_checker.php?test_type=method_exists&unique_id=" . checker_get_unique_id() . " HTTP/1.1\r\n"; $strRequest .= "Host: " . $this->host . "\r\n"; $strRequest .= "\r\n"; if ($res = $this->ConnectToHost()) { return IsHttpResponseSuccess($res, $strRequest); } return false; } function check_bx_crontab() { $connection = \Bitrix\Main\Application::getConnection(); $helper = $connection->getSqlHelper(); $this->arTestVars['check_bx_crontab'] = false; if (defined('BX_CRONTAB')) { return $this->Result(false, GetMessage("MAIN_BX_CRONTAB_DEFINED")); } $bCron = COption::GetOptionString("main", "agents_use_crontab", "N") == 'Y' || defined('BX_CRONTAB_SUPPORT') && BX_CRONTAB_SUPPORT === true || COption::GetOptionString("main", "check_agents", "Y") != 'Y'; if ($bCron) { if (!$connection->query('SELECT LAST_EXEC FROM b_agent WHERE LAST_EXEC > ' . $helper->addDaysToDateTime(-1) . ' AND IS_PERIOD = \'N\' LIMIT 1')->fetch()) { return $this->Result(false, GetMessage("MAIN_CRON_NO_START")); } $this->arTestVars['check_bx_crontab'] = true; return true; } return $this->Result(null, GetMessage("MAIN_AGENTS_HITS")); } function check_pgsql_version() { $connection = \Bitrix\Main\Application::getConnection(); $PgSql_vercheck_min = '11.0.0'; $ver = $connection->getVersion()[0]; if (version_compare($ver, $PgSql_vercheck_min, '<')) { return $this->Result(false, GetMessage('SC_PGSQL_ERR_VER', [ '#CUR#' => $ver, '#REQ#' => $PgSql_vercheck_min, ])); } return true; } function check_pgsql_db_charset() { global $DB; $strError = ''; $res = $DB->Query('SHOW LC_CTYPE'); $f = $res->Fetch(); $collation_database = $f['LC_CTYPE']; $res = $DB->Query("SELECT pg_encoding_to_char(encoding) DB_ENCODING FROM pg_database where datname='" . $DB->ForSql($DB->DBName) . "'"); $f = $res->Fetch(); $character_set_database = $f['DB_ENCODING']; //UTF8 if (!preg_match('/\.(UTF-8|UTF8)$/i', $collation_database)) { $strError = GetMessage('SC_DATABASE_LC_CTYPE', ['#VAL0#' => $collation_database]); } //echo 'CHARSET='.$character_set_database.', COLLATION='.$collation_database; if (!$strError) { return true; } $this->arTestVars['db_charset_fail'] = true; return $this->Result(false, $strError); } function check_pgsql_connection_charset() { $connection = \Bitrix\Main\Application::getConnection(); $strError = ''; if ($this->arTestVars['check_mbstring_fail']) { return $this->Result(null, GetMessage('SC_MBSTRING_NA')); } $res = $connection->query('SHOW client_encoding'); $f = $res->fetch(); $character_set_connection = $f['CLIENT_ENCODING']; $bAllIn1251 = true; $res1 = $connection->query('SELECT C.CHARSET FROM b_lang L, b_culture C WHERE C.ID=L.CULTURE_ID AND L.ACTIVE=\'Y\''); // for 'no kernel mode' while ($f1 = $res1->fetch()) { $bAllIn1251 = $bAllIn1251 && trim(strtolower($f1['CHARSET'])) == 'windows-1251'; } if (defined('BX_UTF') && BX_UTF === true) { if ($character_set_connection != 'UTF8') { $strError = GetMessage('SC_CONNECTION_CHARSET_WRONG', ['#VAL#' => 'utf8', '#VAL1#' => $character_set_connection]); } } else { if ($bAllIn1251 && $character_set_connection != 'WIN1251') { $strError = GetMessage('SC_CONNECTION_CHARSET_WRONG', ['#VAL#' => 'cp1251', '#VAL1#' => $character_set_connection]); } elseif ($character_set_connection == 'UTF8') { $strError = GetMessage('SC_CONNECTION_CHARSET_WRONG_NOT_UTF', ['#VAL#' => $character_set_connection]); } } echo 'character_set_connection=' . $character_set_connection; if (!$strError) { return true; } $this->arTestVars['check_connection_charset_fail'] = true; return $this->Result(false, $strError); } ############################## # MYSQL Tests follow ############################## function check_mysql_bug_version() { global $DB; $MySql_vercheck_min = "5.0.0"; $ver = $DB->GetVersion(); if (version_compare($ver, $MySql_vercheck_min, '<')) { return $this->Result(false, GetMessage('SC_MYSQL_ERR_VER', ['#CUR#' => $ver, '#REQ#' => $MySql_vercheck_min])); } if ($ver == '4.1.21' // sorting || $ver == '5.1.34' // auto_increment || $ver == '5.0.41' // search // || $ver == '5.1.66' // forum page navigation ) { return $this->Result(false, GetMessage('SC_DB_ERR') . ' ' . $ver); } return true; } function check_mysql_mode() { global $DB; $errors = []; $f = $DB->Query('SHOW VARIABLES LIKE \'innodb_strict_mode\'')->Fetch(); if (strtoupper($f['Value']) != 'OFF') { $errors[] = GetMessage('SC_DB_ERR_INNODB_STRICT', ['#VALUE#' => $f['Value']]); } $f = $DB->Query('SHOW VARIABLES LIKE \'sql_mode\'')->Fetch(); if ($f['Value'] <> '') { $errors[] = GetMessage('SC_DB_ERR_MODE') . ' ' . $f['Value']; } $f = $DB->Query('SHOW VARIABLES LIKE \'innodb_large_prefix\'')->Fetch(); if ($f) { if ($f['Value'] === '0' || $f['Value'] === 'OFF') { $errors[] = GetMessage('SC_DB_ERR_INNODB_LARGE_PREFIX', ['#VALUE#' => $f['Value']]); } } $f = $DB->Query('SHOW VARIABLES LIKE \'innodb_default_row_format\'')->Fetch(); if ($f) { if (strtolower($f['Value']) !== 'dynamic') { $errors[] = GetMessage('SC_DB_ERR_INNODB_DEFAULT_ROW_FORMAT', ['#VALUE#' => $f['Value']]); } } $f = $DB->Query('SHOW VARIABLES LIKE \'default_storage_engine\'')->Fetch(); if ($f) { if (strtolower($f['Value']) !== 'innodb') { $errors[] = GetMessage('SC_DB_ERR_DEFAULT_STORAGE_ENGINE', ['#VALUE#' => $f['Value']]); } } return $errors ? $this->Result(false, implode('<br>', $errors)) : true; } function check_mysql_time() { global $DB; $s = time(); while ($s == time()) { ; } $s++; $res = $DB->Query('SELECT NOW() AS A'); $f = $res->Fetch(); if (($diff = abs($s - strtotime($f['A']))) <= 1) { return true; } return $this->Result(false, GetMessage('SC_TIME_DIFF', ['#VAL#' => $diff])); } function check_mysql_table_status() { global $DB; $time = time(); $strError = ''; $i = 0; $res = $DB->Query('SHOW TABLES'); $cnt = $res->SelectedRowsCount(); while ($f = $res->Fetch()) { $i++; $table = current($f); if ($this->arTestVars['last_value']) { if ($this->arTestVars['last_value'] == $table) { unset($this->arTestVars['last_value']); } continue; } if (!$this->fix_mode) { $res0 = $DB->Query('CHECK TABLE ' . $DB->quote($table)); } else { $res0 = $DB->Query('REPAIR TABLE ' . $DB->quote($table)); } $f0 = $res0->Fetch(); if ($f0['Msg_type'] == 'error' || $f0['Msg_type'] == 'warning') { $strError .= GetMessage('SC_TABLE_ERR', ['#VAL#' => $table]) . ' ' . $f0['Msg_text'] . "\n<br>"; } if (time() - $time >= $this->timeout) { $this->arTestVars['last_value'] = $table; $this->test_percent = floor($i / $cnt * 100); return true; } } if (!$strError) { return true; } if (!$this->fix_mode) { $this->arTestVars['check_table_status_fail'] = true; echo $strError; // to log return $this->Result(false, GetMessage('SC_TABLES_NEED_REPAIR') . fix_link(1)); } return $this->Result(false, $strError); } function check_mysql_connection_charset() { global $DB; $strError = ''; if (!empty($this->arTestVars['check_mbstring_fail'])) { return $this->Result(null, GetMessage('SC_MBSTRING_NA')); } $res = $DB->Query('SHOW VARIABLES LIKE "character_set_connection"'); $f = $res->Fetch(); $character_set_connection = $f['Value']; $res = $DB->Query('SHOW VARIABLES LIKE "character_set_results"'); $f = $res->Fetch(); $character_set_results = $f['Value']; $res = $DB->Query('SHOW VARIABLES LIKE "collation_connection"'); $f = $res->Fetch(); $collation_connection = $f['Value']; $bAllIn1251 = true; $res1 = $DB->Query('SELECT C.CHARSET FROM b_lang L, b_culture C WHERE C.ID=L.CULTURE_ID AND L.ACTIVE="Y"'); // for 'no kernel mode' while ($f1 = $res1->Fetch()) { $bAllIn1251 = $bAllIn1251 && trim(strtolower($f1['CHARSET'])) == 'windows-1251'; } if (defined('BX_UTF') && BX_UTF === true) { if (!in_array($character_set_connection, ['utf8', 'utf8mb3', 'utf8mb4'])) { $strError = GetMessage("SC_CONNECTION_CHARSET_WRONG", ['#VAL#' => 'utf8', '#VAL1#' => $character_set_connection]); } elseif (!preg_match('/^(utf8|utf8mb3|utf8mb4)_/', $collation_connection)) { $strError = GetMessage("SC_CONNECTION_COLLATION_WRONG_UTF", ['#VAL#' => $collation_connection]); } } else { if ($bAllIn1251 && $character_set_connection != 'cp1251') { $strError = GetMessage("SC_CONNECTION_CHARSET_WRONG", ['#VAL#' => 'cp1251', '#VAL1#' => $character_set_connection]); } elseif ($character_set_connection == 'utf8') { $strError = GetMessage("SC_CONNECTION_CHARSET_WRONG_NOT_UTF", ['#VAL#' => $character_set_connection]); } } if (!$strError && $character_set_connection != $character_set_results) { $strError = GetMessage('SC_CHARSET_CONN_VS_RES', ['#CONN#' => $character_set_connection, '#RES#' => $character_set_results]); } echo 'character_set_connection=' . $character_set_connection . ', collation_connection=' . $collation_connection . ', character_set_results=' . $character_set_results; if (!$strError) { return true; } $this->arTestVars['check_connection_charset_fail'] = true; return $this->Result(false, $strError); } function check_mysql_db_charset() { global $DB; if (!empty($this->arTestVars['check_mbstring_fail'])) { return $this->Result(null, GetMessage('SC_MBSTRING_NA')); } elseif (!empty($this->arTestVars['check_table_status_fail'])) { return $this->Result(null, GetMessage('SC_TABLES_NEED_REPAIR')); } elseif (!empty($this->arTestVars['check_connection_charset_fail'])) { return $this->Result(null, GetMessage('SC_CONNECTION_CHARSET_NA')); } $strError = ''; $res = $DB->Query('SHOW VARIABLES LIKE \'character_set_connection\''); $f = $res->Fetch(); $character_set_connection = $f['Value']; $res = $DB->Query('SHOW VARIABLES LIKE \'collation_connection\''); $f = $res->Fetch(); $collation_connection = $f['Value']; $res = $DB->Query('SHOW VARIABLES LIKE \'character_set_database\''); $f = $res->Fetch(); $character_set_database = $f['Value']; $res = $DB->Query('SHOW VARIABLES LIKE \'collation_database\''); $f = $res->Fetch(); $collation_database = $f['Value']; if ($this->fix_mode) { if (!$DB->Query($sql = 'ALTER DATABASE ' . $DB->quote($DB->DBName) . ' DEFAULT CHARACTER SET ' . $character_set_connection . ' COLLATE ' . $collation_connection, true)) { $strError = $sql . ' [' . $DB->db_Error . ']'; } } else { if ($character_set_connection != $character_set_database) { $strError = GetMessage('SC_DATABASE_CHARSET_DIFF', ['#VAL0#' => $character_set_connection, '#VAL1#' => $character_set_database]) . fix_link(); } elseif ($collation_database != $collation_connection) { $strError = GetMessage('SC_DATABASE_COLLATION_DIFF', ['#VAL0#' => $collation_connection, '#VAL1#' => $collation_database]) . fix_link(); } } echo 'CHARSET=' . $character_set_database . ', COLLATION=' . $collation_database; if (!$strError) { return true; } $this->arTestVars['db_charset_fail'] = true; return $this->Result(false, $strError); } function check_mysql_table_format() { global $DB; $strError = ''; $res = $DB->Query(" select TABLE_NAME ,ENGINE from information_schema.TABLES where TABLE_SCHEMA = '" . $DB->ForSql($DB->DBName) . "' and TABLE_TYPE = 'BASE TABLE' and TABLE_NAME like 'b\_%' and ( ROW_FORMAT <> 'Dynamic' or ENGINE <> 'InnoDB' ) "); while ($f = $res->Fetch()) { if ($this->fix_mode) { $alter = 'ALTER TABLE ' . $DB->quote($f['TABLE_NAME']) . ' ROW_FORMAT=Dynamic ENGINE=InnoDB'; $res0 = $DB->Query($alter, true); if (!$res0) { $strError .= $alter . ' [' . $DB->db_Error . ']'; break; } } else { $strError .= GetMessage('SC_TABLE_ROW_FORMAT', ['#TABLE#' => $f['TABLE_NAME']]) . '<br>'; $this->arTestVars['iError']++; $this->arTestVars['iErrorAutoFix']++; } } if (!$strError) { return true; } $this->arTestVars['table_format_fail'] = true; if ($this->fix_mode) { return $this->Result(false, $strError); } else { echo $strError; // to log return $this->Result(false, GetMessage('SC_TABLE_ROW_FORMAT_ERRORS', [ '#VAL#' => intval($this->arTestVars['iError']), '#VAL1#' => intval($this->arTestVars['iErrorAutoFix']), ]) . ($this->arTestVars['iErrorAutoFix'] > 0 ? fix_link() : '')); } } function check_mysql_table_charset() { global $DB; $strError = ''; if (!empty($this->arTestVars['check_mbstring_fail'])) { return $this->Result(null, GetMessage('SC_MBSTRING_NA')); } elseif (!empty($this->arTestVars['check_table_status_fail'])) { return $this->Result(null, GetMessage('SC_TABLES_NEED_REPAIR')); } elseif (!empty($this->arTestVars['check_connection_charset_fail'])) { return $this->Result(null, GetMessage('SC_CONNECTION_CHARSET_NA')); } elseif (!empty($this->arTestVars['db_charset_fail'])) { return $this->Result(null, GetMessage('SC_TABLE_CHECK_NA')); } elseif (!empty($this->arTestVars['table_format_fail'])) { return $this->Result(null, GetMessage('SC_TABLE_ROW_FORMAT_NA')); } $res = $DB->Query('SHOW VARIABLES LIKE "character_set_database"'); $f = $res->Fetch(); $charset = trim($f['Value']); $res = $DB->Query('SHOW VARIABLES LIKE "collation_database"'); $f = $res->Fetch(); $collation = trim($f['Value']); $time = time(); $i = 0; $res = $DB->Query('SHOW TABLES LIKE \'b\_%\''); $cnt = $res->SelectedRowsCount(); $arExclusion = [ 'b_sale_loc_search_word' => 'WORD', 'b_search_content_stem' => 'STEM', 'b_search_content_freq' => 'STEM', 'b_search_stem' => 'STEM', 'b_search_tags' => 'NAME', 'b_translate_path' => 'NAME', 'b_translate_phrase' => 'CODE', ]; while ($f = $res->Fetch()) { $i++; $table = current($f); if (!empty($this->arTestVars['last_value'])) { if ($this->arTestVars['last_value'] == $table) { unset($this->arTestVars['last_value']); } continue; } $res0 = $DB->Query('SHOW CREATE TABLE ' . $DB->quote($table), true); if ($res0 === false) { if ($this->fix_mode) { $DB->Query('DROP TABLE ' . $DB->quote($table), true); } else { $strError .= GetMessage('SC_TABLE_BROKEN', ['#TABLE#' => $table]) . "<br>"; $this->arTestVars['iError']++; $this->arTestVars['iErrorAutoFix']++; } continue; } $f0 = $res0->Fetch(); if (preg_match('/DEFAULT CHARSET=([a-z0-9\-_]+)/i', $f0['Create Table'], $regs)) { $t_charset = $regs[1]; if (preg_match('/COLLATE=([a-z0-9\-_]+)/i', $f0['Create Table'], $regs)) { $t_collation = $regs[1]; } else { $res0 = $DB->Query('SHOW CHARSET LIKE \'' . $DB->ForSql(str_replace('_', '\_', $t_charset)) . '\''); $f0 = $res0->Fetch(); $t_collation = $f0['Default collation']; } } else { $res0 = $DB->Query('SHOW TABLE STATUS LIKE \'' . $DB->ForSql(str_replace('_', '\_', $table)) . '\''); $f0 = $res0->Fetch(); if (!$t_collation = $f0['Collation']) { continue; } $t_charset = getCharsetByCollation($t_collation); } if ($charset != $t_charset) { // table charset differs if (!$this->fix_mode) { $strError .= GetMessage('SC_DB_MISC_CHARSET', ['#TABLE#' => $table, '#VAL1#' => $t_charset, '#VAL0#' => $charset]) . "<br>"; $this->arTestVars['iError']++; if ($this->force_repair) { $this->arTestVars['iErrorAutoFix']++; } } elseif ($this->force_repair && !$DB->Query($sql = 'ALTER TABLE ' . $DB->quote($table) . ' CHARACTER SET ' . $charset, true)) { $strError .= $sql . ' [' . $DB->db_Error . ']'; break; } } elseif ($t_collation != $collation) { // table collation differs if (!$this->fix_mode) { $strError .= GetMessage('SC_COLLATE_WARN', ['#TABLE#' => $table, '#VAL1#' => $t_collation, '#VAL0#' => $collation]) . "<br>"; $this->arTestVars['iError']++; $this->arTestVars['iErrorAutoFix']++; } elseif (!$DB->Query($sql = 'ALTER TABLE ' . $DB->quote($table) . ' COLLATE ' . $collation, true)) { $strError .= $sql . ' [' . $DB->db_Error . ']'; break; } } // fields check $arFix = []; $res0 = $DB->Query("SHOW FULL COLUMNS FROM " . $DB->quote($table)); while ($f0 = $res0->Fetch()) { $f_collation = $f0['Collation']; if ($f_collation === null || $f_collation === "NULL") { continue; } $f_charset = getCharsetByCollation($f_collation); if ($charset != $f_charset) { // field charset differs if (!$this->fix_mode) { $strError .= GetMessage('SC_TABLE_CHARSET_WARN', ['#TABLE#' => $table, '#VAL0#' => $charset, '#VAL1#' => $f_charset, '#FIELD#' => $f0['Field']]) . "<br>"; $this->arTestVars['iError']++; if ($this->force_repair) { $this->arTestVars['iErrorAutoFix']++; } } elseif ($this->force_repair) { $arFix[] = ' MODIFY ' . $DB->quote($f0['Field']) . ' ' . $f0['Type'] . ' CHARACTER SET ' . $charset . ($f0['Null'] == 'YES' ? ' NULL' : ' NOT NULL') . ($f0['Default'] === null ? ($f0['Null'] == 'YES' ? ' DEFAULT NULL ' : '') : ' DEFAULT ' . ($f0['Type'] == 'timestamp' && $f0['Default'] ? $f0['Default'] : '"' . $DB->ForSQL($f0['Default']) . '"')) . ' ' . str_ireplace('DEFAULT_GENERATED', '', $f0['Extra']) . ($f0['Comment'] ? ' COMMENT \'' . $DB->ForSql($f0['Comment']) . '\'' : ''); } } elseif ($collation != $f_collation) { if (!empty($arExclusion[$table]) && strtoupper($f0['Field']) == $arExclusion[$table]) { continue; } // field collation differs if (!$this->fix_mode) { $strError .= GetMessage('SC_FIELDS_COLLATE_WARN', ['#TABLE#' => $table, '#VAL0#' => $collation, '#VAL1#' => $f_collation, '#FIELD#' => $f0['Field']]) . "<br>"; if (!isset($this->arTestVars['iError'])) { $this->arTestVars['iError'] = 0; } $this->arTestVars['iError']++; if (!isset($this->arTestVars['iErrorAutoFix'])) { $this->arTestVars['iErrorAutoFix'] = 0; } $this->arTestVars['iErrorAutoFix']++; } else { $arFix[] = ' MODIFY ' . $DB->quote($f0['Field']) . ' ' . $f0['Type'] . ' COLLATE ' . $collation . ($f0['Null'] == 'YES' ? ' NULL' : ' NOT NULL') . ($f0['Default'] === null ? ($f0['Null'] == 'YES' ? ' DEFAULT NULL ' : '') : ' DEFAULT ' . ($f0['Type'] == 'timestamp' && $f0['Default'] ? $f0['Default'] : '"' . $DB->ForSQL($f0['Default']) . '"')) . ' ' . str_ireplace('DEFAULT_GENERATED', '', $f0['Extra']) . ($f0['Comment'] ? ' COMMENT \'' . $DB->ForSql($f0['Comment']) . '\'' : ''); } } } if ($this->fix_mode && count($arFix)) { if (!$DB->Query($sql = 'ALTER TABLE ' . $DB->quote($table) . ' ' . implode(",\n", $arFix), true)) { $strError .= $sql . ' [' . $DB->db_Error . ']'; break; } } if (time() - $time >= $this->timeout) { $this->arTestVars['last_value'] = $table; $this->test_percent = floor($i / $cnt * 100); return true; } } if (!$strError) { return true; } $this->arTestVars['table_charset_fail'] = true; if ($this->fix_mode) { return $this->Result(false, $strError); } else { echo $strError; // to log return $this->Result(false, GetMessage('SC_CHECK_TABLES_ERRORS', ['#VAL#' => intval($this->arTestVars['iError']), '#VAL1#' => intval($this->arTestVars['iErrorAutoFix'])]) . ($this->arTestVars['iErrorAutoFix'] > 0 ? fix_link() : '')); } } function check_mysql_table_structure() { global $DB; $strError = ''; $arInsertExclude = [ 'b_seo_search_engine' => 1, 'b_hot_keys_code' => 1, ]; if (!empty($this->arTestVars['table_charset_fail'])) { return $this->Result(null, GetMessage('SC_TABLE_COLLATION_NA')); } elseif (!empty($this->arTestVars['table_format_fail'])) { return $this->Result(null, GetMessage('SC_TABLE_ROW_FORMAT_NA')); } $DB->Query("SET SQL_MODE=''"); $module = ''; $cnt = $iCurrent = 0; if ($dir = opendir($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules')) { while (false !== ($item = readdir($dir))) { if (str_contains($item, '.')) // skipping all external modules { continue; } $cnt++; if (!empty($this->arTestVars['last_value'])) { $iCurrent++; if ($this->arTestVars['last_value'] == $item) { unset($this->arTestVars['last_value']); } } elseif (!$module) { $module = $item; } } closedir($dir); } else { return false; } $file = $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $module . '/install/db/mysql/install.sql'; if (!file_exists($file)) { $file = $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $module . '/install/mysql/install.sql'; } if (file_exists($file)) // uses database... { $arTableColumns = []; $bModuleInstalled = $DB->Query('SELECT * FROM b_module WHERE id=\'' . $DB->ForSQL($module) . '\'')->Fetch(); if (false === ($query = file_get_contents($file))) { return false; } $arTables = []; $arQuery = $DB->ParseSQLBatch(str_replace("\r", "", $query)); foreach ($arQuery as $sql) { if (preg_match('#^(CREATE TABLE )(IF NOT EXISTS)? *`?([a-z0-9_]+)`?(.*);?$#mis', $sql, $regs)) { $table = $regs[3]; if (str_starts_with($table, 'site_checker_')) { continue; } $bTableExists = $DB->Query('SHOW TABLES LIKE \'' . $DB->ForSql(str_replace('_', '\_', $table)) . '\'')->Fetch(); if (!$bTableExists && $bModuleInstalled) { if ($this->fix_mode) { if (!$DB->Query($sql, true)) { return $this->Result(false, 'Mysql Query Error: ' . $sql . ' [' . $DB->db_Error . ']'); } } else { $strError .= GetMessage('SC_ERR_NO_TABLE', ['#TABLE#' => $table]) . "<br>"; \Bitrix\Main\Application::getInstance()->getSession()['FixQueryList'][] = $sql; $this->arTestVars['iError']++; $this->arTestVars['iErrorAutoFix']++; $this->arTestVars['cntNoTables']++; continue; } } if ($bTableExists || $bModuleInstalled) { $arTables[$table] = $sql; $tmp_table = 'site_checker_' . $table; $DB->Query('DROP TABLE IF EXISTS ' . $DB->quote($tmp_table)); $DB->Query($regs[1] . ' ' . $DB->quote($tmp_table) . $regs[4]); } } elseif (preg_match('#^(ALTER TABLE)( )?`?([a-z0-9_]+)`?(.*);?$#mis', $sql, $regs)) { $table = $regs[3]; if (!$arTables[$table]) { continue; } $tmp_table = 'site_checker_' . $table; $DB->Query($regs[1] . ' ' . $DB->quote($tmp_table) . $regs[4]); } elseif (preg_match('#^INSERT INTO *`?([a-z0-9_]+)`?[^(]*\(?([^)]*)\)?[^V]*VALUES[^(]*\((.+)\);?$#mis', $sql, $regs)) { $table = $regs[1]; if (!$arTables[$table] || !empty($arInsertExclude[$table])) { continue; } $tmp_table = 'site_checker_' . $table; if ($regs[2]) { $arColumns = explode(',', $regs[2]); } else { if (!$arTableColumns[$tmp_table]) { $rs = $DB->Query('SHOW COLUMNS FROM ' . $DB->quote($tmp_table)); while ($f = $rs->Fetch()) { $arTableColumns[$tmp_table][] = $f['Field']; } } $arColumns = $arTableColumns[$tmp_table]; } $strValues = $regs[3]; $ar = explode(",", $strValues); $arValues = []; $i = 0; $str = ''; foreach ($ar as $v) { $str .= ($str ? ',' : '') . $v; if (preg_match('#^ *(-?[0-9]+|\'.*\'|".*"|null|now\(\)) *$#i', $str)) { $arValues[$i] = $str; $str = ''; $i++; } } if (!$str) { $sqlSelect = 'SELECT * FROM ' . $DB->quote($table) . ' WHERE 1=1 '; foreach ($arColumns as $k => $c) { $v = $arValues[$k]; if (!preg_match('#null|now\(\)#i', $v)) { $sqlSelect .= ' AND ' . $c . '=' . $v; } } $rs = $DB->Query($sqlSelect); if (!$rs->Fetch()) { if ($this->fix_mode) { if (!$DB->Query($sql, true)) { return $this->Result(false, 'Mysql Query Error: ' . $sql . ' [' . $DB->db_Error . ']'); } } else { $strError .= GetMessage('SC_ERR_NO_VALUE', ['#TABLE#' => $table, '#SQL#' => $sql]) . "<br>"; \Bitrix\Main\Application::getInstance()->getSession()['FixQueryList'][] = $sql; $this->arTestVars['iError']++; $this->arTestVars['iErrorAutoFix']++; $this->arTestVars['cntNoValues']++; } } } else { echo "Error parsing SQL:\n" . $sql . "\n"; } } } if (file_exists($file = str_replace('/install.sql', '/install_ft.sql', $file))) { if (false === ($query = file_get_contents($file))) { return false; } $query = preg_replace('# on +([a-z_0-9]+) \(#i', ' on site_checker_\\1 (', $query); $arQuery = $DB->ParseSQLBatch(str_replace("\r", "", $query)); foreach ($arQuery as $sql) { if (!$DB->Query($sql, true)) { break; } } } foreach ($arTables as $table => $sql) { $tmp_table = 'site_checker_' . $table; $arIndexes = []; $rs = $DB->Query('SHOW INDEXES FROM ' . $DB->quote($table)); while ($f = $rs->Fetch()) { $column = strtolower($f['Column_name'] . ($f['Sub_part'] ? '(' . $f['Sub_part'] . ')' : '')); if (!empty($arIndexes[$f['Key_name']])) { $arIndexes[$f['Key_name']] .= ',' . $column; } else { $arIndexes[$f['Key_name']] = $column; } } $arIndexes_tmp = []; $arFT = []; $rs = $DB->Query('SHOW INDEXES FROM ' . $DB->quote($tmp_table)); while ($f = $rs->Fetch()) { $column = strtolower($f['Column_name'] . ($f['Sub_part'] ? '(' . $f['Sub_part'] . ')' : '')); if (!empty($arIndexes_tmp[$f['Key_name']])) { $arIndexes_tmp[$f['Key_name']] .= ',' . $column; } else { $arIndexes_tmp[$f['Key_name']] = $column; } if ($f['Index_type'] == 'FULLTEXT') { $arFT[$f['Key_name']] = true; } } foreach ($arIndexes_tmp as $name => $ix) { if (!in_array($ix, $arIndexes)) { if ($arIndexes[$name]) { if ($name == 'PRIMARY') // dropping primary is not supported { continue; } $sql = 'ALTER TABLE ' . $DB->quote($table) . ' DROP INDEX ' . $DB->quote($name); if ($this->fix_mode) { if (!$DB->Query($sql, true)) { return $this->Result(false, 'Mysql Query Error: ' . $sql . ' [' . $DB->db_Error . ']'); } } else { \Bitrix\Main\Application::getInstance()->getSession()['FixQueryList'][] = $sql; $this->arTestVars['iError']++; $this->arTestVars['iErrorAutoFix']++; } } } } $arColumns = []; $rs = $DB->Query('SHOW COLUMNS FROM ' . $DB->quote($table)); while ($f = $rs->Fetch()) { $arColumns[strtolower($f['Field'])] = $f; } $rs = $DB->Query('SHOW COLUMNS FROM ' . $DB->quote($tmp_table)); while ($f_tmp = $rs->Fetch()) { $tmp = TableFieldConstruct($f_tmp); if ($f = $arColumns[strtolower($f_tmp['Field'])]) { if (($cur = TableFieldConstruct($f)) != $tmp) { $sql = 'ALTER TABLE ' . $DB->quote($table) . ' CHANGE ' . $DB->quote($f['Field']) . ' ' . $tmp; if ($this->fix_mode) { if ($this->TableFieldCanBeAltered($f, $f_tmp)) { if (!$DB->Query($sql, true)) { return $this->Result(false, 'Mysql Query Error: ' . $sql . ' [' . $DB->db_Error . ']'); } } else { $this->arTestVars['iErrorFix']++; } } else { \Bitrix\Main\Application::getInstance()->getSession()['FixQueryList'][] = $sql; $strError .= GetMessage('SC_ERR_FIELD_DIFFERS', ['#TABLE#' => $table, '#FIELD#' => $f['Field'], '#CUR#' => $cur, '#NEW#' => $tmp]) . "<br>"; $this->arTestVars['iError']++; if ($this->TableFieldCanBeAltered($f, $f_tmp)) { $this->arTestVars['iErrorAutoFix']++; } $this->arTestVars['cntDiffFields']++; } } } else { $sql = 'ALTER TABLE ' . $DB->quote($table) . ' ADD ' . preg_replace('#auto_increment#i', '', $tmp); // if only Primary Key is missing we will have to pass the test twice if ($this->fix_mode) { if (!$DB->Query($sql, true)) { return $this->Result(false, 'Mysql Query Error: ' . $sql . ' [' . $DB->db_Error . ']'); } } else { \Bitrix\Main\Application::getInstance()->getSession()['FixQueryList'][] = $sql; $strError .= GetMessage('SC_ERR_NO_FIELD', ['#TABLE#' => $table, '#FIELD#' => $f_tmp['Field']]) . "<br>"; $this->arTestVars['iError']++; $this->arTestVars['iErrorAutoFix']++; $this->arTestVars['cntNoFields']++; } } } foreach ($arIndexes_tmp as $name => $ix) { if (!in_array($ix, $arIndexes)) { if ($name == 'PRIMARY' && $arIndexes['PRIMARY']) // Primary key exists { $this->arTestVars['iError']++; $strError .= GetMessage('SC_ERR_NO_INDEX', ['#TABLE#' => $table, '#INDEX#' => $name . ' (' . $ix . ')']) . "<br>"; continue; } $sql = $name == 'PRIMARY' ? 'ALTER TABLE ' . $DB->quote($table) . ' ADD PRIMARY KEY (' . $ix . ')' : 'CREATE ' . ($arFT[$name] ? 'FULLTEXT ' : '') . 'INDEX ' . $DB->quote($name) . ' ON ' . $DB->quote($table) . ' (' . $ix . ')'; if ($this->fix_mode) { if (!$DB->Query($sql, true)) { return $this->Result(false, 'Mysql Query Error: ' . $sql . ' [' . $DB->db_Error . ']'); } } else { \Bitrix\Main\Application::getInstance()->getSession()['FixQueryList'][] = $sql; $strError .= GetMessage('SC_ERR_NO_INDEX', ['#TABLE#' => $table, '#INDEX#' => $name . ' (' . $ix . ')']) . "<br>"; $this->arTestVars['iError']++; $this->arTestVars['iErrorAutoFix']++; $this->arTestVars['cntNoIndexes']++; } } } $DB->Query('DROP TABLE ' . $DB->quote($tmp_table)); } echo $strError; // to log } if ($iCurrent < $cnt) // partial { $this->arTestVars['last_value'] = $module; $this->test_percent = floor($iCurrent / $cnt * 100); return true; } if ($this->fix_mode) { if ($this->arTestVars['iErrorFix'] > 0) { return $this->Result(null, GetMessage('SC_CHECK_TABLES_STRUCT_ERRORS_FIX', [ '#VAL#' => intval($this->arTestVars['iErrorFix']), ])); } } else { if (isset($this->arTestVars['iError']) && $this->arTestVars['iError'] > 0) { if (is_array(\Bitrix\Main\Application::getInstance()->getSession()['FixQueryList']) && count(\Bitrix\Main\Application::getInstance()->getSession()['FixQueryList'])) { echo implode(";\n", \Bitrix\Main\Application::getInstance()->getSession()['FixQueryList']) . ';'; } \Bitrix\Main\Application::getInstance()->getSession()['FixQueryList'] = []; return $this->Result(false, GetMessage('SC_CHECK_TABLES_STRUCT_ERRORS', [ '#VAL#' => intval($this->arTestVars['iError']), '#VAL1#' => intval($this->arTestVars['iErrorAutoFix']), '#NO_TABLES#' => intval($this->arTestVars['cntNoTables']), '#NO_FIELDS#' => intval($this->arTestVars['cntNoFields']), '#DIFF_FIELDS#' => intval($this->arTestVars['cntDiffFields']), '#NO_INDEXES#' => intval($this->arTestVars['cntNoIndexes']), '#NO_VALUES#' => intval($this->arTestVars['cntNoValues']), ]) . ($this->arTestVars['iErrorAutoFix'] > 0 ? fix_link(3) : '')); } } return true; } ############### # } # public static function CommonTest() { if ( defined('BX_CRONTAB') || (defined('CHK_EVENT') && CHK_EVENT === true) || (!isset($_SERVER['HTTP_HOST']) || !$_SERVER['HTTP_HOST']) ) { // can't get real HTTP server vars from cron return "CSiteCheckerTest::CommonTest();"; } if ( ($ntlm_varname = COption::GetOptionString('ldap', 'ntlm_varname', 'REMOTE_USER')) && (trim($_SERVER[$ntlm_varname] ?? '')) ) { // Server NTLM is enabled, no way to connect through a socket return "CSiteCheckerTest::CommonTest();"; } IncludeModuleLangFile($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/admin/site_checker.php'); $step = 0; $ar = null; while (true) { $oTest = new CSiteCheckerTest($step, 1); if ($ar !== null) { $oTest->arTestVars = $ar; } $oTest->ssl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') || (isset($_SERVER["SERVER_PORT"]) && $_SERVER["SERVER_PORT"] == 443); if (preg_match('#^(.+):([0-9]+)$#', $_SERVER['HTTP_HOST'], $regs)) { $oTest->host = $regs[1]; $oTest->port = $regs[2]; if ($oTest->port == 443) { $oTest->ssl = true; } } else { $oTest->host = $_SERVER['HTTP_HOST']; $oTest->port = isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] ? $_SERVER['SERVER_PORT'] : ($oTest->ssl ? 443 : 80); } $oTest->Start(); if ($oTest->result === false) { $error = [ "MESSAGE" => ( IsModuleInstalled('intranet') ? GetMessage("MAIN_SC_GOT_ERRORS", ['#LINK#' => "/bitrix/admin/site_checker.php?lang=" . LANGUAGE_ID . "&express_test=Y"]) : GetMessage("MAIN_SC_SITE_GOT_ERRORS", ['#LINK#' => "/bitrix/admin/site_checker.php?lang=" . LANGUAGE_ID . "&start_test=Y"]) ), "TAG" => "SITE_CHECKER", "MODULE_ID" => "MAIN", 'NOTIFY_TYPE' => CAdminNotify::TYPE_NORMAL, ]; CAdminNotify::Add($error); break; } if ($oTest->percent >= 100) { break; } $step++; $ar = $oTest->arTestVars; } $REMOTE_ADDR = $_SERVER['REMOTE_ADDR']; $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT']; $_SERVER['REMOTE_ADDR'] = '-'; $_SERVER['HTTP_USER_AGENT'] = '-'; CEventLog::Add([ "SEVERITY" => "WARNING", "AUDIT_TYPE_ID" => isset($oTest->arTestVars['site_checker_success']) && $oTest->arTestVars['site_checker_success'] == 'Y' ? 'SITE_CHECKER_SUCCESS' : 'SITE_CHECKER_ERROR', "MODULE_ID" => "main", "ITEM_ID" => 'CSiteCheckerTest::CommonTest();', "URL" => '-', "DESCRIPTION" => '', ]); $_SERVER['REMOTE_ADDR'] = $REMOTE_ADDR; $_SERVER['HTTP_USER_AGENT'] = $HTTP_USER_AGENT; return "CSiteCheckerTest::CommonTest();"; } public static function PhpTestAgent() { IncludeModuleLangFile($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/admin/site_checker.php'); if (version_compare($v = phpversion(), self::MIN_PHP_VER, '<')) { CAdminNotify::Add([ 'MESSAGE' => GetMessage('PHP_VER_NOTIFY', ['#CUR#' => $v, '#REQ#' => self::MIN_PHP_VER]), 'TAG' => 'PHP_VERSION', 'MODULE_ID' => 'MAIN', 'NOTIFY_TYPE' => CAdminNotify::TYPE_ERROR, ]); return "CSiteCheckerTest::PhpTestAgent();"; } CAdminNotify::DeleteByTag('PHP_VERSION'); return ''; } } class CSearchFiles { public $StartTime; public $arFail = []; public $FilesCount = 0; public $MaxFail = 9; public $TimeLimit = 0; public $SkipPath = ''; public $BreakPoint = ''; public function __construct() { $this->StartTime = time(); } function Search($path) { if (time() - $this->StartTime > $this->TimeLimit) { $this->BreakPoint = $path; return empty($this->arFail); } if (count($this->arFail) > $this->MaxFail) { return false; } if ($this->SkipPath) { if (!str_starts_with($this->SkipPath, dirname($path))) { return null; } if ($this->SkipPath == $path) { $this->SkipPath = null; } } if (is_dir($path)) { if (is_readable($path)) { if (!is_writable($path)) { $this->arFail[] = $path; } if ($dir = opendir($path)) { while (false !== $item = readdir($dir)) { if ($item == '.' || $item == '..') { continue; } $this->Search($path . '/' . $item); if ($this->BreakPoint) { break; } } closedir($dir); } } else { $this->arFail[] = $path; } } elseif (!$this->SkipPath) { $this->FilesCount++; if (!is_readable($path) || !is_writable($path)) { $this->arFail[] = $path; } } return empty($this->arFail); } } //////////////////////////////////////////////////////////////////////// ////////// FUNCTIONS /////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// function CheckGetModuleInfo($path) { include_once($path); $arr = explode("/", $path); $i = array_search("modules", $arr); $class_name = $arr[$i + 1]; return CModule::CreateModuleObject($class_name); } function IsHttpResponseSuccess($res, $strRequest) { $strRes = GetHttpResponse($res, $strRequest, $strHeaders); if (trim($strRes) == 'SUCCESS') { return true; } else { PrintHTTP($strRequest, $strHeaders, $strRes); return false; } } function GetHttpResponse($res, $strRequest, &$strHeaders) { fputs($res, $strRequest); $strHeaders = ""; $bChunked = false; $Content_Length = false; while (!feof($res) && ($line = fgets($res, 4096)) && $line != "\r\n") { $strHeaders .= $line; if (preg_match("/Transfer-Encoding: +chunked/i", $line)) { $bChunked = true; } if (preg_match("/Content-Length: +([0-9]+)/i", $line, $regs)) { $Content_Length = $regs[1]; } } $strRes = ""; if ($bChunked) { $maxReadSize = 4096; $line = fgets($res, $maxReadSize); $line = strtolower($line); $strChunkSize = ""; $i = 0; while ($i < strlen($line) && in_array($line[$i], ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"])) { $strChunkSize .= $line[$i]; $i++; } $chunkSize = hexdec($strChunkSize); while ($chunkSize > 0) { $processedSize = 0; $readSize = (($chunkSize > $maxReadSize) ? $maxReadSize : $chunkSize); while ($readSize > 0 && $line = fread($res, $readSize)) { $strRes .= $line; $processedSize += strlen($line); $newSize = $chunkSize - $processedSize; $readSize = (($newSize > $maxReadSize) ? $maxReadSize : $newSize); } $line = fgets($res, $maxReadSize); $line = strtolower($line); $strChunkSize = ""; $i = 0; while ($i < strlen($line) && in_array($line[$i], ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"])) { $strChunkSize .= $line[$i]; $i++; } $chunkSize = hexdec($strChunkSize); } } elseif ($Content_Length !== false) { if ($Content_Length > 0) { $strRes = fread($res, $Content_Length); } } else { while ($line = fread($res, 4096)) { $strRes .= $line; } } fclose($res); return $strRes; } function checker_get_unique_id() { $LICENSE_KEY = ''; @include($_SERVER['DOCUMENT_ROOT'] . '/bitrix/license_key.php'); if ($LICENSE_KEY == '') { $LICENSE_KEY = 'DEMO'; } return md5($_SERVER['DOCUMENT_ROOT'] . filemtime($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/admin/site_checker.php') . $LICENSE_KEY); } function getCharsetByCollation($collation) { global $DB; static $CACHE; if (!$c = &$CACHE[$collation]) { $res0 = $DB->Query('SHOW COLLATION LIKE "' . $collation . '"'); $f0 = $res0->Fetch(); $c = $f0['Charset']; } return $c; } function InitPureDB() { require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/tools.php"); global $DB, $DBDebug, $DBDebugToFile; /** * Defined in dbconn.php * @var $DBDebug * @var $DBDebugToFile */ require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/php_interface/dbconn.php"); if (defined('BX_UTF')) { define('BX_UTF_PCRE_MODIFIER', 'u'); } else { define('BX_UTF_PCRE_MODIFIER', ''); } require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/lib/loader.php"); require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/autoload.php"); // Database-dependent classes CAllDatabase::registerAutoload(); $DB = new CDatabase; $DB->debug = $DBDebug; $DB->DebugToFile = $DBDebugToFile; if (!$DB->DoConnect()) { CDatabase::showConnectionError(); die(); } } function TableFieldConstruct($field) { global $DB; $tmp = $DB->quote($field['Field']) . ' '; if (preg_match("/^(TINYINT|SMALLINT|MEDIUMINT|INT|BIGINT)\\(\d+\\)(.*)/i", $field['Type'], $matches)) { // As of MySQL 8.0.17, the ZEROFILL attribute is deprecated for numeric data types, as is the display width attribute for integer data types $tmp .= $matches[1] . $matches[2]; } else { $tmp .= $field['Type']; } if ($field['Null'] == 'YES') { $tmp .= ' NULL'; } else { $tmp .= ' NOT NULL'; } if ($field['Default'] === null) { if ($field['Null'] == 'YES') { $tmp .= ' DEFAULT NULL '; } } else { $tmp .= ' DEFAULT '; if (($field['Type'] == 'timestamp' || $field['Type'] == 'datetime') && !preg_match('#^\d{4}#', $field['Default'])) { $tmp .= $field['Default']; } elseif ($field['Type'] == 'text' && preg_match("/^'.*'$/", $field['Default'])) { // MariaDB's bug with text fields default values in single quotes $tmp .= $field['Default']; } else { $tmp .= "'" . $DB->ForSQL($field['Default']) . "'"; } } $tmp .= ' ' . str_ireplace('DEFAULT_GENERATED', '', $field['Extra']); return trim($tmp); } function fix_link($mode = 2) { return ' <a href="javascript:show_popup(\'' . GetMessageJS('SC_FIX_DATABASE') . '\', \'?fix_mode=' . $mode . '\', \'' . GetMessageJS('SC_FIX_DATABASE_CONFIRM') . '\')">' . GetMessage('SC_FIX') . '</a>'; } function PrintHTTP($strRequest, $strHeaders, $strRes) { echo "== Request ==\n" . (($l = strlen($strRequest)) > 1000 ? substr($strRequest, 0, 1000) . ' ... (' . $l . ' bytes)' : $strRequest) . "\n" . "== Response ==\n" . $strHeaders . "\n" . "== Body ==\n" . (($l = strlen($strRes)) > 1000 ? substr($strRes, 0, 1000) . ' ... (' . $l . ' bytes)' : $strRes) . "\n" . "==========\n"; }