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) { // перевіряємо
		echo 'рядки відрізняються!';
	}
}

Може здатися, що 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');
версію: 3.0