flock()
La fonction flock() en PHP permet de mettre en place un mécanisme simple de verrouillage de fichiers pour éviter les conflits d'accès concurrent.
Qu'est-ce que la fonction flock() ?
La fonction flock() effectue un verrouillage de fichier en PHP. Un verrou permet à un processus d'indiquer aux autres : « Je travaille avec ce fichier — attendez votre tour. » Sans cela, deux scripts s'exécutant simultanément peuvent entrelacer leurs écritures et corrompre un fichier. C'est une condition de course classique, et flock() est l'outil le plus simple que PHP vous offre pour la prévenir.
Cette page couvre ce que fait la fonction, ses types de verrous, un exemple complet et fonctionnel que vous pouvez exécuter, les pièges courants, et sa place parmi les autres fonctions PHP de gestion de fichiers.
Une note sur le verrouillage « consultatif »
Sur les systèmes de type Unix, flock() est consultatif : le verrou n'est respecté que par les processus qui appellent également flock() sur le même fichier. Un programme qui ignore le verrouillage peut toujours lire ou écraser le fichier librement. Le verrouillage ne vous protège donc que si tous les scripts qui accèdent au fichier coopèrent. Sous Windows, le verrouillage est obligatoire (appliqué par le système d'exploitation), ce qui entraîne un comportement légèrement différent selon les plateformes — ne vous fiez pas à un verrouillage obligatoire dans du code portable.
Syntaxe
flock($stream, $operation, &$would_block = null): bool| Paramètre | Description |
|---|---|
$stream | Un pointeur de fichier retourné par fopen(). |
$operation | L'une des constantes de verrou ci-dessous, éventuellement combinée avec LOCK_NB via un OU bit à bit. |
$would_block | Facultatif. Défini à 1 si le verrou aurait bloqué (seulement pertinent avec LOCK_NB). Passé par référence. |
La fonction retourne true en cas de succès ou false en cas d'échec.
Types de verrous
| Constante | Signification |
|---|---|
LOCK_SH | Verrou partagé (lecteur). Plusieurs processus peuvent détenir un verrou partagé simultanément, mais aucun ne peut en détenir un exclusif pendant ce temps. À utiliser lors des lectures. |
LOCK_EX | Verrou exclusif (écrivain). Un seul processus peut le détenir ; tous les autres — lecteurs et écrivains — attendent. À utiliser lors des écritures. |
LOCK_UN | Libère le verrou actuellement détenu sur le flux. |
LOCK_NB | Modificateur non bloquant. Combinez-le avec LOCK_SH ou LOCK_EX (ex. `LOCK_EX |
Par défaut, flock() bloque : si un autre processus détient un verrou exclusif, votre appel attend que le verrou soit libéré. Ajoutez LOCK_NB si vous préférez échouer rapidement.
Comment utiliser la fonction flock()
Le schéma est toujours le même en quatre étapes :
- Ouvrir le fichier avec
fopen()en utilisant un mode adapté à ce que vous ferez ('r+','c','a', …). - Acquérir le verrou avec
flock($file, LOCK_EX)(ouLOCK_SHpour lire). - Lire ou écrire dans le fichier.
- Libérer avec
flock($file, LOCK_UN)et fermer avecfclose().
Un exemple complet et exécutable
Ce script ouvre un fichier compteur, le verrouille exclusivement, incrémente le nombre stocké et le réécrit — le type de lecture-modification-écriture qui doit être verrouillé pour être sûr en cas d'accès concurrent :
<?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);En l'exécutant trois fois, on obtient Counter is now: 1, puis 2, puis 3. Parce que la séquence lecture-incrémentation-écriture se déroule sous LOCK_EX, deux processus ne peuvent jamais lire la même valeur et écrire tous les deux 2.
Échouer rapidement avec un verrou non bloquant
Quand vous ne souhaitez pas attendre — par exemple une tâche cron qui devrait passer son tour si une précédente est encore en cours — combinez LOCK_EX avec 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);Pièges courants
- Les verrous sont attachés au descripteur de fichier ouvert, pas au chemin. Appeler
fopen()deux fois sur le même fichier donne deux descripteurs indépendants, et un verrou sur l'un ne bloque pas l'autre dans le même processus. - Utilisez
'c'/'c+', et non'w', lors du verrouillage. Le mode'w'tronque le fichier à l'instant où vous l'ouvrez — avant d'acquérir le verrou — ce qui annule l'intérêt du verrouillage. Tronquez explicitement avecftruncate()après avoir obtenu le verrou. flock()ne fonctionne pas de manière fiable sur NFS ou certains systèmes de fichiers réseau ou FAT. Pour la coordination entre plusieurs serveurs, utilisez un vrai service de verrouillage (un verrou de ligne de base de données, Redis, etc.) à la place.fclose()libère tout verrou restant, mais déverrouillez explicitement avecLOCK_UNpour que le fichier soit à nouveau disponible dès que vous avez terminé.
Conclusion
flock() est l'outil intégré de PHP pour coordonner l'accès concurrent à un fichier. Utilisez LOCK_EX autour des écritures, LOCK_SH autour des lectures, et LOCK_NB quand vous préférez échouer plutôt qu'attendre. N'oubliez pas que le verrouillage sous Unix est consultatif — il ne vous protège que si tous les scripts qui accèdent au fichier y participent. Pour un travail de fichier de plus haut niveau, consultez fwrite(), fread() et file_put_contents().