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');