Your IP : 18.118.12.124


Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/analytics/
Upload File :
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/analytics/analyticsevent.php

<?php

declare(strict_types=1);

namespace Bitrix\Main\Analytics;

use Bitrix\Main\ArgumentException;
use Bitrix\Main\Config\Configuration;
use Bitrix\Main\Context;
use Bitrix\Main\Loader;
use Bitrix\Main\Web\Json;

final class AnalyticsEvent
{
	public const STATUS_SUCCESS = 'success';
	public const STATUS_ERROR = 'error';
	public const STATUS_ATTEMPT = 'attempt';
	public const STATUS_CANCEL = 'cancel';

	private ?string $section;
	private ?string $subSection;
	private ?string $element;
	private ?string $type;
	private ?string $p1;
	private ?string $p2;
	private ?string $p3;
	private ?string $p4;
	private ?string $p5;
	/** @var string  */
	private string $status = self::STATUS_SUCCESS;
	private ?int $userId;
	private string $userAgent;

	private bool $isInvalid = false;

	public function __construct(
		private string $event,
		private string $tool,
		private string $category,
	)
	{
		$userAgent = Context::getCurrent()?->getRequest()->getUserAgent();
		if ($userAgent && \is_string($userAgent))
		{
			$this->userAgent = $userAgent;
		}
	}

	public function setUserId(int $userId): self
	{
		$this->userId = $userId;

		return $this;
	}

	public function setSection(string $section): self
	{
		$this->section = $section;

		return $this;
	}

	public function setSubSection(string $subSection): self
	{
		$this->subSection = $subSection;

		return $this;
	}

	public function setElement(string $element): self
	{
		$this->element = $element;

		return $this;
	}

	public function setType(string $type): self
	{
		$this->type = $type;

		return $this;
	}

	/**
	 * @throws ArgumentException
	 */
	public function setP1(string $p1): self
	{
		$this->validatePField($p1);
		$this->p1 = $p1;

		return $this;
	}

	/**
	 * @throws ArgumentException
	 */
	public function setP2(string $p2): self
	{
		$this->validatePField($p2);
		$this->p2 = $p2;

		return $this;
	}

	/**
	 * @throws ArgumentException
	 */
	public function setP3(string $p3): self
	{
		$this->validatePField($p3);
		$this->p3 = $p3;

		return $this;
	}

	/**
	 * @throws ArgumentException
	 */
	public function setP4(string $p4): self
	{
		$this->validatePField($p4);
		$this->p4 = $p4;

		return $this;
	}

	/**
	 * @throws ArgumentException
	 */
	public function setP5(string $p5): self
	{
		$this->validatePField($p5);
		$this->p5 = $p5;

		return $this;
	}

	public function setStatus(string $status): self
	{
		$this->status = $status;

		return $this;
	}

	public function setUserAgent(string $userAgent): self
	{
		$this->userAgent = $userAgent;

		return $this;
	}

	public function markAsSuccess(): self
	{
	    return $this->setStatus(self::STATUS_SUCCESS);
	}

	public function markAsCanceled(): self
	{
	    return $this->setStatus(self::STATUS_CANCEL);
	}

	public function markAsError(): self
	{
	    return $this->setStatus(self::STATUS_ERROR);
	}

	public function markAsAttempt(): self
	{
	    return $this->setStatus(self::STATUS_ATTEMPT);
	}

	/**
	 * @throws ArgumentException
	 */
	private function validatePField(string $value): void
	{
		$invalidValue = substr_count($value, '_') > 1;
		if ($invalidValue)
		{
			$this->isInvalid = true;
		}

		if ($invalidValue && $this->isDevMode())
		{
			throw new ArgumentException('Value for p{1-5} field must contain a single underscore.');
		}
	}

	/**
	 * @throws ArgumentException
	 */
	private function validateRequiredFields(): void
	{
		if (empty($this->event) || empty($this->tool) || empty($this->category))
		{
			$this->isInvalid = true;

			if ($this->isDevMode())
			{
				throw new ArgumentException('Event, tool and category fields are required and should be filled.');
			}
		}
	}

	private function isDevMode(): bool
	{
		$exceptionHandling = Configuration::getValue('exception_handling');

		return !empty($exceptionHandling['debug']);
	}

	public function exportToArray(): array
	{
		return [
			'event' => $this->event,
			'tool' => $this->tool,
			'category' => $this->category,
			'section' => $this->section ?? null,
			'subSection' => $this->subSection ?? null,
			'element' => $this->element ?? null,
			'type' => $this->type ?? null,
			'p1' => $this->p1 ?? null,
			'p2' => $this->p2 ?? null,
			'p3' => $this->p3 ?? null,
			'p4' => $this->p4 ?? null,
			'p5' => $this->p5 ?? null,
			'status' => $this->status ?? null,
			'userAgent' => $this->userAgent ?? null,
		];
	}

	/**
	 * @throws ArgumentException
	 */
	public function send(): void
	{
		if (!\defined('ANALYTICS_V2_FILENAME') || !is_writable(ANALYTICS_V2_FILENAME))
		{
			return;
		}

		$this->validateRequiredFields();
		if ($this->isInvalid)
		{
			return;
		}

		if (!isset($this->userId) && !\defined('BX_CHECK_AGENT_START') && ($GLOBALS['USER'] instanceof \CUser))
		{
			$this->userId = (int)$GLOBALS['USER']->getId();
		}

		$data = $this->buildLogData();
		$jsonData = Json::encode($data, JSON_UNESCAPED_UNICODE);

		$fp = @fopen(ANALYTICS_V2_FILENAME, "ab");
		if ($fp && flock($fp, LOCK_EX))
		{
			@fwrite($fp, $jsonData . PHP_EOL);
			@fflush($fp);
			@flock($fp, LOCK_UN);
			@fclose($fp);
		}
	}

	private function buildLogData(): array
	{
		$data = [
			'date' => date('Y-m-d H:i:s'),
			'host' => Context::getCurrent()->getServer()->getHttpHost(),
			'dbname' => \defined('BX24_DB_NAME') ? BX24_DB_NAME : null,
			'userId' => $this->userId ?? 0,
			'event' => $this->exportToArray(),
		];

		if (Loader::includeModule('bitrix24'))
		{
			$data['license'] = \CBitrix24::getLicenseType();
		}

		return $data;
	}
}