SafeStream: Безопасность для файлов
Nette\Utils\SafeStream гарантирует, что каждое чтение и запись в файл изолированы. Это означает, что ни один поток не начнет читать файл, который ещё не полностью записан, или несколько потоков не будут перезаписывать один и тот же файл.
Установка:
composer require nette/safe-stream
Для чего это полезно?
Чем на самом деле полезны изолированные операции? Начнем с простого примера, который многократно записывает в файл, а затем считывает из него одну и ту же строку:
$s = str_repeat('Long String', 10000);
$counter = 1000;
while ($counter--) {
file_put_contents('file', $s); // пишем
$readed = file_get_contents('file'); // читаем
if ($s !== $readed) { // check it
echo 'strings are different!';
}
}
Может показаться, что echo 'strings differ!'
никогда не может
возникнуть. Верно и обратное. Попробуйте запустить этот сценарий в
двух вкладках браузера одновременно. Ошибка возникнет почти сразу.
Одна из вкладок будет читать файл в то время, когда другая ещё не успела всё записать, поэтому содержимое будет неполным.
Поэтому код небезопасен, если он выполняется несколько раз в одно и то же время (т. е. в нескольких потоках). Что не редкость в интернете, часто сервер отвечает большому количеству пользователей одновременно. Поэтому очень важно обеспечить надежную работу приложения даже при выполнении в несколько потоков (thread-safe). В противном случае данные будут потеряны и возникнут труднообнаруживаемые ошибки.
Но, как вы видите, встроенные функции PHP для чтения и записи файлов не являются изолированными и атомарными.
Как использовать SafeStream?
SafeStream создает безопасный протокол для чтения и записи файлов в
изоляции с использованием стандартных функций PHP. Всё, что вам нужно
сделать, это указать nette.safe://
перед именем файла:
file_put_contents('nette.safe://file', $s);
$s = file_get_contents('nette.safe://file');
SafeStream гарантирует, что одновременно в файл может писать не более одного потока. Остальные потоки ожидают в очереди. Если ни один поток не ведет запись, любое количество потоков может читать файл параллельно.
Все обычные функции PHP могут быть использованы с протоколом, например:
// 'r' означает открыть только для чтения
$handle = fopen('nette.safe://file.txt', 'r');
$ini = parse_ini_file('nette.safe://translations.neon');