溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

php文件鎖錯(cuò)誤案例以及解決方案

發(fā)布時(shí)間:2020-05-13 09:40:40 來(lái)源:億速云 閱讀:189 作者:Leah 欄目:編程語(yǔ)言

本篇文章主要探討php文件鎖發(fā)生錯(cuò)誤的解決方法。有一定的參考價(jià)值,有需要的朋友可以參考一下,跟隨小編一起來(lái)看解決方法吧。

微信公眾號(hào)項(xiàng)目調(diào)用微信公眾號(hào)的接口都需要access_token,它的有效期是2小時(shí)。當(dāng)時(shí)我的做法是把它存放在文件中,格式使用的是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)['expire'] <= time()){
        $token = loadToken($tokenFile);
    } else {
        $token = json_decode($tokenJson, true)['access_token'];
    }
    
    return $token;
}
function loadToken ($tokenFile) 
{
    $fp = fopen($tokenFile, 'r+');
    
    $tokenJson = ...; // 調(diào)用微信接口獲取到token
    fwrite($fp, json_encode($tokenJson));
    
    return $tokenJson['access_token'];
}

出現(xiàn)的問(wèn)題:

項(xiàng)目運(yùn)行一段時(shí)間后就會(huì)出問(wèn)題,但過(guò)一兩秒后再刷新就正常了。

問(wèn)題原因分析:

假設(shè)token已經(jīng)過(guò)期了,這時(shí)候有2個(gè)請(qǐng)求來(lái)了,分別命名為A、B。A來(lái)了,發(fā)現(xiàn)token到期后,去調(diào)用微信接口獲取新的token,獲取后,更新到存放token的文件中。

但是,文件沒(méi)有完全更新完畢的時(shí)候,B來(lái)了,讀入存放token的文件。因?yàn)閠oken文件中數(shù)據(jù)沒(méi)有更新完整,B讀到的數(shù)據(jù)就會(huì)產(chǎn)生錯(cuò)誤。

另外還有可能是A和B同時(shí)在更新文件內(nèi)容,這樣就會(huì)產(chǎn)生數(shù)據(jù)混亂,也會(huì)導(dǎo)致錯(cuò)誤發(fā)生。

如何規(guī)避這個(gè)錯(cuò)誤呢?

文件鎖機(jī)制可以完成。

在PHP中提供了 flock()函數(shù),可以對(duì)文件使用鎖定機(jī)制(鎖定或釋放文件)。當(dāng)一個(gè)進(jìn)程在訪問(wèn)文件時(shí)加上鎖,其他進(jìn)程要想對(duì)該文件進(jìn)行訪問(wèn),則必須等到鎖定被釋放以后。這樣就可以避免在并發(fā)訪問(wèn)同一個(gè)文件時(shí)破壞數(shù)據(jù)。

函數(shù)原型如下:

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

  • handle

    文件系統(tǒng)指針,是典型地由 fopen() 創(chuàng)建的 resource(資源)。

  • operation

operation    可以是以下值之一:

LOCK_SH取得共享鎖定(讀取的程序)。

LOCK_EX 取得獨(dú)占鎖定(寫入的程序)。

LOCK_UN 釋放鎖定(無(wú)論共享或獨(dú)占)。

LOCK_NB附加鎖定(Windows 上還不支持)。

  • wouldblock

如果鎖定會(huì)堵塞的話(EWOULDBLOCK    錯(cuò)誤碼情況下),可選的第三個(gè)參數(shù)會(huì)被設(shè)置為 TRUE。(Windows 上不支持)

demo

demo1.php

<?php
 
$file = 'data.txt';
$handler = fopen($file, 'a+') or die('文件資源打開失敗');
// 取得獨(dú)占鎖
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('文件資源打開失敗');
 
// 取得獨(dú)占鎖
if (flock($handler, LOCK_EX)) {
    fwrite($handler, 'sometest string');
    flock($handler, LOCK_UN);
} else {
    echo '鎖定失敗';
}
 
fclose($handler);

先運(yùn)行demo1.php然后立即運(yùn)行demo2.php,會(huì)發(fā)現(xiàn),因?yàn)楸籨emo1.php鎖定了文件,demo2.php寫入不了新內(nèi)容,只有等demo1.php釋放了鎖定,demo2.php才能拿到獨(dú)占鎖,然后才能寫入文件。

解決問(wèn)題

學(xué)完這些知識(shí)后,就能解決我之前的問(wèn)題了。改進(jìn)的代碼如下:

<?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');    // 取得獨(dú)占鎖    
    if (flock($fp, LOCK_EX)) {
        $tokenJson = ...; // 調(diào)用微信接口獲取到token     
        fwrite($fp, json_encode($tokenJson)); 
        flock($fp, LOCK_UN);    
    } else {
        return false;    
    }
    
    return $tokenJson['access_token'];
}

以上就是php文件鎖發(fā)生錯(cuò)誤的解決方法的詳細(xì)內(nèi)容,代碼示例簡(jiǎn)單明了,如果在日常工作遇到此問(wèn)題。通過(guò)這篇文章,希望你能有所收獲,更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI