Your IP : 3.145.63.95


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

<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage main
 * @copyright 2001-2014 Bitrix
 */

namespace Bitrix\Main\Data;

use Bitrix\Main;
use Bitrix\Main\Config;
use Bitrix\Main\Diag;

class Cache
{
	/** @var ICacheEngine | \ICacheBackend */
	protected $cacheEngine;

	protected $content;
	protected $vars;
	protected int $ttl = 0;
	protected string $uniqueString = '';
	protected string $baseDir = 'cache';
	protected string $initDir = '';
	protected string $filename = '';
	protected bool $isStarted = false;

	protected static $showCacheStat = false;
	protected static $clearCache = null;
	protected static $clearCacheSession = null;

	protected bool $forceRewriting = false;
	protected bool $hasOutput = true;

	public static function createCacheEngine($params = [])
	{
		static $cacheEngine = null;
		if ($cacheEngine)
		{
			return clone $cacheEngine;
		}

		// Events can't be used here because events use cache

		$cacheType = 'files';
		$v = Config\Configuration::getValue('cache');
		if ($v != null && isset($v['type']) && !empty($v['type']))
		{
			$cacheType = $v['type'];
		}

		if (is_array($cacheType))
		{
			if (isset($cacheType['class_name']))
			{
				if (!isset($cacheType['extension']) || extension_loaded($cacheType['extension']))
				{
					if (isset($cacheType['required_file']) && ($requiredFile = Main\Loader::getLocal($cacheType['required_file'])) !== false)
					{
						require_once($requiredFile);
					}

					if (isset($cacheType['required_remote_file']))
					{
						require_once($cacheType['required_remote_file']);
					}

					$className = $cacheType['class_name'];
					if (class_exists($className))
					{
						$cacheEngine = new $className($params);
					}
				}
			}
		}
		else
		{
			switch ($cacheType)
			{
				case 'redis':
					$cacheEngine = new CacheEngineRedis($params);
					break;
				case 'memcached':
					$cacheEngine = new CacheEngineMemcached($params);
					break;
				case 'memcache':
					$cacheEngine = new CacheEngineMemcache($params);
					break;
				case 'apc':
				case 'apcu':
					$cacheEngine = new CacheEngineApc($params);
					break;
				case 'files':
					$cacheEngine = new CacheEngineFiles($params);
					break;
				default:
					$cacheEngine = new CacheEngineNone();
					break;
			}
		}

		if ($cacheEngine == null)
		{
			$cacheEngine = new CacheEngineNone();
			trigger_error('Cache engine is not found', E_USER_WARNING);
		}

		if (!$cacheEngine->isAvailable())
		{
			$cacheEngine = new CacheEngineNone();
			trigger_error('Cache engine is not available', E_USER_WARNING);
		}

		return clone $cacheEngine;
	}

	public static function getCacheEngineType()
	{
		$obj = static::createCacheEngine();
		$class = get_class($obj);
		if (($pos = mb_strrpos($class, "\\")) !== false)
		{
			$class = mb_substr($class, $pos + 1);
		}

		return mb_strtolower($class);
	}

	/**
	 * @param array $params
	 * @return static Cache
	 */
	public static function createInstance($params = [])
	{
		$cacheEngine = static::createCacheEngine($params);
		return new static($cacheEngine);
	}

	public function __construct($cacheEngine)
	{
		$this->cacheEngine = $cacheEngine;
	}

	public static function setShowCacheStat($showCacheStat)
	{
		static::$showCacheStat = $showCacheStat;
	}

	public static function getShowCacheStat()
	{
		return static::$showCacheStat;
	}

	/**
	 * A privileged user wants to skip cache on this hit.
	 * @param bool $clearCache
	 */
	public static function setClearCache($clearCache)
	{
		static::$clearCache = $clearCache;
	}

	/**
	 * A privileged user wants to skip cache on this session.
	 * @param bool $clearCacheSession
	 */
	public static function setClearCacheSession($clearCacheSession)
	{
		static::$clearCacheSession = $clearCacheSession;
	}

	public static function getSalt()
	{
		$context = Main\Application::getInstance()->getContext();
		$server = $context->getServer();

		$scriptName = $server->get('SCRIPT_NAME');
		if ($scriptName == '/bitrix/urlrewrite.php' && (($v = $server->get('REAL_FILE_PATH')) != null))
		{
			$scriptName = $v;
		}
		elseif ($scriptName == '/404.php' && (($v = $server->get('REAL_FILE_PATH')) != null))
		{
			$scriptName = $v;
		}
		return '/' . mb_substr(md5($scriptName), 0, 3);
	}

	/**
	 * Returns true if a privileged user wants to skip reading from cache (on this hit or session).
	 * @return bool
	 */
	public static function shouldClearCache()
	{
		global $USER;

		$application = Main\Application::getInstance();

		if (!$application->isInitialized())
		{
			return false;
		}

		$kernelSession = $application->getKernelSession();

		if (isset(static::$clearCacheSession) || isset(static::$clearCache))
		{
			if ($USER instanceof \CUser && $USER->CanDoOperation('cache_control'))
			{
				if (isset(static::$clearCacheSession))
				{
					if (static::$clearCacheSession === true)
					{
						$kernelSession['SESS_CLEAR_CACHE'] = 'Y';
					}
					else
					{
						unset($kernelSession['SESS_CLEAR_CACHE']);
					}
				}

				if (isset(static::$clearCache) && (static::$clearCache === true))
				{
					return true;
				}
			}
		}

		if (isset($kernelSession['SESS_CLEAR_CACHE']) && $kernelSession['SESS_CLEAR_CACHE'] === 'Y')
		{
			return true;
		}

		return false;
	}

	public static function getPath($uniqueString)
	{
		$un = md5($uniqueString);
		return mb_substr($un, 0, 2) . '/' . $un . '.php';
	}

	public function clean($uniqueString, $initDir = false, $baseDir = 'cache')
	{
		$personalRoot = Main\Application::getPersonalRoot();
		$baseDir = $personalRoot . '/' . $baseDir . '/';
		$filename = $this->getPath($uniqueString);

		if (static::$showCacheStat)
		{
			Diag\CacheTracker::add(0, '', $baseDir, $initDir, '/' . $filename, 'C');
		}

		return $this->cacheEngine->clean($baseDir, $initDir, '/' . $filename);
	}

	public function cleanDir($initDir = false, $baseDir = 'cache')
	{
		$personalRoot = Main\Application::getPersonalRoot();
		$baseDir = $personalRoot . '/' . $baseDir . '/';

		if (static::$showCacheStat)
		{
			Diag\CacheTracker::add(0, "", $baseDir, $initDir, "", "C");
		}

		return $this->cacheEngine->clean($baseDir, $initDir);
	}

	public function initCache($ttl, $uniqueString, $initDir = false, $baseDir = 'cache')
	{
		if ($initDir === false)
		{
			$initDir = 'default';
		}

		$personalRoot = Main\Application::getPersonalRoot();
		$this->baseDir = $personalRoot . '/' . $baseDir . '/';
		$this->initDir = $initDir;
		$this->filename = '/' . $this->getPath($uniqueString);
		$this->ttl = $ttl;
		$this->uniqueString = $uniqueString;
		$this->vars = false;

		if ($ttl <= 0 || $this->forceRewriting || static::shouldClearCache())
		{
			return false;
		}

		$data = ['CONTENT' => '', 'VARS' => ''];
		if (!$this->cacheEngine->read($data, $this->baseDir, $this->initDir, $this->filename, $this->ttl))
		{
			return false;
		}

		if (!is_array($data) || empty($data) || !isset($data['CONTENT']) || !isset($data['VARS']))
		{
			return false;
		}

		if (static::$showCacheStat)
		{
			$read = 0;
			$path = '';
			if ($this->cacheEngine instanceof ICacheEngineStat)
			{
				$read = $this->cacheEngine->getReadBytes();
				$path = $this->cacheEngine->getCachePath();
			}
			elseif ($this->cacheEngine instanceof \ICacheBackend)
			{
				/** @noinspection PhpUndefinedFieldInspection */
				$read = $this->cacheEngine->read;

				/** @noinspection PhpUndefinedFieldInspection */
				$path = $this->cacheEngine->path;
			}

			Diag\CacheTracker::addCacheStatBytes($read);
			Diag\CacheTracker::add($read, $path, $this->baseDir, $this->initDir, $this->filename, 'R');
		}

		$this->content = $data['CONTENT'];
		$this->vars = $data['VARS'];

		return true;
	}

	public function output()
	{
		if ($this->hasOutput)
		{
			echo $this->content;
		}
	}

	public function noOutput()
	{
		$this->hasOutput = false;
	}

	public function getVars()
	{
		return $this->vars;
	}

	public function startDataCache($TTL = false, $uniqueString = false, $initDir = false, $vars = array(), $baseDir = 'cache')
	{
		$narg = func_num_args();
		if ($narg <= 0)
		{
			$TTL = $this->ttl;
		}

		if ($narg <= 1)
		{
			$uniqueString = $this->uniqueString;
		}

		if ($narg <= 2)
		{
			$initDir = $this->initDir;
		}

		if ($narg <= 3)
		{
			$vars = $this->vars;
		}

		if ($this->initCache($TTL, $uniqueString, $initDir, $baseDir))
		{
			$this->output();
			return false;
		}

		if ($TTL <= 0)
		{
			return true;
		}

		if ($this->hasOutput)
		{
			ob_start();
		}

		$this->vars = $vars;
		$this->isStarted = true;

		return true;
	}

	public function abortDataCache()
	{
		if (!$this->isStarted)
		{
			return;
		}

		$this->isStarted = false;
		if ($this->hasOutput)
		{
			ob_end_flush();
		}
	}

	public function endDataCache($vars = false)
	{
		if (!$this->isStarted)
		{
			return;
		}

		$this->isStarted = false;
		$data = [
			'CONTENT' => $this->hasOutput ? ob_get_contents() : '',
			'VARS' => ($vars !== false ? $vars : $this->vars),
		];

		$this->cacheEngine->write($data, $this->baseDir, $this->initDir, $this->filename, $this->ttl);

		if (static::$showCacheStat)
		{
			$written = 0;
			$path = '';
			if ($this->cacheEngine instanceof ICacheEngineStat)
			{
				$written = $this->cacheEngine->getWrittenBytes();
				$path = $this->cacheEngine->getCachePath();
			}
			elseif ($this->cacheEngine instanceof \ICacheBackend)
			{
				/** @noinspection PhpUndefinedFieldInspection */
				$written = $this->cacheEngine->written;

				/** @noinspection PhpUndefinedFieldInspection */
				$path = $this->cacheEngine->path;
			}
			Diag\CacheTracker::addCacheStatBytes($written);
			Diag\CacheTracker::add($written, $path, $this->baseDir, $this->initDir, $this->filename, 'W');
		}

		if ($this->hasOutput)
		{
			if (ob_get_contents() <> '')
			{
				ob_end_flush();
			}
			else
			{
				ob_end_clean();
			}
		}
	}

	public function isCacheExpired($path)
	{
		return $this->cacheEngine->isCacheExpired($path);
	}

	public function isStarted()
	{
		return $this->isStarted;
	}

	public static function clearCache($full = false, $initDir = ''): bool
	{
		if (($full !== true) && ($full !== false) && ($initDir === '') && is_string($full))
		{
			$initDir = $full;
			$full = true;
		}

		$res = true;

		if ($full === true)
		{
			$obCache = static::createInstance();
			$obCache->cleanDir($initDir, 'cache');
		}

		$path = Main\Loader::getPersonal('cache' . $initDir);
		if (is_dir($path) && ($handle = opendir($path)))
		{
			while (($file = readdir($handle)) !== false)
			{
				if ($file === '.' || $file === '..')
				{
					continue;
				}

				if (is_dir($path . '/' . $file))
				{
					if (!static::clearCache($full, $initDir . '/' . $file))
					{
						$res = false;
					}
					else
					{
						@chmod($path . '/' . $file, BX_DIR_PERMISSIONS);
						//We suppress error handle here because there may be valid cache files in this dir
						@rmdir($path . '/' . $file);
					}
				}
				elseif ($full)
				{
					@chmod($path . '/' . $file, BX_FILE_PERMISSIONS);
					if (!unlink($path . '/' . $file))
					{
						$res = false;
					}
				}
				elseif (mb_substr($file, -4) === '.php')
				{
					$c = static::createInstance();
					if ($c->isCacheExpired($path . '/' . $file))
					{
						@chmod($path . '/' . $file, BX_FILE_PERMISSIONS);
						if (!unlink($path . '/' . $file))
						{
							$res = false;
						}
					}
				}
				else
				{
					//We should skip unknown file
					//it will be deleted with full cache cleanup
				}
			}
			closedir($handle);
		}

		return $res;
	}

	/**
	 * Sets the forced mode to ignore TTL and rewrite the cache.
	 * @param bool $mode
	 */
	public function forceRewriting($mode)
	{
		$this->forceRewriting = (bool) $mode;
	}
}