Nette Documentation Preview

syntax
SafeStream: bezpečně na soubory
*******************************

.[perex]
Nette\Utils\SafeStream garantuje, že každé čtení a zápis do souboru proběhne izolovaně. To znamená, že žádné vlákno nezačne číst soubor, který ještě není celý zapsán, nebo více vláken nebude přepisovat tentýž soubor.


Instalace
---------

Knihovnu stáhnete a nainstalujete pomocí nástroje [Composer|/best-practices/composer]:

```shell
composer require nette/safe-stream
```


K čemu je to dobré?
-------------------

K čemu jsou izolované operace vlastně dobré? Začněme jednoduchým příkladem, který opakovaně zapisuje do souboru a následně z něj čte tentýž řetězec:

```php
$s = str_repeat('Long String', 10000);

$counter = 1000;
while ($counter--) {
	file_put_contents('soubor', $s); // write it
	$readed = file_get_contents('soubor'); // read it
	if ($s !== $readed) { // check it
		echo 'řetězce se liší!';
	}
}
```

Může se zdát, že volání `echo 'řetězce se liší!'` nikdy nemůže nastat. Opak je pravdou. Schválně si zkuste tento skript spustit ve dvou tabech prohlížeče zároveň. Chyba se dostaví prakticky okamžitě.

Jedna ze záložek totiž přečte soubor ve chvíli, kde jej druhá ještě nestihla celý zapsat, takže obsah nebude kompletní.

Uvedený kód tedy není bezpečný, pokud se v jednu chvíli provádí vícekrát (tedy ve více vláknech). Což na internetu není nic neobvyklého, často v jednu chvíli odpovídá server velkému počtu uživatelů. Takže zajistit, aby vaše aplikace fungovala spolehlivě i při provádění ve více vláknech (thread-safe), je velmi důležité. Jinak dojde ke ztrátě dat a vzniku těžko odhalitelných chyb.

Jak ale vidíte, nativní PHP funkce pro čtení a zápis souborů izolované a atomické nejsou.


Jak používat SafeStream?
------------------------

SafeStream vytváří bezpečný protokol, pomocí něhož lze izolovaně číst a zapisovat soubory prostřednictvím standardních PHP funkcí. Stačí jen uvést `nette.safe://` před jménem souboru:

```php
file_put_contents('nette.safe://soubor', $s);
$s = file_get_contents('nette.safe://soubor');
```

SafeStream zajišťuje, že v jednu chvíli může do souboru zapisovat maximálně jedno vlákno. Ostatní vlákna čekají ve frontě. Pokud žádné vlákno nezapisuje, může soubor číst paralelně libovolný počet vláken.

S protokolem lze používat všechny běžné PHP funkce, například:

```php
// 'r' znamená otevřít pouze pro čtení
$handle = fopen('nette.safe://file.txt', 'r');

$ini = parse_ini_file('nette.safe://translations.neon');
```

{{composer: nette/safe-stream}}
{{leftbar: utils/@left-menu}}

SafeStream: bezpečně na soubory

Nette\Utils\SafeStream garantuje, že každé čtení a zápis do souboru proběhne izolovaně. To znamená, že žádné vlákno nezačne číst soubor, který ještě není celý zapsán, nebo více vláken nebude přepisovat tentýž soubor.

Instalace

Knihovnu stáhnete a nainstalujete pomocí nástroje Composer:

composer require nette/safe-stream

K čemu je to dobré?

K čemu jsou izolované operace vlastně dobré? Začněme jednoduchým příkladem, který opakovaně zapisuje do souboru a následně z něj čte tentýž řetězec:

$s = str_repeat('Long String', 10000);

$counter = 1000;
while ($counter--) {
	file_put_contents('soubor', $s); // write it
	$readed = file_get_contents('soubor'); // read it
	if ($s !== $readed) { // check it
		echo 'řetězce se liší!';
	}
}

Může se zdát, že volání echo 'řetězce se liší!' nikdy nemůže nastat. Opak je pravdou. Schválně si zkuste tento skript spustit ve dvou tabech prohlížeče zároveň. Chyba se dostaví prakticky okamžitě.

Jedna ze záložek totiž přečte soubor ve chvíli, kde jej druhá ještě nestihla celý zapsat, takže obsah nebude kompletní.

Uvedený kód tedy není bezpečný, pokud se v jednu chvíli provádí vícekrát (tedy ve více vláknech). Což na internetu není nic neobvyklého, často v jednu chvíli odpovídá server velkému počtu uživatelů. Takže zajistit, aby vaše aplikace fungovala spolehlivě i při provádění ve více vláknech (thread-safe), je velmi důležité. Jinak dojde ke ztrátě dat a vzniku těžko odhalitelných chyb.

Jak ale vidíte, nativní PHP funkce pro čtení a zápis souborů izolované a atomické nejsou.

Jak používat SafeStream?

SafeStream vytváří bezpečný protokol, pomocí něhož lze izolovaně číst a zapisovat soubory prostřednictvím standardních PHP funkcí. Stačí jen uvést nette.safe:// před jménem souboru:

file_put_contents('nette.safe://soubor', $s);
$s = file_get_contents('nette.safe://soubor');

SafeStream zajišťuje, že v jednu chvíli může do souboru zapisovat maximálně jedno vlákno. Ostatní vlákna čekají ve frontě. Pokud žádné vlákno nezapisuje, může soubor číst paralelně libovolný počet vláken.

S protokolem lze používat všechny běžné PHP funkce, například:

// 'r' znamená otevřít pouze pro čtení
$handle = fopen('nette.safe://file.txt', 'r');

$ini = parse_ini_file('nette.safe://translations.neon');