Blog / Article #16
Verrouiller un fichier avec PHP

star

19 Decembre 2012

Verrouiller un fichier avec php

Verrouiller un fichier avec PHP

 On peut avoir besoin de verrouiller des fichiers dans le cas ou on aurait besoin d'écrire à l'intérieur assez souvent, comme pour un petit script de comptage de visiteurs ou un truc comme ça, ou plusieurs instances serveur pourraient être amenées à faire ce boulot d'ouverture écriture à un moment unique, ce qui planterait le script en question. Une fonction native nommée flock()  existe mais elle n'est pas toujours prise en charge sur les anciennes versions de PHP4 par exemple.

La seule solution du monde

Il existe une solution de contournement qui ressemble beaucoup à un bricolage de foire mais qui peut rendre service quand on doit mettre en place un système de lecture/écriture de fichiers dans un environnement serveur d'un autre age. Je ne critique pas, des fois, on a pas le choix pour X ou Y raisons... (Donc la en l’occurrence je n'ai pas le choix ! ok ?)  :)

Verrouiller

Il s'agit de créer simplement un fichier temporaire en mode x, à coté du fichier à éditer. Le mode x indique à la fonction fopen  de créer le fichier si il n'existe pas, ou sinon de retourner une erreur. Cela signifie que le processus va être en mesure de créer ce fichier et qu'il va servir de blocage jusqu’à ce qu'il soit supprimé. Le code ci dessous met en œuvre la fonction de verrouillage. Elle va créer un fichier temporaire lock.txt avec n'importe quel contenu. Le fichier indique que le verrouillage du fichier visite.txt (par exemple) est enclenché.

function lock(){
    if($lock = @fopen('lock.txt', 'x')){
        fwrite($lock, "ce qu'on veut");
        fclose($lock);
        return true;
    }
    else
        return false;    
}

Deverrouiller

La fonction suivante va simplement désenclencher le verrouillage en supprimant le fichier lock.txt. Elle peut être utilisé aussi pour forcer l'annulation du blocage, tout est permis a ce niveau la, soyons fou ! :)

function unlock(){
    unlink('lock.txt');
}

Juste pour illustrer nous pouvons utiliser le mécanisme de verrouillage suivant. Supposons qu'il existe donc un script de comptage de visites ou un truc dans le genre, exécuté à chaque requêtes sur une page. La valeur de comptage est lue, incrémentée puis réécrite dans le fichier donc cette opération, même si elle est assez rapide, doit être exécutée en bloquant le fichier de manière exclusive pour ne pas qu'une autre instance puisse lire la valeur avant qu'elle soit réécrite. Tout d'abord le script est en attente d’acquérir un verrou (via lock.txt), lorsque le fichier est dispo, il incrémente le compteur et déverrouille les potentielles demandes en attente.

while(!lock())
    sleep(1);

$nb = file_get_contents('visites.txt');
file_put_contents('visites.txt', intval($nb)+1);
unlock();

Une idée d'amélioration

Bon ensuite, on est pas obligé de faire les bourrins avec un sleep(1) quand même c'est pour l'exemple hein ? On pourrait imaginer la création (dans un dossier dédié) d'un fichier qui prendrait le numéro de processus courant retourné par la fonction getmypid()  par exemple (pour pas en trouver deux pareil...) au cas ou le lock.txt serait existant. Un simple scan de ce dossier permettrais alors de voir combien d'instances se sont cassées le nez sur le verrouillage. Il suffirait donc avant de finaliser le unlock de boucler sur le résultat du scan et d'incrémenter la valeur de visite.txt, en supprimant chaque fichiers correspondant, tant qu'il y en a dans le dossier, mais a moins d'avoir un site très beaucoup fréquenté, ce problème ne devrait pas se poser, et un usleep(70)  devrait faire l'affaire tant que le lock() ne renvoie pas true...

Des solutions il y en a 150 alors bon celle ci vaut ce qu'elle vaut... :D


Merci pour le +1

Auteur de l'article
Retour a la liste