Current Path : /var/www/axolotl/data/www/msk.axolotls.ru/bitrix/modules/disk/lib/internals/ |
Current File : /var/www/axolotl/data/www/msk.axolotls.ru/bitrix/modules/disk/lib/internals/cleaner.php |
<?php namespace Bitrix\Disk\Internals; use Bitrix\Disk\BaseObject; use Bitrix\Disk\Configuration; use Bitrix\Disk\Driver; use Bitrix\Disk\File; use Bitrix\Disk\Folder; use Bitrix\Disk\Internals\Rights\Table\RightSetupSessionTable; use Bitrix\Disk\ObjectTtl; use Bitrix\Disk\ShowSession; use Bitrix\Disk\SystemUser; use Bitrix\Disk\Version; use Bitrix\Main\Application; use Bitrix\Main\FileTable as MainFileTable; use Bitrix\Main\Entity\Query; use Bitrix\Main\Type\DateTime; final class Cleaner { const DELETE_TYPE_PORTION = 2; const DELETE_TYPE_TIME = 3; /** * Returns the fully qualified name of this class. * @return string */ public static function className() { return self::class; } /** * Deletes show session and connected files from cloud. * * @param int $type Deleting type. You can choose delete files by portion or by time. * @param int $limit Limit which will be used for deleting files by portion or by time. * So, count of files which we want to delete or maximum duration of the removal process. * @return string */ public static function deleteShowSession($type = self::DELETE_TYPE_PORTION, $limit = 10) { $portion = $limit; if($type === self::DELETE_TYPE_TIME) { $portion = 100; } $startTime = time(); foreach(ShowSession::getModelList(array( 'filter' => array( '=IS_EXPIRED' => true, ), 'limit' => $portion, )) as $showSession) { if($type === self::DELETE_TYPE_TIME && (time() - $startTime > $limit)) { break; } $showSession->delete(); } unset($showSession); return static::className() . "::deleteShowSession({$type}, {$limit});"; } /** * Deletes unnecessary files, which don't relate to version or object. * * @param int $type Deleting type. You can choose delete files by portion or by time. * @param int $limit Limit which will be used for deleting files by portion or by time. * So, count of files which we want to delete or maximum duration of the removal process. * @return string */ public static function deleteUnnecessaryFiles($type = self::DELETE_TYPE_PORTION, $limit = 10) { $portion = $limit; if($type === self::DELETE_TYPE_TIME) { $portion = 100; } $query = new Query(MainFileTable::getEntity()); $query ->addSelect('ID') ->addFilter('=EXTERNAL_ID', 'unnecessary') ->addFilter('=MODULE_ID', Driver::INTERNAL_MODULE_ID) ->setLimit($portion) ; $workLoad = false; $dbResult = $query->exec(); $startTime = time(); while($row = $dbResult->fetch()) { $workLoad = true; if($type === self::DELETE_TYPE_TIME && (time() - $startTime > $limit)) { break; } \CFile::delete($row['ID']); } if(!$workLoad) { return ''; } return static::className() . "::deleteUnnecessaryFiles({$type}, {$limit});"; } public static function deleteVersionsByTtlAgent($type = self::DELETE_TYPE_PORTION, $limit = 10): string { self::deleteVersionsByTtl($type, $limit); return self::class . "::deleteVersionsByTtlAgent({$type}, {$limit});"; } public static function deleteVersionsByTtl($type = self::DELETE_TYPE_PORTION, $limit = 10): void { $dayLimit = Configuration::getFileVersionTtl(); if ($dayLimit === -1) { return; } $portion = $limit; if ($type === self::DELETE_TYPE_TIME) { $portion = 100; } $connection = Application::getConnection(); $ttlTime = $connection->getSqlHelper()->convertToDbDateTime( DateTime::createFromTimestamp(time() - $dayLimit * 86400) ); $result = $connection->query( " SELECT v.ID FROM b_disk_version v INNER JOIN b_disk_object obj ON obj.ID = v.OBJECT_ID LEFT JOIN b_disk_attached_object atta ON v.OBJECT_ID = atta.OBJECT_ID AND v.ID = atta.VERSION_ID WHERE atta.OBJECT_ID IS NULL AND v.CREATE_TIME < {$ttlTime} AND v.FILE_ID <> obj.FILE_ID LIMIT {$portion} "); $versionIds = []; foreach ($result as $row) { $versionIds[] = $row['ID']; } if (!$versionIds) { return; } $versions = Version::getModelList([ 'filter' => [ '@ID' => $versionIds, ] ]); $startTime = time(); foreach ($versions as $version) { if ($type === self::DELETE_TYPE_TIME && (time() - $startTime > $limit)) { break; } $version->delete(SystemUser::SYSTEM_USER_ID); } } public static function deleteTrashCanFilesByTtlAgent($type = self::DELETE_TYPE_PORTION, $limit = 10): string { self::deleteTrashCanFilesByTtl($type, $limit); return self::class . "::deleteTrashCanFilesByTtlAgent({$type}, {$limit});"; } public static function deleteTrashCanFilesByTtl($type = self::DELETE_TYPE_PORTION, $limit = 10): void { $ttl = Configuration::getTrashCanTtl(); if ($ttl === -1) { return; } $portion = $limit; if ($type === self::DELETE_TYPE_TIME) { $portion = 100; } $connection = Application::getConnection(); $ttlTime = $connection->getSqlHelper()->convertToDbDateTime( DateTime::createFromTimestamp(time() - $ttl * 86400) ); $deletedTypeNone = ObjectTable::DELETED_TYPE_NONE; $fileType = ObjectTable::TYPE_FILE; $result = $connection->query( " SELECT obj.ID FROM b_disk_object obj INNER JOIN b_disk_deleted_log_v2 log ON log.OBJECT_ID = obj.ID WHERE obj.STORAGE_ID = log.STORAGE_ID AND log.CREATE_TIME < {$ttlTime} AND obj.DELETED_TYPE > {$deletedTypeNone} AND obj.TYPE = {$fileType} LIMIT {$portion} "); $objectIds = []; foreach ($result as $row) { $objectIds[] = $row['ID']; } if (!$objectIds) { return; } $objects = BaseObject::getModelList([ 'filter' => [ '@ID' => $objectIds, ] ]); $startTime = time(); foreach ($objects as $object) { if ($type === self::DELETE_TYPE_TIME && (time() - $startTime > $limit)) { break; } if ($object instanceof File) { $object->delete(SystemUser::SYSTEM_USER_ID); } } } public static function deleteTrashCanEmptyFolderByTtlAgent($type = self::DELETE_TYPE_PORTION, $limit = 10): string { self::deleteTrashCanEmptyFolderByTtl($type, $limit); return self::class . "::deleteTrashCanEmptyFolderByTtlAgent({$type}, {$limit});"; } public static function deleteTrashCanEmptyFolderByTtl($type = self::DELETE_TYPE_PORTION, $limit = 10): void { $ttl = Configuration::getTrashCanTtl(); if ($ttl === -1) { return; } $portion = $limit; if ($type === self::DELETE_TYPE_TIME) { $portion = 100; } $connection = Application::getConnection(); $ttlTime = $connection->getSqlHelper()->convertToDbDateTime( DateTime::createFromTimestamp(time() - $ttl * 86400) ); $deletedTypeNone = ObjectTable::DELETED_TYPE_NONE; $folderType = ObjectTable::TYPE_FOLDER; $result = $connection->query( " SELECT obj.ID FROM b_disk_object obj INNER JOIN b_disk_deleted_log_v2 log ON log.OBJECT_ID = obj.ID WHERE NOT EXISTS(SELECT 'x' FROM b_disk_object p WHERE p.PARENT_ID = obj.ID) AND obj.STORAGE_ID = log.STORAGE_ID AND log.CREATE_TIME < {$ttlTime} AND obj.DELETED_TYPE > {$deletedTypeNone} AND obj.TYPE = {$folderType} LIMIT {$portion} "); $objectIds = []; foreach ($result as $row) { $objectIds[] = $row['ID']; } if (!$objectIds) { return; } $objects = BaseObject::getModelList([ 'filter' => [ '@ID' => $objectIds, ] ]); $startTime = time(); foreach ($objects as $object) { if ($type === self::DELETE_TYPE_TIME && (time() - $startTime > $limit)) { break; } if ($object instanceof Folder) { $object->deleteTree(SystemUser::SYSTEM_USER_ID); } } } /** * Deletes files which have to die by ttl. * * @param int $type Deleting type. You can choose delete files by portion or by time. * @param int $limit Limit which will be used for deleting files by portion or by time. * So, count of files which we want to delete or maximum duration of the removal process. * @return string */ public static function deleteByTtl($type = self::DELETE_TYPE_PORTION, $limit = 10) { $portion = $limit; if($type === self::DELETE_TYPE_TIME) { $portion = 100; } /** @var ObjectTtl[] $ttls */ $ttls = ObjectTtl::getModelList(array( 'with' => array('object'), 'limit' => $portion, 'order' => array('DEATH_TIME' => 'ASC') )); $workLoad = false; $startTime = time(); foreach ($ttls as $ttl) { $workLoad = true; if($type === self::DELETE_TYPE_TIME && (time() - $startTime > $limit)) { break; } if ($ttl->isReadyToDeath()) { $ttl->deleteObject(SystemUser::SYSTEM_USER_ID); $ttl->delete(SystemUser::SYSTEM_USER_ID); } } if(!$workLoad) { return ''; } return static::className() . "::deleteByTtl({$type}, {$limit});"; } /** * Deletes old right setup sessions. * * @return string */ public static function deleteRightSetupSession() { $connection = Application::getConnection(); $sqlHelper = $connection->getSqlHelper(); $tableName = RightSetupSessionTable::getTableName(); $statusFinished = RightSetupSessionTable::STATUS_FINISHED; $deathTime = $sqlHelper->addSecondsToDateTime(60*60*24*31, 'CREATE_TIME'); $connection->queryExecute(" DELETE FROM {$tableName} WHERE STATUS = {$statusFinished} AND NOW() > {$deathTime} "); return static::className() . "::deleteRightSetupSession();"; } public static function emptyOldDeletedLogEntries() { $deletedLogManager = Driver::getInstance()->getDeletedLogManager(); $tableClass = $deletedLogManager->getLogTable(); $tableClass::deleteOldEntries(); return static::className() . "::emptyOldDeletedLogEntries();"; } /** * Restores storages's missing root folder. * * @return string */ public static function restoreMissingRootFolder() { $connection = Application::getConnection(); $driver = Driver::getInstance(); $workLoad = false; $result = $connection->query(" SELECT storage.ID, storage.ROOT_OBJECT_ID, storage.NAME, storage.ENTITY_TYPE, storage.ENTITY_ID, storage.SITE_ID FROM b_disk_storage storage left join b_disk_object folder on storage.ROOT_OBJECT_ID = folder.ID WHERE folder.ID is NULL LIMIT 10 "); while ($row = $result->fetch()) { $workLoad = true; $storage = \Bitrix\Disk\Storage::getById($row['ID']); if ($storage instanceof \Bitrix\Disk\Storage) { $storage->delete(\Bitrix\Disk\SystemUser::SYSTEM_USER_ID); } else { $connection->queryExecute('DELETE FROM b_disk_storage WHERE ID = '.(int)$row['ID']); } if ($row['ENTITY_TYPE'] === 'Bitrix\Disk\ProxyType\User') { $storage = $driver->addUserStorage($row['ENTITY_ID']); } elseif ($row['ENTITY_TYPE'] === 'Bitrix\Disk\ProxyType\Group') { $storage = $driver->addGroupStorage($row['ENTITY_ID']); } elseif ($row['ENTITY_TYPE'] === 'Bitrix\Disk\ProxyType\Common') { $storage = $driver->addCommonStorage(array( 'NAME' => $row['NAME'], 'ENTITY_ID' => $row['ENTITY_ID'], 'SITE_ID' => $row['SITE_ID'], 'ENTITY_MISC_DATA' => $row['ENTITY_MISC_DATA'], ), array()); $data = unserialize($row['ENTITY_MISC_DATA']); if(is_array($data) && !empty($data['BASE_URL'])) { $storage->changeBaseUrl($data['BASE_URL']); } } } if (!$workLoad) { return ''; } return static::className(). '::restoreMissingRootFolder();'; } /** * Deletes files that were left after version merge. * * @param int $limit Limit which will be used for deleting files by portion or by time. * @param string $fromDate Starting date. * @param int $timeLimit Agent life time limit. * * @return string */ public static function deleteUnregisteredVersionFiles($limit = 100, $fromDate = '', $timeLimit = 20) { $limit = (int)$limit; if ($limit <= 0) { $limit = 100; } if (empty($fromDate) || strlen($fromDate) != 10) { $fromDate = '2018-11-14'; } $timeLimit = (int)$timeLimit; if (defined('START_EXEC_TIME') && START_EXEC_TIME > 0) { $startTime = START_EXEC_TIME; } else { $startTime = getmicrotime(); } $connection = Application::getConnection(); $workLoad = false; $result = $connection->query(" select ID from b_file where MODULE_ID = 'disk' AND ID not in (SELECT FILE_ID FROM b_disk_version) AND ID not in (SELECT FILE_ID FROM b_disk_object WHERE TYPE = ".\Bitrix\Disk\Internals\ObjectTable::TYPE_FILE." AND ID = REAL_OBJECT_ID AND FILE_ID IS NOT NULL) AND SUBDIR not like 'disk_preview/%' AND SUBDIR like 'disk/%' AND TIMESTAMP_X >= '{$fromDate} 00:00:00' LIMIT {$limit} "); while ($row = $result->fetch()) { $workLoad = true; \CFile::Delete($row['ID']); if ($timeLimit > 0) { $currentTime = getmicrotime(); if (($currentTime - $startTime) >= $timeLimit) { break; } } } if (!$workLoad) { return ''; } return static::className(). "::deleteUnregisteredVersionFiles('{$limit}', '{$fromDate}', '{$timeLimit}');"; } }