Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/search/tools/ |
Upload File : |
<?php IncludeModuleLangFile(__FILE__); class CSearchSphinx extends CSearchFullText { public $arForumTopics = []; public $db = false; private static $fields = [ 'title' => 'field', 'body' => 'field', 'module_id' => 'uint', 'module' => 'string', 'item_id' => 'uint', 'item' => 'string', 'param1_id' => 'uint', 'param1' => 'string', 'param2_id' => 'uint', 'param2' => 'string', 'date_change' => 'timestamp', 'date_from' => 'timestamp', 'date_to' => 'timestamp', 'custom_rank' => 'uint', 'tags' => 'mva', 'right' => 'mva', 'site' => 'mva', 'param' => 'mva', ]; private static $typesMap = [ 'timestamp' => 'rt_attr_timestamp', 'string' => 'rt_attr_string', 'bigint' => 'rt_attr_bigint', 'uint' => 'rt_attr_uint', 'field' => 'rt_field', 'mva' => 'rt_attr_multi', ]; private $errorText = ''; private $errorNumber = 0; public $tags = ''; public $query = ''; public $SITE_ID = ''; public $connectionIndex = ''; public $indexName = ''; public function connect($connectionIndex, $indexName = '', $ignoreErrors = false) { global $APPLICATION; if (!preg_match('/^[a-zA-Z0-9_]+$/', $indexName)) { if ($ignoreErrors) { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_CONN_ERROR_INDEX_NAME')); } else { throw new \Bitrix\Main\Db\ConnectionException('Sphinx connect error', GetMessage('SEARCH_SPHINX_CONN_ERROR_INDEX_NAME')); } return false; } if (!$this->canConnect()) { if ($ignoreErrors) { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_CONN_EXT_IS_MISSING')); } else { throw new \Bitrix\Main\Db\ConnectionException('Sphinx connect error', GetMessage('SEARCH_SPHINX_CONN_EXT_IS_MISSING')); } return false; } $error = ''; $this->db = $this->internalConnect($connectionIndex, $error); if (!$this->db) { if ($ignoreErrors) { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_CONN_ERROR', ['#ERRSTR#' => $error])); } else { throw new \Bitrix\Main\Db\ConnectionException('Sphinx connect error', GetMessage('SEARCH_SPHINX_CONN_ERROR', ['#ERRSTR#' => $error])); } return false; } if ($ignoreErrors) { $result = $this->query('SHOW TABLES'); if (!$result) { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_CONN_ERROR', ['#ERRSTR#' => $this->getError()])); return false; } if ($indexName == '') { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_CONN_NO_INDEX')); return false; } $indexType = ''; while ($res = $this->fetch($result)) { if ($indexName === $res['Index']) { $indexType = $res['Type']; } } if ($indexType == '') { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_CONN_INDEX_NOT_FOUND')); return false; } if ($indexType != 'rt') { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_CONN_INDEX_WRONG_TYPE')); return false; } $indexColumns = []; $result = $this->query('DESCRIBE `' . $indexName . '`'); if (!$result) { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_DESCR_ERROR', ['#ERRSTR#' => $this->getError()])); return false; } while ($res = $this->fetch($result)) { $indexColumns[$res['Field']] = $res['Type']; } $missed = []; foreach (self::$fields as $name => $type) { if (!isset($indexColumns[$name]) || $indexColumns[$name] !== $type) { $missed[] = self::$typesMap[$type] . ' = ' . $name; } } if (!empty($missed)) { $APPLICATION->ThrowException(GetMessage('SEARCH_SPHINX_NO_FIELDS', ['#FIELD_LIST#' => implode(', ', $missed)])); return false; } } $this->indexName = $indexName; $this->connectionIndex = $connectionIndex; return true; } public function truncate() { $this->query('truncate rtindex ' . $this->indexName); $this->connect($this->connectionIndex, $this->indexName); } public function deleteById($ID) { $this->query('delete from ' . $this->indexName . ' where id = ' . intval($ID)); } public function replace($ID, $arFields) { $DB = CDatabase::GetModuleConnection('search'); if (array_key_exists('~DATE_CHANGE', $arFields)) { $arFields['DATE_CHANGE'] = $arFields['~DATE_CHANGE']; unset($arFields['~DATE_CHANGE']); } elseif (array_key_exists('LAST_MODIFIED', $arFields)) { $arFields['DATE_CHANGE'] = $arFields['LAST_MODIFIED']; unset($arFields['LAST_MODIFIED']); } elseif (array_key_exists('DATE_CHANGE', $arFields)) { $arFields['DATE_CHANGE'] = $DB->FormatDate($arFields['DATE_CHANGE'], 'DD.MM.YYYY HH:MI:SS', CLang::GetDateFormat()); } $DATE_FROM = intval(MakeTimeStamp($arFields['DATE_FROM'])); if ($DATE_FROM > 0) { $DATE_FROM -= CTimeZone::GetOffset(); } $DATE_TO = intval(MakeTimeStamp($arFields['DATE_TO'])); if ($DATE_TO > 0) { $DATE_TO -= CTimeZone::GetOffset(); } $DATE_CHANGE = intval(MakeTimeStamp($arFields['DATE_CHANGE'])); if ($DATE_CHANGE > 0) { $DATE_CHANGE -= CTimeZone::GetOffset(); } $BODY = CSearch::KillEntities($arFields['BODY']) . "\r\n" . $arFields['TAGS']; $sql = ' REPLACE INTO ' . $this->indexName . ' ( id ,module_id ,module ,item_id ,item ,param1_id ,param1 ,param2_id ,param2 ,date_change ,date_from ,date_to ,custom_rank ,tags ,right ,site ,param ,title ,body ) VALUES ( ' . $ID . ' ,' . sprintf('%u', crc32($arFields['MODULE_ID'])) . " ,'" . $this->Escape($arFields['MODULE_ID']) . "' ," . sprintf('%u', crc32($arFields['ITEM_ID'])) . " ,'" . $this->Escape($arFields['ITEM_ID']) . "' ," . sprintf('%u', crc32($arFields['PARAM1'])) . " ,'" . $this->Escape($arFields['PARAM1']) . "' ," . sprintf('%u', crc32($arFields['PARAM2'])) . " ,'" . $this->Escape($arFields['PARAM2']) . "' ," . $DATE_CHANGE . ' ,' . $DATE_FROM . ' ,' . $DATE_TO . ' ,' . intval($arFields['CUSTOM_RANK']) . ' ,(' . $this->tags($arFields['SITE_ID'], $arFields['TAGS']) . ') ,(' . $this->rights($arFields['PERMISSIONS']) . ') ,(' . $this->sites($arFields['SITE_ID']) . ') ,(' . $this->params($arFields['PARAMS']) . ") ,'" . $this->Escape($arFields['TITLE']) . "' ,'" . $this->Escape($BODY) . "' ) "; $result = $this->query($sql); if ($result) { $this->tagsRegister($arFields['SITE_ID'], $arFields['TAGS']); } else { throw new \Bitrix\Main\Db\SqlQueryException('Sphinx select error', $this->getError(), $sql); } } public function update($ID, $arFields) { $DB = CDatabase::GetModuleConnection('search'); $ID = intval($ID); $arUpdate = []; $bReplace = array_key_exists('TITLE', $arFields) || array_key_exists('BODY', $arFields) || array_key_exists('MODULE_ID', $arFields) || array_key_exists('ITEM_ID', $arFields) || array_key_exists('PARAM1', $arFields) || array_key_exists('PARAM2', $arFields) ; if (array_key_exists('~DATE_CHANGE', $arFields)) { $arFields['DATE_CHANGE'] = $arFields['~DATE_CHANGE']; unset($arFields['~DATE_CHANGE']); } elseif (array_key_exists('LAST_MODIFIED', $arFields)) { $arFields['DATE_CHANGE'] = $arFields['LAST_MODIFIED']; unset($arFields['LAST_MODIFIED']); } elseif (array_key_exists('DATE_CHANGE', $arFields)) { $arFields['DATE_CHANGE'] = $DB->FormatDate($arFields['DATE_CHANGE'], 'DD.MM.YYYY HH:MI:SS', CLang::GetDateFormat()); } if (array_key_exists('DATE_CHANGE', $arFields)) { $DATE_CHANGE = intval(MakeTimeStamp($arFields['DATE_CHANGE'])); if ($DATE_CHANGE > 0) { $DATE_CHANGE -= CTimeZone::GetOffset(); } $arUpdate['date_change'] = $DATE_CHANGE; } if (array_key_exists('DATE_FROM', $arFields)) { $DATE_FROM = intval(MakeTimeStamp($arFields['DATE_FROM'])); if ($DATE_FROM > 0) { $DATE_FROM -= CTimeZone::GetOffset(); } $arUpdate['date_from'] = $DATE_FROM; } if (array_key_exists('DATE_TO', $arFields)) { $DATE_TO = intval(MakeTimeStamp($arFields['DATE_TO'])); if ($DATE_TO > 0) { $DATE_TO -= CTimeZone::GetOffset(); } $arUpdate['date_to'] = $DATE_TO; } if (array_key_exists('CUSTOM_RANK', $arFields)) { $arUpdate['custom_rank'] = '' . intval($arFields['CUSTOM_RANK']) . ''; } if (array_key_exists('TAGS', $arFields)) { $arUpdate['tags'] = '(' . $this->tags($arFields['SITE_ID'], $arFields['TAGS']) . ')'; } if (array_key_exists('PERMISSIONS', $arFields)) { $arUpdate['right'] = '(' . $this->rights($arFields['PERMISSIONS']) . ')'; } if (array_key_exists('SITE_ID', $arFields)) { $arUpdate['site'] = '(' . $this->sites($arFields['SITE_ID']) . ')'; } if (array_key_exists('PARAMS', $arFields)) { $arUpdate['param'] = '(' . $this->params($arFields['PARAMS']) . ')'; } if (!empty($arUpdate) && !$bReplace) { foreach ($arUpdate as $columnName => $sqlValue) { $arUpdate[$columnName] = $columnName . '=' . $sqlValue; } $this->query(' UPDATE ' . $this->indexName . ' SET ' . implode(', ', $arUpdate) . ' WHERE id = ' . $ID ); } elseif ($bReplace) { $dbItem = $DB->Query(' SELECT * ,' . $DB->DateToCharFunction('DATE_CHANGE') . ' as LAST_MODIFIED ,' . $DB->DateToCharFunction('DATE_FROM') . ' as DATE_FROM ,' . $DB->DateToCharFunction('DATE_TO') . ' as DATE_TO FROM b_search_content WHERE ID = ' . $ID ); $searchItem = $dbItem->fetch(); if ($searchItem) { $dbTags = $DB->Query('SELECT * from b_search_tags WHERE SEARCH_CONTENT_ID=' . $ID); while ($tag = $dbTags->fetch()) { $searchItem['TAGS'] .= $tag['NAME'] . ','; } $dbRights = $DB->Query('SELECT * from b_search_content_right WHERE SEARCH_CONTENT_ID=' . $ID); while ($right = $dbRights->fetch()) { $searchItem['PERMISSIONS'][] = $right['GROUP_CODE']; } $dbSites = $DB->Query('SELECT * from b_search_content_site WHERE SEARCH_CONTENT_ID=' . $ID); while ($site = $dbSites->fetch()) { $searchItem['SITE_ID'][$site['SITE_ID']] = $site['URL']; } $dbParams = $DB->Query('SELECT * from b_search_content_param WHERE SEARCH_CONTENT_ID=' . $ID); while ($param = $dbParams->fetch()) { $searchItem['PARAMS'][$param['PARAM_NAME']][] = $param['PARAM_VALUE']; } $this->replace($ID, $searchItem); } } } function tags($arLID, $sContent) { $tags = []; if (is_array($arLID)) { foreach ($arLID as $site_id => $url) { $arTags = tags_prepare($sContent, $site_id); foreach ($arTags as $tag) { $tags[] = sprintf('%u', crc32($tag)); } } } return implode(',', $tags); } function tagsRegister($arLID, $sContent) { $DB = CDatabase::GetModuleConnection('search'); static $tagMap = []; if (is_array($arLID)) { foreach ($arLID as $site_id => $url) { $arTags = tags_prepare($sContent, $site_id); foreach ($arTags as $tag) { $tag_id = sprintf('%u', crc32($tag)); if ($tag_id > 0x7FFFFFFF) { $tag_id = -(0xFFFFFFFF - $tag_id + 1); } if (!isset($tagMap[$tag_id])) { $rs = $DB->Query('select * from b_search_tags where SEARCH_CONTENT_ID=' . $tag_id . " AND SITE_ID='??'"); $tagMap[$tag_id] = $rs->fetch(); if (!$tagMap[$tag_id]) { $DB->Query('insert into b_search_tags values (' . $tag_id . ", '??', '" . $DB->ForSql($tag) . "')"); } } } } } } function tagsFromArray($arTags) { $tags = []; if (is_array($arTags)) { foreach ($arTags as $tag) { $tags[] = sprintf('%u', crc32($tag)); } } return implode(',', $tags); } function rights($arRights) { $rights = []; if (is_array($arRights)) { foreach ($arRights as $group_id) { if (is_numeric($group_id)) { $rights[$group_id] = sprintf('%u', crc32('G' . intval($group_id))); } else { $rights[$group_id] = sprintf('%u', crc32($group_id)); } } } return implode(',', $rights); } function sites($arSites) { $sites = []; if (is_array($arSites)) { foreach ($arSites as $site_id => $url) { $sites[$site_id] = sprintf('%u', crc32($site_id)); } } else { $sites[$arSites] = sprintf('%u', crc32($arSites)); } return implode(',', $sites); } function params($arParams) { $params = []; if (is_array($arParams)) { foreach ($arParams as $k1 => $v1) { $name = trim($k1); if ($name != '') { if (!is_array($v1)) { $v1 = [$v1]; } foreach ($v1 as $v2) { $value = trim($v2); if ($value != '') { $params[] = sprintf('%u', crc32(urlencode($name) . '=' . urlencode($value))); } } } } } return implode(',', $params); } public function getErrorText() { return $this->errorText; } public function getErrorNumber() { return $this->errorNumber; } public function search($arParams, $aSort, $aParamsEx, $bTagsCloud) { $result = []; $this->errorText = ''; $this->errorNumber = 0; $this->tags = trim($arParams['TAGS']); $limit = 0; if (is_array($aParamsEx) && isset($aParamsEx['LIMIT'])) { $limit = intval($aParamsEx['LIMIT']); unset($aParamsEx['LIMIT']); } $offset = 0; if (is_array($aParamsEx) && isset($aParamsEx['OFFSET'])) { $offset = intval($aParamsEx['OFFSET']); unset($aParamsEx['OFFSET']); } if (is_array($aParamsEx) && !empty($aParamsEx)) { $aParamsEx['LOGIC'] = 'OR'; $arParams[] = $aParamsEx; } $this->SITE_ID = $arParams['SITE_ID']; $arWhere = []; $cond1 = implode("\n\t\t\t\t\t\tand ", $this->prepareFilter($arParams, true)); $rights = $this->CheckPermissions(); if ($rights) { $arWhere[] = 'right in (' . $rights . ')'; } $strQuery = trim($arParams['QUERY']); if ($strQuery != '') { $arWhere[] = "MATCH('" . $this->Escape($strQuery) . "')"; $this->query = $strQuery; } if ($cond1 != '') { $arWhere[] = 'cond1 = 1'; } if ($strQuery || $this->tags || $bTagsCloud) { if ($limit <= 0) { $limit = intval(COption::GetOptionInt('search', 'max_result_size')); } if ($limit <= 0) { $limit = 500; } $ts = time() - CTimeZone::GetOffset(); if ($bTagsCloud) { $sql = ' select groupby() tag_id ,count(*) cnt ,max(date_change) dc_tmp ,if(date_to, date_to, ' . $ts . ') date_to_nvl ,if(date_from, date_from, ' . $ts . ') date_from_nvl ' . ($cond1 != '' ? ',' . $cond1 . ' as cond1' : '') . ' from ' . $this->indexName . ' where ' . implode("\nand\t", $arWhere) . ' group by tags order by cnt desc limit 0, ' . $limit . ' option max_matches = ' . $limit . ' '; $DB = CDatabase::GetModuleConnection('search'); $startTime = microtime(true); $r = $this->query($sql); if ($DB->ShowSqlStat) { $DB->addDebugQuery($sql, microtime(true) - $startTime); } if (!$r) { throw new \Bitrix\Main\Db\SqlQueryException('Sphinx select error', $this->getError(), $sql); } else { while ($res = $this->fetch($r)) { $result[] = $res; } } } else { $sql = ' select id ,item ,param1 ,param2 ,module_id ,param2_id ,date_change ,custom_rank ,weight() as rank ' . ($cond1 != '' ? ',' . $cond1 . ' as cond1' : '') . ' ,if(date_to, date_to, ' . $ts . ') date_to_nvl ,if(date_from, date_from, ' . $ts . ') date_from_nvl from ' . $this->indexName . ' where ' . implode("\nand\t", $arWhere) . ' ' . $this->__PrepareSort($aSort) . ' limit ' . $offset . ', ' . $limit . ' option max_matches = ' . ($offset + $limit) . ' '; $DB = CDatabase::GetModuleConnection('search'); $startTime = microtime(true); $r = $this->query($sql); if ($DB->ShowSqlStat) { $DB->addDebugQuery($sql, microtime(true) - $startTime); } if (!$r) { throw new \Bitrix\Main\Db\SqlQueryException('Sphinx select error', $this->getError(), $sql); } else { $forum = sprintf('%u', crc32('forum')); while ($res = $this->fetch($r)) { if ($res['module_id'] == $forum) { if (array_key_exists($res['param2_id'], $this->arForumTopics)) { continue; } $this->arForumTopics[$res['param2_id']] = true; } $result[] = $res; } } } } else { $this->errorText = GetMessage('SEARCH_ERROR3'); $this->errorNumber = 3; } return $result; } function searchTitle($phrase = '', $arPhrase = [], $nTopCount = 5, $arParams = [], $bNotFilter = false, $order = '') { $sqlWords = []; foreach (array_reverse($arPhrase, true) as $word => $pos) { $word = $this->Escape($word); if (empty($sqlWords) && !preg_match("/[\\n\\r \\t]$/", $phrase)) { $sqlWords[] = $word . '*'; } else { $sqlWords[] = $word; } } $match = '@title ' . implode(' ', array_reverse($sqlWords)); $checkDates = false; if (array_key_exists('CHECK_DATES', $arParams)) { if ($arParams['CHECK_DATES'] == 'Y') { $checkDates = true; } unset($arParams['CHECK_DATES']); } $arWhere = $this->prepareFilter($arParams); $cond1 = ''; if (isset($arWhere['cond1'])) { $cond1 = $arWhere['cond1']; unset($arWhere['cond1']); } $ts = time() - CTimeZone::GetOffset(); if ($checkDates) { $arWhere[] = 'date_from_nvl <= ' . $ts; $arWhere[] = 'date_to_nvl >= ' . $ts; } $rights = $this->CheckPermissions(); if ($rights) { $arWhere[] = 'right in (' . $rights . ')'; } $arWhere[] = 'site = ' . sprintf('%u', crc32(SITE_ID)); $arWhere[] = "match('" . $match . "')"; $sql = ' select id ,weight() as rank ' . ($cond1 != '' ? ',' . $cond1 . ' as cond1' : '') . ' ,if(date_to, date_to, ' . $ts . ') date_to_nvl ,if(date_from, date_from, ' . $ts . ') date_from_nvl from ' . $this->indexName . ' where ' . implode("\nand\t", $arWhere) . ' ' . ($cond1 != '' ? ' and cond1 = ' . intval(!$bNotFilter) : '') . ' ' . $this->__PrepareSort($order) . ' limit 0, ' . $nTopCount . ' option max_matches = ' . $nTopCount . ' '; $DB = CDatabase::GetModuleConnection('search'); $startTime = microtime(true); $r = $this->query($sql); if ($DB->ShowSqlStat) { $DB->addDebugQuery($sql, microtime(true) - $startTime); } if (!$r) { throw new \Bitrix\Main\Db\SqlQueryException('Sphinx select error', $this->getError(), $sql); } else { $result = []; while ($res = $this->fetch($r)) { $result[] = $res['id']; } return $result; } } function getRowFormatter() { return new CSearchSphinxFormatter($this); } function filterField($field, $value, $inSelect) { $arWhere = []; if (is_array($value)) { if (!empty($value)) { $s = ''; if ($inSelect) { foreach ($value as $i => $v) { $s .= ',' . sprintf('%u', crc32($v)); } $arWhere[] = 'in(' . $field . ' ' . $s . ')'; } else { foreach ($value as $i => $v) { $s .= ($s ? ' or ' : '') . $field . ' = ' . sprintf('%u', crc32($v)); } $arWhere[] = '(' . $s . ')'; } } } else { if ($value !== false) { $arWhere[] = $field . ' = ' . sprintf('%u', crc32($value)); } } return $arWhere; } function prepareFilter($arFilter, $inSelect = false) { $arWhere = []; if (!is_array($arFilter)) { $arFilter = []; } $orLogic = false; if (array_key_exists('LOGIC', $arFilter)) { $orLogic = ($arFilter['LOGIC'] == 'OR'); unset($arFilter['LOGIC']); } foreach ($arFilter as $field => $val) { $field = mb_strtoupper($field); if ( is_array($val) && count($val) == 1 && $field !== 'URL' && $field !== 'PARAMS' && !is_numeric($field) ) { $val = $val[0]; } switch ($field) { case 'ITEM_ID': case '=ITEM_ID': $arWhere = array_merge($arWhere, $this->filterField('item_id', $val, $inSelect)); break; case '!ITEM_ID': if ($val !== false) { $arWhere[] = 'item_id <> ' . sprintf('%u', crc32($val)); } break; case 'MODULE_ID': case '=MODULE_ID': if ($val !== false && $val !== 'no') { $arWhere[] = 'module_id = ' . sprintf('%u', crc32($val)); } break; case 'PARAM1': case '=PARAM1': $arWhere = array_merge($arWhere, $this->filterField('param1_id', $val, $inSelect)); break; case '!PARAM1': case '!=PARAM1': if ($val !== false) { $arWhere[] = 'param1_id <> ' . sprintf('%u', crc32($val)); } break; case 'PARAM2': case '=PARAM2': $arWhere = array_merge($arWhere, $this->filterField('param2_id', $val, $inSelect)); break; case '!PARAM2': case '!=PARAM2': if ($val !== false) { $arWhere[] = 'param2_id <> ' . sprintf('%u', crc32($val)); } break; case 'DATE_CHANGE': if ($val <> '') { $arWhere[] = 'date_change >= ' . intval(MakeTimeStamp($val) - CTimeZone::GetOffset()); } break; case '<=DATE_CHANGE': if ($val <> '') { $arWhere[] = 'date_change <= ' . intval(MakeTimeStamp($val) - CTimeZone::GetOffset()); } break; case '>=DATE_CHANGE': if ($val <> '') { $arWhere[] = 'date_change >= ' . intval(MakeTimeStamp($val) - CTimeZone::GetOffset()); } break; case 'SITE_ID': if ($val !== false) { if ($inSelect) { $arWhere[] = 'in(site, ' . sprintf('%u', crc32($val)) . ')'; } else { $arWhere[] = 'site = ' . sprintf('%u', crc32($val)); } } break; case 'CHECK_DATES': if ($val == 'Y') { $ts = time() - CTimeZone::GetOffset(); if ($inSelect) { $arWhere[] = 'if(date_from, date_from, ' . $ts . ') <= ' . $ts; $arWhere[] = 'if(date_to, date_to, ' . $ts . ') >= ' . $ts; } else { $arWhere[] = 'date_from_nvl <= ' . $ts; $arWhere[] = 'date_to_nvl >= ' . $ts; } } break; case 'TAGS': $arTags = explode(',', $val); foreach ($arTags as $i => &$strTag) { $strTag = trim($strTag, " \n\r\t\""); if ($strTag == '') { unset($arTags[$i]); } } unset($strTag); $arWhere = array_merge($arWhere, $this->filterField('tags', $arTags, $inSelect)); break; case 'PARAMS': if (is_array($val)) { $params = $this->params($val); if ($params != '') { if ($inSelect) { $arWhere[] = 'in(param, ' . $params . ')'; } else { foreach (explode(',', $params) as $param) { $arWhere[] = 'param = ' . $param; } } } } break; case 'URL': //TODO case 'QUERY': case 'LIMIT': case 'USE_TF_FILTER': break; default: if (is_numeric($field) && is_array($val)) { $subFilter = $this->prepareFilter($val, true); if (!empty($subFilter)) { if (isset($subFilter['cond1'])) { $arWhere['cond1'][] = '(' . implode(')and(', $subFilter) . ')'; } else { $arWhere[] = '(' . implode(')and(', $subFilter) . ')'; } } } else { //AddMessage2Log("field: $field; val: ".print_r($val, 1)); } break; } } if (isset($arWhere['cond1'])) { $arWhere['cond1'] = '(' . implode(')and(', $arWhere['cond1']) . ')'; } if ($orLogic && !empty($arWhere)) { $arWhere = [ 'cond1' => '(' . implode(')or(', $arWhere) . ')' ]; } return $arWhere; } function CheckPermissions() { global $USER; $DB = CDatabase::GetModuleConnection('search'); $arResult = []; if (!$USER->IsAdmin()) { if ($USER->GetID() > 0) { CSearchUser::CheckCurrentUserGroups(); $rs = $DB->Query('SELECT GROUP_CODE FROM b_search_user_right WHERE USER_ID = ' . $USER->GetID()); while ($ar = $rs->Fetch()) { $arResult[] = $ar['GROUP_CODE']; } } else { $arResult[] = 'G2'; } } return $this->rights($arResult); } function __PrepareSort($aSort = []) { $arOrder = []; if (!is_array($aSort)) { $aSort = [$aSort => 'ASC']; } $this->flagsUseRatingSort = 0; foreach ($aSort as $key => $ord) { $ord = mb_strtoupper($ord) <> 'ASC' ? 'DESC' : 'ASC'; $key = mb_strtolower($key); switch ($key) { case 'date_change': case 'custom_rank': case 'id': case 'param1': case 'param2': case 'date_from': case 'date_to': $arOrder[] = $key . ' ' . $ord; break; case 'item_id': $arOrder[] = 'item ' . $ord; break; case 'module_id': $arOrder[] = 'module ' . $ord; break; case 'rank': $arOrder[] = 'rank ' . $ord; break; } } if (count($arOrder) == 0) { $arOrder[] = 'custom_rank DESC'; $arOrder[] = 'rank DESC'; $arOrder[] = 'date_change DESC'; } return ' ORDER BY ' . implode(', ',$arOrder); } public function Escape($str) { static $search = [ '\\', "'", '/', ')', '(', '$', '~', '!', '@', '^', '-', '|', '<', "\x0", '=', ]; static $replace = [ '\\\\', "\\'", '\\\\/', '\\\\)', '\\\\(', '\\\\$', '\\\\~', '\\\\!', '\\\\@', '\\\\^', '\\\\-', '\\\\|', '\\\\<', ' ', ' ', ]; $str = str_replace($search, $replace, $str); $stat = count_chars($str, 1); if (isset($stat[ord('"')]) && $stat[ord('"')] % 2 === 1) { $str = str_replace('"', '\\\"', $str); } return $str; } public function Escape2($str) { static $search = [ '\\', "'", '"', "\x0", ]; static $replace = [ '\\\\', "\\'", '\\\\"', ' ', ]; return str_replace($search, $replace, $str); } protected function canConnect() { return function_exists('mysqli_connect'); } protected function internalConnect($connectionIndex, &$error) { $error = ''; if (function_exists('mysqli_connect')) { $result = mysqli_init(); if (mb_strpos($connectionIndex, ':') !== false) { list($host, $port) = explode(':', $connectionIndex, 2); $port = intval($port); } else { $host = $connectionIndex; $port = 0; } if ($port > 0) { if (!$result->real_connect($host, '', '', '', $port)) { $error = mysqli_connect_error(); $result = false; } } else { if (!$result->real_connect($host, '', '', '')) { $error = mysqli_connect_error(); $result = false; } } } else { $result = false; $error = 'No MySql connection function has been found.'; } return $result; } public function query($query) { if (is_object($this->db)) { $result = $this->db->query($query); } else { $result = false; } return $result; } public function fetch($queryResult) { if (is_object($this->db)) { $result = mysqli_fetch_assoc($queryResult); } else { $result = false; } return $result; } public function getError() { if (is_object($this->db)) { $result = '[' . $this->db->errno . '] ' . $this->db->error; } else { $result = ''; } return $result; } } class CSearchSphinxFormatter extends CSearchFormatter { /** @var CSearchSphinx */ private $sphinx = null; function __construct($sphinx) { $this->sphinx = $sphinx; } function format($r) { if ($r) { if (array_key_exists('tag_id', $r)) { return $this->formatTagsRow($r); } elseif (array_key_exists('id', $r)) { return $this->formatRow($r); } } } function formatTagsRow($r) { $DB = CDatabase::GetModuleConnection('search'); $tag_id = $r['tag_id']; if ($tag_id > 0x7FFFFFFF) { $tag_id = -(0xFFFFFFFF - $tag_id + 1); } $rs = $DB->Query(' select st.NAME from b_search_tags st where st.SEARCH_CONTENT_ID = ' . $tag_id . " and st.SITE_ID = '??' "); $rt = $rs->Fetch(); if ($rt) { $rt['NAME'] = htmlspecialcharsex($rt['NAME']); $rt['CNT'] = $r['cnt']; $rt['FULL_DATE_CHANGE'] = ConvertTimeStamp($r['dc_tmp'] + CTimeZone::GetOffset(), 'FULL'); $rt['DATE_CHANGE'] = ConvertTimeStamp($r['dc_tmp'] + CTimeZone::GetOffset(), 'SHORT'); } return $rt; } function formatRow($r) { $DB = CDatabase::GetModuleConnection('search'); if ($this->sphinx->SITE_ID) { $rs = $DB->Query(' select sc.ID ,sc.MODULE_ID ,sc.ITEM_ID ,sc.TITLE ,sc.TAGS ,sc.BODY ,sc.PARAM1 ,sc.PARAM2 ,sc.UPD ,sc.DATE_FROM ,sc.DATE_TO ,sc.URL ,sc.CUSTOM_RANK ,' . $DB->DateToCharFunction('sc.DATE_CHANGE') . ' as FULL_DATE_CHANGE ,' . $DB->DateToCharFunction('sc.DATE_CHANGE', 'SHORT') . ' as DATE_CHANGE ,scsite.SITE_ID ,scsite.URL SITE_URL ,sc.USER_ID from b_search_content sc INNER JOIN b_search_content_site scsite ON sc.ID=scsite.SEARCH_CONTENT_ID where ID = ' . $r['id'] . " and scsite.SITE_ID = '" . $DB->ForSql($this->sphinx->SITE_ID) . "' "); } else { $rs = $DB->Query(' select sc.ID ,sc.MODULE_ID ,sc.ITEM_ID ,sc.TITLE ,sc.TAGS ,sc.BODY ,sc.PARAM1 ,sc.PARAM2 ,sc.UPD ,sc.DATE_FROM ,sc.DATE_TO ,sc.URL ,sc.CUSTOM_RANK ,' . $DB->DateToCharFunction('sc.DATE_CHANGE') . ' as FULL_DATE_CHANGE ,' . $DB->DateToCharFunction('sc.DATE_CHANGE', 'SHORT') . ' as DATE_CHANGE ,\'\' as SITE_ID from b_search_content sc where ID = ' . $r['id'] . ' '); } $r = $rs->Fetch(); if ($r) { $r['TITLE_FORMATED'] = $this->buildExcerpts(htmlspecialcharsex($r['TITLE'])); $r['TITLE_FORMATED_TYPE'] = 'html'; $r['TAGS_FORMATED'] = tags_prepare($r['TAGS'], SITE_ID); $r['BODY_FORMATED'] = $this->buildExcerpts(htmlspecialcharsex($r['BODY'])); $r['BODY_FORMATED_TYPE'] = 'html'; } return $r; } public function buildExcerpts($str) { $sql = "CALL SNIPPETS( '" . $this->sphinx->Escape2($str) . "' ,'" . $this->sphinx->Escape($this->sphinx->indexName) . "' ,'" . $this->sphinx->Escape($this->sphinx->query . ' ' . $this->sphinx->tags) . "' ,500 as limit ,1 as query_mode )"; $result = $this->sphinx->query($sql); if ($result) { $res = $this->sphinx->fetch($result); if ($res) { return $res['snippet']; } else { return ''; } } else { throw new \Bitrix\Main\Db\SqlQueryException('Sphinx select error', $this->sphinx->getError(), $sql); } } }