W3docs

flock()

La función flock() de PHP permite implementar un mecanismo sencillo de bloqueo de archivos para evitar condiciones de carrera entre procesos.

¿Qué es la función flock()?

La función flock() realiza el bloqueo de archivos en PHP. Un bloqueo permite que un proceso le indique a los demás: "Estoy trabajando con este archivo — espera tu turno". Sin él, dos scripts que se ejecuten al mismo tiempo pueden entrelazar sus escrituras y corromper un archivo. Esto es una clásica condición de carrera, y flock() es la herramienta más sencilla que PHP ofrece para prevenirla.

Esta página explica qué hace la función, sus tipos de bloqueo, un ejemplo completo y funcional que puedes ejecutar, los errores comunes que suelen cometerse, y dónde encaja entre las demás funciones de archivo de PHP.

Una nota sobre el bloqueo "consultivo"

En sistemas tipo Unix, flock() es consultivo (advisory): el bloqueo solo se respeta entre procesos que también llaman a flock() sobre el mismo archivo. Un programa que ignora el bloqueo puede seguir leyendo o sobreescribiendo el archivo libremente. Por tanto, el bloqueo solo te protege si todos los scripts que acceden al archivo cooperan. En Windows, el bloqueo es obligatorio (lo impone el sistema operativo), por lo que el comportamiento difiere ligeramente entre plataformas — no confíes en el cumplimiento obligatorio en código portable.

Sintaxis

flock($stream, $operation, &$would_block = null): bool
ParámetroDescripción
$streamUn puntero de archivo devuelto por fopen().
$operationUna de las constantes de bloqueo que se muestran a continuación, opcionalmente combinada con LOCK_NB mediante OR.
$would_blockOpcional. Se establece en 1 si el bloqueo habría quedado a la espera (solo tiene sentido con LOCK_NB). Se pasa por referencia.

La función devuelve true en caso de éxito o false en caso de error.

Tipos de bloqueo

ConstanteSignificado
LOCK_SHBloqueo compartido (lectura). Varios procesos pueden mantener un bloqueo compartido al mismo tiempo, pero ninguno puede tener uno exclusivo mientras tanto. Úsalo al leer.
LOCK_EXBloqueo exclusivo (escritura). Solo un proceso puede mantenerlo; todos los demás — lectores y escritores — esperan. Úsalo al escribir.
LOCK_UNLibera el bloqueo que se tiene actualmente sobre el stream.
LOCK_NBModificador no bloqueante. Combínalo con LOCK_SH o LOCK_EX (p. ej., `LOCK_EX

Por defecto, flock() bloquea: si otro proceso tiene un bloqueo exclusivo, tu llamada espera hasta que el bloqueo quede libre. Añade LOCK_NB cuando prefieras fallar rápido.

Cómo usar la función flock()

El patrón siempre consta de los mismos cuatro pasos:

  1. Abre el archivo con fopen() usando un modo adecuado para lo que vayas a hacer ('r+', 'c', 'a', …).
  2. Adquiere el bloqueo con flock($file, LOCK_EX) (o LOCK_SH para leer).
  3. Lee o escribe el archivo.
  4. Libera con flock($file, LOCK_UN) y cierra con fclose().

Un ejemplo completo y ejecutable

Este script abre un archivo de contador, lo bloquea en modo exclusivo, incrementa el número almacenado y lo vuelve a escribir — el tipo de lectura-modificación-escritura que debe estar bloqueado para ser seguro bajo concurrencia:

<?php

$filename = 'counter.txt';

// 'c' opens for read/write, creating the file if missing,
// and does NOT truncate it (unlike 'w').
$file = fopen($filename, 'c+');

if ($file === false) {
    exit("Could not open file.\n");
}

if (flock($file, LOCK_EX)) {        // block until we hold the lock
    $current = (int) stream_get_contents($file);
    $current++;

    rewind($file);                  // back to the start
    ftruncate($file, 0);            // clear old contents
    fwrite($file, (string) $current);
    fflush($file);                  // push to disk before unlocking

    flock($file, LOCK_UN);          // release the lock
    echo "Counter is now: $current\n";
} else {
    echo "Could not acquire lock.\n";
}

fclose($file);

Si se ejecuta tres veces, imprime Counter is now: 1, luego 2, luego 3. Dado que la lectura-incremento-escritura ocurre bajo LOCK_EX, dos procesos nunca pueden leer el mismo valor y ambos escribir 2.

Fallar rápido con un bloqueo no bloqueante

Cuando no quieres esperar — por ejemplo, un cron job que debería saltarse la ejecución si el anterior aún está en marcha — combina LOCK_EX con LOCK_NB:

<?php

$file = fopen('job.lock', 'c');

if (flock($file, LOCK_EX | LOCK_NB)) {
    echo "Got the lock, doing work...\n";
    // ... long-running task ...
    flock($file, LOCK_UN);
} else {
    echo "Another instance is already running. Exiting.\n";
}

fclose($file);

Errores comunes

  • Los bloqueos se asocian al identificador de archivo abierto, no a la ruta. Llamar a fopen() dos veces sobre el mismo archivo da lugar a dos identificadores independientes, y un bloqueo en uno no bloquea al otro dentro del mismo proceso.
  • Usa 'c'/'c+', no 'w', al bloquear. El modo 'w' trunca el archivo en el momento en que lo abres — antes de adquirir el bloqueo —, lo que anula el propósito. Trunca explícitamente con ftruncate() después de obtener el bloqueo.
  • flock() no funciona de forma fiable sobre NFS ni sobre algunos sistemas de archivos en red o FAT. Para la coordinación entre servidores, usa un servicio de bloqueo real (un bloqueo de fila en base de datos, Redis, etc.).
  • fclose() libera cualquier bloqueo pendiente, pero libera explícitamente con LOCK_UN para que el archivo vuelva a estar disponible tan pronto como hayas terminado.

Conclusión

flock() es la herramienta integrada de PHP para coordinar el acceso concurrente a un archivo. Usa LOCK_EX alrededor de las escrituras, LOCK_SH alrededor de las lecturas, y LOCK_NB cuando prefieras fallar antes que esperar. Recuerda que el bloqueo en Unix es consultivo — solo te protege cuando todos los scripts que acceden al archivo participan. Para trabajar con archivos a un nivel más alto, consulta fwrite(), fread() y file_put_contents().

Práctica

Práctica
¿Cuál es la función de flock() en PHP?
¿Cuál es la función de flock() en PHP?
Was this page helpful?