I remembered that I had made a related mistake before. The scene at that time was this: There was a WeChat public account project, and the interface to call the WeChat public account required access_token
, and its validity period is 2 hours. What I did at that time was to store it in a file, and the format was json
. {"access_token":"easWasdw32323", "expire":1588219064}
. The pseudo code is as follows:
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']; }
Problems that occur:
There will be problems after the project runs for a period of time, but it will be normal after refreshing after a second or two.
Analysis of the cause of the problem:
Assume that the token has expired. At this time, two requests come, named A and B respectively. When A comes, he finds that after the token expires, he calls the WeChat interface to obtain a new token. After obtaining it, he updates it to the file storing the token.
However, when the file was not completely updated, B came and read in the file storing the token. Because the data in the token file is not updated completely, the data read by B will cause errors.
In addition, it is possible that A and B are updating the file content at the same time, which will cause data confusion and lead to errors.
How to avoid this error?
The file locking mechanism can be completed.
The flock() function is provided in PHP, which can use the locking mechanism (lock or release the file) on the file. When a process locks a file when accessing it, other processes must wait until the lock is released if they want to access the file. This avoids data corruption during concurrent access to the same file.
The function prototype is as follows:
flock ( resource $handle , int $operation [, int &$wouldblock ] ) : bool
handle
:
The file system pointer is a resource typically created by fopen().
## Operation
<?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);
<?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']; }
The above is the detailed content of Problems and solutions caused by PHP file lock (a real case). For more information, please follow other related articles on the PHP Chinese website!