Файлы PHP в Bitrix: все аспекты работы с файловой системой
В CMS Bitrix работа с файлами является неотъемлемой частью разработки: загрузка изображений, документов, обработка медиафайлов через API. В статье рассматриваются ключевые подходы к управлению файлами с использованием встроенных классов, таких как CFile, и методы интеграции с инфоблоками. Приводятся готовые примеры кода с пояснениями, а также разбираются типичные ошибки.
Основной способ: использование класса CFile
Как корректно загрузить файл на сервер и сохранить его в базе данных Bitrix?
Наиболее эффективное решение - применение метода CFile::SaveFile, который принимает данные из $_FILES, массив параметров и идентификатор модуля. Пример ниже демонстрирует загрузку одного изображения с проверкой типа и размера.
<?php
// Файл upload.php в корне сайта
require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userfile'])) {
$file = $_FILES['userfile'];
$allowedMime = ['image/jpeg', 'image/png', 'image/gif'];
$maxSize = 5 * 1024 * 1024; // 5 МБ
if ($file['error'] !== UPLOAD_ERR_OK) {
$error = 'Ошибка загрузки: код ' . $file['error'];
} elseif (!in_array($file['type'], $allowedMime)) {
$error = 'Недопустимый формат файла';
} elseif ($file['size'] > $maxSize) {
$error = 'Файл слишком большой';
} else {
$arFile = [
'name' => $file['name'],
'size' => $file['size'],
'tmp_name' => $file['tmp_name'],
'type' => $file['type'],
'MODULE_ID' => 'main',
];
$fid = CFile::SaveFile($arFile, 'uploads');
if ($fid > 0) {
$result = 'Файл сохранён. ID: ' . $fid . ', путь: ' . CFile::GetPath($fid);
} else {
$error = 'Не удалось сохранить файл';
}
}
}
?>
файл bitrix php (файл bitrix php)
Файл сохранён. ID: 123, путь: /upload/uploads/2024/01/image.jpg
File php bitrix (работа с файлами в bitrix (php))
Проблемы:
- Если $_FILES пуст - стоит проверить enctype формы (multipart/form-data).
- Большие файлы могут превышать лимиты PHP (upload_max_filesize, post_max_size). Рекомендуется увеличить значения в php.ini или через .htaccess.
- Ошибка доступа к временной папке - проверить права на /tmp и /upload.
Как прикрепить файл к элементу инфоблока?
Для сохранения файла как свойства типа «Файл» элемента инфоблока используется CIBlockElement::SetPropertyValuesEx. Пример:
$arFile = CFile::MakeFileArray($_FILES['doc']['tmp_name']);
$propValue = ['VALUE' => $arFile, 'DESCRIPTION' => 'Документ'];
CIBlockElement::SetPropertyValuesEx($elementId, $iblockId, ['MY_FILE' => $propValue]);
В результате файл копируется в папку upload/iblock и привязывается к свойству.
Ошибки: свойство может не существовать - проверить код свойства в инфоблоке. Значение должно быть массивом с ключом VALUE.
Как обработать загруженное изображение (ресайз, кроп)?
Класс CFile предоставляет метод ResizeImageGet для создания копий изображения без загрузки в память:
$resized = CFile::ResizeImageGet(
$fileId,
['width' => 300, 'height' => 200],
BX_RESIZE_IMAGE_PROPORTIONAL_ALT,
true
);
echo 'Путь к уменьшенной копии: ' . $resized['src'];
Путь к уменьшенной копии: /upload/resize_cache/main/abc/300_200_1/image.jpg
Проблемы: если исходный файл не изображение или повреждён, возвращается false. Нужно предварительно проверять CFile::IsImage($fileId).
Как загрузить несколько файлов одновременно?
Используется массив $_FILES['files']['name'] (с квадратными скобками в имени поля). Пример циклической обработки:
foreach ($_FILES['files']['tmp_name'] as $key => $tmpName) {
if ($_FILES['files']['error'][$key] !== UPLOAD_ERR_OK) continue;
$arFile = [
'name' => $_FILES['files']['name'][$key],
'size' => $_FILES['files']['size'][$key],
'tmp_name' => $tmpName,
'type' => $_FILES['files']['type'][$key],
'MODULE_ID' => 'main',
];
$fid = CFile::SaveFile($arFile, 'multi');
// Сохранить fid в БД или в сессию
}
Типичная ошибка: неверная структура массива из формы - нужно указывать name="files[]" в HTML.
Как удалить файл через API?
Удаление записи о файле и самого файла с диска:
CFile::Delete($fileId);
Метод автоматически удаляет все производные (resize_cache), если они существуют.
Если файл используется другими сущностями (например, прикреплён к нескольким элементам), удаление может привести к ошибкам. Рекомендуется проверять файл через CFile::GetList или использовать CFile::Delete только при уверенности.
Ниже приведены расширенные примеры с подробными комментариями.
Пример 1. Загрузка файла с одновременным созданием миниатюры
// Загрузка, сохранение, ресайз и удаление оригинала (опционально)
function uploadAndThumbnail($fileArray, $thumbWidth = 150, $thumbHeight = 150) {
$fileId = CFile::SaveFile($fileArray, 'products');
if (!$fileId) return false;
$thumb = CFile::ResizeImageGet($fileId, ['width' => $thumbWidth, 'height' => $thumbHeight], BX_RESIZE_IMAGE_EXACT);
// Возвращаем массив с ID оригинала и путём к превью
return [
'ORIGINAL_ID' => $fileId,
'THUMB_SRC' => $thumb['src'],
];
}
// Использование
$result = uploadAndThumbnail([
'name' => 'photo.jpg',
'size' => 1024000,
'tmp_name' => $_FILES['photo']['tmp_name'],
'type' => 'image/jpeg',
'MODULE_ID' => 'iblock',
], 200, 200);
if ($result) {
echo 'Оригинал ID: ' . $result['ORIGINAL_ID'] . ', миниатюра: ' . $result['THUMB_SRC'];
} else {
echo 'Ошибка';
}
Оригинал ID: 456, миниатюра: /upload/resize_cache/iblock/abc/200_200_1/photo.jpg
Пример 2. Получение всех файлов, прикреплённых к элементу инфоблока
$elementId = 123;
$iblockId = 5;
$propertyCode = 'FILES'; // множественное свойство типа «Файл»
$files = CIBlockElement::GetProperty($iblockId, $elementId, [], ['CODE' => $propertyCode]);
while ($file = $files->Fetch()) {
if ($file['VALUE'] > 0) {
$arFile = CFile::GetByID($file['VALUE'])->Fetch();
echo 'Файл: ' . $arFile['ORIGINAL_NAME'] . ' (' . $arFile['FILE_SIZE'] . ' байт)
';
echo 'Путь: ' . CFile::GetPath($file['VALUE']) . '
';
}
}
Файл: report.pdf (204800 байт) Путь: /upload/iblock/abc/report.pdf Файл: image.png (512000 байт) Путь: /upload/iblock/def/image.png
Пример 3. Загрузка файла через асинхронный запрос (AJAX)
// front-end (JavaScript)
const formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch('/ajax/upload.php', {
method: 'POST',
body: formData
}).then(res => res.json()).then(data => console.log(data));
// back-end (ajax/upload.php)
require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_FILES['file'])) {
$fid = CFile::SaveFile($_FILES['file'], 'ajax');
if ($fid) {
echo json_encode(['status' => 'ok', 'fileId' => $fid]);
} else {
echo json_encode(['status' => 'error']);
}
}
Пример 4. Работа с временными файлами (CFile::MakeFileArray)
// Создать файл из строки и временно сохранить
$tempFile = CFile::MakeFileArray([
'content' => 'Hello, world!',
'filename' => 'hello.txt'
]);
$fid = CFile::SaveFile($tempFile, 'temp');
// $tempFile содержит путь и tmp_name, но после сохранения можно удалить
unlink($tempFile['tmp_name']);
Файл сохранён как временный, ID: 789
Пример 5. Обработка ошибок при загрузке через агент
// Агент для пакетной загрузки файлов из внешнего источника
function agentBatchUpload() {
$urls = ['https://example.com/1.jpg', 'https://example.com/2.jpg'];
foreach ($urls as $url) {
$temp = CFile::MakeFileArray($url);
if ($temp === false) {
AddMessage2Log('Не удалось загрузить: ' . $url, 'upload_agent');
continue;
}
CFile::SaveFile($temp, 'external');
}
return 'agentBatchUpload();';
}
Важно: в агенте не использовать глобальные переменные, все данные получать внутри функции.
Пример 6. Изменение прав доступа к файлу через API
$fileId = 100;
$arFile = CFile::GetByID($fileId)->Fetch();
$filePath = $_SERVER['DOCUMENT_ROOT'] . $arFile['SUBDIR'] . '/' . $arFile['FILE_NAME'];
chmod($filePath, 0644); // или 0444 для только чтения
Не рекомендуется изменять права на файлы, созданные системой, если нет веских причин.