Tehnički članak

Zaštita XLSX lista u Delphiju: 15 dozvoljenih opcija

Predajte gotovu radnu svesku kolegi i tražite da je filtrira, ne da je prepisuje. Zato štitite list. U starijim HotXLS verzijama taj potez je upisivao jednu stvar u datoteku: <sheetProtection sheet="1" objects="1" scenarios="1"/>, hard-kodirano, svaki put. List bi se zaključao, hash lozinke bi bio prikačen i korisnik ne bi mogao ništa, čak ni sortiranje i filtriranje koje ste zapravo želeli da ostavite otvorenim. Excelov dijalog "Protect Sheet" ima petnaest kućica za potvrdu upravo zbog toga, a engine nije umeo da izrazi nijednu od njih. Tu rupu zatvara model zaštite u v2.91.0

HotXLS je nativna VCL spreadsheet komponenta za Delphi i C++Builder koja čita i piše XLS i XLSX bez instaliranog Excela. Ovaj članak govori o XLSX strani zaštite radnog lista: novi TXLSXSheetProtectionOption enum, a AllowOption svojstvo koje uključuje svaku dozvolu, i jedno OOXML pravilo kodiranja koje sapliće svakoga ko ručno piše <sheetProtection><sheetProtection>

element by hand

Šta zapravo štiti zaštita radnog listaxl/worksheets/sheetN.xmlPrvo granica, jer ona određuje koliko bilo šta od ovoga treba da vam uliva poverenje. Zaštita radnog lista u OOXML spreadsheet formatu (ECMA-376) je politika interakcije, ne enkripcija. Ona govori usklađenoj aplikaciji koje izmene treba da odbije dok je list zaštićen. Vrednosti ćelija i dalje stoje u .xlsxxl/worksheets/sheetN.xml<sheetProtection> u običnom tekstu; raspakujte

.xlsx i videćete ih tamo. Opciona lozinka se čuva kao kratki legacy hash, ne kao ključ koji nešto šifrira. Svako ko preimenuje datoteku, otvori deo i ukloni <sheetProtection>

liniju čita i menja sve

Dakle, zaštita odgovara na pitanje "spreči kolegu da slučajno pregazi formulu", a ne "sačuvaj ove podatke od nekoga ko je motivisan". To su različiti problemi i traže različite alate. Ako vam treba poverljivost, želite enkripciju na nivou radne sveske pokrivenu u TXLSXSheetProtectionOptionAES-protected XLSX output

  • xlsxSpoEditObjects, koja zaista šifrira paket. Zaštita lista i enkripcija radne sveske lepo rade zajedno, ali samo je druga prava brava. Držite tu liniju jasnom i ostatak ove stranice je samo instalacijaxlsxSpoEditScenariosPetnaest opcija i svojstvo AllowOption
  • xlsxSpoFormatCellsSvaki radni list sada nosi skup xlsxSpoFormatColumns vrednosti koje opisuju šta korisnik još sme da radi dok je list zaštićen. Članovi se mapiraju jedan-na-jedan na OOXML atribute i na Excel dijalog kućice za potvrdu:xlsxSpoFormatRows,
  • xlsxSpoInsertColumns - uređivanje crtačkih objekata i what-if scenarijaxlsxSpoInsertRows, xlsxSpoInsertHyperlinks,
  • xlsxSpoDeleteColumns - formatiranje ćelija, kolona, redovaxlsxSpoDeleteRows,
  • xlsxSpoSelectLockedCells, xlsxSpoSelectUnlockedCells - umetanje kolona, redova, linkova
  • xlsxSpoSort, xlsxSpoAutoFilter - brisanje kolona, redovaxlsxSpoPivotTables,

, AllowOption - pomeranje selekcije na zaključane ili otključane ćelijeTXLSXWorksheet, AllowOption[Opt] = True znači da je radnja dozvoljena; postavljanje na False je zabranjuje. Čitav skup je takođe dostupan odjednom kroz SheetProtectionOptions, kao TXLSXSheetProtectionOptions (običan Pascal set of skup), pa ga možete sačuvati, vratiti ili potpuno zameniti

Podrazumevano stanje je važno i namerno: tek napravljeni radni list počinje sa svakom opcijom dozvoljenom. Konstruktor popunjava SheetProtectionOptions sa punim opsegom, [Low(TXLSXSheetProtectionOption)..High(TXLSXSheetProtectionOption)]. Odatle suzbijate samo one radnje koje želite da zabranite, umesto da pravite skup dozvola od nule. Taj izbor je ono što čini da writerovo pravilo kodiranja, ispod, odgovara Excelovom ponašanju

Štiti list, ali ostavlja sortiranje i filter otvorenim

Evo uobičajenog slučaja od početka do kraja: zaštitite gotov izveštaj tako da raspored ne može da se preoblikuje, ali pustite čitaoca da ga sortira i filtrira. Primetite da Protect i opcije su nezavisni. Protect prebacuje list u zaštićeno stanje i čuva opcioni hash lozinke; ne dira skup opcija. AllowOption zasebno, a prekidači stupaju na snagu tek kada je list zaštićen i sačuvan

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;

Dve stvari treba pročitati iz tog primera. Sort i AutoFilter linije se pišu eksplicitno iako su obe podrazumevano True; to je dokumentacija za sledećeg održavaoca, a ne funkcionalni zahtev. A pošto su podrazumevane vrednosti dozvoljavajuće, jedine linije koje menjaju izlaznu datoteku su one koje opciju postavljaju na False. To nije slučajnost ovog API-ja, to je OOXML žičani format koji se vidi kroz njega, i to vodi u sledeći odeljak

Pravilo kodiranja: izostavljeno znači dozvoljeno, attr=0 znači zabranjeno

Ovo je jedina kontraintuitivna činjenica u celoj mogućnosti, i tu ručno <sheetProtection> često krene po zlu. U OOXML-u svaki atribut po radnji je jedna zabrane zastavica, a njen izostanak znači dozvolu. Atribut koji nedostaje znači da je radnja dozvoljena. Atribut upisan kao "0" znači da je radnja zabranjena dok je list zaštićen. Ne postoji formatCells="1" u ispravnoj datoteci da znači "formatiranje je dozvoljeno"; atribut jednostavno izostavite. (Podrazumevana vrednost za izostavljen atribut je OOXML boolean podrazumevano true, a ovi atributi su nazvani tako da "true" znači da je odgovarajuće uređivanje dozvoljeno.)

HotXLS writer to preslikava potpuno isto. On upisuje sheet="1" da uključi zaštitu, a zatim prolazi kroz skup opcija i upisuje attr="0" samo za opcije koje ste postavili na False. Dozvoljene radnje ne doprinose izlazu. Dakle, radna sveska iz prethodnog odeljka serijalizuje se otprilike ovako, noseći samo zabranjene radnje plus hash lozinke:

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

Ako ste došli iz starog hard-kodiranog stringa i očekivali da vidite svaki atribut eksplicitno naveden, ovo izgleda oskudno, gotovo pogrešno. A ipak je ispravno. Datoteka koja bi navela sort="1" i autoFilter="1" značila bi isto usklađenom čitaču, ali Excel sam piše minimalni oblik samo sa zabranama, i praćenje toga čini difove malim, a povratne prolaze dosadnim. objects i scenarios atributi prate isto pravilo: oni su podrazumevano dozvoljeni, pa se pojavljuju kao "0" kada ih zabranite, što je obrnuto od starog objects="1" scenarios="1" koji je bio upisivan bezuslovno

Ponovno čitanje zaštite: round-trip vernost

Model dozvola koji možete da upišete, ali ne i da pročitate, jednosmerna je ulica, a uobičajeni simptom je ciklus učitaj-izmeni-sačuvaj koji tiho proširuje dozvole. HotXLS to zatvara. Kada ParseWorksheetXml naiđe na <sheetProtection> element, on postavlja list kao zaštićen, hvata hash lozinke ako postoji, a zatim dekodira svaki atribut po radnji nazad u AllowOption koristeći istu konvenciju unazad: atribut prisutan i jednak "0" zabranjuje radnju; odsutan atribut ostavlja opciju na njenom dozvoljenom podrazumevanom stanju

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;

Učitajte datoteku koju je writer proizveo i dobićete Sort i AutoFilter nazad kao True, FormatCells kao False - skup koji ste sačuvali, netaknut. Ta simetrija je cela poenta: izmenite jednu ćeliju u zaštićenom, delimično dozvoljenom listu i sačuvajte ponovo, a četrnaest dozvola koje niste dirali prežive umesto da se sruše nazad na stari sve-ili-ništa podrazumevani model

Praktične napomene i granice

Nekoliko stvari koje vredi znati pre nego što ovo povežete u pipeline za izveštaje:

  • Lozinka je po dizajnu slaba. zaštita XLSX radnog lista čuva 16-bitni legacy hash (isti onaj koji Excel koristi decenijama), ovde zadržan zbog interoperabilnosti. On odvraća od slučajnih izmena; ne odoleva napadaču. Ne tretirajte ga kao čuvara tajni. Za stvarnu zaštitu, šifrujte radnu svesku
  • Postavljanje opcija pre zaštite je u redu. AllowOption može da se dodeli bilo da je list trenutno zaštićen ili nije; prekidači samo opisuju šta će zaštita dozvoliti kada Protect bude na snazi. UnProtect briše zaštićeno stanje i hash, ali ostavlja skup opcija na mestu za sledeći put
  • Semantika zaključanih ćelija i dalje važi. Zaštita samo blokira izmene ćelija čiji je Locked atribut postavljen (podrazumevano u radnoj svesci). Ostavljanje ulaznog regiona uredljivim posao je stila ćelije, ne opcije zaštite; dva sloja se kombinuju isto kao u Excelu
  • Ovo je XLSX engine. Model opcija preslikava starija svojstva XLS engine-a Allow*, ali ovde imenovanja enuma i svojstva (xlsxSpo*, AllowOption) pripadaju TXLSXWorksheet u lxHandleX. Ako na istim listovima upravljate i rasporedom štampe, vodič kroz zaštitu i podešavanje stranice objašnjava kako ova podešavanja stoje uz oblasti štampe i zaglavlja, a validacija podataka, AutoFilter i tabele prirodno se uklapaju sa ostavljanjem xlsxSpoAutoFilter otvorenim na zaključanom izveštaju

Finozrni model zaštite i ostatak XLSX read/write engine-a dolaze u HotXLS Component za Delphi i C++Builder; stranica proizvoda nosi potpuni API radnog lista, uključujući kompletnu referencu opcija zaštite