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âmetro | Descrição |
|---|---|
$stream | Um ponteiro de arquivo retornado por fopen(). |
$operation | Uma das constantes de bloqueio abaixo, opcionalmente combinada com LOCK_NB usando OR. |
$would_block | Opcional. 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
| Constante | Significado |
|---|---|
LOCK_SH | Bloqueio compartilhado (leitor). Muitos processos podem manter um bloqueio compartilhado ao mesmo tempo, mas nenhum pode manter um exclusivo enquanto isso. Use ao ler. |
LOCK_EX | Bloqueio exclusivo (escritor). Apenas um processo pode mantê-lo; todos os outros — leitores e escritores — aguardam. Use ao escrever. |
LOCK_UN | Libera o bloqueio atualmente mantido no stream. |
LOCK_NB | Modificador 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:
- Abra o arquivo com
fopen()usando um modo adequado ao que você fará ('r+','c','a', …). - Adquira o bloqueio com
flock($file, LOCK_EX)(ouLOCK_SHpara leitura). - Leia ou escreva no arquivo.
- Libere com
flock($file, LOCK_UN)e feche comfclose().
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 comftruncate()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 comLOCK_UNpara 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().