SafeStream: segurança em arquivos

Nette SafeStream garante que cada leitura e escrita em um arquivo ocorra isoladamente. Isso significa que nenhuma thread começará a ler um arquivo que ainda não foi totalmente escrito, ou múltiplas threads não sobrescreverão o mesmo arquivo.

Instalação:

composer require nette/safe-stream

Para que serve?

Para que servem as operações isoladas, afinal? Comecemos com um exemplo simples que escreve repetidamente em um arquivo e depois lê a mesma string dele:

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

$counter = 1000;
while ($counter--) {
	file_put_contents('arquivo', $s); // escreve
	$readed = file_get_contents('arquivo'); // lê
	if ($s !== $readed) { // verifica
		echo 'as strings diferem!';
	}
}

Pode parecer que a chamada echo 'as strings diferem!' nunca pode ocorrer. O oposto é verdadeiro. Tente executar este script em duas abas do navegador ao mesmo tempo. O erro ocorrerá praticamente imediatamente.

Uma das abas lerá o arquivo no momento em que a outra ainda não terminou de escrevê-lo completamente, então o conteúdo não estará completo.

O código fornecido, portanto, não é seguro se executado várias vezes ao mesmo tempo (ou seja, em múltiplas threads). O que não é nada incomum na internet, muitas vezes um servidor responde a um grande número de usuários ao mesmo tempo. Portanto, garantir que sua aplicação funcione de forma confiável mesmo quando executada em múltiplas threads (thread-safe) é muito importante. Caso contrário, ocorrerá perda de dados e surgirão erros difíceis de detectar.

Mas, como você pode ver, as funções nativas do PHP para leitura e escrita de arquivos não são isoladas e atômicas.

Como usar SafeStream?

SafeStream cria um protocolo seguro através do qual arquivos podem ser lidos e escritos isoladamente usando funções PHP padrão. Basta prefixar nette.safe:// antes do nome do arquivo:

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

SafeStream garante que no máximo uma thread possa escrever no arquivo por vez. Outras threads esperam na fila. Se nenhuma thread estiver escrevendo, qualquer número de threads pode ler o arquivo em paralelo.

Todas as funções PHP comuns podem ser usadas com o protocolo, por exemplo:

// 'r' significa abrir apenas para leitura
$handle = fopen('nette.safe://file.txt', 'r');

$ini = parse_ini_file('nette.safe://translations.neon');
versão: 3.0