Работа с файлами в CMS Bitrix на PHP: практические решения

Раздел: Разработка на PHP -> CMS Bitrix

Работа с файлами в Bitrix (PHP): обзор методов и решений

Наиболее эффективный способ работы с файлами в среде Bitrix - использование встроенного класса CFile. Этот класс предоставляет единый интерфейс для сохранения, загрузки, удаления и обработки файлов с автоматическим управлением путями и записью метаданных в базу данных.

Как стандартизировать загрузку файла через форму и сохранить его в инфоблок?

Пример обработки файла, переданного через $_FILES, и добавления элемента инфоблока с файловым полем:


use Bitrix\Main\Context;
use Bitrix\Main\HttpRequest;

$request = Context::getCurrent()->getRequest();
if ($request->isPost()) {
    $fileArray = $request->getFile('MY_FILE');
    if ($fileArray && $fileArray['error'] === UPLOAD_ERR_OK) {
        $fileId = CFile::SaveFile($fileArray, 'iblock');
        if ($fileId) {
            $el = new CIBlockElement;
            $arFields = [
                'IBLOCK_ID' => 3,
                'NAME' => 'Документ с файлом',
                'ACTIVE' => 'Y',
                'PROPERTY_VALUES' => ['FILE' => $fileId]
            ];
            if ($el->Add($arFields)) {
                echo 'Файл сохранён, ID элемента: ' . $el->LAST_ID;
            }
        } else {
            echo 'Ошибка при сохранении файла';
        }
    }
}
  

Типичные ошибки:

  • Пропуск вызова CFile::SaveFile() до передачи в CIBlockElement::Add - файл не будет сохранён.
  • Использование некорректного модуля (например, 'iblock' вместо 'main').
  • Недостаточно прав на запись в временную директорию или в папку upload.

Решение: проверять результат CFile::SaveFile(), использовать отладку через AddMessage2Log.

Как безопасно получить путь к файлу на сервере по его ID?


$fileId = 123; // ID из таблицы b_file
$arFile = CFile::GetFileArray($fileId);
if ($arFile) {
    $serverPath = $arFile['SRC']; // относительный путь от корня сайта
    $fullPath = $_SERVER['DOCUMENT_ROOT'] . $serverPath;
    // Можно читать файл
    $content = file_get_contents($fullPath);
}
  

Ошибка: путь может быть неверным, если файл находится на другом сервере (CDN) или в защищённой директории. Рекомендуется использовать CFile::GetPath() для прямого пути.

Как скопировать или переместить файл внутри файловой системы Bitrix?

Использование функции CopyFile():


$source = $_SERVER['DOCUMENT_ROOT'] . '/upload/tmp/source.pdf';
$target = $_SERVER['DOCUMENT_ROOT'] . '/upload/files/dest.pdf';
if (CopyFile($source, $target)) {
    echo 'Файл скопирован';
} else {
    echo 'Ошибка копирования - проверьте права и пути';
}
  

Проблема: функция CopyFile() не обновляет записи в b_file. Если файл уже был зарегистрирован, нужно создавать новый элемент через CFile::SaveFile().

Как загрузить файл по URL и сохранить его как временный или постоянный?


$url = 'https://example.com/image.jpg';
$content = file_get_contents($url);
if ($content !== false) {
    $tmpFile = tempnam(sys_get_temp_dir(), 'bxtmp');
    file_put_contents($tmpFile, $content);
    $arFile = CFile::MakeFileArray($tmpFile);
    if ($arFile) {
        $fileId = CFile::SaveFile($arFile, 'iblock');
        unlink($tmpFile);
        echo 'Файл загружен, ID: ' . $fileId;
    }
}
  

Проблема: большие файлы могут привести к переполнению памяти. Рекомендуется использовать потоковую запись через fwrite и CFile::MakeFileArray.

Как удалить файл из инфоблока вместе с записью в b_file?


$elementId = 456;
$el = new CIBlockElement;
$arElement = $el->GetByID($elementId)->Fetch();
if ($arElement) {
    $propValue = $arElement['PROPERTY_FILE_VALUE']; // ID файла
    $el->Delete($elementId); // удаляет элемент и все его свойства
    CFile::Delete($propValue); // физически удаляет файл
}
  

Внимание: CIBlockElement::Delete не всегда автоматически вызывает CFile::Delete для свойств типа «Файл». Лучше удалять файлы явно после удаления элемента.

Как работать с файловым полем пользовательского свойства (UF)?


$userId = 1;
$user = new CUser;
$arUser = $user->GetByID($userId)->Fetch();
if ($arUser) {
    $fileId = $arUser['UF_AVATAR']; // ID файла
    if ($fileId) {
        $arFile = CFile::GetFileArray($fileId);
        echo 'Путь к аватару: ' . $arFile['SRC'];
    }
}
  

Для обновления аватара через форму используйте тот же подход с CFile::SaveFile и передачей ID в CUser::Update.

Проблема: при обновлении пользователя без загрузки нового файла нужно передавать старый ID, иначе поле обнулится.

Каждый из вариантов применяется в зависимости от источника файла (локальная загрузка, URL, системные файлы) и контекста (инфоблоки, пользователи, рабочий стол). Выбор метода диктуется требованиями к производительности и безопасности.

Расширенные примеры работы с файлами в Bitrix

Пример 1: Пакетная загрузка нескольких файлов из формы в одно свойство типа «Набор файлов».

Пример

// В форме: <input type="file" name="FILES[]" multiple>
$files = $_FILES['FILES'];
$fileIds = [];
if (is_array($files['tmp_name'])) {
    foreach ($files['tmp_name'] as $index => $tmpName) {
        if ($files['error'][$index] === UPLOAD_ERR_OK) {
            $arFile = [
                'name' => $files['name'][$index],
                'size' => $files['size'][$index],
                'tmp_name' => $tmpName,
                'type' => $files['type'][$index]
            ];
            $fileId = CFile::SaveFile($arFile, 'iblock');
            if ($fileId) $fileIds[] = $fileId;
        }
    }
}
if (!empty($fileIds)) {
    $el = new CIBlockElement;
    $arFields = [
        'IBLOCK_ID' => 3,
        'NAME' => 'Несколько файлов',
        'PROPERTY_VALUES' => ['MULTI_FILE' => $fileIds]
    ];
    $el->Add($arFields);
}

Результат: элемент инфоблока с прикреплёнными файлами. В базе свойство типа «Набор файлов» хранит сериализованный массив ID.

// В админке файлы отображаются как список ссылок

Пример 2: Создание файла на лету и его регистрация в системе без физической загрузки.

Пример

$content = 'Содержимое динамического файла';
$tmpPath = tempnam(sys_get_temp_dir(), 'bx');
file_put_contents($tmpPath, $content);
$arFile = CFile::MakeFileArray($tmpPath);
$arFile['name'] = 'generated.txt';
unlink($tmpPath); // удаляем исходный временный файл
if ($arFile) {
    $fileId = CFile::SaveFile($arFile, 'main');
    if ($fileId) {
        echo 'ID созданного файла: ' . $fileId;
        // Далее можно прикрепить к элементу или скачать
    }
}
ID созданного файла: 789

Пример 3: Изменение файла (замена) через обновление элемента инфоблока.

Пример

$elementId = 456;
$el = new CIBlockElement;
$arFields = [
    'PROPERTY_VALUES' => [
        'FILE' => [
            'VALUE' => CFile::SaveFile(
                $_FILES['NEW_FILE'],
                'iblock',
                false,
                false,
                true // перезапись существующего файла?
            ),
            'OLD_VALUE' => $oldFileId // передаём старый ID для удаления
        ]
    ]
];
$el->Update($elementId, $arFields);

Это пример из документации Bitrix: свойство типа «Файл» при передаче массива с ключами VALUE и OLD_VALUE автоматически удаляет старый файл при успешном сохранении нового.

Пример 4: Чтение файла через CFile::GetContents (если доступен) или вручную.

Пример

$fileId = 100;
$arFile = CFile::GetFileArray($fileId);
if ($arFile) {
    $fullPath = $_SERVER['DOCUMENT_ROOT'] . $arFile['SRC'];
    if (file_exists($fullPath)) {
        $handle = fopen($fullPath, 'r');
        while (!feof($handle)) {
            $line = fgets($handle);
            echo htmlspecialchars($line) . '<br>';
        }
        fclose($handle);
    }
}

Вывод: построчное отображение текстового файла в браузере.

Пример 5: Получение размера и MIME-типа без загрузки файла.

Пример

$fileId = 101;
$arFile = CFile::GetFileArray($fileId);
if ($arFile) {
    echo 'Размер: ' . CFile::FormatSize($arFile['FILE_SIZE']);
    echo 'Тип: ' . $arFile['CONTENT_TYPE'];
    echo 'Дата: ' . $arFile['TIMESTAMP_X'];
}
Размер: 1.2 Мб
Тип: application/pdf
Дата: 2025-04-01 12:34:56

Пример 6: Удаление файла по ID с проверкой существования записи.

Пример

$fileId = 999;
$dbFile = CFile::GetByID($fileId);
if ($dbFile->Fetch()) {
    CFile::Delete($fileId);
    echo 'Файл удалён';
} else {
    echo 'Файл с таким ID не найден';
}

Пример 7: Работа с временными файлами Bitrix (система временных меток).

Пример

$tempFileId = CFile::SaveFile($_FILES['TEMP'], 'main', false, true);
// третий параметр 'subdir' - можно передать false для корня upload/tmp
// четвёртый 'tmp' - true означает временное хранилище
if ($tempFileId) {
    sleep(3600);
    // При следующем запуске агента файл может быть очищен
}

Система временных файлов автоматически удаляет файлы старше определённого периода (настраивается в главном модуле).

Работа с файлами в Bitrix (PHP) - comments

En
File php bitrix (php)