Heim >Backend-Entwicklung >PHP-Tutorial >Probleme und Lösungen, die durch die PHP-Dateisperre verursacht werden (ein realer Fall)

Probleme und Lösungen, die durch die PHP-Dateisperre verursacht werden (ein realer Fall)

齐天大圣
齐天大圣Original
2020-05-03 09:37:291940Durchsuche

Ein echter Fall

Mir fiel ein, dass ich schon einmal einen ähnlichen Fehler gemacht hatte. Die Szene zu dieser Zeit war folgende: Es gab ein Projekt für ein öffentliches WeChat-Konto, und die Schnittstelle zum Aufrufen des öffentlichen WeChat-Kontos war erforderlich access_token und ihre Gültigkeitsdauer beträgt 2 Stunden. Was ich damals gemacht habe, war, es in einer Datei im Format json zu speichern. {"access_token":"easWasdw32323", "expire":1588219064}. Der Pseudocode lautet wie folgt:

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;];
}

Probleme:

Das Projekt wird nach einiger Zeit Probleme haben, aber nach einer Aktualisierung nach einer Sekunde oder einer Weile wird es normal sein zwei.

Analyse der Ursache des Problems:

Angenommen, das Token ist abgelaufen. Zu diesem Zeitpunkt kommen zwei Anfragen mit den Namen A und B. Als A kommt, stellt er fest, dass er nach Ablauf des Tokens die WeChat-Schnittstelle aufruft, um ein neues Token zu erhalten. Nachdem er es erhalten hat, aktualisiert er es in der Datei, in der das Token gespeichert ist.

Als die Datei jedoch nicht vollständig aktualisiert wurde, kam B und las die Datei, in der das Token gespeichert war. Da die Daten in der Token-Datei nicht vollständig aktualisiert werden, führen die von B gelesenen Daten zu Fehlern.

Darüber hinaus ist es möglich, dass A und B den Dateiinhalt gleichzeitig aktualisieren, was zu Datenverwirrung und Fehlern führt.

Wie vermeide ich diesen Fehler?

Der Dateisperrmechanismus kann abgeschlossen werden.

Die Funktion flock() wird in PHP bereitgestellt, die den Sperrmechanismus (Datei sperren oder freigeben) für die Datei verwenden kann. Wenn ein Prozess beim Zugriff auf eine Datei eine Datei sperrt, müssen andere Prozesse warten, bis die Sperre aufgehoben wird, wenn sie auf die Datei zugreifen möchten. Dadurch wird eine Datenbeschädigung beim gleichzeitigen Zugriff auf dieselbe Datei vermieden.

Der Funktionsprototyp lautet wie folgt:

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

  • handle:

    Der Dateisystemzeiger ist normalerweise Wird von fopen() verwendet und erstellte Ressource.

  • Operation

Operation kann einer der folgenden Werte sein:

LOCK_SH erwirbt die gemeinsame Sperre (Leseprogramm).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

  • Wenn die Sperre blockiert wird (EWOULDBLOCK-Fehlercode), wird der optionale dritte Parameter auf TRUE gesetzt. (Nicht unterstützt unter Windows)

    wouldblockdemo

  • 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);

Führen Sie zuerst demo1.php und dann sofort demo2.php aus , werden Sie feststellen, dass demo2.php keinen neuen Inhalt schreiben kann, da die Datei durch demo1.php gesperrt ist. Erst nachdem demo1.php die Sperre aufgehoben hat, kann demo2.php die exklusive Sperre erhalten und dann die Datei schreiben.

Probleme lösen

Nachdem ich mir dieses Wissen angeeignet habe, werde ich in der Lage sein, meine bisherigen Probleme zu lösen. Der verbesserte Code lautet wie folgt:

<?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;];
}

Das obige ist der detaillierte Inhalt vonProbleme und Lösungen, die durch die PHP-Dateisperre verursacht werden (ein realer Fall). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn