PHP (31) - Zamykání souborů

Zamykání souborů je k dispozici od PHP 3.0.7.

Chceme-li zapisovat data do souborů na jakékoli síti, nejen na internetu, musíme zvážit možnost, že několik uživatelů by mohlo chtít provádět zápis do téhož souboru současně. To by mohlo poškodit soubor nebo mít za následek ztrátu dat jednoho či více uživatelů. Z tohoto důvodu je nutné soubor zamknout tak, aby nebyl po dobu provádění zápisu přístupný ostatním uživatelům pro zápis. Toto je jen drobná komplikace, ale velké množství skriptů na internetu soubory nezamyká. Jestliže však chcete své soubory chránit před poškozením, musíte je zamknout.

Na rozdíl od obyčejných textových souborů MySQL databáze nevyžaduje zamykání, protože má zamykání automatické. To je jedna z výhod MySQL.

Jsou v principu 2 typy zamykání:

  1. sdílený zámek pro čtení souborů, který povolí přístup ke stejnému souboru několika uživatelům současně 
  2. výhradní zámek pro psaní souborů, který současný přístup ke stejnému souboru několika uživatelům nepovolí

Soubor se po otevření zamkne příkazem flock() a potom se zase uvolní před zavřením. Tento příklad otevře soubor "registrace.cgi", zamkne, načte data do řetězce $data, uvolní zámek a zavře soubor:

$soubor = 'registrace.cgi';
$klika = fopen( $soubor, 'r' );
if ($klika == false) {
    exit ('Nelze otevřít registrační soubor.');
}
$zamek = flock ($klika, LOCK_SH);
if ($zamek == false) {
    exit ('Nelze zamknout registrační soubor. Zkuste znovu.');
}

$data = fread($klika, filesize($soubor));
flock ($klika, LOCK_UN);
fclose($klika);

Druhý parametr funkce flock() může mít 3 hodnoty:

  1. LOCK_SH (resp. 1 u verzí do PHP 4.0.1) k získání sdíleného zámku (čtení)
  2. LOCK_EX (resp. 2 u verzí do PHP 4.0.1) k získání výhradního zámku (zápis)
  3. LOCK_UN (resp. 3 u verzí do PHP 4.0.1) k uvolnění zámku (sdíleného nebo výhradního)

Není zapotřebí uvolnit zámky souborů, které zůstaly náhodně zamknuty po předčasném ukončení programu. Je dobrý nápad co nejdříve v průběhu programu zámky uvolnit.

Tento způsob zamykání souborů je dostatečný při malém množství uživatelů. Program jednoduše zastaví, když najde zamknutý soubor a uživatel musí jít zpět a pokusit se o otevření a zamknutí souboru znovu. Elegantnějším řešením je vytvoření smyčky, která automaticky provede několik pokusů. Ve většině případů však stačí shora uvedené jednoduché zamykání.

Další komplikace mohou vzniknout, když si uživatel nejprve prohlíží data na monitoru a až potom provádí nějaké změny. V tomto případě by bylo potřeba zamknout soubor hned na začátku, aby měl uživatel na monitoru aktuální verzi souboru, která se nezmění po dobu prohlížení. Toto ovšem nelze prakticky zajistit, protože jeden uživatel by mohl nechat soubor uzamknutý delší dobu. Lepším řešením je tedy soubor nejprve zamknout sdíleným zámkem. Než ale začneme zapisovat data do souboru, musíme jej uvolnit a zavřít. Teprve potom jej můžeme otevřít pro zápis, zamknout s výhradním zámkem a zjistit, zda se soubor zatím nezměnil. Když se soubor nezměnil, můžeme pak zapsat data do souboru, uvolnit a zavřít.

Jestli se rozhodnete zamykat soubor, je nutné zamykat pro všechny přístupy, jinak by se mohlo stát, že skripty bez flocku nebudou mít k souboru přístup a uživatel nebude vědět proč.