W3docs

flock()

A função flock() é uma função nativa do PHP que permite realizar um mecanismo simples de bloqueio de arquivos para evitar condições de corrida.

O que é a Função flock()?

A função flock() realiza bloqueio de arquivo em PHP. Um bloqueio permite que um processo avise outros: "Estou trabalhando com este arquivo — aguarde a sua vez." Sem ele, dois scripts executando ao mesmo tempo podem intercalar suas escritas e corromper um arquivo. Isso é uma clássica condição de corrida, e flock() é a ferramenta mais simples que o PHP oferece para evitá-la.

Esta página aborda o que a função faz, seus tipos de bloqueio, um exemplo completo e funcional que você pode executar, as armadilhas que costumam pegar as pessoas de surpresa, e onde ela se encaixa entre as outras funções de arquivo do PHP.

Uma observação sobre bloqueio "consultivo"

Em sistemas Unix, flock() é consultivo: o bloqueio só é respeitado por processos que também chamam flock() no mesmo arquivo. Um programa que ignora o bloqueio ainda pode ler ou sobrescrever o arquivo livremente. Portanto, o bloqueio só protege você se todos os scripts que acessam o arquivo cooperarem. No Windows, o bloqueio é obrigatório (imposto pelo sistema operacional), então o comportamento difere ligeiramente entre plataformas — não confie no bloqueio obrigatório em código portável.

Sintaxe

flock($stream, $operation, &$would_block = null): bool
ParâmetroDescrição
$streamUm ponteiro de arquivo retornado por fopen().
$operationUma das constantes de bloqueio abaixo, opcionalmente combinada com LOCK_NB usando OR.
$would_blockOpcional. Definido como 1 se o bloqueio teria ficado aguardando (só significativo com LOCK_NB). Passado por referência.

A função retorna true em caso de sucesso ou false em caso de falha.

Tipos de bloqueio

ConstanteSignificado
LOCK_SHBloqueio compartilhado (leitor). Muitos processos podem manter um bloqueio compartilhado ao mesmo tempo, mas nenhum pode manter um exclusivo enquanto isso. Use ao ler.
LOCK_EXBloqueio exclusivo (escritor). Apenas um processo pode mantê-lo; todos os outros — leitores e escritores — aguardam. Use ao escrever.
LOCK_UNLibera o bloqueio atualmente mantido no stream.
LOCK_NBModificador não bloqueante. Combine com LOCK_SH ou LOCK_EX (ex.: `LOCK_EX

Por padrão, flock() bloqueia: se outro processo mantém um bloqueio exclusivo, sua chamada fica esperando até que o bloqueio seja liberado. Adicione LOCK_NB quando preferir falhar rapidamente.

Como Usar a Função flock()

O padrão é sempre o mesmo em quatro etapas:

  1. Abra o arquivo com fopen() usando um modo adequado ao que você fará ('r+', 'c', 'a', …).
  2. Adquira o bloqueio com flock($file, LOCK_EX) (ou LOCK_SH para leitura).
  3. Leia ou escreva no arquivo.
  4. Libere com flock($file, LOCK_UN) e feche com fclose().

Um exemplo completo e executável

Este script abre um arquivo contador, bloqueia-o exclusivamente, incrementa o número armazenado e o escreve de volta — o tipo de leitura-modificação-escrita que deve ser bloqueado para ser seguro sob concorrência:

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

Executando-o três vezes, imprime Counter is now: 1, depois 2, depois 3. Como a leitura-incremento-escrita acontece sob LOCK_EX, dois processos nunca podem ler o mesmo valor e ambos escreverem 2.

Falhando rapidamente com um bloqueio não bloqueante

Quando você não quer aguardar — por exemplo, um job cron que deve ser ignorado se um anterior ainda estiver em execução — combine LOCK_EX com 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);

Armadilhas comuns

  • Os bloqueios estão associados ao handle de arquivo aberto, não ao caminho. Chamar fopen() duas vezes no mesmo arquivo fornece dois handles independentes, e um bloqueio em um não bloqueia o outro no mesmo processo.
  • Use 'c'/'c+', não 'w', ao bloquear. O modo 'w' trunca o arquivo no instante em que você o abre — antes de adquirir o bloqueio — prejudicando o propósito. Trunque explicitamente com ftruncate() após obter o bloqueio.
  • flock() não funciona de forma confiável sobre NFS ou alguns sistemas de arquivos em rede/FAT. Para coordenação entre múltiplos servidores, use um serviço de bloqueio real (um bloqueio de linha de banco de dados, Redis, etc.).
  • fclose() libera qualquer bloqueio remanescente, mas libere explicitamente com LOCK_UN para que o arquivo fique disponível novamente assim que terminar.

Conclusão

flock() é a ferramenta nativa do PHP para coordenar o acesso concorrente a um arquivo. Use LOCK_EX ao escrever, LOCK_SH ao ler e LOCK_NB quando preferir falhar a aguardar. Lembre-se de que o bloqueio no Unix é consultivo — ele só protege você quando todos os scripts que acessam o arquivo participam. Para trabalho de arquivo em nível superior, consulte fwrite(), fread() e file_put_contents().

Prática

Prática
Qual é a função de flock() em PHP?
Qual é a função de flock() em PHP?
Was this page helpful?