شما یک workbook نهایی را به یک همکار میدهید و از او میخواهید آن را filter کند، نه اینکه بازنویسیاش کند. پس sheet را protect میکنید. در نسخههای قدیمی HotXLS این حرکت فقط یک چیز را داخل فایل مینوشت: <sheetProtection sheet="1" objects="1" scenarios="1"/>، بهشکل hard-coded، هر بار. sheet قفل میشد، hash رمز ضمیمه میشد، و کاربر اصلاً هیچ کاری نمیتوانست بکند، حتی sort و filterی را که واقعاً میخواستید باز بماند. خودِ Excel در dialog «Protect Sheet» پانزده checkbox دارد دقیقاً به همین دلیل، و engine هیچکدامشان را نمیتوانست بیان کند. این فاصله همان چیزی است که model محافظت v2.91.0 آن را میبندد
HotXLS یک مؤلفهٔ بومی VCL spreadsheet برای Delphi و C++Builder است که XLS و XLSX را بدون نصب Excel میخواند و مینویسد. این مقاله دربارهٔ سمت XLSX محافظت worksheet است: enum تازهٔ TXLSXSheetProtectionOption، property AllowOption که هر permission را toggle میکند، و تنها قانون encoding در OOXML که هر کسی را که یک <sheetProtection> element را با دست مینویسد زمین میزند
محافظت worksheet واقعاً چه چیزی را guard میکند
اول مرز، چون همین تصمیم میدهد چقدر باید به این چیزها اعتماد کنید. محافظت worksheet در فرمت spreadsheet OOXML (ECMA-376) یک policy تعامل است، نه encryption. این به یک application سازگار میگوید هنگام protected بودن sheet کدام editها را رد کند. مقدارهای cell هنوز داخل xl/worksheets/sheetN.xml بهصورت plain text نشستهاند؛ .xlsx را unzip کنید و همانجا هستند. password اختیاری بهشکل یک hash قدیمی کوتاه ذخیره میشود، نه یک key که چیزی را scramble کند. هر کسی که فایل را rename کند، part را باز کند، و خط <sheetProtection> را بردارد، همه چیز را میخواند و ویرایش میکند
پس محافظت پاسخ میدهد «نذار همکارم تصادفی یک formula را خراب کند»، نه «این داده را از کسی که جدی دنبال آن است مخفی نگه دار». اینها مسئلههای متفاوتی با ابزارهای متفاوت هستند. اگر محرمانگی میخواهید، باید سراغ encryption سطح workbook بروید که در پوشش داده شده است، که واقعاً package را encipher میکند. محافظت sheet و encryption workbook بهخوبی با هم ترکیب میشوند، اما فقط دومی یک lock است. این خط را صاف نگه دارید و بقیهٔ این صفحه فقط plumbing است
پانزده گزینه و property AllowOption
هر worksheet حالا یک مجموعه از TXLSXSheetProtectionOption values را حمل میکند که توضیح میدهند کاربر وقتی sheet protected است هنوز چه کارهایی میتواند بکند. اعضا یکبهیک به attributeهای OOXML و checkboxهای dialog Excel نگاشت میشوند:
xlsxSpoEditObjects،xlsxSpoEditScenarios— ویرایش drawing objectها و scenarioهای what-ifxlsxSpoFormatCells،xlsxSpoFormatColumns،xlsxSpoFormatRows— قالببندی دوبارهٔ cellها، ستونها، ردیفهاxlsxSpoInsertColumns،xlsxSpoInsertRows،xlsxSpoInsertHyperlinks— درج ستونها، ردیفها، linkهاxlsxSpoDeleteColumns،xlsxSpoDeleteRows— حذف ستونها، ردیفهاxlsxSpoSelectLockedCells،xlsxSpoSelectUnlockedCells— جابهجا کردن selection روی cellهای locked یا unlockedxlsxSpoSort،xlsxSpoAutoFilter،xlsxSpoPivotTables— مرتبسازی rangeها، استفاده از dropdownهای AutoFilter، کار با PivotTableها
شما بیتهای فرد را از طریق property indexی AllowOption روی TXLSXWorksheet میخوانید و مینویسید. AllowOption[Opt] = True یعنی آن action مجاز است؛ تنظیم آن False یعنی آن را ممنوع میکند. کل مجموعه را هم میتوان یکجا از طریق SheetProtectionOptions، یک TXLSXSheetProtectionOptions (یک Pascal سادهٔ set of) هم میتوان به آن رسید، پس میتوانید آن را ذخیره کنید، برگردانید، یا یکجا جایگزینش کنید
اهمیت default و عمدی بودن آن: یک worksheet تازهساختهشده با همهٔ گزینهها مجاز شروع میکند. سازنده SheetProtectionOptions را با بازهٔ کامل seed میکند، [Low(TXLSXSheetProtectionOption)..High(TXLSXSheetProtectionOption)]. از آنجا به بعد با حذف actionهایی که میخواهید ممنوع کنید جلو میروید، نه اینکه از صفر یک permission set بسازید. همین انتخاب است که rule encoding نویسنده، پایینتر، را با رفتار Excel همراستا میکند
محافظت از یک sheet اما باز گذاشتن sort و filter
این هم حالت رایج از ابتدا تا انتها: یک report نهایی را protect کنید تا layout آن نتواند reshaped شود، اما به خواننده اجازه دهید آن را sort و filter کند. توجه کنید که Protect و options مستقلاند. Protect sheet را به حالت protected میبرد و hash اختیاری رمز را ذخیره میکند؛ به مجموعهٔ options دست نمیزند. شما AllowOption را جداگانه تنظیم میکنید، و toggleها وقتی sheet protected و saved شود اثر میگذارند
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;
دو چیز از آن snippet ارزش توجه دارد. Sort و AutoFilter خطها با وجود اینکه هر دو روی True پیشفرض هستند، صریح نوشته میشوند؛ این documentation برای maintainer بعدی است، نه یک نیاز functional. و چون defaultها permissive هستند، تنها خطهایی که فایل خروجی را تغییر میدهند همانهاییاند که یک option را به False تنظیم میکنند. این اتفاقی در این API نیست، بلکه wire format OOXML است که خودش را نشان میدهد، و همین به بخش بعدی میرسد
قانون encoding: حذف یعنی اجازه، attr=0 یعنی منع
این تنها fact خلافانتظار در کل این feature است، و جایی است که OOXML دستنویس معمولاً اشتباه میشود. در OOXML هر attribute مربوط به هر action یک <sheetProtection> است منع flag، و نبودنش یعنی permission. یک attribute که غایب است یعنی action مجاز است. یک attribute که به صورت "0" نوشته شده یعنی action وقتی sheet protected است ممنوع است. در یک فایل well-formed هیچ formatCells="1"ی برای معنی «قالببندی مجاز است» وجود ندارد؛ شما فقط attribute را حذف میکنید. (default برای یک attribute غایب، default بولی OOXML یعنی true است، و این attributeها طوری نامگذاری شدهاند که «true» یعنی edit متناظر مجاز است.)
Writer در HotXLS دقیقاً همان را mirror میکند. sheet="1" را مینویسد تا protection را روشن کند، سپس مجموعهٔ options را walk میکند و attr="0" فقط برای گزینههایی مینویسد که به False تنظیم کردهاید. actionهای مجاز هیچ چیزی به output اضافه نمیکنند. پس workbook بخش قبلی چیزی شبیه این serializes میشود، و فقط actionهای ممنوع و hash رمز را حمل میکند:
// 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.
اگر از رشتهٔ قدیمی hard-coded آمده باشید و انتظار داشته باشید هر attribute بهصراحت نوشته شود، این sparse به نظر میرسد، تقریباً غلط. اما درست است. فایلی که sort="1" و autoFilter="1" را فهرست کرده باشد برای یک reader سازگار همان معنی را میدهد، اما خود Excel حداقلنویسی forbid-only را مینویسد، و همسانسازی با آن diffها را کوچک و round-tripها را boring نگه میدارد. objects و scenarios attributeها همان rule را دنبال میکنند: آنها default-permitted هستند، پس فقط وقتی به صورت "0" ظاهر میشوند که آنها را ممنوع کنید، که برعکسِ objects="1" scenarios="1" قدیمی است که بدون شرط emit میشد
خواندن محافظت به عقب: fidelity در round-trip
یک permission model که بتوانید آن را بنویسید اما نتوانید بخوانید، یک درِ یکطرفه است، و symptom معمول load-edit-save چرخهای است که بیصدا permissions را گسترش میدهد. HotXLS این را میبندد. وقتی ParseWorksheetXml به یک <sheetProtection> element میرسد، sheet را protected میکند، hash رمز را اگر موجود باشد میگیرد، و سپس هر attribute هر action را به AllowOptionآیند، با همان convention برعکس: attributeی که present است و برابر "0" است action را ممنوع میکند؛ attribute غایب option را روی default مجازش میگذارد
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;
وقتی فایلی را که writer تولید کرده load کنید، Sort و AutoFilter را به صورت True، FormatCells را به صورت False پس میگیرید، یعنی مجموعهای که save کرده بودید intact برمیگردد. این symmetry کل هدف است: یک cell را در یک sheet protected و partially-permitted ویرایش کنید و دوباره save کنید، و آن چهارده permissionی که دست نزده بودید بهجای برگشتن به default قدیمی all-or-nothing باقی بمانند
نکات عملی و محدودیتها
قبل از اینکه این را وارد pipeline گزارش کنید، چند چیز ارزش دانستن دارند:
- رمز بهصورت عمدی ضعیف است. worksheet protection در XLSX یک legacy hash شانزدهبیتی را ذخیره میکند (همان چیزی که Excel دهههاست استفاده کرده)، و اینجا برای interoperability نگه داشته شده است. این فقط edits اتفاقی را بازمیدارد؛ در برابر یک attacker مقاومت نمیکند. آن را secret نگهدارنده فرض نکنید. برای حفاظت واقعی، workbook را encrypt کنید
- تنظیم options پیش از protect کردن کاملاً درست است.
AllowOptionرا میتوان چه sheet در حال حاضر protected باشد چه نباشد assign کرد؛ toggleها فقط توصیف میکنند که protection چه چیزهایی را وقتیProtectفعال است مجاز خواهد کرد.UnProtectstate protected و hash را پاک میکند اما مجموعهٔ options شما را برای دفعهٔ بعد سر جایش میگذارد - معنای cell قفلشده همچنان برقرار است. protection فقط editهایی را روی cellهایی block میکند که attribute
Lockedآنها set شده باشد (default workbook). editable گذاشتن یک input region کار style cell است، نه یک option محافظت؛ این دو لایه مثل Excel با هم ترکیب میشوند - این موتور XLSX است. model گزینهها با propertyهای قدیمیتر موتور XLS
Allow*را mirror میکند، اما نامهای enum و property اینجا (xlsxSpo*,AllowOption) متعلق بهTXLSXWorksheetدرlxHandleX. اگر روی همین sheetها layout چاپ را هم کنترل میکنید، walkthrough محافظت و page-setup توضیح میدهد این تنظیمها کنار print areaها و headerها چگونه مینشینند، و data validation، AutoFilter و tables طبیعی با باز گذاشتنxlsxSpoAutoFilterروی یک report قفلشده جفت میشود
مدل محافظت دقیق و بقیهٔ engine read/write XLSX در HotXLS Component برای Delphi و C++Builder ship میشوند؛ صفحهٔ محصول reference کامل worksheet API شامل مرجع کامل optionهای محافظت را دارد