Your IP : 3.148.210.23


Current Path : /var/www/axolotl/data/www/yar.axolotls.ru/bitrix/modules/tasks/classes/general/
Upload File :
Current File : /var/www/axolotl/data/www/yar.axolotls.ru/bitrix/modules/tasks/classes/general/taskfiles.php

<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage tasks
 * @copyright 2001-2013 Bitrix
 * 
 * @deprecated
 * This entity is no longer supported and used by tasks module. See user fields and disk instead.
 */

use Bitrix\Tasks\Util\User;

class CTaskFiles
{
	const TEMPORARY_FILES_TTL = 86400;	// keep temporary files at least 24 hours
	const GC_PROBABILITY      = 0.01;	// probability to start garbage collection


	/**
	 * Check files accessibility by user.
	 *
	 * @param array $arFilesIds
	 * @param integer $userId
	 * 
	 * @return array $arAccessMap, such as $arAccessMap = array('f' . $fileId => true/false, ...)
	 */
	public static function checkFilesAccessibilityByUser($arFilesIds, $userId)
	{
		$arAccessMap = array();
		$arFilesIds = array_unique($arFilesIds);
		$arMustBeCheckedFilesIds = $arFilesIds;	// for preventing check again already checked file id

		// Admin and B24-admin can view any file
		if (
			CTasksTools::IsAdmin($userId)
			|| CTasksTools::IsPortalB24Admin($userId)
		)
		{
			foreach ($arFilesIds as $fileId)
				$arAccessMap['f' . $fileId] = true;

			return ($arAccessMap);
		}

		// init access map to FALSE (access denied) by default
		foreach ($arFilesIds as $fileId)
			$arAccessMap['f' . $fileId] = false;

		// files that are temporary saved by user
		$arAccessibleFilesIds = self::getRegisteredTemporaryFilesList($userId);

		$arTmp = $arMustBeCheckedFilesIds;
		foreach ($arTmp as $key => $fileId)
		{
			if (in_array( (int) $fileId, $arAccessibleFilesIds, true))
			{
				$arAccessMap['f' . $fileId] = true;
				unset($arMustBeCheckedFilesIds[$key]);
			}
		}

		// user can access files, that are already attached to tasks, accessibly by user
		$arAccessibleFilesIds = self::getFilesAttachedInAccessibleTasks($userId, $arMustBeCheckedFilesIds);

		$arTmp = $arMustBeCheckedFilesIds;
		foreach ($arTmp as $key => $fileId)
		{
			if (in_array( (int) $fileId, $arAccessibleFilesIds, true))
			{
				$arAccessMap['f' . $fileId] = true;
				unset($arMustBeCheckedFilesIds[$key]);
			}
		}

		// check if file is in tasks' templates, that are accessible for this user
		if ( ! empty($arMustBeCheckedFilesIds) )
		{
			$arAccessibleFilesIds = self::getFilesAttachedInAccessibleTemplates($userId);

			foreach ($arMustBeCheckedFilesIds as $fileId)
			{
				if (in_array( (int) $fileId, $arAccessibleFilesIds, true))
					$arAccessMap['f' . $fileId] = true;
			}
		}

		return ($arAccessMap);
	}


	public static function isUserfieldFileAccessibleByUser($taskId, $fileId, $userId)
	{
		/**
		 * @global CUserTypeManager $USER_FIELD_MANAGER
		 */
		global $USER_FIELD_MANAGER;

		$isAccessible = false;

		$fileId = (int) $fileId;

		if ( ! ($fileId >= 1) )
			return (false);

		static $arOrder  = array();
		static $arSelect = array('ID');
		$arFilter = array('ID' => $taskId);
		$arParams = array('USER_ID' => $userId);

		$r = CTasks::GetList($arOrder, $arFilter, $arSelect, $arParams);
		$arTask = $r->Fetch();

		if ( ! $arTask )
			return (false);

		// We got the task, it means user have access to this task and to all files of this task

		$arUserFields = $USER_FIELD_MANAGER->GetUserFields('TASKS_TASK', $arTask['ID'], LANGUAGE_ID, $userId);

		$bFileAttachedToGivenTask = false;

		foreach($arUserFields as $arUserField)
		{
			if ($arUserField['USER_TYPE']['USER_TYPE_ID'] !== 'file')
				continue;

			if ( ! is_array($arUserField['VALUE']) )
				$arUserField['VALUE'] = array($arUserField['VALUE']);

			foreach ($arUserField['VALUE'] as $attachedFileId)
			{
				if ($fileId === (int)$attachedFileId)
				{
					$bFileAttachedToGivenTask = true;
					break;
				}
			}
		}

		if ($bFileAttachedToGivenTask)
			$isAccessible = true;

		return ($isAccessible);
	}


	public static function isFileAccessibleByUser($fileId, $userId)
	{
		$arFilesIds = array($fileId);
		$ar = self::checkFilesAccessibilityByUser($arFilesIds, $userId);

		if ($ar['f' . $fileId] === true)
			return (true);
		else
			return (false);
	}

	/**
	 * This function saves given file temporary.
	 * After it, if CTaskFiles::Add() called with given FILE_ID,
	 * this file will be marked as permamently saved.
	 * 
	 * But if timeout TEMPORARY_FILES_TTL seconds occured,
	 * this files can be removed by garbage collector.
	 * 
	 * Garbage collector runs at probability GC_PROBABILITY at every 
	 * SaveFileTemporary() call.
	 *
	 * @param integer $userId
	 * @param string $fileName
	 * @param string $fileSize
	 * @param string $fileTmpName
	 * @param string $fileType
	 * 
	 * @return int $fileId
	 */
	public static function saveFileTemporary($userId, $fileName, $fileSize, $fileTmpName, $fileType)
	{
		$userId = (int) $userId;

		$arFile = array(
			'name'      => $fileName,
			'size'      => $fileSize,
			'tmp_name'  => $fileTmpName,
			'type'      => $fileType,
			'MODULE_ID' => 'tasks'
		);

		/** @noinspection PhpDynamicAsStaticMethodCallInspection */
		$fileId = CFile::SaveFile($arFile, 'tasks');

		if ($fileId > 0)
			self::registerTemporaryFileInDb($userId, $fileId);

		// Run garbage collector
		if (mt_rand(1, 100000) <= (self::GC_PROBABILITY * 100000))
			self::removeExpiredTemporaryFiles();

		return ($fileId);
	}


	public static function markFileTemporary($userId, $fileId)
	{
		self::registerTemporaryFileInDb($userId, $fileId);
	}


	public static function removeTemporaryFile($userId, $fileId)
	{
		$userId = (int) $userId;
		$fileId = (int) $fileId;

		if (self::isTemporaryFileRegistered($userId, $fileId))
		{
			self::unregisterTemporaryFiles(array($fileId));
			CFile::Delete($fileId);
		}
	}


	/**
	 * Return true, when file with given file_id is registered
	 * as temporary saved file. Returns true even file age is more than
	 * self::TEMPORARY_FILES_TTL seconds, but not removed yet.
	 */
	public static function isTemporaryFileRegistered($userId, $fileId)
	{
		$arFiles = self::getRegisteredTemporaryFilesList($userId);

		return (in_array( (int) $fileId, $arFiles, true));
	}


	/**
	 * Returns ids of files, that was temporary saved. Return ids for
	 * files, that was saved more than self::TEMPORARY_FILES_TTL seconds ago too
	 * (until they be removed by self::removeOrphanedFiles()).
	 *
	 * @param integer $userId
	 * @return array of file ids
	 */
	public static function getRegisteredTemporaryFilesList($userId)
	{
		/**
		 * @global CDatabase $DB
		 */
		global $DB;

		$arFiles = array();

		$userId = (int) $userId;

		$rc = $DB->Query(
			"SELECT FILE_ID FROM b_tasks_files_temporary
			WHERE USER_ID = $userId");

		while ($ar = $rc->Fetch())
			$arFiles[] = (int) $ar['FILE_ID'];

		// For backward compatibility. Just uploaded files was registered in 
		// $_SESSION["TASKS_UPLOADED_FILES"] in past
		if (isset($_SESSION['TASKS_UPLOADED_FILES']) && count($_SESSION['TASKS_UPLOADED_FILES']))
		{
			$loggedUserId = (int) User::getId();

			// this files list can be used only if logged user and checked user are equals
			if ($loggedUserId)
			{
				if ($loggedUserId === $userId)
				{
					foreach ($_SESSION['TASKS_UPLOADED_FILES'] as $fileId)
						$arFiles[] = (int) $fileId;
				}
			}
		}

		return (array_unique($arFiles));
	}


	function CheckFields(&$arFields, /** @noinspection PhpUnusedParameterInspection */ $ID = false)
	{
		/**
		 * @global CMain $APPLICATION
		 */
		global $APPLICATION;

		$arMsg = Array();

		if (!is_set($arFields, "TASK_ID"))
		{
			$arMsg[] = array("text" => GetMessage("TASKS_BAD_TASK_ID"), "id" => "ERROR_TASKS_BAD_TASK_ID");
		}
		else
		{
			/** @noinspection PhpDeprecationInspection */
			$r = CTasks::GetByID($arFields["TASK_ID"], false);
			if (!$r->Fetch())
			{
				$arMsg[] = array("text" => GetMessage("TASKS_BAD_TASK_ID_EX"), "id" => "ERROR_TASKS_BAD_TASK_ID_EX");
			}
		}

		if (!is_set($arFields, "FILE_ID"))
		{
			$arMsg[] = array("text" => GetMessage("TASKS_BAD_FILE_ID"), "id" => "ERROR_TASKS_BAD_FILE_ID");
		}
		else
		{
			/** @noinspection PhpDynamicAsStaticMethodCallInspection */
			$r = CFile::GetByID($arFields["FILE_ID"]);
			if (!$r->Fetch())
			{
				$arMsg[] = array("text" => GetMessage("TASKS_BAD_FILE_ID_EX"), "id" => "ERROR_TASKS_BAD_FILE_ID_EX");
			}
		}

		if (!empty($arMsg))
		{
			$e = new CAdminException($arMsg);
			$APPLICATION->ThrowException($e);
			return false;
		}

		return true;
	}


	/**
	 * @param integer $taskId
	 * @param array $arFilesIds
	 * @return bool
	 */
	public static function CheckFieldsMultiple($taskId, $arFilesIds)
	{
		/**
		 * @global CMain $APPLICATION
		 */
		global $APPLICATION;

		$arMsg = array();

		if ( ! ($taskId > 0) )
		{
			$arMsg[] = array("text" => GetMessage("TASKS_BAD_TASK_ID"), "id" => "ERROR_TASKS_BAD_TASK_ID");
		}
		else
		{
			/** @noinspection PhpDeprecationInspection */
			$r = CTasks::GetByID($taskId, false);
			if (!$r->Fetch())
			{
				$arMsg[] = array("text" => GetMessage("TASKS_BAD_TASK_ID_EX"), "id" => "ERROR_TASKS_BAD_TASK_ID_EX");
			}
		}


		if ( ! is_array($arFilesIds) )
		{
			$arMsg[] = array("text" => GetMessage("TASKS_BAD_FILE_ID"), "id" => "ERROR_TASKS_BAD_FILE_ID");
		}
		elseif ( ! empty($arFilesIds) )
		{
			$arFilesIds = array_unique($arFilesIds);
			$arNotFetchedFilesIds = $arFilesIds;
			/** @noinspection PhpDynamicAsStaticMethodCallInspection */
			$r = CFile::GetList(array(), array('@ID' => implode(',', $arFilesIds)));

			while ($ar = $r->Fetch())
			{
				$fileId = (int) $ar['ID'];

				$key = array_search($fileId, $arFilesIds);

				if ($key !== false)
					unset ($arNotFetchedFilesIds[$key]);
			}

			if (count($arNotFetchedFilesIds))
			{
				$arMsg[] = array("text" => GetMessage("TASKS_BAD_FILE_ID_EX"), "id" => "ERROR_TASKS_BAD_FILE_ID_EX");
			}
		}

		if (!empty($arMsg))
		{
			$e = new CAdminException($arMsg);
			$APPLICATION->ThrowException($e);
			return false;
		}

		return true;
	}


	public static function AddMultiple($taskId, $arFilesIds, $arParams = array())
	{
		global $DB;

		$taskId = (int) $taskId;
		$userId = null;

		$bCheckRightsOnFiles = true;

		if (is_array($arParams))
		{
			if (isset($arParams['USER_ID']) && ($arParams['USER_ID'] > 0))
				$userId = (int) $arParams['USER_ID'];

			if (isset($arParams['CHECK_RIGHTS_ON_FILES']))
			{
				if ( ! in_array(
						$arParams['CHECK_RIGHTS_ON_FILES'],
						array(true, false, 'Y', 'N'),
						true
				))
				{
					throw new Exception();
				}

				if (
					($arParams['CHECK_RIGHTS_ON_FILES'] === false)
					|| ($arParams['CHECK_RIGHTS_ON_FILES'] === 'N')
				)
				{
					$bCheckRightsOnFiles = false;
				}
				else
					$bCheckRightsOnFiles = true;
			}
		}

		if ($userId === null)
		{
			$userId = User::getId();
			if(!$userId)
			{
				$userId = User::getAdminId();
			}
		}

		if ( ! self::CheckFieldsMultiple($taskId, $arFilesIds) )
			return (false);

		if ($bCheckRightsOnFiles)
		{
			$ar = self::checkFilesAccessibilityByUser($arFilesIds, $userId);

			// If we have one file, that is not accessible, than emit error
			foreach ($arFilesIds as $fileId)
			{
				if (
					( ! isset($ar['f' . $fileId]) )
					|| ($ar['f' . $fileId] === false)
				)
				{
					/** @var CMain $APPLICATION */
					global $APPLICATION;
					$e = new CAdminException(array(array('text' => GetMessage('TASKS_BAD_FILE_ID_EX'), 'id' => 'ERROR_TASKS_BAD_FILE_ID_EX')));
					$APPLICATION->ThrowException($e);
					return (false);
				}
			}
		}

		$arFields = array('ID' => 1, 'FILE_ID' => false, 'TASK_ID' => (int) $taskId);

		foreach ($arFilesIds as $fileId)
		{
			$arFields['FILE_ID'] = $fileId;
			// There is duplicate key error can occured, because CTasks::Update()
			// transmit all files ids to CTaskFiles::AddMultiple().
			// So, ignore DB errors.
			// TODO: patch CTasks::Update() to transmit only new file ids, or check duplicates here.
			$DB->Add('b_tasks_file', $arFields, array(), 'tasks', $ignore_errors = true);
		}

		// Mark that attached files is not temporary now, but permament (if it was temporary)
		$arTempFiles = self::getRegisteredTemporaryFilesList($userId);
		$arTempFilesInJustAttachedToTask = array_intersect($arFilesIds, $arTempFiles);
		self::unregisterTemporaryFiles($arTempFilesInJustAttachedToTask);

		return (true);
	}


	/**
	 * Used for tasks.task.template component
	 * 
	 * @deprecated
	 */
	public static function removeTemporaryStatusForFiles($arFilesIds, $userId)
	{
		if ( ! is_array($arFilesIds) )
			return (false);

		if ( ! count($arFilesIds) )
			return (null);

		$arTempFiles = self::getRegisteredTemporaryFilesList($userId);

		if (is_array($arTempFiles) && count($arTempFiles))
		{
			$arTempFilesInJustAttachedToTask = array_intersect($arFilesIds, $arTempFiles);

			if (is_array($arTempFilesInJustAttachedToTask) && count($arTempFilesInJustAttachedToTask))
			{
				self::unregisterTemporaryFiles($arTempFilesInJustAttachedToTask);
				return (true);
			}
		}

		return (null);
	}


	public function Add($arFields, $arParams = array())
	{
		/**
		 * @global CDatabase $DB
		 */
		global $DB;

		$userId = null;

		$bCheckRightsOnFiles = false;

		if (is_array($arParams))
		{
			if (isset($arParams['USER_ID']) && ($arParams['USER_ID'] > 0))
				$userId = (int) $arParams['USER_ID'];

			if (isset($arParams['CHECK_RIGHTS_ON_FILES']))
			{
				if ( ! in_array(
						$arParams['CHECK_RIGHTS_ON_FILES'],
						array(true, false, 'Y', 'N'),
						true
				))
				{
					throw new Exception();
				}

				if (
					($arParams['CHECK_RIGHTS_ON_FILES'] === false)
					|| ($arParams['CHECK_RIGHTS_ON_FILES'] === 'N')
				)
				{
					$bCheckRightsOnFiles = false;
				}
				else
					$bCheckRightsOnFiles = true;
			}
		}

		if ($userId === null)
		{
			$userId = User::getId();
			if(!$userId)
			{
				$userId = User::getAdminId();
			}
		}

		if ($this->CheckFields($arFields))
		{
			if ($bCheckRightsOnFiles)
			{
				if ( ! self::isFileAccessibleByUser( (int) $arFields['FILE_ID'], $userId) )
				{
					/**
					 * @global CMain $APPLICATION
					 */
					global $APPLICATION;
					$e = new CAdminException(array(array('text' => GetMessage('TASKS_BAD_FILE_ID_EX'), 'id' => 'ERROR_TASKS_BAD_FILE_ID_EX')));
					$APPLICATION->ThrowException($e);
					return false;
				}
			}

			$arFields["ID"] = 1;
			$ID = $DB->Add("b_tasks_file", $arFields, Array(), "tasks");

			// Mark that attached files is not temporary now, but permament (if it was temporary)
			if (self::isTemporaryFileRegistered($userId, $arFields['FILE_ID']))
				self::unregisterTemporaryFiles(array($arFields['FILE_ID']));

			return $ID;
		}

		return false;
	}


	public static function Delete($TASK_ID, $FILE_ID)
	{
		global $DB;

		$TASK_ID = (int) $TASK_ID;
		$FILE_ID = (int) $FILE_ID;

		// First, ensure that file is attached to given task
		$rsFiles = CTaskFiles::GetList(array(), array('FILE_ID' => $FILE_ID, 'TASK_ID' => $TASK_ID));
		if ( ( ! $rsFiles ) || ( ! $rsFiles->Fetch() ) )
			return (false);

		$strSql = "DELETE FROM b_tasks_file WHERE TASK_ID = ".$TASK_ID." AND FILE_ID = ".$FILE_ID;
		$result = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);

		if ($result)
		{
			$rsFiles = CTaskFiles::GetList(array(), array("FILE_ID" => $FILE_ID));

			if (!$arFile = $rsFiles->Fetch())
				CFile::Delete($FILE_ID);
		}

		return $result;
	}


	public static function GetFilter($arFilter)
	{
		if (!is_array($arFilter))
			$arFilter = array();

		$arSqlSearch = array();

		foreach ($arFilter as $key => $val)
		{
			$res = CTasks::MkOperationFilter($key);
			$key = $res["FIELD"];
			$cOperationType = $res["OPERATION"];

			$key = mb_strtoupper($key);

			switch ($key)
			{
				case "TASK_ID":
				case "FILE_ID":
					$arSqlSearch[] = CTasks::FilterCreate("TF.".$key, $val, "number", $bFullJoin, $cOperationType);
					break;
			}
		}

		// Remove empty strings
		$arSqlSearchReturn = array();
		foreach ($arSqlSearch as &$str)
		{
			if ($str !== '')
				$arSqlSearchReturn[] = $str;
		}
		unset($str);

		return $arSqlSearchReturn;
	}


	/**
	 * @param $arOrder
	 * @param $arFilter
	 * @return bool|CDBResult
	 *
	 * @var CDatabase $DB
	 */
	public static function GetList($arOrder, $arFilter)
	{
		global $DB;

		$arSqlSearch = CTaskFiles::GetFilter($arFilter);

		$strSql = "
			SELECT
				TF.*
			FROM
				b_tasks_file TF
			".(sizeof($arSqlSearch) ? "WHERE ".implode(" AND ", $arSqlSearch) : "")."
		";

		if (!is_array($arOrder))
			$arOrder = Array();

		$arSqlOrder = [];
		foreach ($arOrder as $by => $order)
		{
			$by = mb_strtolower($by);
			$order = mb_strtolower($order);
			if ($order != "asc")
				$order = "desc";

			if ($by == "task")
				$arSqlOrder[] = " TF ".$order." ";
			elseif ($by == "file")
				$arSqlOrder[] = " TF.FILE_ID ".$order." ";
			elseif ($by == "rand")
				$arSqlOrder[] = CTasksTools::getRandFunction();
			else
				$arSqlOrder[] = " TF.FILE_ID ".$order." ";
		}

		$strSqlOrder = "";
		DelDuplicateSort($arSqlOrder);
		for ($i = 0, $arSqlOrderCnt = count($arSqlOrder); $i < $arSqlOrderCnt; $i++)
		{
			if ($i == 0)
				$strSqlOrder = " ORDER BY ";
			else
				$strSqlOrder .= ",";

			$strSqlOrder .= $arSqlOrder[$i];
		}

		$strSql .= $strSqlOrder;

		return $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
	}


	/**
	 * @param integer $FILE_ID
	 * @return bool|CDBResult
	 *
	 * @var Cdatabase $DB
	 */
	public static function DeleteByFileID($FILE_ID)
	{
		global $DB;

		$FILE_ID = intval($FILE_ID);
		$strSql = "DELETE FROM b_tasks_file WHERE FILE_ID = ".$FILE_ID;
		$result = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);

		if ($result)
		{
			CFile::Delete($FILE_ID);
		}

		return $result;
	}


	/**
	 * @param integer $TASK_ID
	 * @param array $SAVE_FILES
	 * @return bool|CDBResult
	 *
	 * @var CDatabase $DB
	 */
	public static function DeleteByTaskID($TASK_ID, $SAVE_FILES = array())
	{
		global $DB;

		$rsTaskFiles = CTaskFiles::GetList(array(), array("TASK_ID" => $TASK_ID));

		$sqrWhereAdditional = '';
		if (is_array($SAVE_FILES) && count($SAVE_FILES))
			$sqrWhereAdditional .= 'AND FILE_ID NOT IN (' . implode(',', array_map('intval', $SAVE_FILES)) . ')';

		$TASK_ID = intval($TASK_ID);
		$strSql = "DELETE FROM b_tasks_file WHERE TASK_ID = " . $TASK_ID . ' ' . $sqrWhereAdditional;
		$result = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);

		if ($result)
		{
			$arFilesToDelete = array();
			while ($arTaskFiles = $rsTaskFiles->Fetch())
			{
				// Skip files, that attached to some existing tasks
				$rsFiles = CTaskFiles::GetList(array(), array("FILE_ID" => $arTaskFiles["FILE_ID"]));
				if (!$arFile = $rsFiles->Fetch())
				{
					if (!in_array($arTaskFiles["FILE_ID"], $SAVE_FILES))
					{
						$arFilesToDelete[] = $arTaskFiles["FILE_ID"];
					}
				}
			}

			foreach ($arFilesToDelete as $file)
			{
				CFile::Delete($file);
			}
		}

		return $result;
	}


	private static function getFilesAttachedInAccessibleTemplates($userId)
	{
		$arAccessibleFilesIds = array();	// Array of accessible files ids

		$rsTemplate = CTaskTemplates::GetList(
			array(),
			array('CREATED_BY' => $userId)
		);

		while ($arTemplate = $rsTemplate->Fetch())
		{
			$arTemplate['FILES'] = unserialize($arTemplate['FILES']);

			if (is_array($arTemplate['FILES']))
			{
				foreach ($arTemplate['FILES'] as $fileId)
					$arAccessibleFilesIds[] = (int) $fileId;
			}
		}

		return (array_unique($arAccessibleFilesIds));
	}


	private static function getFilesAttachedInAccessibleTasks($userId, $arFilesIds)
	{
		$arAccessibleFilesIds = array();	// Array of accessible files ids

		$arTasksWithFiles  = array();	// Tasks with given files
		$arAccessibleTasks = array();	// Tasks that user can access
		$arTaskFiles       = array();	// Mapped FILE_ID to array of TASK_ID, that contains this file

		// Usage of 'f' prefix prevents createing indexed array, 
		// but forces associative. So, PHP wouldn't fill in the gaps in 
		// index values.
		// It should improves perfomance and prevent big memory usage.

		// Init $arTaskFiles
		foreach ($arFilesIds as $fileId)
			$arTaskFiles['f' . $fileId] = array();


		$rsTaskFile = self::GetList(
			array(),
			array('FILE_ID' => $arFilesIds)
		);

		while ($arTaskFile = $rsTaskFile->Fetch())
		{
			$taskId = (int) $arTaskFile['TASK_ID'];
			$fileId = (int) $arTaskFile['FILE_ID'];
			
			$arTasksWithFiles[] = $taskId;
			$arTaskFiles['f' . $fileId][] = $taskId;
		}

		$arTasksWithFiles = array_unique($arTasksWithFiles);

		$rsTask = CTasks::GetList(
			array(),
			array('ID' => $arTasksWithFiles),
			array('ID'),
			array('USER_ID' => $userId)
		);

		while ($arTask = $rsTask->Fetch())
			$arAccessibleTasks[] = (int) $arTask['ID'];

		// user can access files, that are already attached to tasks, accessibly by user
		foreach ($arFilesIds as $fileId)
		{
			$arTasksIds = array_unique($arTaskFiles['f' . $fileId]);

			if (count(array_intersect($arTasksIds, $arAccessibleTasks)))
				$arAccessibleFilesIds[] = (int) $fileId;
		}

		return ($arAccessibleFilesIds);
	}


	private static function unregisterTemporaryFiles($arFilesIds)
	{
		global $DB;

		if ( ! is_array($arFilesIds) )
			throw new Exception();

		$arIds = array_unique(array_map('intval', $arFilesIds));

		if (is_array($arIds) && count($arIds))
		{
			$DB->Query("DELETE FROM b_tasks_files_temporary 
				WHERE FILE_ID IN (" . implode(', ', $arIds) . ")");
		}
	}


	/**
	 * @param integer $userId
	 * @param integer $fileId
	 *
	 * @var CDatabase $DB
	 */
	private static function registerTemporaryFileInDb($userId, $fileId)
	{
		global $DB;

		$uts    = (int) time();
		$fileId = (int) $fileId;
		$userId = (int) $userId;

		$DB->query(
			"INSERT INTO b_tasks_files_temporary (USER_ID, FILE_ID, UNIX_TS)
			VALUES ($userId, $fileId, $uts)
		");
	}

	/**
	 * @var CDatabase $DB
	 */
	private static function removeExpiredTemporaryFiles()
	{
		global $DB;

		$orphanedTimestamp = (int) (time() - self::TEMPORARY_FILES_TTL);

		$DB->Query("DELETE FROM b_tasks_files_temporary 
			WHERE UNIX_TS < " . $orphanedTimestamp);
	}
}