Artikel Teknis

Proteksi Sheet XLSX di Delphi: 15 Opsi Izin

Anda menyerahkan workbook yang sudah selesai kepada rekan kerja dan meminta mereka memfilternya, bukan menuliskannya ulang. Jadi Anda melindungi sheet. Pada build HotXLS yang lebih lama, tindakan itu hanya menulis satu hal ke file: <sheetProtection sheet="1" objects="1" scenarios="1"/>, selalu hard-coded. Sheet terkunci, hash password terpasang, dan pengguna tidak bisa melakukan apa pun, bahkan sort dan filter yang sebenarnya ingin Anda biarkan tetap terbuka. Dialog "Protect Sheet" milik Excel punya lima belas kotak centang justru karena alasan ini, dan engine sebelumnya tidak bisa merepresentasikan satupun dari semuanya. Kesenjangan itulah yang ditutup oleh model proteksi v2.91.0

HotXLS adalah komponen spreadsheet VCL native untuk Delphi dan C++Builder yang membaca dan menulis XLS dan XLSX tanpa Excel terpasang. Artikel ini membahas sisi XLSX dari proteksi worksheet: enum baru TXLSXSheetProtectionOption, properti AllowOption yang menyalakan dan mematikan setiap izin, dan satu aturan encoding OOXML yang sering menjatuhkan siapa pun yang menulis elemen <sheetProtection> secara manual

Apa yang Sebenarnya Dilindungi Worksheet Protection

Pertama, batasnya, karena dari situ terlihat seberapa jauh Anda boleh mempercayai semua ini. Proteksi worksheet dalam format spreadsheet OOXML (ECMA-376) adalah kebijakan interaksi, bukan enkripsi. Fungsinya memberi tahu aplikasi yang patuh pada spesifikasi edit mana yang harus ditolak saat sheet dilindungi. Nilai sel tetap berada di xl/worksheets/sheetN.xml sebagai teks biasa; unzip file .xlsx, dan isinya ada di sana. Password opsional disimpan sebagai hash lawas pendek, bukan kunci yang mengenkripsi apa pun. Siapa pun yang mengganti nama file, membuka bagian itu, lalu menghapus baris <sheetProtection> bisa membaca dan mengubah semuanya

Jadi proteksi menjawab "cegah rekan kerja saya tanpa sengaja merusak rumus", bukan "jaga data ini tetap rahasia dari orang yang memang berniat membukanya". Itu dua masalah yang berbeda dengan alat yang berbeda. Jika Anda butuh kerahasiaan, Anda memerlukan enkripsi di level workbook seperti yang dibahas di output XLSX terlindungi AES, yang benar-benar mengenkripsi paket. Proteksi sheet dan enkripsi workbook bisa dipakai bersama tanpa masalah, tetapi hanya yang kedua yang benar-benar menjadi kunci. Pegang garis itu dengan jelas, dan sisanya di halaman ini hanya soal plumbing

Kelima Belas Opsi dan Properti AllowOption

Setiap worksheet sekarang membawa sekumpulan nilai TXLSXSheetProtectionOption yang menjelaskan apa yang masih boleh dilakukan pengguna saat sheet dilindungi. Anggotanya memetakan satu banding satu ke atribut OOXML dan ke kotak centang di dialog Excel:

  • xlsxSpoEditObjects, xlsxSpoEditScenarios: mengedit objek gambar dan skenario what-if
  • xlsxSpoFormatCells, xlsxSpoFormatColumns, xlsxSpoFormatRows: memformat ulang sel, kolom, dan baris
  • xlsxSpoInsertColumns, xlsxSpoInsertRows, xlsxSpoInsertHyperlinks: menyisipkan kolom, baris, dan tautan
  • xlsxSpoDeleteColumns, xlsxSpoDeleteRows: menghapus kolom dan baris
  • xlsxSpoSelectLockedCells, xlsxSpoSelectUnlockedCells: memindahkan seleksi ke sel yang terkunci atau tidak terkunci
  • xlsxSpoSort, xlsxSpoAutoFilter, xlsxSpoPivotTables: mengurutkan rentang, memakai dropdown AutoFilter, dan bekerja dengan PivotTable

Anda membaca dan menulis bit individual melalui properti terindeks AllowOption pada TXLSXWorksheet. AllowOption[Opt] = True berarti aksi diizinkan; mengaturnya ke False melarangnya. Seluruh set juga bisa diakses sekaligus lewat SheetProtectionOptions, sebuah TXLSXSheetProtectionOptions (set Pascal biasa), sehingga Anda bisa menyimpannya, memulihkannya, atau menggantinya sekaligus

Default-nya penting dan itu disengaja: worksheet yang baru dibuat memulai dengan semua opsi diizinkan. Konstruktor mengisi SheetProtectionOptions dengan rentang penuh, [Low(TXLSXSheetProtectionOption)..High(TXLSXSheetProtectionOption)]. Dari sana Anda mempersempitnya dengan mengecualikan aksi yang ingin dilarang, bukan membangun set izin dari nol. Pilihan itu membuat aturan encoding writer di bawah selaras dengan perilaku Excel

Melindungi Sheet tetapi Membiarkan Sort dan Filter Tetap Terbuka

Berikut kasus yang paling umum dari awal sampai akhir: lindungi laporan yang sudah selesai agar tata letaknya tidak bisa diubah, tetapi biarkan pembaca melakukan sort dan filter. Perhatikan bahwa Protect dan opsi-opsinya saling independen. Protect mengubah sheet menjadi status terlindungi dan menyimpan hash password opsional; fitur ini tidak menyentuh set opsi. Anda mengatur AllowOption secara terpisah, dan toggle itu berlaku setelah sheet dilindungi dan disimpan

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;

Ada dua hal yang perlu dibaca dari cuplikan itu. Baris Sort dan AutoFilter ditulis secara eksplisit meskipun keduanya default-nya True; itu dokumentasi untuk maintainer berikutnya, bukan kebutuhan fungsional. Dan karena default-nya permisif, satu-satunya baris yang mengubah file output adalah yang mengatur opsi ke False. Itu bukan kebetulan API ini, melainkan bentuk wire format OOXML yang terlihat jelas, dan itulah yang dibahas pada bagian berikut

Aturan Encoding: Omit Berarti Allow, attr=0 Berarti Larang

Ini adalah fakta paling tidak intuitif di seluruh fitur ini, dan di sinilah <sheetProtection> yang ditulis manual sering salah. Dalam OOXML, setiap atribut per aksi adalah flag larangan, dan ketidakhadirannya berarti izin. Atribut yang tidak ada berarti aksi itu diizinkan. Atribut yang ditulis sebagai "0" berarti aksi itu dilarang selama sheet dilindungi. Tidak ada formatCells="1" di file yang benar untuk berarti "formatting diizinkan"; Anda cukup tidak menuliskan atribut itu. (Default untuk atribut yang tidak ada adalah default boolean OOXML bernilai true, dan atribut-atribut ini dinamai sehingga "true" berarti edit terkait diizinkan)

Writer HotXLS menirunya persis. Writer menuliskan sheet="1" untuk menyalakan proteksi, lalu menelusuri set opsi dan menulis attr="0" hanya untuk opsi yang Anda set ke False. Aksi yang diizinkan tidak menyumbang apa pun ke output. Jadi workbook dari bagian sebelumnya akan terserialisasi kira-kira seperti ini, hanya membawa aksi yang dilarang plus hash password:

// 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.

Jika Anda datang dari string lama yang hard-coded dan mengira akan melihat setiap atribut dituliskan semua, tampilan ini memang terasa ringkas, bahkan hampir salah. Padahal benar. File yang mencantumkan sort="1" dan autoFilter="1" akan bermakna sama bagi pembaca yang patuh spesifikasi, tetapi Excel sendiri menulis bentuk minimal yang hanya berisi larangan, dan menirunya menjaga diff tetap kecil serta round-trip tetap tenang. Atribut objects dan scenarios mengikuti aturan yang sama: default-nya diizinkan, jadi keduanya hanya muncul sebagai "0" saat Anda melarangnya, kebalikan dari objects="1" scenarios="1" lama yang selalu ditulis tanpa syarat

Membaca Kembali Proteksi: Fidelity Round-Trip

Model izin yang bisa Anda tulis tetapi tidak bisa dibaca balik adalah jalan satu arah, dan gejala umumnya adalah siklus load-edit-save yang diam-diam memperluas izin. HotXLS menutup celah itu. Saat ParseWorksheetXml menemukan elemen <sheetProtection>, ia menandai sheet sebagai terlindungi, menangkap hash password jika ada, lalu mendekode setiap atribut per aksi kembali ke AllowOption dengan konvensi yang sama dalam arah sebaliknya: atribut yang ada dan bernilai "0" melarang aksi; atribut yang tidak ada membiarkan opsi tetap pada default yang diizinkan

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;

Load file yang dihasilkan writer dan Anda mendapatkan Sort serta AutoFilter kembali sebagai True, FormatCells sebagai False - set yang Anda simpan, utuh. Simetri itu inti semuanya: ubah satu sel di sheet yang dilindungi namun hanya sebagian diizinkan lalu simpan ulang, dan empat belas izin yang tidak Anda sentuh tetap bertahan alih-alih jatuh kembali ke default lama yang serba boleh atau serba tidak boleh

Catatan Praktis dan Batasannya

Beberapa hal yang layak diketahui sebelum Anda memasukkannya ke pipeline laporan:

  • Password memang lemah sejak desainnya. Proteksi worksheet XLSX menyimpan hash legacy 16-bit, sama seperti yang dipakai Excel selama puluhan tahun, demi kompatibilitas. Fungsinya mencegah edit tidak sengaja; bukan untuk menahan penyerang. Jangan memperlakukannya sebagai penjaga rahasia. Untuk proteksi yang nyata, enkripsi workbook
  • Mengatur opsi sebelum melindungi tidak masalah. AllowOption dapat diisi baik sheet sedang dilindungi maupun tidak; toggle itu hanya menjelaskan apa yang akan diizinkan proteksi ketika Protect aktif. UnProtect membersihkan status terlindungi dan hash, tetapi membiarkan set opsi Anda tetap ada untuk lain waktu
  • Semantik locked cell tetap berlaku. Proteksi hanya memblokir edit pada sel yang atribut Locked-nya diatur (default workbook). Membiarkan area input tetap bisa diedit adalah tugas style sel, bukan opsi proteksi; kedua lapisan ini bekerja sama seperti di Excel
  • Ini engine XLSX. Model opsi ini mengikuti properti Allow* yang lebih lama di engine XLS, tetapi nama enum dan properti di sini (xlsxSpo*, AllowOption) milik TXLSXWorksheet di lxHandleX. Jika Anda juga mengatur tata letak cetak pada sheet yang sama, panduan proteksi dan page setup menjelaskan bagaimana setelan ini berdampingan dengan area cetak dan header, dan validasi data, AutoFilter, dan tabel cocok secara alami dengan membiarkan xlsxSpoAutoFilter tetap terbuka pada laporan yang terkunci

Model proteksi yang lebih granular dan seluruh engine baca/tulis XLSX lainnya hadir di HotXLS Component untuk Delphi dan C++Builder; halaman produk memuat API worksheet lengkap termasuk referensi lengkap opsi proteksi