Nette SafeStream
Nette SafeStream garantiza que cada operación de lectura y escritura de archivos ocurre de forma aislada. Eso significa que ningún hilo empezará a leer un archivo que todavía no se ha terminado de escribir, ni varios hilos sobrescribirán el mismo archivo.
Instalación:
composer require nette/safe-stream
¿Para qué sirve?
¿Para qué sirven realmente las operaciones aisladas? Empecemos con un ejemplo sencillo que escribe repetidamente en un archivo y después lee de él la misma cadena:
$s = str_repeat('Long String', 10000);
$counter = 1000;
while ($counter--) {
file_put_contents('file', $s); // la escribe
$readed = file_get_contents('file'); // la lee
if ($s !== $readed) { // la comprueba
echo '¡las cadenas son distintas!';
}
}
Podría parecer que la llamada echo '¡las cadenas son distintas!' no puede ocurrir nunca. Es justo al revés.
Pruebe a ejecutar este script en dos pestañas del navegador a la vez. El error se producirá casi de inmediato.
Una de las pestañas leerá el archivo en un momento en el que la otra no ha terminado de escribirlo del todo, así que el contenido estará incompleto.
Por tanto, el código no es seguro si se ejecuta varias veces de forma concurrente (es decir, en varios hilos). Eso no es raro en internet, ya que los servidores suelen responder a un gran número de usuarios a la vez. Asegurarse de que su aplicación funciona de forma fiable también cuando se ejecuta en varios hilos (thread-safe) es fundamental. En caso contrario pueden producirse pérdidas de datos y errores difíciles de detectar.
Pero, como ve, las funciones nativas de PHP para leer y escribir archivos no son aisladas ni atómicas.
¿Cómo se usa SafeStream?
SafeStream crea un protocolo seguro con el que se pueden leer y escribir archivos de forma aislada usando las funciones
estándar de PHP. Solo tiene que anteponer al nombre del archivo el prefijo nette.safe://:
file_put_contents('nette.safe://file', $s);
$s = file_get_contents('nette.safe://file');
SafeStream asegura que como mucho un hilo puede escribir en el archivo a la vez. Los demás hilos esperan en una cola. Si ningún hilo está escribiendo, cualquier número de hilos puede leer el archivo en paralelo.
Con el protocolo se pueden usar todas las funciones habituales de PHP, por ejemplo:
// 'r' significa abrir solo para lectura
$handle = fopen('nette.safe://file.txt', 'r');
$ini = parse_ini_file('nette.safe://config.ini');
Limitaciones
SafeStream aísla la lectura y la escritura del contenido de los archivos, pero no puede hacer atómicas todas las operaciones. Tenga presentes estos límites:
- La información sobre los archivos no está aislada. Las funciones que solo consultan metadatos, como
file_exists(),filesize()ois_file(), no participan en el bloqueo. Pueden devolver información sobre un archivo que otro hilo está escribiendo en ese momento. - Borrar un archivo abierto en Windows. A diferencia de Unix, Windows no le deja borrar un archivo que otro hilo tiene
abierto en ese momento, así que
unlink('nette.safe://file')puede fallar. - Reversión automática de las escrituras incompletas. Si una escritura falla a mitad (por ejemplo, porque se llena el disco), al cerrar el archivo SafeStream lo trunca al tamaño que tenía antes de empezar a escribir, así que nunca deja tras de sí datos escritos a medias.
Si está actualizando a una versión más reciente, vea la página de actualización.