Configuring Safety Data Sheet Display for Products in 1C-Bitrix
A Safety Data Sheet (SDS / MSDS) is a mandatory document for chemical substances, paints and coatings, cleaning agents, industrial gases, and certain other product categories. For online sales on a Bitrix-based store the requirement is straightforward: the document must be accessible to the buyer before purchase. In practice this means a PDF in the product card with version control and a download option.
Document Storage
Safety data sheets are stored in the Bitrix file storage (/upload/) via the main module. The link between a document and a product is established through a file-type infoblock property:
Property SAFETY_DATA_SHEET (type F — file):
- Multiple: no (one current SDS per product)
- Required: no (not applicable to all products)
- Hint description: "PDF safety data sheet (GOST 30333-2007)"
For version control — an additional property SAFETY_DATA_SHEET_DATE (type DateTime) stores the document version date.
Bulk Upload
Safety data sheets often arrive in bulk from a supplier as a ZIP archive with filenames based on the product SKU. Bulk import script:
function importSdsDocuments(string $zipPath, int $iblockId): array
{
$zip = new \ZipArchive();
$zip->open($zipPath);
$results = ['ok' => 0, 'not_found' => [], 'error' => []];
for ($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
if (!str_ends_with(strtolower($filename), '.pdf')) continue;
// Extract SKU from filename (e.g. "ART-12345_msds.pdf")
preg_match('/^([A-Z0-9\-]+)/i', $filename, $matches);
$article = $matches[1] ?? '';
$product = \CIBlockElement::GetList([], [
'IBLOCK_ID' => $iblockId,
'PROPERTY_ARTICLE' => $article,
], false, ['nPageSize' => 1], ['ID', 'NAME'])->GetNext();
if (!$product) {
$results['not_found'][] = $filename;
continue;
}
// Save file
$tmpPath = sys_get_temp_dir() . '/' . $filename;
file_put_contents($tmpPath, $zip->getFromIndex($i));
$fileId = \CFile::SaveFile([
'name' => $filename,
'tmp_name' => $tmpPath,
'type' => 'application/pdf',
], 'sds_documents');
if ($fileId) {
\CIBlockElement::SetPropertyValuesEx($product['ID'], $iblockId, [
'SAFETY_DATA_SHEET' => $fileId,
'SAFETY_DATA_SHEET_DATE' => date('d.m.Y'),
]);
$results['ok']++;
}
}
$zip->close();
return $results;
}
Display in the Product Card
In the bitrix:catalog.element component template, add the safety data sheet block:
<?php if (!empty($arResult['PROPERTIES']['SAFETY_DATA_SHEET']['VALUE'])): ?>
<?php $sdsFile = \CFile::GetFileArray($arResult['PROPERTIES']['SAFETY_DATA_SHEET']['VALUE']); ?>
<div class="product-sds">
<h4>Safety Documentation</h4>
<a href="<?= \CFile::GetPath($arResult['PROPERTIES']['SAFETY_DATA_SHEET']['VALUE']) ?>"
download="<?= htmlspecialchars($sdsFile['ORIGINAL_NAME']) ?>"
class="sds-download-btn">
<span class="pdf-icon"></span>
Safety Data Sheet (PDF)
<?php if (!empty($arResult['PROPERTIES']['SAFETY_DATA_SHEET_DATE']['VALUE'])): ?>
<small>version dated <?= $arResult['PROPERTIES']['SAFETY_DATA_SHEET_DATE']['VALUE'] ?></small>
<?php endif; ?>
</a>
<p class="sds-note">In accordance with GOST 30333-2007</p>
</div>
<?php endif; ?>
The download attribute forces the browser to download the file rather than open it inline.
SDS Presence Validation on Catalog Addition
For categories where an SDS is mandatory (e.g. "Chemicals", "Paints and Coatings"), validation is configured via the OnBeforeIBlockElementAdd event handler:
AddEventHandler('iblock', 'OnBeforeIBlockElementAdd', function(&$fields) {
$requiredSdsSections = \Bitrix\Main\Config\Option::get('sds_module', 'required_sections', '');
$requiredSectionIds = array_filter(explode(',', $requiredSdsSections));
if (in_array($fields['IBLOCK_SECTION_ID'], $requiredSectionIds)) {
if (empty($fields['PROPERTY_VALUES']['SAFETY_DATA_SHEET'])) {
// Warning (not a hard block — the editor can fill it in later)
$GLOBALS['APPLICATION']->ThrowException(
'Warning: a safety data sheet is recommended for this section.',
'SDS_MISSING'
);
}
}
});
Report on Products Missing an SDS
Admin report GET /bitrix/admin/sds_report.php: a list of products in "chemical" sections without an attached safety data sheet, with a quick-upload button directly from the table.
SELECT ie.ID, ie.NAME, s.NAME as section_name
FROM b_iblock_element ie
JOIN b_iblock_section s ON s.ID = ie.IBLOCK_SECTION_ID
LEFT JOIN b_iblock_element_property iep
ON iep.IBLOCK_ELEMENT_ID = ie.ID
AND iep.IBLOCK_PROPERTY_ID = (
SELECT ID FROM b_iblock_property
WHERE IBLOCK_ID = ie.IBLOCK_ID AND CODE = 'SAFETY_DATA_SHEET'
)
WHERE ie.IBLOCK_ID = ? AND ie.ACTIVE = 'Y'
AND s.ID IN (/* sections requiring SDS */)
AND (iep.VALUE IS NULL OR iep.VALUE = '')
ORDER BY s.NAME, ie.NAME;
Timeline
| Phase | Duration |
|---|---|
| Infoblock property configuration | 0.5 days |
| Bulk import script from ZIP | 1 day |
| Product card display template | 1 day |
| Missing documents report | 1 day |
| Testing | 0.5 days |
| Total | 4 days |







