Maison > Article > développement back-end > Problèmes et solutions causés par le verrouillage de fichiers PHP (un cas réel)
Je me suis souvenu que j'avais déjà commis une erreur connexe. La scène à cette époque était la suivante : il y avait un projet de compte public WeChat, et l'interface pour appeler le compte public WeChat était requise access_token
, et sa durée de validité est de 2 heures. Ce que j'ai fait à cette époque, c'était de le stocker dans un fichier, en utilisant le format json
. {"access_token":"easWasdw32323", "expire":1588219064}
. Le pseudocode est le suivant :
function getToken ($tokenFile) { $tokenJson = file_get_contents($tokenFile); if (!$tokenJson) { $token = loadToken($tokenFile); } else if (json_decode($tokenJson, true)['expire'] <= time()){ $token = loadToken($tokenFile); } else { $token = json_decode($tokenJson, true)['access_token']; } return $token; } function loadToken ($tokenFile) { $fp = fopen($tokenFile, 'r+'); $tokenJson = ...; // 调用微信接口获取到token fwrite($fp, json_encode($tokenJson)); return $tokenJson['access_token']; }
Problèmes :
Des problèmes surviendront après l'exécution du projet pendant un certain temps, mais ce sera normal après une actualisation après une seconde ou deux .
Analyse de la cause du problème :
Supposons que le token ait expiré A ce moment, deux requêtes arrivent, nommées respectivement A et B. Lorsque A arrive, il constate qu'après l'expiration du jeton, il appelle l'interface WeChat pour obtenir un nouveau jeton. Après l'avoir obtenu, il le met à jour dans le fichier stockant le jeton.
Cependant, lorsque le fichier n'a pas été complètement mis à jour, B est venu lire le fichier stockant le jeton. Étant donné que les données du fichier de jetons ne sont pas complètement mises à jour, les données lues par B provoqueront des erreurs.
De plus, il est possible que A et B mettent à jour le contenu du fichier en même temps, ce qui entraînerait une confusion des données et entraînerait des erreurs.
Comment éviter cette erreur ?
Le mécanisme de verrouillage des fichiers peut être complété.
La fonction flock() est fournie en PHP, qui permet d'utiliser le mécanisme de verrouillage (verrouiller ou libérer le fichier) sur le fichier. Lorsqu'un processus verrouille un fichier lors de son accès, les autres processus doivent attendre que le verrou soit libéré s'ils souhaitent accéder au fichier. Cela évite la corruption des données lors de l'accès simultané au même fichier.
Le prototype de la fonction est le suivant :
flock ( resource $handle , int $operation [, int &$wouldblock ] ) : bool
handle
:
Le pointeur du système de fichiers est généralement utilisé par la ressource fopen () créée.
opération
opération peut être l'une des valeurs suivantes :
LOCK_SH acquiert le verrou partagé (programme de lecture).
Si le verrou est bloqué (code d'erreur EWOULDBLOCK), le troisième paramètre facultatif qui sera défini est TRUE. (Non pris en charge sous Windows) wouldblock
<?php $file = 'data.txt'; $handler = fopen($file, 'a+') or die('文件资源打开失败'); // 取得独占锁 if (flock($handler, LOCK_EX)) { sleep(5); flock($handler, LOCK_UN); } else { echo '锁定失败'; } fclose($handler);demo2.php
<?php $file = 'data.txt'; $handler = fopen($file, 'a+') or die('文件资源打开失败'); // 取得独占锁 if (flock($handler, LOCK_EX)) { fwrite($handler, 'sometest string'); flock($handler, LOCK_UN); } else { echo '锁定失败'; } fclose($handler);
<?php function getToken ($tokenFile){ $tokenJson = file_get_contents($tokenFile); if (!$tokenJson) { $token = loadToken($tokenFile); } else if (json_decode($tokenJson, true)['expire'] <= time()){ $token = loadToken($tokenFile); } else { $token = json_decode($tokenJson, true)['access_token']; } return $token; } function loadToken ($tokenFile) { $fp = fopen($tokenFile, 'w'); // 取得独占锁 if (flock($fp, LOCK_EX)) { $tokenJson = ...; // 调用微信接口获取到token fwrite($fp, json_encode($tokenJson)); flock($fp, LOCK_UN); } else { return false; } return $tokenJson['access_token']; }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!