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