403Webshell
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 :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/search/tools/sphinx.php
<?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);
		}
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit