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