Your IP : 3.144.31.187


Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/classes/general/
Upload File :
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/classes/general/undo.php

<?php
IncludeModuleLangFile(__FILE__);

class CUndo
{
	public static function Add($params = array())
	{
		global $DB, $USER, $CACHE_MANAGER;

		$ID = '1'.md5(uniqid(rand(), true));
		$strContent = serialize($params['arContent']);
		$userID = $USER->GetId();

		$arFields = array(
			'ID' => $ID,
			'MODULE_ID' => $params['module'],
			'UNDO_TYPE' => $params['undoType'],
			'UNDO_HANDLER' => $params['undoHandler'],
			'CONTENT' => $strContent,
			'USER_ID' => $userID,
			'TIMESTAMP_X' => time(),
		);

		$DB->Add("b_undo", $arFields, Array("CONTENT"));

		$CACHE_MANAGER->Clean(mb_substr($ID, 0, 3), "b_undo");

		return $ID;
	}

	public static function Escape($ID)
	{
		global $USER, $CACHE_MANAGER;
		if (!isset($USER) || !is_object($USER) || !$USER->IsAuthorized())
			return false;

		$arUndo = null;
		$cacheId = mb_substr($ID, 0, 3);
		if ($CACHE_MANAGER->Read(48 * 3600, $cacheId, "b_undo"))
		{
			$arUndoCache = $CACHE_MANAGER->Get($cacheId);
		}
		else
		{
			$arUndoCache = array();
			$arUndoList = CUndo::GetList(array('arFilter' => array('%ID' => $cacheId."%")));
			foreach ($arUndoList as $ar)
			{
				if (!isset($arUndoCache[$ar["ID"]]) && !isset($arUndoCache[$ar["ID"]][$ar["USER_ID"]]))
					$arUndoCache[$ar["ID"]][$ar["USER_ID"]] = $ar;
			}
			$CACHE_MANAGER->Set($cacheId, $arUndoCache);
		}
		$arUndo = $arUndoCache[$ID][$USER->GetId()] ?? false;

		if (!$arUndo)
			return false;

		// Include module
		if ($arUndo['MODULE_ID'] && $arUndo['MODULE_ID'] <> '')
		{
			if (!CModule::IncludeModule($arUndo['MODULE_ID']))
				return false;
		}

		// Get params for Escaping
		$arParams = unserialize($arUndo['CONTENT'], ['allowed_classes' => false]);

		// Check and call Undo handler
		$p = mb_strpos($arUndo['UNDO_HANDLER'], "::");
		if ($p === false)
		{
			if (function_exists($arUndo['UNDO_HANDLER'])) // function
			{
				call_user_func($arUndo['UNDO_HANDLER'], array($arParams, $arUndo['UNDO_TYPE']));
			}
		}
		else
		{
			$className = mb_substr($arUndo['UNDO_HANDLER'], 0, $p);
			if (class_exists($className)) //class
			{
				$methodName = mb_substr($arUndo['UNDO_HANDLER'], $p + 2);
				if (method_exists($className, $methodName)) //static method
				{
					call_user_func_array(array($className, $methodName), array($arParams, $arUndo['UNDO_TYPE']));
				}
			}
		}

		// Del entry
		CUndo::Delete($ID);
		return true;
	}

	public static function GetList($Params = array())
	{
		global $DB;

		$arFilter = $Params['arFilter'];
		$arOrder = $Params['arOrder'] ?? array('ID' => 'asc');

		$arFields = array(
			"ID" => array("FIELD_NAME" => "U.ID", "FIELD_TYPE" => "string"),
			"MODULE_ID" => array("FIELD_NAME" => "U.MODULE_ID", "FIELD_TYPE" => "string"),
			"UNDO_TYPE" => array("FIELD_NAME" => "U.UNDO_TYPE", "FIELD_TYPE" => "string"),
			"UNDO_HANDLER" => array("FIELD_NAME" => "U.UNDO_HANDLER", "FIELD_TYPE" => "string"),
			"CONTENT" => array("FIELD_NAME" => "U.CONTENT", "FIELD_TYPE" => "string"),
			"USER_ID" => array("FIELD_NAME" => "U.USER_ID", "FIELD_TYPE" => "int"),
			"TIMESTAMP_X" => array("FIELD_NAME" => "U.TIMESTAMP_X", "FIELD_TYPE" => "int"),
		);

		$arSqlSearch = array();

		if (is_array($arFilter))
		{
			foreach ($arFilter as $key => $val)
			{
				$n = mb_strtoupper($key);
				if ($n == '%ID')
					$arSqlSearch[] = "(U.ID like '".$DB->ForSql($val)."')";
				elseif ($n == 'ID' || $n == 'USER_ID')
					$arSqlSearch[] = GetFilterQuery("U.".$n, $val, 'N');
				elseif (isset($arFields[$n]))
					$arSqlSearch[] = GetFilterQuery($arFields[$n]["FIELD_NAME"], $val);
			}
		}

		$strOrderBy = '';
		foreach ($arOrder as $by => $order)
		{
			$by = mb_strtoupper($by);
			if (isset($arFields[$by]))
			{
				$strOrderBy .= $arFields[$by]["FIELD_NAME"].' '.(mb_strtolower($order) == 'desc'? 'desc': 'asc').',';
			}
		}

		if ($strOrderBy)
		{
			$strOrderBy = "ORDER BY ".rtrim($strOrderBy, ",");
		}

		$strSqlSearch = GetFilterSqlSearch($arSqlSearch);
		$strSql = "
			SELECT
				U.*
			FROM
				b_undo U
			WHERE
				$strSqlSearch
			$strOrderBy";

		$res = $DB->Query($strSql);
		$arResult = array();
		while ($arRes = $res->Fetch())
			$arResult[] = $arRes;

		return $arResult;
	}

	public static function Delete($ID)
	{
		global $DB, $CACHE_MANAGER;

		$DB->Query("DELETE FROM b_undo WHERE ID='".$DB->ForSql($ID)."'");

		$CACHE_MANAGER->Clean(mb_substr($ID, 0, 3), "b_undo");
	}

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

		// All entries older than one day
		$timestamp = mktime(date("H"), date("i"), 0, date("m"), date("d") - 1, date("Y"));
		$DB->Query("delete from b_undo where TIMESTAMP_X <= ".$timestamp);

		$CACHE_MANAGER->CleanDir("b_undo");

		return "CUndo::CleanUpOld();";
	}

	public static function ShowUndoMessage($ID)
	{
		\Bitrix\Main\Application::getInstance()->getSession()['BX_UNDO_ID'] = $ID;
	}

	public static function CheckNotifyMessage()
	{
		global $USER, $APPLICATION;
		$session = \Bitrix\Main\Application::getInstance()->getSession();
		if (!$session->isStarted() || !$session->has('BX_UNDO_ID'))
			return;

		$ID = $session['BX_UNDO_ID'];
		unset($session['BX_UNDO_ID']);

		$arUndoList = CUndo::GetList(array('arFilter' => array('ID' => $ID, 'USER_ID' => $USER->GetId())));
		if (!$arUndoList)
			return;

		$arUndo = $arUndoList[0];
		$detail = GetMessage('MAIN_UNDO_TYPE_'.mb_strtoupper($arUndo['UNDO_TYPE']));

		$s = "
<script>
window.BXUndoLastChanges = function()
{
	if (!confirm(\"".GetMessage("MAIN_UNDO_ESCAPE_CHANGES_CONFIRM")."\"))
		return;

	BX.ajax.get(\"/bitrix/admin/public_undo.php?undo=".$ID."&".bitrix_sessid_get()."\", null, function(result)
	{
		if (result && result.toUpperCase().indexOf(\"ERROR\") != -1)
			BX.admin.panel.Notify(\"".GetMessage("MAIN_UNDO_ESCAPE_ERROR")."\");
		else
			window.location = window.location;
	});
};
BX.ready(function()
{
	setTimeout(function()
	{
		BX.admin.panel.Notify('".$detail." <a href=\"javascript: void(0);\" onclick=\"window.BXUndoLastChanges(); return false;\" title=\"".GetMessage("MAIN_UNDO_ESCAPE_CHANGES_TITLE")."\">".GetMessage("MAIN_UNDO_ESCAPE_CHANGES")."</a>');
	}, 100);
});
</script>";

		$APPLICATION->AddHeadString($s);
	}
}

class CAutoSave
{
	/*'ID', 'COPY_ID', 'ENTITY_ID', 'mid', 'WEB_FORM_ID', 'CONTRACT_ID', 'COURSE_ID', 'IBLOCK_SECTION_ID', 'IBLOCK_ID', 'CHANNEL_ID', 'VOTE_ID', 'DICTIONARY_ID', 'CHAPTER_ID', 'LESSON_ID', */

	private $formId = '';
	private $autosaveId = '';

	private $bInited = false;

	private $bSkipRestore = false;

	private static $bAllowed = null;
	private static $arImportantParams = array(
		'LANG' => 1,
		'SITE' => 1,
		'PATH' => 1,
		'TYPE' => 1,
		'EVENT_NAME' => 1,
		'SHOW_ERROR' => 1,
		'NAME' => 1,
		'FULL_SRC' => 1,
		'ACTION' => 1,
		'LOGICAL' => 1,
		'ADMIN' => 1,
		'ADDITIONAL' => 1,
		'NEW' => 1,
		'MODE' => 1,
		'CONDITION' => 1,
		'QUESTION_TYPE' => 1,
	);

	public function __construct()
	{
		global $USER;

		if ($USER->IsAuthorized())
		{
			if (isset($_REQUEST['autosave_id']) && mb_strlen($_REQUEST['autosave_id']) == 33)
			{
				$this->bSkipRestore = true;
				$this->autosaveId = preg_replace("/[^a-z0-9_]/i", "", $_REQUEST['autosave_id']);
			}
			else
			{
				$this->formId = self::_GetFormID();
			}

			addEventHandler('main', 'OnBeforeLocalRedirect', array($this, 'Reset'));

			if (!defined('BX_PUBLIC_MODE'))
			{
				CJSCore::Init(array('autosave'));
			}
		}
	}

	public function Init($admin = true)
	{
		global $USER;

		if (!$USER->IsAuthorized())
			return false;

		if (!$this->bInited)
		{
			$DISABLE_STANDARD_NOTIFY = ($admin? 'false': 'true');

			if (defined('BX_PUBLIC_MODE') && BX_PUBLIC_MODE == 1)
				echo CJSCore::GetHTML(array('autosave'));
			?>
			<input type="hidden" name="autosave_id" id="autosave_marker_<?=$this->GetID()?>" value="<?=$this->GetID()?>"/>
			<script type="text/javascript">window.autosave_<?=$this->GetID()?> = new top.BX.CAutoSave({
					form_marker: 'autosave_marker_<?=$this->GetID()?>',
					form_id: '<?=$this->GetID()?>',
					DISABLE_STANDARD_NOTIFY: <?=$DISABLE_STANDARD_NOTIFY?>
				});
			</script>
			<?
			$this->checkRestore();

			$this->bInited = true;
		}
		return true;
	}

	public function checkRestore()
	{
		$key = addEventHandler('main', 'OnAutoSaveRestore', array($this, 'Restore'));
		CUndo::Escape($this->GetID());
		removeEventHandler('main', 'OnAutoSaveRestore', $key);
	}

	public function Reset()
	{
		global $USER, $DB, $CACHE_MANAGER;

		if (!$USER->IsAuthorized())
			return false;

		$ID = $this->GetID();
		$DB->Query("DELETE FROM b_undo WHERE ID='".$DB->ForSQL($ID)."' AND USER_ID='".$USER->GetID()."'");

		$CACHE_MANAGER->Clean(mb_substr($ID, 0, 3), "b_undo");

		return true;
	}

	public function Set($data)
	{
		global $DB, $USER, $CACHE_MANAGER;

		if (!$USER->IsAuthorized())
			return false;

		if (!is_array($data) || empty($data))
			return false;

		$ID = $this->GetID();
		$arFields = array(
			'MODULE_ID' => 'main',
			'UNDO_TYPE' => 'autosave',
			'UNDO_HANDLER' => 'CAutoSave::_Restore',
			'CONTENT' => serialize($data),
			'USER_ID' => $USER->GetID(),
			'TIMESTAMP_X' => time(),
		);
		$arBinds = array(
			"CONTENT" => $arFields["CONTENT"],
		);

		$strUpdate = $DB->PrepareUpdate("b_undo", $arFields);
		$rs = $DB->QueryBind("UPDATE b_undo SET ".$strUpdate." WHERE ID = '".$DB->ForSQL($ID)."'", $arBinds);
		if ($rs->AffectedRowsCount() == 0)
		{
			$arFields['ID'] = $ID;
			$DB->Add("b_undo", $arFields, array("CONTENT"), "", true);
		}

		$CACHE_MANAGER->Clean(mb_substr($ID, 0, 3), "b_undo");
		return true;
	}

	public function Restore($arFields)
	{
		if (is_array($arFields))
		{
?>
<script type="text/javascript">BX.ready(function(){
	if (window.autosave_<?=$this->GetID();?>)
	{
		window.autosave_<?=$this->GetID();?>.Restore(<?=CUtil::PhpToJSObject($arFields);?>);
	}
});</script>
<?
		}
	}

	public function GetID()
	{
		global $USER;

		if (!$this->autosaveId)
		{
			$this->autosaveId = '2'.md5($this->formId.'|'.$USER->GetID());
		}

		return $this->autosaveId;
	}

	private static function _GetFormID()
	{
		global $APPLICATION;

		$arParams = array();
		foreach ($_GET as $param => $value)
		{
			$param = strtoupper($param);

			if (substr($param, -2) == 'ID' || array_key_exists($param, self::$arImportantParams))
				$arParams[$param] = $value;
		}

		ksort($arParams);

		$url = mb_strtolower($APPLICATION->GetCurPage()).'?';
		foreach ($arParams as $param => $value)
		{
			if (is_array($value))
				$value = implode('|', $value);

			$url .= urlencode($param).'='.urlencode($value).'&';
		}

		return $url;
	}

	public static function _Restore($arFields)
	{
		foreach (GetModuleEvents("main", "OnAutoSaveRestore", true) as $arEvent)
		{
			ExecuteModuleEventEx($arEvent, array($arFields));
		}
	}

	public static function Allowed()
	{
		global $USER, $APPLICATION;

		if (!$USER->IsAuthorized())
			return false;

		if (self::$bAllowed == null)
		{
			$arOpt = CUserOptions::GetOption('global', 'settings', []);
			self::$bAllowed = (!isset($arOpt['autosave']) || $arOpt['autosave'] != 'N') && $APPLICATION->GetCurPage() != '/bitrix/admin/update_system.php';
		}

		return self::$bAllowed;
	}
}