Bonjour, je voudrais mettre un verrou sur un fichier, pour que tant que le verrou n'est pas libéré, être au courant pour mettre en attente le 2ème traitement sur ce même fichier.
Je pensais que les verrous en écriture gèrent le fait de ne pas pouvoir écrire à 2 en même temps et donc, que si on met un verrou en écriture sur un fichier, on ne peut pas en mettre un deuxième tant que le premier n'est pas libéré.
j'ai fait le test ci-dessous en l'appelant 2 fois de suite à partir du même client web (car c'est mon cas d'utilisation) , mais il montre que l'on peut successivement acquérir un verrou en écriture sur un même fichier sans qu'il ne soit libéré entre 2, il semble qu'il est exécuté sur apache par le même utilisateur et que de ce fait, le script peut ré-exécuter un flock sur le fichier pour éventuellement changer le mode de verrou ou déverrouiller le fichier.

en effet voici les log retournés par l'exécution de ce script sur apache linux et PHP 5.6 :
(identique lors de 2 appels successifs )


  • ------ begin ---------
  • lock_for_writing
  • file opened
  • verrous mis
  • file_put_content: ok
  • file_put_contents_locking file opened
  • verrous relach\xc3\xa9
  • file_put_contents return = fait


et voici le code :
monTest appel une fonction file_put_contents_locking qui en retour de appel une fonction générique lock_for_writing qui lock 2 fois de suite un même fichier en écriture sans problème (voir //1 et //2) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?php
 
class maClass
{
 
    public function lock_for_writing($name, $handler)
    {
        error_log("lock_for_writing", 0);
        $filename = sys_get_temp_dir().'/'.$name.'.lock';
        $file = fopen($filename, 'w');
        if ($file === false) {
            error_log("fopen return false", 0);
            return false;
        }else{
            error_log("file opened", 0);
        }
 
        //
        $lock = flock($file, LOCK_EX);//pour acquérir un verrou exclusif (écriture)
        if (!$lock) {//il y a une erreur? (ou le fichier est locké?)
            fclose($file);
            error_log("flock erreur ou fichier locké", 0);
            return false;
        }else{
                error_log("verrous mis", 0);
        }
 
        // on arrive ici si le vérrou est mis
        $result = $handler();//on exécute la tâche a faire (passée en paramettre dans $handler) une fois le vérrou mis
 
        //une fois la tâche exécutée on libère le verrou
        //$lock2 = flock($file, LOCK_UN);//pour libérer un verrou (partagé ou exclusif).
        //if (!$lock2) {//il y a une erreur? (ou le fichier est locké?)
        //    error_log("verrous non relaché", 0);
        //}else{
        //    error_log("verrous relaché", 0);
        //}
 
        fclose($file);
        return $result;
    }
 
    //appel de la fonction générique en passant la fonction à éxécuter en paramettre
    public function file_put_contents_locking($name, $string)
    {
        return $this->lock_for_writing($name, function() use ($name, $string) {
            $filename = sys_get_temp_dir().'/'.$name.'.lock';
            error_log("file_put_content: ".$string, 0);
            //return file_put_contents($filename, $string);
 
 
            $file = fopen($filename, 'w');
            if ($file === false) {
                error_log("file_put_contents_locking fopen return false", 0);
                return "pas fait";
            }else{
                error_log("file_put_contents_locking file opened", 0);
            }
            //ftruncate($file, 0);     // effacement du contenu
            fwrite($file, $string);
            fflush($file);
            return "fait";
        });
    }
 
    public function monTest()
    {
        error_log("------ begin ---------", 0);
        $ret = $this->file_put_contents_locking("lefichier", "ok");
        error_log("file_put_contents return = ".strval($ret), 0);
    }
}
 
$mc = new maClass;
$mc->monTest();
 
?>
Merci de votre aide