Home  >  Article  >  Backend Development  >  Problems and solutions caused by PHP file lock (a real case)

Problems and solutions caused by PHP file lock (a real case)

齐天大圣
齐天大圣Original
2020-05-03 09:37:291823browse

A real case

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)[&#39;expire&#39;] <= time()){
        $token = loadToken($tokenFile);
    } else {
        $token = json_decode($tokenJson, true)[&#39;access_token&#39;];
    }
    
    return $token;
}
function loadToken ($tokenFile) 
{
    $fp = fopen($tokenFile, &#39;r+&#39;);
    
    $tokenJson = ...; // 调用微信接口获取到token
    fwrite($fp, json_encode($tokenJson));
    
    return $tokenJson[&#39;access_token&#39;];
}

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

## This can be one of the following values:

(read program).

LOCK_EX Get the exclusive lock (written program).                                                                                                                                                        use using ’                   ’ ’ s ’ ’ s ’ ’ ‐ ‐ ‐ ‐ ‐ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ to release the lock (whether shared or exclusive).

LOCK_NB additional lock (Windows is not supported).

    wouldblock
  • If the lock will block (EWOULDBLOCK error code), the optional third The parameter will be set to TRUE. (Not supported on Windows)
demo

demo1.php

<?php
 
$file = &#39;data.txt&#39;;
$handler = fopen($file, &#39;a+&#39;) or die(&#39;文件资源打开失败&#39;);
// 取得独占锁
if (flock($handler, LOCK_EX)) {
    sleep(5);
    flock($handler, LOCK_UN);
} else {
    echo &#39;锁定失败&#39;;
}
 
fclose($handler);

demo2.php

<?php
$file = &#39;data.txt&#39;;
$handler = fopen($file, &#39;a+&#39;) or die(&#39;文件资源打开失败&#39;);
 
// 取得独占锁
if (flock($handler, LOCK_EX)) {
    fwrite($handler, &#39;sometest string&#39;);
    flock($handler, LOCK_UN);
} else {
    echo &#39;锁定失败&#39;;
}
 
fclose($handler);

Run demo1.php first and then run demo2.php immediately , you will find that because the file is locked by demo1.php, demo2.php cannot write new content. Only after demo1.php releases the lock can demo2.php get the exclusive lock and then write the file.

SOLVING PROBLEMS

After learning this knowledge, I will be able to solve my previous problems. The improved code is as follows:

<?php
function getToken ($tokenFile){
    $tokenJson = file_get_contents($tokenFile);
    
    if (!$tokenJson) {
            $token = loadToken($tokenFile);    
    } else if (json_decode($tokenJson, true)[&#39;expire&#39;] <= time()){ 
           $token = loadToken($tokenFile);
    } else {
            $token = json_decode($tokenJson, true)[&#39;access_token&#39;];    
    }
    return $token;
}

function loadToken ($tokenFile) {
    $fp = fopen($tokenFile, &#39;w&#39;);    // 取得独占锁    
    if (flock($fp, LOCK_EX)) {
        $tokenJson = ...; // 调用微信接口获取到token     
        fwrite($fp, json_encode($tokenJson)); 
        flock($fp, LOCK_UN);    
    } else {
        return false;    
    }
    
    return $tokenJson[&#39;access_token&#39;];
}

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn