Как стать автором
Поиск
Написать публикацию
Обновить

Ограничения загрузки файлов в Битрикс 24

Уровень сложностиСредний
Время на прочтение6 мин
Количество просмотров169

Пока сотрудники компании саботируют работу в битрикс 24, общаясь в сторонних менеджерах и обмениваясь файлами по почте, локальной сети, флешках и тд., никаких проблем принципе нет — функций много, они никому не нужны = ничего настраивать не нужно.

Но как только к примеру будет принято волевое решение перевести компанию в 500 человек во внутренний менеджер и директор компании начнет в нем строчить подчиненным. Окажется, что битрикс такой классный, что по дефолту позволяет грузить в систему любые файлы в любом количестве. А какого-либо интерфейса для настройки ограничений нет.

Раньше было три официальных костыля которые предлагали не только на форумах ну и в техподдержке битры.

  1. Ограничение загружаемого файла во всем битиксе, путем задания настроек php post_max_size
    upload_max_filesize

  2. Обработчик события AddEventHandler(«im», «OnAfterFileUpload», «CheckFileSize») Который ограничить размер файла передаваемого в чате корпоративного портала

  3. Ограничить размер диска для конкретного сотрудника.

$storage = \Bitrix\Disk\Driver::getInstance()->getStorageByUserId($userId);
$storage->setSizeLimit(1048576000); // 1гб

Но нынче первых два пункта перестали работать. 1 — так как — «файлы загружаются на портал частями, и ограничение на уровне PHP не срабатывает. «. 2 — «В новом чате Bitrix24 Messenger нет возможности ограничить размер загружаемого файла через событие OnAfterFileUpload. «.

Для реализации ограничений мною были сделаны следующие пункты:

  1. Создать ограничение на загрузку на сотрудника за все время 3Гб (размер Диска)

  2. Установить ограничение по размеру файла во всем Битрикс 500мб

  3. Установить временное хранение файлов больше 150мб (во всем Битрикс)

  4. Установить временное хранение файлов больше 50мб (в мессенжере)

  5. Установить срок хранения всех файлов в чатах 2 года

1 Вешаем на событие которое фиксирует создание нового пользователя. У меня это событие авторизации сотрудника, где уже ранее создавался маркер говорящий о том это первая авторизация его или нет. (init.php)

// Вызов события после авторизации пользователя
use Bitrix\Main\Loader;
AddEventHandler("main", "OnAfterUserAuthorize", "OnAfterUserCongratulations");
function OnAfterUserCongratulations($arUser) {
    if ($arUser["user_fields"]['PERSONAL_ICQ'] !== "Y") {  // используем поле ICQ, делаем его - Признак показа открытки  
        //"сообщение для новичка" при первой авторизации для вывода открытки                                                 
        require_once $_SERVER["DOCUMENT_ROOT"] . "/local/php_interface/new_user_otkrytka.php";
                                                         
        //  Ограничить размер диска для конкретного сотрудника
        Loader::includeModule('disk');
        $storage = \Bitrix\Disk\Driver::getInstance()->getStorageByUserId($userId);
        $storage->setSizeLimit(3148576000); // 3гб
    }
}

Важно! Должна быть активна настройка «Разрешить квотирование хранилищ».
Настройки > Настройки продукта > Настройки модулей > Диск

// Посмотреть лимит
use Bitrix\Main\Loader;
Loader::includeModule('disk');
$userId = 419;
$storage = Driver::getInstance()->getStorageByUserId($userId);
$limit = $storage->getSizeLimit();
echo "Лимит диска пользователя с ID {$userId}: " . ($limit ? $limit . " байт" : "не установлен") . "\n";

//отключить лимит
use Bitrix\Main\Loader;
Loader::includeModule('disk');
$userId = 419; //кому?
$storage = \Bitrix\Disk\Driver::getInstance()->getStorageByUserId($userId);
$storage->setSizeLimit(null);

2, 3 и 4 — Так как хотелось и дать возможность передавать друг другу большие файлы и при этом держать это все под контролем, было создано 3 ограничение. Больше 500мб — не дает загружать вообще. больше 150 мб, во всем битрикс кроме чата и больше 50 мб в чате дает загружать но срок хранения файлов 2 недели. Для хранения очереди файлов на удаление используем Highload‑блок, очереди чистим скриптом через крон. Повесил это все на событие «onAfterAddFile. Информирование путем вывода на экран Пуш уведомления. (полезный прием который позволяет выводить сообщение из init.php )

use \Bitrix\Main\EventManager;

use Bitrix\Main\SystemException;
use Bitrix\Main\Loader;
use Bitrix\Main\Type\DateTime;
use Bitrix\Disk\File;
// Ограничения загрузки файлов
EventManager::getInstance()->addEventHandler("disk", "onAfterAddFile", function(\Bitrix\Main\Event $event) {
    
          $maxFileSize = 150000000;
       $maxFileSizeChat = 50000000;
	$veryLargeFileSize = 500000000; // 500 MB - порог для "очень больших" файлов
	$n_del = 14; // Длительность хранения больших файлов
	
	list($fields) = $event->getParameters(); // массив с первым элементом — File

    if (!$fields instanceof File) {
        return;
    }
    
    $fileId = $fields->getFileId(); // Это ID файла      
    $fileSize = $fields->getSize(); // Размер в байтах
    $userId = $fields->getCreatedBy(); // Кто загрузил

    if ($fileSize > $maxFileSizeChat)  // Проверяем, превышает ли файл лимиты
    {
        $diskObjectId = $fields->getParentId(); // Получаем ID родительского объекта
        if (!$diskObjectId){			
            return;
		}
		
        $diskObject = (array) \Bitrix\Disk\Internals\ObjectTable::getList(['filter' => ['ID' => $diskObjectId]])->fetch(); // Получаем объект из базы
        if (!$diskObject['NAME']){
            return;
		}
		
        $chatId = intval(str_replace('chat', '', $diskObject['NAME'])); // Извлекаем chatId из имени объекта ( если  это чат )

        if ($fileSize > $veryLargeFileSize) { // Очень большой файл - удаляем сразу    			
				$limitName = $veryLargeFileSize / 1000000;	// МБ
				deleteFileAndNotify($fileId, $userId, $limitName);
			}else{
				// проверяем это чат лили нет
				if (!$chatId){ 
					if ($fileSize > $maxFileSize){ // Проверка размера файла
						$limitName = $maxFileSize / 1000000;	// МБ
						addToHighloadBlock($fields);
						$message = 'Файл больше '.$limitName.'МБ, будет удален через '.$n_del.' дней';
						PullNotifyUser($userId, $message); // Отправляем пуш уведомление
					}
				}else{ 
					$limitName = $maxFileSizeChat / 1000000;	// МБ
					addToHighloadBlock($fields);
					$message = 'Файл больше '.$limitName.'МБ, будет удален через '.$n_del.' дней';
					PullNotifyUser($userId, $message); // Отправляем пуш уведомление
				}			
		}
    }
});


// Удаляет файл
function deleteFileAndNotify($fileId, $userId, $limitName)
{
	// Подготовка удаления файла
	$diskFile = \Bitrix\Disk\File::load(['=FILE_ID' => $fileId]);
	if ($diskFile instanceof \Bitrix\Disk\BaseObject)
	{
		$arFile = $diskFile->toArray();
		$diskFile->delete($userId); // Удаляем файл
        $message = 'Файл превышает лимит '.$limitName.'МБ';
		
        PullNotifyUser($userId, $message); // Отправляем пуш уведомление
	}
	throw new SystemException("Файл слишком большой и был удалён.");		
}


// Отправляет уведомление пользователю
function PullNotifyUser($userId, $message)
{
    if (\Bitrix\Main\Loader::includeModule('pull')) {
        \CPullStack::AddByUser($userId, [
            'module_id' => 'main',
            'command' => 'file_warning_limit',
            'params' => ['message' => $message]
        ]);
    }
}


// Добавляет файл в Highload-блок для отложенного удаления

function addToHighloadBlock($fields)
{
    if (!Loader::includeModule('highloadblock')) {
        return false;
    }
       
    $hlBlockId = 22; // ID Highload-блока
    $hlBlock = \Bitrix\Highloadblock\HighloadBlockTable::getById($hlBlockId)->fetch();
    
    if (!$hlBlock) {
        return false;
    }
    
    $entity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlBlock);
    $entityDataClass = $entity->getDataClass();
    
    // Добавляем запись
    $result = $entityDataClass::add([
        'UF_FILE_ID' => $fields->getFileId(),
        'UF_OBJECT_ID' => $fields->getId(),
        'UF_CREATED_BY' => $fields->getCreatedBy(),
        'UF_CREATED_AT' => new DateTime(),
        'UF_DELETE_AT' => (new DateTime())->add('14 days'),
        'UF_SIZE' => $fields->getSize(),
        'UF_STATUS' => 'WAITING_DELETION',
    ]);
    
    return $result->isSuccess();
}

Скрипт обработки очереди на удаления файлов (cron).

use Bitrix\Main\Loader;
use Bitrix\Main\Type\DateTime;

Loader::includeModule('disk');
Loader::includeModule('highloadblock');

$hlBlockId = 22; // ID вашего HL-блока
$hlBlock = \Bitrix\Highloadblock\HighloadBlockTable::getById($hlBlockId)->fetch();
$entity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlBlock);
$entityDataClass = $entity->getDataClass();

// Находим файлы, которые нужно удалить
$records = $entityDataClass::getList([
    'filter' => [
        '<=UF_DELETE_AT' => new DateTime(),
        '=UF_STATUS' => 'WAITING_DELETION'
    ]
]);

while ($record = $records->fetch()) {
    $diskFile = \Bitrix\Disk\File::load(['=FILE_ID' => $record['UF_FILE_ID']]);
    if ($diskFile instanceof \Bitrix\Disk\BaseObject) {
        if ($diskFile->delete($GLOBALS['USER']->getId())) {  // Удаляем
            // Помечаем как удалённый
            $entityDataClass::update($record['ID'], [
                'UF_STATUS' => 'DELETED',
                'UF_DELETED_AT' => new DateTime()
            ]);
        }
    }
}

5 В чатах было принято решение удалять все файлы старше 2 лет . Скрипт запускаемый кроном раз в день чистит именно файлы загружаемые в чатах

\CTimeZone::Disable(); // Отключить часовой пояс
$cutoffDate = (new \Bitrix\Main\Type\DateTime())->add('-2 years'); // Срок хранения 2 года

$files = \Bitrix\Disk\Internals\ObjectTable::getList([
    'filter' => [
        '=TYPE' => 3, // Файлы
        '=STORAGE_ID' => 4646, // Хранилище мессенжера
        '<CREATE_TIME' => $cutoffDate
    ],
    'select' => ['ID', 'NAME', 'SIZE', 'CREATE_TIME'],
    'limit' => 1000
]);

$deleted = 0;
$errors = 0;

while ($file = $files->fetch()) {
    $obj = \Bitrix\Disk\File::getById($file['ID']);
    if ($obj) {
        try {
            if ($obj->delete(1)) { // От имени Bitrix
                echo "Удалён файл ID: {$file['ID']}, {$file['NAME']} </br>";
                $deleted++;
            }
        } catch (\Exception $e) {
            echo "Ошибка: {$e->getMessage()}\n";
            $errors++;
        }
    }
}
echo "Всего удалено: $deleted, ошибок: $errors\n";
\CTimeZone::Enable(); // Включить часовой пояс
Теги:
Хабы:
+1
Комментарии1

Публикации

Ближайшие события