SafeStream: безпечна робота з файлами

Nette SafeStream гарантує, що кожне читання та запис до файлу відбудеться ізольовано. Це означає, що жоден потік не почне читати файл, який ще не повністю записаний, або кілька потоків не будуть перезаписувати той самий файл.

Встановлення:

composer require nette/safe-stream

Для чого це потрібно?

Для чого власне потрібні ізольовані операції? Почнемо з простого прикладу, який повторно записує до файлу та потім читає з нього той самий рядок:

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

$counter = 1000;
while ($counter--) {
	file_put_contents('soubor', $s); // запис
	$readed = file_get_contents('soubor'); // читання
	if ($s !== $readed) { // перевірка
		echo 'рядки відрізняються!';
	}
}

Може здатися, що виклик echo 'рядки відрізняються!' ніколи не може статися. Насправді все навпаки. Спробуйте запустити цей скрипт у двох вкладках браузера одночасно. Помилка з'явиться практично миттєво.

Одна з вкладок прочитає файл у момент, коли друга ще не встигла його повністю записати, тому вміст буде неповним.

Отже, наведений код не є безпечним, якщо він виконується одночасно кілька разів (тобто в кількох потоках). Що в Інтернеті не є чимось незвичайним, часто сервер одночасно відповідає великій кількості користувачів. Тому забезпечення надійної роботи вашої програми навіть при виконанні в кількох потоках (thread-safe) є дуже важливим. Інакше відбудеться втрата даних та виникнення важко виявлених помилок.

Але, як бачите, нативні функції PHP для читання та запису файлів не є ізольованими та атомарними.

Як використовувати SafeStream?

SafeStream створює безпечний протокол, за допомогою якого можна ізольовано читати та записувати файли через стандартні функції PHP. Достатньо лише вказати nette.safe:// перед назвою файлу:

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

SafeStream забезпечує, що одночасно до файлу може записувати максимум один потік. Інші потоки чекають у черзі. Якщо жоден потік не записує, файл може читати паралельно будь-яка кількість потоків.

З протоколом можна використовувати всі звичайні функції PHP, наприклад:

// 'r' означає відкрити лише для читання
$handle = fopen('nette.safe://file.txt', 'r');

$ini = parse_ini_file('nette.safe://translations.neon');
версія: 3.0