PHP ファイルロックによって引き起こされる問題と解決策 (実際のケース)

齐天大圣
リリース: 2023-04-08 15:44:02
オリジナル
1898 人が閲覧しました

実際のケース

私は以前に関連する間違いを犯したことを思い出しました。その時の状況は次のとおりです。WeChat パブリック アカウント プロジェクトがあり、WeChat パブリック アカウントを呼び出すためのインターフェイスには access_token が必要で、その有効期間は 2 時間でした。そのとき私がやったのはファイルに保存することで、形式は json でした。 {"access_token":"easWasdw32323", "expire":1588219064}。疑似コードは次のとおりです。

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;];
}
ログイン後にコピー

発生する問題:

プロジェクトを一定期間実行すると問題が発生しますが、その後は正常になります。 1 ~ 2 秒後にリフレッシュされます。

問題の原因の分析:

トークンの有効期限が切れたと仮定すると、この時点で、それぞれ A と B という名前の 2 つのリクエストが来ます。 A が来ると、トークンの有効期限が切れた後、WeChat インターフェイスを呼び出して新しいトークンを取得し、取得後、トークンを保存するファイルを更新します。

しかし、ファイルが完全に更新されていないときに、B がトークンを格納したファイルを読みに来ました。トークン ファイル内のデータが完全に更新されていないため、B によって読み取られたデータはエラーを引き起こします。

さらに、A と B がファイルの内容を同時に更新している可能性があり、データの混乱が生じ、エラーが発生する可能性があります。

このエラーを回避するにはどうすればよいですか?

ファイルのロック機構を完成させることができます。

PHP では flock() 関数が提供されており、ファイルのロック メカニズム (ファイルのロックまたは解放) を使用できます。プロセスがファイルにアクセスするときにファイルをロックすると、他のプロセスがそのファイルにアクセスする場合は、ロックが解除されるまで待つ必要があります。これにより、同じファイルへの同時アクセス時のデータ破損が回避されます。

関数のプロトタイプは次のとおりです:

flock ( resource $handle , int $operation [, int &$wouldblock ] ) : bool

  • handle:

    ファイル システム ポインターは、通常は fopen() によって作成されるリソースです。

  • ## 操作

## これは、次の値のいずれかになります:

(プログラムの読み取り)。

LOCK_EX 排他ロック(書き込まれたプログラム)を取得します。 '’ 's’ '' '' – ‐ ‐ ‐ ‐ - を使用して、ロックを解放します(共有または排他的かどうか)。

LOCK_NB 追加のロック (Windows はサポートされていません)。

    wouldblock
  • ロックがブロックされる場合 (EWOULDBLOCK エラー コード)、オプションの 3 番目のパラメータが設定されます「TRUE」にします。 (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);
ログイン後にコピー

demo1.php を最初に実行してから、demo2.php を実行します。このファイルは、demo1.php によってロックされているため、demo2.php は新しいコンテンツを書き込むことができません。demo1.php がロックを解放した後でのみ、demo2.php が排他ロックを取得してファイルを書き込むことができます。

問題の解決

この知識を学べば、以前の問題を解決できるようになります。改善されたコードは次のとおりです:

<?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;];
}
ログイン後にコピー

以上がPHP ファイルロックによって引き起こされる問題と解決策 (実際のケース)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート