Teknik Makale

Delphi'de XLSX Sayfa Koruması: 15 Allow Option

Bitmiş bir çalışma kitabını bir iş arkadaşınıza veriyor ve ondan bunu yeniden yazmasını değil filtrelemesini istiyorsunuz. Bu yüzden sayfayı korumaya alıyorsunuz. Eski HotXLS derlemelerinde bu hareket dosyaya her seferinde tek bir şey yazıyordu: <sheetProtection sheet="1" objects="1" scenarios="1"/>. Sayfa kilitleniyor, parola özeti ekleniyor ve kullanıcı hiçbir şey yapamıyordu; hatta sizin açık bırakmak istediğiniz sıralama ve filtrelemeyi bile. Excel'in kendi "Sayfayı Koru" iletişim kutusunda tam da bu nedenle on beş onay kutusu vardır ve motor bunların hiçbirini ifade edemiyordu. v2.91.0 koruma modelinin kapattığı boşluk budur

HotXLS, Excel kurulu olmadan XLS ve XLSX okuyup yazan, Delphi ve C++Builder için yerel bir VCL spreadsheet component'tir. Bu makale, çalışma sayfası korumasının XLSX tarafını ele alır: yeni TXLSXSheetProtectionOption enum'u, her izni açıp kapatan AllowOption özelliği ve <sheetProtection> öğesini elle yazan herkesi yanıltan tek OOXML kodlama kuralı

Çalışma sayfası koruması gerçekte neyi korur

Önce sınırdan başlayalım, çünkü buna ne kadar güvenmeniz gerektiğini o belirler. OOXML spreadsheet biçiminde (ECMA-376) çalışma sayfası koruması şifreleme değil, etkileşim ilkesidir. Sayfa koruma altındayken uyumlu bir uygulamaya hangi düzenlemeleri reddedeceğini söyler. Hücre değerleri hâlâ xl/worksheets/sheetN.xml içinde düz metin olarak durur; .xlsx dosyasını zip'ten çıkarırsanız hepsi oradadır. İsteğe bağlı parola, herhangi bir şeyi karıştıran bir anahtar olarak değil, kısa bir eski tip özet olarak saklanır. Dosyanın adını değiştirip parçayı açan ve <sheetProtection> satırını kaldıran herkes her şeyi okur ve düzenler

Dolayısıyla koruma, "iş arkadaşım yanlışlıkla bir formülü bozmasın" sorusuna cevap verir; "bu veriyi niyetli bir kişiden gizli tut" sorusuna değil. Bunlar farklı araçlar gerektiren iki ayrı problemdir. Gizlilik gerekiyorsa, AES korumalı XLSX çıktı bölümünde ele alınan çalışma kitabı düzeyindeki şifrelemeyi istersiniz; gerçekten paketi şifreleyen odur. Sayfa koruması ile çalışma kitabı şifrelemesi birlikte sorunsuz çalışır, ancak gerçek kilit yalnızca ikincisidir. Bu çizgiyi net tutarsanız, sayfanın geri kalanı sadece tesisat işidir

On beş seçenek ve AllowOption özelliği

Artık her çalışma sayfası, sayfa koruma altındayken kullanıcının yine de neler yapabileceğini açıklayan bir TXLSXSheetProtectionOption değerleri kümesi taşır. Üyeler OOXML özniteliklerine ve Excel iletişim kutusundaki onay kutularına bire bir karşılık gelir:

  • xlsxSpoEditObjects, xlsxSpoEditScenarios — çizim nesnelerini ve what-if senaryolarını düzenleme
  • xlsxSpoFormatCells, xlsxSpoFormatColumns, xlsxSpoFormatRows — hücreleri, sütunları ve satırları yeniden biçimlendirme
  • xlsxSpoInsertColumns, xlsxSpoInsertRows, xlsxSpoInsertHyperlinks — sütun, satır ve bağlantı ekleme
  • xlsxSpoDeleteColumns, xlsxSpoDeleteRows — sütun ve satır silme
  • xlsxSpoSelectLockedCells, xlsxSpoSelectUnlockedCells — seçimi kilitli veya kilitsiz hücrelere taşıma
  • xlsxSpoSort, xlsxSpoAutoFilter, xlsxSpoPivotTables — aralıkları sıralama, AutoFilter açılır menülerini kullanma ve PivotTable'larla çalışma

Tek tek bitleri AllowOption üzerinde bulunan dizinli TXLSXWorksheet özelliği üzerinden okuyup yazarsınız. AllowOption[Opt] = True, eylemin izinli olduğu anlamına gelir; bunu False olarak ayarlamak eylemi yasaklar. Kümenin tamamına aynı anda SheetProtectionOptions üzerinden de erişilebilir; bu, bir TXLSXSheetProtectionOptions'tür (düz bir Pascal set of), böylece bunu saklayabilir, geri yükleyebilir veya topluca değiştirebilirsiniz

Varsayılan önemlidir ve bilinçli olarak seçilmiştir: yeni oluşturulan bir çalışma sayfası, tüm seçeneklere izin verilmiş şekilde başlar. Kurucu, SheetProtectionOptions alanını tam aralıkla, yani [Low(TXLSXSheetProtectionOption)..High(TXLSXSheetProtectionOption)] ile doldurur. Sıfırdan bir izin kümesi kurmak yerine, yasaklamak istediğiniz eylemleri çıkararak daraltırsınız. Bu tercih, aşağıdaki yazıcı kodlama kuralının Excel davranışıyla hizalanmasını sağlar

Sayfayı koruyup sıralama ile filtrelemeyi açık bırakmak

Yaygın durumun uçtan uca hali şöyledir: bitmiş bir raporu, düzeni yeniden şekillendirilemesin diye koruyun ama okuyucunun sıralamasına ve filtrelemesine izin verin. Burada Protect ile seçeneklerin bağımsız olduğuna dikkat edin. Protect, sayfayı korumalı duruma geçirir ve isteğe bağlı parola özetini saklar; seçenek kümesine dokunmaz. AllowOption öğesini ayrı olarak ayarlarsınız ve sayfa korunduktan ve kaydedildikten sonra anahtarlar etkisini gösterir

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;

Bu parçacıkta okunması gereken iki nokta var. Sort ve AutoFilter satırları, her ikisinin varsayılanı da True olmasına rağmen açıkça yazılmıştır; bu işlevsel bir gereksinim değil, bir sonraki bakımcı için belgelendirmedir. Ve varsayılanlar izin verici olduğu için, çıktı dosyasını gerçekten değiştiren tek satırlar bir seçeneği False olarak ayarlayan satırlardır. Bu, API'nin rastlantısal bir sonucu değildir; OOXML kablo biçiminin yüzeye çıkmış hâlidir ve sıradaki bölüm tam olarak budur

Kodlama kuralı: omit izin verir, attr=0 yasaklar

Tüm özelliğin içindeki sezgiye ters düşen tek gerçek budur ve elle yazılmış <sheetProtection> çoğunlukla burada yanlış gider. OOXML'de eylem başına her öznitelik bir yasaklama bayrağıdır ve yokluğu izin anlamına gelir. Eksik bir öznitelik, eyleme izin verildiği anlamına gelir. "0" olarak yazılmış bir öznitelik ise, sayfa korunurken o eylemin yasak olduğu anlamına gelir. Biçimlendirmenin izinli olduğunu anlatmak için düzgün oluşturulmuş bir dosyada formatCells="1" diye bir şey yoktur; özniteliği basitçe dışarıda bırakırsınız. (Eksik özniteliğin varsayılanı OOXML boolean varsayılanı olan true'dur ve bu öznitelikler, "true" karşılık gelen düzenlemenin izinli olduğunu gösterecek şekilde adlandırılmıştır)

HotXLS yazıcısı bunu bire bir yansıtır. Korumayı açmak için sheet="1" yazar, ardından seçenek kümesini dolaşır ve yalnızca attr="0" olarak ayarladığınız seçenekler için False yazar. İzinli eylemler çıktıya hiçbir şey eklemez. Dolayısıyla önceki bölümdeki çalışma kitabı, parola özetiyle birlikte yalnızca yasaklanan eylemleri taşıyan şu tür bir şeye serileştirilir:

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

Eski sabit kodlanmış dizgeden geldiyseniz ve her özniteliğin açıkça yazıldığını görmeyi bekliyorsanız, bu seyrek, hatta neredeyse yanlış görünür. Oysa doğrudur. sort="1" ve autoFilter="1" öğelerini listeleyen bir dosya, uyumlu bir okuyucu için aynı anlama gelirdi; ama Excel'in kendisi de en küçük, yalnızca yasakları içeren biçimi yazar ve onunla eşleşmek farkları küçük, round-trip işlemlerini de sıkıcı derecede güvenilir tutar. objects ve scenarios öznitelikleri aynı kuralı izler: varsayılan olarak izinli oldukları için, bunlar yalnızca siz yasakladığınızda "0" olarak görünür; bu da eskiden koşulsuz yazılan objects="1" scenarios="1" davranışının tam tersidir

Korumayı geri okuma: round-trip doğruluğu

Yazabildiğiniz ama okuyamadığınız bir izin modeli tek yönlü kapıdır ve bunun alışılmış belirtisi, yükle-düzenle-kaydet döngüsünün sessizce izinleri genişletmesidir. HotXLS bunu kapatır. ParseWorksheetXml bir <sheetProtection> öğesiyle karşılaştığında, sayfayı korumalı olarak işaretler, varsa parola özetini alır ve ardından her eylem başına özniteliği ters yönde aynı kuralla tekrar AllowOption içine çözer: mevcut ve "0" değerine eşit bir öznitelik eylemi yasaklar; eksik öznitelik ise seçeneği izinli varsayılanında bırakır

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;

Yazıcının ürettiği dosyayı yüklerseniz, Sort ile AutoFilter değerlerini yeniden True olarak, FormatCells değerini ise False olarak alırsınız — kaydettiğiniz küme bozulmadan geri gelir. Asıl amaç bu simetridir: korumalı ama kısmen izinli bir sayfada tek bir hücreyi düzenleyip yeniden kaydedin, dokunmadığınız on dört izin eski hepsi-ya-da-hiçbiri varsayılanına çökmez, yaşamaya devam eder

Pratik notlar ve sınırlar

Bunu bir rapor hattına bağlamadan önce bilinmesi faydalı birkaç şey:

  • Parola tasarım gereği zayıftır XLSX çalışma sayfası koruması, birlikte çalışabilirlik için burada korunan 16 bitlik eski bir özet saklar (Excel'in onlarca yıldır kullandığı özetin aynısı). Yanlışlıkla yapılan düzenlemeleri caydırır; saldırgana direnmez. Bunu bir sır saklama mekanizması gibi görmeyin. Gerçek koruma için çalışma kitabını şifreleyin
  • Koruma etkinleştirilmeden önce seçenekleri ayarlamak sorun değildir AllowOption, sayfa şu anda korumalı olsun ya da olmasın atanabilir; bu anahtarlar yalnızca Protect etkin olduğunda korumanın neye izin vereceğini tanımlar. UnProtect, korumalı durumu ve özeti temizler ama seçenek kümenizi bir sonraki kullanım için yerinde bırakır
  • Kilitli hücre semantiği hâlâ geçerlidir Koruma, yalnızca Locked niteliği ayarlanmış hücrelerdeki düzenlemeleri engeller (çalışma kitabı varsayılanı budur). Bir giriş bölgesini düzenlenebilir bırakmak koruma seçeneğinin değil, hücre stilinin işidir; iki katman Excel'dekiyle aynı şekilde birleşir
  • Bu, XLSX motorudur Seçenek modeli, XLS motorunun daha eski Allow* özelliklerini yansıtır; ancak buradaki enum ve özellik adları (xlsxSpo*, AllowOption) TXLSXWorksheet birimine ve lxHandleX içeriğine aittir. Aynı sayfalarda yazdırma düzenini de yönetiyorsanız, koruma ve sayfa ayarı anlatımı bu ayarların yazdırma alanları ve üstbilgilerle nasıl yan yana durduğunu açıklar; veri doğrulama, AutoFilter ve tablolar ise kilitli bir raporda xlsxSpoAutoFilter öğesini açık bırakmakla doğal biçimde eşleşir

İnce taneli koruma modeli ve XLSX okuma/yazma motorunun geri kalanı, Delphi ve C++Builder için HotXLS Component içinde sunulur; ürün sayfası, tam koruma seçeneği başvurusu da dahil olmak üzere eksiksiz çalışma sayfası API'sini içerir