Ви передаєте готову книгу колезі й просите його відфільтрувати її, а не переписувати. Тож ви захищаєте аркуш. У старіших збірках HotXLS цей жест записував у файл лише одне: <sheetProtection sheet="1" objects="1" scenarios="1"/>, жорстко закодоване, кожного разу. Аркуш блокувався, хеш пароля додавався, і користувач не міг зробити взагалі нічого, навіть сортування й фільтрацію, які ви хотіли залишити відкритими. У діалозі Excel "Protect Sheet" є п'ятнадцять прапорців саме з цієї причини, а рушій не міг представити жоден із них. Саме цю прогалину закриває модель захисту v2.91.0
HotXLS - це нативний VCL-компонент електронних таблиць для Delphi та C++Builder, який читає і записує XLS та XLSX без встановленого Excel. Ця стаття присвячена частині захисту аркуша у XLSX: новому TXLSXSheetProtectionOption enum, а AllowOption властивості, яка вмикає або вимикає кожен дозвіл, і єдиному правилу кодування OOXML, на якому спотикається кожен, хто пише <sheetProtection> елемент вручну
Що саме захищає захист аркуша
Спершу межа, бо від неї залежить, наскільки всьому цьому можна довіряти. Захист аркуша у форматі електронних таблиць OOXML (ECMA-376) є політикою взаємодії, а не шифруванням. Він підказує сумісній програмі, які редагування відхиляти, поки аркуш захищений. Значення клітинок і далі лежать у xl/worksheets/sheetN.xml у відкритому вигляді; розпакуйте .xlsx і вони прямо там. Необов'язковий пароль зберігається як короткий застарілий хеш, а не як ключ, що щось шифрує. Будь-хто, хто перейменує файл, відкриє частину і прибере <sheetProtection> рядок читає і редагує все
Тож захист відповідає не на "зупинити колегу від випадкового знищення формули", а на "зберегти ці дані від людини, яка діє свідомо". Це різні проблеми з різними інструментами. Якщо вам потрібна конфіденційність, вам потрібне шифрування на рівні книги, описане в XLSX-вивід із захистом AES, який справді шифрує пакет. Захист аркуша і шифрування книги добре поєднуються, але замком є лише друге. Тримайте цю межу чітко, і решта цієї сторінки - просто технічна обв'язка
П'ятнадцять параметрів і властивість AllowOption
Кожен аркуш тепер містить набір TXLSXSheetProtectionOption значень, що описують, що користувач і далі може робити, поки аркуш захищений. Елементи відображаються один до одного у властивості OOXML та прапорцях діалогу Excel:
xlsxSpoEditObjects,xlsxSpoEditScenarios- редагування графічних об'єктів і сценаріїв «що буде, якщо»xlsxSpoFormatCells,xlsxSpoFormatColumns,xlsxSpoFormatRows- змінення форматування клітинок, стовпців і рядківxlsxSpoInsertColumns,xlsxSpoInsertRows,xlsxSpoInsertHyperlinks- вставлення стовпців, рядків, посиланьxlsxSpoDeleteColumns,xlsxSpoDeleteRows- видалення стовпців і рядківxlsxSpoSelectLockedCells,xlsxSpoSelectUnlockedCells- переміщення виділення на заблоковані або незаблоковані клітинкиxlsxSpoSort,xlsxSpoAutoFilter,xlsxSpoPivotTables- сортування діапазонів, використання спадних списків AutoFilter, робота зі зведеними таблицями
Ви читаєте і записуєте окремі біти через індексовану AllowOption властивість на TXLSXWorksheet. AllowOption[Opt] = True означає, що дія дозволена; встановлення цього False забороняє її. Увесь набір також доступний одразу через SheetProtectionOptions, TXLSXSheetProtectionOptions (звичайний Pascal set of), тож ви можете зберегти його, відновити або повністю замінити
За замовчуванням це важливо, і так зроблено навмисно: щойно створений аркуш починає з дозволеними всіма параметрами. Конструктор заповнює SheetProtectionOptions повним набором, [Low(TXLSXSheetProtectionOption)..High(TXLSXSheetProtectionOption)]. Далі ви звужуєте його, виключаючи дії, які хочете заборонити, а не збираючи набір дозволів з нуля. Саме тому правило кодування записувача, наведене нижче, узгоджується з поведінкою Excel
Захист аркуша з відкритими сортуванням і фільтром
Ось типовий випадок у повному циклі: захистити готовий звіт, щоб макет не можна було змінити, але дозволити читачеві сортувати і фільтрувати його. Зверніть увагу, що Protect та параметри не залежать один від одного. Protect переводить аркуш у захищений стан і зберігає необов'язковий хеш пароля; це не зачіпає набір параметрів. Ви налаштовуєте AllowOption окремо, а перемикачі почнуть діяти після того, як аркуш буде захищено і збережено
var
wb: TXLSXWorkbook;
sh: TXLSXWorksheet;
begin
wb := TXLSXWorkbook.Create;
try
sh := wb.Sheets.Add('Protected');
sh.Cells[1, 1].Value := 'Region'; sh.Cells[1, 2].Value := 'Units';
sh.Cells[2, 1].Value := 'North'; sh.Cells[2, 2].Value := 120;
sh.Cells[3, 1].Value := 'South'; sh.Cells[3, 2].Value := 98;
// Protect with a password. This only sets the protected state + hash;
// the option set is left at its all-permitted default.
sh.Protect('HotXLS-2026');
// Narrow: keep sort + AutoFilter, forbid reshaping and reformatting.
sh.AllowOption[xlsxSpoSort] := True;
sh.AllowOption[xlsxSpoAutoFilter] := True;
sh.AllowOption[xlsxSpoFormatCells] := False;
sh.AllowOption[xlsxSpoFormatColumns] := False;
sh.AllowOption[xlsxSpoFormatRows] := False;
sh.AllowOption[xlsxSpoInsertRows] := False;
sh.AllowOption[xlsxSpoDeleteRows] := False;
if wb.SaveAs('protection.xlsx') <> 1 then
Writeln('SaveAs failed');
finally
wb.Free;
end;
end;
Дві речі, на які варто звернути увагу в цьому фрагменті. Рядки Sort та AutoFilter записані явно, хоча обидва мають значення за замовчуванням True; це документація для наступного супроводжувальника, а не функціональна вимога. А оскільки значення за замовчуванням дозволяють усе, єдині рядки, що змінюють вихідний файл, це ті, де параметру надають значення False. Це не випадковість цього API, а прояв формату обміну OOXML, і саме про це наступний розділ
Правило кодування: відсутній атрибут означає дозвіл, attr=0 означає заборону
Це єдиний неочевидний факт у всій функції, і саме тут саморобний <sheetProtection> зазвичай працює неправильно. В OOXML кожен атрибут для окремої дії є прапорцем заборони, а його відсутність означає дозвіл. Відсутній атрибут означає, що дію дозволено. Атрибут, записаний як "0" означає, що дію заборонено, поки аркуш захищено. У правильно сформованому файлі немає formatCells="1" щоб означати "форматування дозволено"; ви просто не додаєте цей атрибут. (Значенням за замовчуванням для відсутнього атрибута є булеве значення OOXML true, а ці атрибути названі так, що "true" означає, що відповідне редагування дозволене.)
Записувач HotXLS відтворює це точно. Він виводить sheet="1" щоб увімкнути захист, потім проходить по набору параметрів і записує attr="0" лише для параметрів, які ви встановили в False. Дозволені дії не додають нічого до виходу. Тож книга з попереднього розділу серіалізується приблизно так, зберігаючи лише заборонені дії та хеш пароля:
// Conceptual output for the snippet above (attributes elided for brevity):
// <sheetProtection sheet="1"
// formatCells="0" formatColumns="0" formatRows="0"
// insertRows="0" deleteRows="0"
// password="...4-hex..."/>
// Note what is NOT there: no sort, no autoFilter, no selectLockedCells.
// Their absence is exactly what tells Excel those actions stay allowed.
Якщо ви прийшли зі старого жорстко заданого рядка і чекали побачити кожен атрибут виписаним явно, це виглядає мізерно, майже неправильно. Але це правильно. Файл, у якому були б перелічені sort="1" та autoFilter="1" означав би для сумісного читача те саме, але сам Excel пише мінімальну форму лише із заборонами, а її відтворення зменшує різницю у diff і робить повторне збереження передбачуваним. Атрибути objects та scenarios підкоряються тому самому правилу: за замовчуванням вони дозволені, тож з'являються лише як "0" коли ви їх забороняєте, що є протилежністю старого objects="1" scenarios="1", який виводився безумовно
Зчитування захисту назад: точність round-trip
Модель дозволів, яку можна записати, але не прочитати, це дорога в один бік, і типовий симптом тут - цикл завантаження-редагування-збереження, який непомітно розширює дозволи. HotXLS це усуває. Коли ParseWorksheetXml досягає <sheetProtection> елемента, він вмикає захист аркуша, зберігає хеш пароля, якщо він є, а потім декодує кожен атрибут для окремої дії назад у AllowOption використовуючи ту саму домовленість у зворотному напрямку: наявний атрибут, що дорівнює "0" забороняє дію; відсутній атрибут залишає для параметра дозволене значення за замовчуванням
var
wb: TXLSXWorkbook;
sh: TXLSXWorksheet;
begin
wb := TXLSXWorkbook.Create;
try
wb.LoadFromFile('protection.xlsx');
sh := wb.Sheets[1]; // XLSX sheets are 1-based
if sh.IsProtected then
begin
Writeln('Protected; password hash present: ',
sh.SheetProtectHash <> '');
Writeln('Sort allowed: ', sh.AllowOption[xlsxSpoSort]);
Writeln('AutoFilter allowed: ', sh.AllowOption[xlsxSpoAutoFilter]);
Writeln('FormatCells allowed:', sh.AllowOption[xlsxSpoFormatCells]);
end;
finally
wb.Free;
end;
end;
Відкрийте файл, який створив записувач, і ви отримаєте Sort та AutoFilter назад як True, FormatCells як False - той самий набір, який ви зберегли, без змін. Саме в цьому й полягає симетрія: змініть одну клітинку на захищеному аркуші з частково дозволеними діями і збережіть знову, і чотирнадцять дозволів, яких ви не чіпали, збережуться замість того, щоб знову звалитися до старого режиму все або нічого
Практичні примітки та обмеження
Кілька речей, які варто знати, перш ніж вбудовувати це в конвеєр звітів:
- Пароль за задумом слабкий. Захист аркуша XLSX зберігає спадковий 16-бітний хеш (той самий, який Excel використовує десятиліттями), і це залишено тут для сумісності. Він відвертає випадкові зміни; він не стримує зловмисника. Не вважайте його сховищем секретів. Для справжнього захисту шифруйте книгу
- Встановлювати параметри перед захистом можна.
AllowOptionможна призначати незалежно від того, чи захищено аркуш зараз; перемикачі просто описують, що буде дозволено, колиProtectнабуде чинності.UnProtectскидає стан захищеності та хеш, але залишає ваш набір параметрів на місці до наступного разу - Семантика заблокованих клітинок усе ще діє. Захист блокує лише редагування клітинок, для яких атрибут
Lockedвстановлено (типове значення книги). Залишити область введення редагованою - це завдання стилю клітинки, а не параметра захисту; ці два рівні поєднуються так само, як в Excel - Це механізм XLSX. Модель параметрів повторює старі
Allow*властивості механізму XLS, але назви переліку та властивостей тут (xlsxSpo*,AllowOption) належатьTXLSXWorksheetуlxHandleX. Якщо ви також керуєте макетом друку на тих самих аркушах, огляд захисту та налаштування сторінки пояснює, як ці параметри співіснують із діапазонами друку та верхніми колонтитулами, а перевірка даних, AutoFilter і таблиці природно поєднується з тим, щоб лишитиxlsxSpoAutoFilterвідкритим на захищеному звіті
Деталізована модель захисту та решта механізму читання/запису XLSX постачаються в HotXLS Component для Delphi та C++Builder; на сторінці продукту наведено повний API аркушів, включно з повною довідкою щодо параметрів захисту