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/main/classes/general/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/main/classes/general/user_counter.php
<?php

use Bitrix\Main\Config\Option;

class CAllUserCounter
{
	public const ALL_SITES = '**';
	public const LIVEFEED_CODE = '**';
	public const SYSTEM_USER_ID = 0;

	protected static $counters = [];
	private static $isLiveFeedJobOn = false;

	public static function GetValue($user_id, $code, $site_id = SITE_ID)
	{
		$user_id = (int)$user_id;

		if ($user_id < 0)
		{
			return false;
		}

		$arCodes = self::GetValues($user_id, $site_id);
		if (isset($arCodes[$code]))
		{
			return (int)$arCodes[$code];
		}

		return 0;
	}

	public static function GetValues($user_id, $site_id = SITE_ID, &$arLastDate = [])
	{
		static $diff;

		$user_id = (int)$user_id;
		if ($user_id < 0)
		{
			return [];
		}

		if (!is_array($arLastDate))
		{
			$arLastDate = [];
		}

		if ($diff === false)
		{
			$diff = CTimeZone::GetOffset();
		}

		if (!isset(self::$counters[$user_id][$site_id]))
		{
			$arAll = self::getValuesFromDB($user_id);

			if (is_array($arAll))
			{
				foreach($arAll as $arItem)
				{
					if (
						$arItem["SITE_ID"] == $site_id
						|| $arItem["SITE_ID"] === self::ALL_SITES
					)
					{
						if (!isset(self::$counters[$user_id][$site_id][$arItem["CODE"]]))
						{
							self::$counters[$user_id][$site_id][$arItem["CODE"]] = 0;
						}
						self::$counters[$user_id][$site_id][$arItem["CODE"]] += $arItem["CNT"];

						if (!isset($arLastDate[$user_id]))
						{
							$arLastDate[$user_id] = [];
						}
						if (!isset($arLastDate[$user_id][$site_id]))
						{
							$arLastDate[$user_id][$site_id] = [];
						}

						if (isset($arItem["LAST_DATE_TS"]))
						{
							$arLastDate[$user_id][$site_id][$arItem["CODE"]] = $arItem["LAST_DATE_TS"] - $diff;
						}
					}
				}
			}
		}

		return (self::$counters[$user_id][$site_id] ?? []);
	}

	public static function GetAllValues($user_id)
	{
		$arCounters = [];
		$user_id = (int)$user_id;
		if ($user_id < 0)
		{
			return $arCounters;
		}

		$arSites = Array();
		$by = '';
		$order = '';
		$res = CSite::GetList($by, $order, Array("ACTIVE" => "Y"));
		while ($row = $res->Fetch())
		{
			$arSites[] = $row['ID'];
		}

		$arAll = self::getValuesFromDB($user_id);

		foreach ($arAll as $arItem)
		{
			if ($arItem['SITE_ID'] === self::ALL_SITES)
			{
				foreach ($arSites as $siteId)
				{
					if (isset($arCounters[$siteId][$arItem['CODE']]))
					{
						$arCounters[$siteId][$arItem['CODE']] += (int)$arItem['CNT'];
					}
					else
					{
						$arCounters[$siteId][$arItem['CODE']] = (int)$arItem['CNT'];
					}
				}
			}
			elseif (isset($arCounters[$arItem['SITE_ID']][$arItem['CODE']]))
			{
				$arCounters[$arItem['SITE_ID']][$arItem['CODE']] += (int)$arItem['CNT'];
			}
			else
			{
				$arCounters[$arItem['SITE_ID']][$arItem['CODE']] = (int)$arItem['CNT'];
			}
		}

		return $arCounters;
	}

	private static function getValuesFromDB(int $userId = 0)
	{
		global $CACHE_MANAGER, $DB;

		if (
			CACHED_b_user_counter !== false
			&& $CACHE_MANAGER->read(CACHED_b_user_counter, 'user_counter' . $userId, 'user_counter')
		)
		{
			$result = $CACHE_MANAGER->get('user_counter' . $userId);
		}
		else
		{
			$strSQL = '
				SELECT CODE, SITE_ID, CNT, ' . $DB->datetimeToTimestampFunction('LAST_DATE') . ' LAST_DATE_TS
				FROM b_user_counter
				WHERE USER_ID = ' . $userId;

			$res = $DB->query($strSQL);
			$result = [];
			while ($rowFields = $res->fetch())
			{
				$rowFields['CODE'] = self::getGroupedCode($rowFields['CODE']);
				$result[] = $rowFields;
			}

			$result = self::getValuesForCache($result);

			if (CACHED_b_user_counter !== false)
			{
				$CACHE_MANAGER->set('user_counter' . $userId, $result);
			}
		}

		return $result;
	}

	private static function getValuesForCache(array $counters = []): array
	{
		$cachedCounters = [];

		foreach ($counters as $counter)
		{
			$key = $counter['CODE'] . '_' . $counter['SITE_ID'];

			if (!isset($cachedCounters[$key]))
			{
				$cachedCounters[$key] = $counter;
				$cachedCounters[$key]['CNT'] = (int)$counter['CNT'];
			}
			else
			{
				$cachedCounters[$key]['CNT'] += (int)$counter['CNT'];
				if (isset($counter['LAST_DATE_TS']))
				{
					$cachedCounters[$key]['LAST_DATE_TS'] = $counter['LAST_DATE_TS'];
				}
			}
		}

		return array_values($cachedCounters);
	}

	public static function GetLastDate($user_id, $code, $site_id = SITE_ID)
	{
		global $DB;

		$user_id = (int)$user_id;
		if ($user_id < 0 || $code == '')
		{
			return 0;
		}

		$strSQL = "
			SELECT " . $DB->DateToCharFunction("LAST_DATE") . " LAST_DATE
			FROM b_user_counter
			WHERE USER_ID = ".$user_id."
			AND (SITE_ID = '".$site_id."' OR SITE_ID = '" . self::ALL_SITES . "')
			AND CODE = '" . $DB->ForSql($code) . "'
		";

		$result = 0;
		$dbRes = $DB->Query($strSQL);
		if ($arRes = $dbRes->Fetch())
		{
			$result = MakeTimeStamp($arRes["LAST_DATE"]);
		}

		return $result;
	}

	public static function ClearAll($user_id, $site_id = SITE_ID, $sendPull = true)
	{
		global $DB, $CACHE_MANAGER;

		$user_id = (int)$user_id;
		if ($user_id < 0)
		{
			return false;
		}

		$strSQL = "
			UPDATE b_user_counter SET
			CNT = 0
			WHERE USER_ID = ".$user_id."
			AND (SITE_ID = '".$site_id."' OR SITE_ID = '".self::ALL_SITES."')";
		$DB->Query($strSQL);

		if ($site_id === self::ALL_SITES)
		{
			if (self::$counters)
			{
				unset(self::$counters[$user_id]);
			}
		}
		elseif (self::$counters)
		{
			unset(self::$counters[$user_id][$site_id]);
		}

		$CACHE_MANAGER->Clean("user_counter" . $user_id, "user_counter");

		if ($sendPull)
		{
			self::SendPullEvent($user_id);
		}

		return true;
	}

	public static function ClearByTag($tag, $code, $site_id = SITE_ID, $sendPull = true)
	{
		global $DB, $CACHE_MANAGER;

		if ($tag == '' || $code == '')
		{
			return false;
		}

		$strSQL = "
			UPDATE b_user_counter SET
			CNT = 0
			WHERE TAG = '" . $DB->ForSQL($tag) . "' AND CODE = '" . $DB->ForSQL($code) . "'
			AND (SITE_ID = '" . $site_id . "' OR SITE_ID = '" . self::ALL_SITES . "')";
		$DB->Query($strSQL);

		self::$counters = [];
		$CACHE_MANAGER->CleanDir("user_counter");

		if ($sendPull && self::CheckLiveMode())
		{
			global $DB;

			$arSites = Array();
			$by = '';
			$order = '';
			$res = CSite::GetList($by, $order, Array("ACTIVE" => "Y"));
			while ($row = $res->Fetch())
			{
				$arSites[] = $row['ID'];
			}

			$helper = \Bitrix\Main\Application::getConnection()->getSqlHelper();

			$strSQL = "
				SELECT uc.USER_ID as CHANNEL_ID, 'private' as CHANNEL_TYPE, uc.USER_ID, uc.SITE_ID, uc.CODE, uc.CNT
				FROM b_user_counter uc
				INNER JOIN b_user u ON u.ID = uc.USER_ID AND (CASE WHEN u.EXTERNAL_AUTH_ID IN ('" . implode("', '", \Bitrix\Main\UserTable::getExternalUserTypes())."') THEN 'Y' ELSE 'N' END) = 'N' AND u.LAST_ACTIVITY_DATE > " . $helper->addSecondsToDateTime('(-3600)')."
				WHERE TAG = '".$DB->ForSQL($tag)."' AND CODE = '".$DB->ForSQL($code)."'
				AND (SITE_ID = '".$site_id."' OR SITE_ID = '" . self::ALL_SITES . "')";

			$res = $DB->Query($strSQL);

			$pullMessage = [];
			while ($row = $res->Fetch())
			{
				if (!(
					$row['CHANNEL_TYPE'] === 'private'
					|| (
						$row['CHANNEL_TYPE'] === 'shared'
						&& (int)$row['USER_ID'] === 0
					)
				))
				{
					continue;
				}

				if ($row['SITE_ID'] === self::ALL_SITES)
				{
					foreach ($arSites as $siteId)
					{
						if (isset($pullMessage[$row['CHANNEL_ID']][$siteId][$row['CODE']]))
						{
							$pullMessage[$row['CHANNEL_ID']][$siteId][$row['CODE']] += (int)$row['CNT'];
						}
						else
						{
							$pullMessage[$row['CHANNEL_ID']][$siteId][$row['CODE']] = (int)$row['CNT'];
						}
					}
				}
				elseif (isset($pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$row['CODE']]))
				{
					$pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$row['CODE']] += (int)$row['CNT'];
				}
				else
				{
					$pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$row['CODE']] = (int)$row['CNT'];
				}
			}

			foreach ($pullMessage as $channelId => $arMessage)
			{
				\Bitrix\Pull\Event::add($channelId, Array(
					'module_id' => 'main',
					'command'   => 'user_counter',
					'expiry' 	=> 3600,
					'params'    => $arMessage,
				));
			}
		}

		return true;
	}

	public static function CheckLiveMode()
	{
		return (
			CModule::IncludeModule('pull')
			&& CPullOptions::GetNginxStatus()
		);
	}

	protected static function SendPullEvent($user_id, $code = "", $bMultiple = false)
	{
		$user_id = (int)$user_id;
		if ($user_id < 0)
		{
			return false;
		}

		if (self::CheckLiveMode())
		{
			global $DB;

			$arSites = Array();
			$by = '';
			$order = '';
			$res = CSite::GetList($by, $order, Array("ACTIVE" => "Y"));
			while ($row = $res->Fetch())
			{
				$arSites[] = $row['ID'];
			}

			$helper = \Bitrix\Main\Application::getConnection()->getSqlHelper();
			$strSQL = "
				SELECT uc.USER_ID as CHANNEL_ID, 'private' as CHANNEL_TYPE, uc.USER_ID, uc.SITE_ID, uc.CODE, uc.CNT
				FROM b_user_counter uc
				INNER JOIN b_user u ON u.ID = uc.USER_ID AND (CASE WHEN u.EXTERNAL_AUTH_ID IN ('" . implode("', '", \Bitrix\Main\UserTable::getExternalUserTypes())."') THEN 'Y' ELSE 'N' END) = 'N' AND u.LAST_ACTIVITY_DATE > ".$helper->addSecondsToDateTime('(-3600)')."
				WHERE uc.USER_ID = " . (int)$user_id
				.(
				$code <> ''
					? (
				$bMultiple
					? " AND uc.CODE LIKE '".$DB->ForSQL($code)."%'"
					: " AND uc.CODE = '".$DB->ForSQL($code)."'"
				)
					: ""
				)."
			";
			$res = $DB->Query($strSQL);

			$pullMessage = Array();
			while ($row = $res->Fetch())
			{
				$key = ($code <> '' ? $code : $row['CODE']);

				if (!(
					$row['CHANNEL_TYPE'] === 'private'
					|| (
						$row['CHANNEL_TYPE'] === 'shared'
						&& (int)$row['USER_ID'] === 0
					)
				))
				{
					continue;
				}
				if ($row['SITE_ID'] === self::ALL_SITES)
				{
					foreach ($arSites as $siteId)
					{
						if (isset($pullMessage[$row['CHANNEL_ID']][$siteId][$key]))
						{
							$pullMessage[$row['CHANNEL_ID']][$siteId][$key] += (int)$row['CNT'];
						}
						else
						{
							$pullMessage[$row['CHANNEL_ID']][$siteId][$key] = (int)$row['CNT'];
						}
					}
				}
				elseif (isset($pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$key]))
				{
					$pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$key] += (int)$row['CNT'];
				}
				else
				{
					$pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$key] = (int)$row['CNT'];
				}
			}

			foreach ($pullMessage as $channelId => $arMessage)
			{
				\Bitrix\Pull\Event::add($channelId, Array(
					'module_id' => 'main',
					'command'   => 'user_counter',
					'expiry' 	=> 3600,
					'params'    => $arMessage,
				));
			}
		}
	}

	public static function addValueToPullMessage($row, $arSites = array(), &$pullMessage = [])
	{
		$code = self::getGroupedCode($row["CODE"]);

		if ($row['SITE_ID'] === self::ALL_SITES)
		{
			foreach($arSites as $siteId)
			{
				if (isset($pullMessage[$row['CHANNEL_ID']][$siteId][$code]))
				{
					$pullMessage[$row['CHANNEL_ID']][$siteId][$code] += (int)$row['CNT'];
				}
				else
				{
					$pullMessage[$row['CHANNEL_ID']][$siteId][$code] = (int)$row['CNT'];
				}
			}
		}
		elseif (isset($pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$code]))
		{
			$pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$code] += (int)$row['CNT'];
		}
		else
		{
			$pullMessage[$row['CHANNEL_ID']][$row['SITE_ID']][$code] = (int)$row['CNT'];
		}
	}

	public static function getGroupedCounters($counters)
	{
		$result = array();

		foreach ($counters as $siteId => $data)
		{
			$result[$siteId] = self::getGroupedCounterRecords($data);
		}

		return $result;
	}

	public static function getGroupedCounterRecords($records)
	{
		$result = array();

		foreach ($records as $code => $value)
		{
			$code = self::getGroupedCode($code);

			if (isset($result[$code]))
			{
				$result[$code] += $value;
			}
			else
			{
				$result[$code] = $value;
			}
		}

		return $result;
	}

	private static function getGroupedCode($code)
	{
		$result = $code;

		if (mb_strpos($code, self::LIVEFEED_CODE) === 0)
		{
			$result = self::LIVEFEED_CODE;
		}

		return $result;
	}

	public static function OnSocNetLogCommentDelete($commentId)
	{
		CUserCounter::DeleteByCode(self::LIVEFEED_CODE . 'LC' . (int)$commentId);
	}

	public static function OnSocNetLogDelete($logId)
	{
		CUserCounter::DeleteByCode(self::LIVEFEED_CODE . 'L' . (int)$logId);
	}

	// legacy function
	public static function GetValueByUserID($user_id, $site_id = SITE_ID, $code = self::ALL_SITES)
	{
		return self::GetValue($user_id, $code, $site_id);
	}
	public static function GetCodeValuesByUserID($user_id, $site_id = SITE_ID)
	{
		return self::GetValues($user_id, $site_id);
	}
	public static function GetLastDateByUserAndCode($user_id, $site_id = SITE_ID, $code = self::ALL_SITES)
	{
		return self::GetLastDate($user_id, $code, $site_id);
	}

	public static function DeleteOld()
	{
		global $DB;

		$days = (int)Option::get('main', 'user_counter_days', 20);

		$time = $DB->CharToDateFunction(GetTime(time()- $days*60*60*24, "FULL"));
		$DB->Query("DELETE FROM b_user_counter WHERE TIMESTAMP_X <= ".$time);

		return "CUserCounter::DeleteOld();";
	}

	public static function Set($user_id, $code, $value, $site_id = SITE_ID, $tag = '', $sendPull = true)
	{
		global $DB, $CACHE_MANAGER;

		$value = (int)$value;
		$user_id = (int)$user_id;
		if ($user_id < 0 || $code == '')
		{
			return false;
		}

		$rs = $DB->Query("
			SELECT CNT FROM b_user_counter
			WHERE USER_ID = ".$user_id."
			AND SITE_ID = '".$DB->ForSQL($site_id)."'
			AND CODE = '".$DB->ForSQL($code)."'
		");

		if ($cntVal = $rs->Fetch())
		{
			$ssql = "";
			if ($tag != "")
			{
				$ssql = ", TAG = '".$DB->ForSQL($tag)."'";
			}

			if($cntVal['CNT'] != $value)
			{
				$DB->Query("
					UPDATE b_user_counter SET
					CNT = " . $value . " " . $ssql . ",
					SENT = 0
					WHERE USER_ID = " . $user_id . "
					AND SITE_ID = '" . $DB->ForSQL($site_id) . "'
					AND CODE = '" . $DB->ForSQL($code) . "'
				");
			}
			else
			{
				$sendPull = false;
			}
		}
		else
		{
			$DB->Query("
				INSERT INTO b_user_counter
				(CNT, USER_ID, SITE_ID, CODE, TAG)
				VALUES
				(".$value.", ".$user_id.", '".$DB->ForSQL($site_id)."', '".$DB->ForSQL($code)."', '".$DB->ForSQL($tag)."')
			", true);
		}

		if (self::$counters && isset(self::$counters[$user_id]))
		{
			if ($site_id === self::ALL_SITES)
			{
				foreach(self::$counters[$user_id] as $key => $tmp)
				{
					self::$counters[$user_id][$key][$code] = $value;
				}
			}
			else
			{
				if (!isset(self::$counters[$user_id][$site_id]))
				{
					self::$counters[$user_id][$site_id] = [];
				}

				self::$counters[$user_id][$site_id][$code] = $value;
			}
		}

		$CACHE_MANAGER->Clean("user_counter" . $user_id, "user_counter");

		if ($sendPull)
		{
			self::SendPullEvent($user_id, $code);
		}

		return true;
	}

	public static function Increment($user_id, $code, $site_id = SITE_ID, $sendPull = true, $increment = 1)
	{
		global $CACHE_MANAGER;
		$connection = \Bitrix\Main\Application::getConnection();
		$helper = $connection->getSqlHelper();

		$user_id = (int)$user_id;
		if ($user_id < 0 || $code == '')
		{
			return false;
		}

		$increment = (int)$increment;

		$merge = $helper->prepareMerge('b_user_counter', ['USER_ID', 'SITE_ID', 'CODE'], [
			'USER_ID' => $user_id,
			'SITE_ID' => $site_id,
			'CODE' => $code,
			'CNT' => $increment,
		], [
			'CNT' => new \Bitrix\Main\DB\SqlExpression('b_user_counter.CNT + ' . $increment),
		]);
		if ($merge[0])
		{
			$connection->query($merge[0]);
		}

		if (isset(self::$counters[$user_id]) && is_array(self::$counters[$user_id]))
		{
			if ($site_id === self::ALL_SITES)
			{
				foreach(self::$counters[$user_id] as $key => $tmp)
				{
					if (isset(self::$counters[$user_id][$key][$code]))
					{
						self::$counters[$user_id][$key][$code] += $increment;
					}
					else
					{
						self::$counters[$user_id][$key][$code] = $increment;
					}
				}
			}
			else
			{
				if (!isset(self::$counters[$user_id][$site_id]))
				{
					self::$counters[$user_id][$site_id] = [];
				}

				if (isset(self::$counters[$user_id][$site_id][$code]))
				{
					self::$counters[$user_id][$site_id][$code] += $increment;
				}
				else
				{
					self::$counters[$user_id][$site_id][$code] = $increment;
				}
			}
		}
		$CACHE_MANAGER->Clean("user_counter".$user_id, "user_counter");

		if ($sendPull)
		{
			self::SendPullEvent($user_id, $code);
		}

		return true;
	}

	/**
	 * @deprecated
	 * @param $user_id
	 * @param $code
	 * @param string $site_id
	 * @param bool $sendPull
	 * @param int $decrement
	 * @return bool
	 */
	public static function Decrement($user_id, $code, $site_id = SITE_ID, $sendPull = true, $decrement = 1)
	{
		global $CACHE_MANAGER;
		$connection = \Bitrix\Main\Application::getConnection();
		$helper = $connection->getSqlHelper();

		$user_id = (int)$user_id;
		if ($user_id < 0 || $code == '')
		{
			return false;
		}

		$decrement = (int)$decrement;

		$merge = $helper->prepareMerge('b_user_counter', ['USER_ID', 'SITE_ID', 'CODE'], [
			'USER_ID' => $user_id,
			'SITE_ID' => $site_id,
			'CODE' => $code,
			'CNT' => -$decrement,
		], [
			'CNT' => new \Bitrix\Main\DB\SqlExpression('b_user_counter.CNT - ' . $decrement),
		]);
		if ($merge[0])
		{
			$connection->query($merge[0]);
		}

		if (self::$counters && self::$counters[$user_id])
		{
			if ($site_id === self::ALL_SITES)
			{
				foreach (self::$counters[$user_id] as $key => $tmp)
				{
					if (isset(self::$counters[$user_id][$key][$code]))
					{
						self::$counters[$user_id][$key][$code] -= $decrement;
					}
					else
					{
						self::$counters[$user_id][$key][$code] = -$decrement;
					}
				}
			}
			else
			{
				if (!isset(self::$counters[$user_id][$site_id]))
				{
					self::$counters[$user_id][$site_id] = [];
				}

				if (isset(self::$counters[$user_id][$site_id][$code]))
				{
					self::$counters[$user_id][$site_id][$code] -= $decrement;
				}
				else
				{
					self::$counters[$user_id][$site_id][$code] = -$decrement;
				}
			}
		}

		$CACHE_MANAGER->Clean("user_counter".$user_id, "user_counter");

		if ($sendPull)
		{
			self::SendPullEvent($user_id, $code);
		}

		return true;
	}

	public static function IncrementWithSelect($sub_select, $sendPull = true, $arParams = array())
	{
		global $CACHE_MANAGER;
		$connection = \Bitrix\Main\Application::getConnection();
		$helper = $connection->getSqlHelper();

		if ($sub_select <> '')
		{
			$pullInclude = (
				$sendPull
				&& self::CheckLiveMode()
			);

			if (
				is_array($arParams)
				&& isset($arParams["TAG_SET"])
			)
			{
				$insertFields = ['USER_ID', 'CNT', 'SITE_ID', 'CODE', 'SENT', 'TAG'];
				if (is_array($arParams) && isset($arParams["SET_TIMESTAMP"]))
				{
					$insertFields[] = 'TIMESTAMP_X';
				}
				$strSQL = $helper->prepareMergeSelect(
					'b_user_counter',
					['USER_ID', 'SITE_ID', 'CODE'],
					$insertFields,
					'(' . $sub_select . ')',
					[
						'CNT' => new \Bitrix\Main\DB\SqlExpression('b_user_counter.CNT + ?v', 'CNT'),
						'SENT' => new \Bitrix\Main\DB\SqlExpression('?v', 'SENT'),
						'TAG' => $arParams["TAG_SET"],
					]
				);
			}
			elseif (
				is_array($arParams)
				&& isset($arParams["TAG_CHECK"])
			)
			{
				$insertFields = ['USER_ID', 'CNT', 'SITE_ID', 'CODE', 'SENT'];
				if (is_array($arParams) && isset($arParams["SET_TIMESTAMP"]))
				{
					$insertFields[] = 'TIMESTAMP_X';
				}
				$strSQL = $helper->prepareMergeSelect(
					'b_user_counter',
					['USER_ID', 'SITE_ID', 'CODE'],
					$insertFields,
					'(' . $sub_select . ')',
					[
						'CNT' => new \Bitrix\Main\DB\SqlExpression("CASE WHEN b_user_counter.TAG = '" . $helper->forSQL($arParams["TAG_CHECK"]) . "' THEN b_user_counter.CNT ELSE b_user_counter.CNT + ?v END", 'CNT'),
						'SENT' => new \Bitrix\Main\DB\SqlExpression("CASE WHEN b_user_counter.TAG = '" . $helper->forSQL($arParams["TAG_CHECK"]) . "' THEN b_user_counter.SENT ELSE ?v END", 'SENT'),
					]
				);
			}
			else
			{
				$insertFields = ['USER_ID', 'CNT', 'SITE_ID', 'CODE', 'SENT'];
				if (is_array($arParams) && isset($arParams["SET_TIMESTAMP"]))
				{
					$insertFields[] = 'TIMESTAMP_X';
				}
				$strSQL = $helper->prepareMergeSelect(
					'b_user_counter',
					['USER_ID', 'SITE_ID', 'CODE'],
					$insertFields,
					'(' . $sub_select . ')',
					[
						'CNT' => new \Bitrix\Main\DB\SqlExpression("b_user_counter.CNT + ?v", 'CNT'),
						'SENT' => new \Bitrix\Main\DB\SqlExpression("?v", 'SENT'),
					]
				);
			}

			$connection->query($strSQL);

			if (
				!is_array($arParams)
				|| (
					!isset($arParams["TAG_SET"])
					&& (
						!isset($arParams["CLEAN_CACHE"])
						|| $arParams["CLEAN_CACHE"] != "N"
					)
				)
			)
			{
				self::$counters = [];
				$CACHE_MANAGER->CleanDir("user_counter");
			}

			if ($pullInclude)
			{
				$arSites = Array();
				$by = '';
				$order = '';
				$res = CSite::GetList($by, $order, Array("ACTIVE" => "Y"));
				while($row = $res->Fetch())
				{
					$arSites[] = $row['ID'];
				}

				if (
					!empty($arParams["USERS_TO_PUSH"])
					&& is_array($arParams["USERS_TO_PUSH"])
				)
				{
					if($connection->lock('pull'))
					{
						$helper = $connection->getSqlHelper();

						$strSQL = "
							SELECT uc.USER_ID as CHANNEL_ID, uc.USER_ID, uc.SITE_ID, uc.CODE, uc.CNT
							FROM b_user_counter uc
							INNER JOIN b_user u ON u.ID = uc.USER_ID AND (CASE WHEN u.EXTERNAL_AUTH_ID IN ('" . implode("', '", \Bitrix\Main\UserTable::getExternalUserTypes())."') THEN 'Y' ELSE 'N' END) = 'N' AND u.LAST_ACTIVITY_DATE > " . $helper->addSecondsToDateTime('(-3600)')."
							WHERE uc.SENT = '0' AND uc.USER_ID IN (" . implode(", ", $arParams["USERS_TO_PUSH"]) . ")
						";

						$res = $connection->Query($strSQL);

						$pullMessage = Array();
						while($row = $res->fetch())
						{
							self::addValueToPullMessage($row, $arSites, $pullMessage);
						}

						$connection->Query("UPDATE b_user_counter SET SENT = '1' WHERE SENT = '0' AND CODE NOT LIKE '". self::LIVEFEED_CODE . "L%'");

						$connection->unlock('pull');

						if (self::CheckLiveMode())
						{
							foreach ($pullMessage as $channelId => $arMessage)
							{
								\Bitrix\Pull\Event::add($channelId, Array(
									'module_id' => 'main',
									'command' => 'user_counter',
									'expiry' => 3600,
									'params' => $arMessage,
								));
							}
						}
					}
				}
				else
				{
					CUserCounterPage::setNewEvent();
				}
			}
		}
	}

	public static function Clear($user_id, $code, $site_id = SITE_ID, $sendPull = true, $bMultiple = false, $cleanCache = true)
	{
		global $CACHE_MANAGER;
		$connection = \Bitrix\Main\Application::getConnection();
		$helper = $connection->getSqlHelper();

		$user_id = (int)$user_id;
		if (
			$user_id < 0
			|| $code == ''
		)
		{
			return false;
		}

		if (!is_array($site_id))
		{
			$site_id = [ $site_id ];
		}

		if ($bMultiple)
		{
			if($connection->lock('counter_delete'))
			{
				$siteToDelete = "";
				foreach ($site_id as $i => $site_id_tmp)
				{
					if ($i > 0)
					{
						$siteToDelete .= ",";
					}
					$siteToDelete .= "'".$helper->forSQL($site_id_tmp)."'";
				}

				$strDeleteSQL = "
					DELETE FROM b_user_counter
					WHERE
						USER_ID = ".$user_id."
						AND SITE_ID IN (".$siteToDelete.")
						AND CODE LIKE '".$helper->forSQL($code)."L%'
					";

				$connection->query($strDeleteSQL);

				foreach ($site_id as $i => $site_id_tmp)
				{
					$merge = $helper->prepareMerge('b_user_counter', ['USER_ID', 'SITE_ID', 'CODE'], [
						'USER_ID' => $user_id,
						'SITE_ID' => $site_id_tmp,
						'CODE' => $code,
						'CNT' => 0,
						'LAST_DATE' => new \Bitrix\Main\DB\SqlExpression($helper->getCurrentDateTimeFunction()),
					], [
						'CNT' => 0,
						'LAST_DATE' => new \Bitrix\Main\DB\SqlExpression($helper->getCurrentDateTimeFunction()),
					]);
					if ($merge[0])
					{
						$connection->query($merge[0]);
					}
				}

				$connection->unlock('counter_delete');
			}
		}
		else
		{
			foreach ($site_id as $i => $site_id_tmp)
			{
				$merge = $helper->prepareMerge('b_user_counter', ['USER_ID', 'SITE_ID', 'CODE'], [
					'USER_ID' => $user_id,
					'SITE_ID' => $site_id_tmp,
					'CODE' => $code,
					'CNT' => 0,
					'LAST_DATE' => new \Bitrix\Main\DB\SqlExpression($helper->getCurrentDateTimeFunction()),
				], [
					'CNT' => 0,
					'LAST_DATE' => new \Bitrix\Main\DB\SqlExpression($helper->getCurrentDateTimeFunction()),
				]);
				if ($merge)
				{
					$connection->Query($merge[0]);
				}
			}
		}

		if (self::$counters && self::$counters[$user_id])
		{
			foreach ($site_id as $site_id_tmp)
			{
				if ($site_id_tmp === self::ALL_SITES)
				{
					foreach (self::$counters[$user_id] as $key => $tmp)
					{
						self::$counters[$user_id][$key][$code] = 0;
					}
					break;
				}

				if (!isset(self::$counters[$user_id][$site_id_tmp]))
				{
					self::$counters[$user_id][$site_id_tmp] = array();
				}

				self::$counters[$user_id][$site_id_tmp][$code] = 0;
			}
		}

		if ($cleanCache)
		{
			$CACHE_MANAGER->Clean('user_counter' . $user_id, 'user_counter');
		}

		if ($sendPull)
		{
			self::SendPullEvent($user_id, $code);
		}

		return true;
	}

	public static function DeleteByCode($code)
	{
		global $DB, $CACHE_MANAGER;

		if ($code == '')
		{
			return false;
		}

		$pullMessage = Array();
		$bPullEnabled = false;

		$connection = \Bitrix\Main\Application::getConnection();

		$isLiveFeed = (
			str_starts_with($code, self::LIVEFEED_CODE)
			&& $code !== self::LIVEFEED_CODE
		);

		if ($isLiveFeed)
		{
			$DB->Query(
				"DELETE FROM b_user_counter WHERE CODE = '".$code."'"
			);

			self::$counters = [];
			$CACHE_MANAGER->CleanDir("user_counter");

			if (self::$isLiveFeedJobOn === false && self::CheckLiveMode())
			{
				$application = \Bitrix\Main\Application::getInstance();
				$application && $application->addBackgroundJob([__CLASS__, 'sendLiveFeedPull']);

				self::$isLiveFeedJobOn = true;
			}

			return true;
		}

		if (
			self::CheckLiveMode()
			&& $connection->lock('pull')
		)
		{
			$bPullEnabled = true;

			$arSites = [];
			$by = '';
			$order = '';
			$res = CSite::GetList($by, $order, array("ACTIVE" => "Y"));
			while($row = $res->Fetch())
			{
				$arSites[] = $row['ID'];
			}

			$helper = $connection->getSqlHelper();
			$strSQL = "
				SELECT uc.USER_ID as CHANNEL_ID, uc.USER_ID, uc.SITE_ID, uc.CODE, uc.CNT
				FROM b_user_counter uc
				INNER JOIN b_user u ON u.ID = uc.USER_ID AND (CASE WHEN u.EXTERNAL_AUTH_ID IN ('" . implode("', '", \Bitrix\Main\UserTable::getExternalUserTypes()) . "') THEN 'Y' ELSE 'N' END) = 'N' AND u.LAST_ACTIVITY_DATE > ".$helper->addSecondsToDateTime('(-3600)')."
				WHERE uc.CODE = '" . $code . "'";

			$res = $DB->Query($strSQL);

			while($row = $res->Fetch())
			{
				self::addValueToPullMessage($row, $arSites, $pullMessage);
			}
		}

		$DB->Query("DELETE FROM b_user_counter WHERE CODE = '".$code."'");

		self::$counters = [];
		$CACHE_MANAGER->CleanDir("user_counter");

		if ($bPullEnabled)
		{
			$connection->unlock('pull');
		}

		if (self::CheckLiveMode())
		{
			foreach ($pullMessage as $channelId => $arMessage)
			{
				\Bitrix\Pull\Event::add($channelId, Array(
					'module_id' => 'main',
					'command' => 'user_counter',
					'expiry' 	=> 3600,
					'params' => $arMessage,
				));
			}
		}

		return null;
	}

	protected static function dbIF($condition, $yes, $no)
	{
		return "CASE WHEN ".$condition." THEN ".$yes." ELSE ".$no."END ";
	}

	// legacy function
	public static function ClearByUser($user_id, $site_id = SITE_ID, $code = self::ALL_SITES, $bMultiple = false, $sendPull = true)
	{
		return self::Clear($user_id, $code, $site_id, $sendPull, $bMultiple);
	}

	public static function sendLiveFeedPull()
	{
		global $DB;

		$pullMessage = [];

		$connection = \Bitrix\Main\Application::getConnection();

		$connection->lock('pull');

		$sites = [];
		$by = '';
		$order = '';
		$queryObject = CSite::getList($by, $order, ['ACTIVE' => 'Y']);
		while ($row = $queryObject->fetch())
		{
			$sites[] = $row['ID'];
		}

		$helper = $connection->getSqlHelper();

		$strSQL = "
			SELECT uc.USER_ID as CHANNEL_ID, uc.USER_ID, uc.SITE_ID, uc.CODE, uc.CNT
			FROM b_user_counter uc
			INNER JOIN b_user u ON u.ID = uc.USER_ID AND (CASE WHEN u.EXTERNAL_AUTH_ID IN ('"
			. implode("', '", \Bitrix\Main\UserTable::getExternalUserTypes())
			. "') THEN 'Y' ELSE 'N' END) = 'N' AND u.LAST_ACTIVITY_DATE > "
			.$helper->addSecondsToDateTime('(-3600)')."
			WHERE uc.CODE LIKE '" . self::LIVEFEED_CODE . "%'
		";

		$queryObject = $DB->Query($strSQL);
		while($row = $queryObject->fetch())
		{
			self::addValueToPullMessage($row, $sites, $pullMessage);
		}

		$connection->unlock('pull');

		foreach ($pullMessage as $channelId => $arMessage)
		{
			\Bitrix\Pull\Event::add($channelId, [
				'module_id' => 'main',
				'command' => 'user_counter',
				'expiry' => 3600,
				'params' => $arMessage,
			]);
		}
	}
}

class CUserCounter extends CAllUserCounter
{
}

Youez - 2016 - github.com/yon3zu
LinuXploit