问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

php 文件锁 有用吗

发布网友 发布时间:2022-04-07 05:24

我来回答

2个回答

懂视网 时间:2022-04-07 09:45

一个真实案例

想起自己之前犯过一个相关的错误。当时场景是这样的:有一个微信公众号项目,调用微信公众号的接口都需要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)['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'];
}

出现的问题:

项目运行一段时间后就会出问题,但过一两秒后再刷新就正常了。

问题原因分析:

假设token已经过期了,这时候有2个请求来了,分别命名为A、B。A来了,发现token到期后,去调用微信接口获取新的token,获取后,更新到存放token的文件中。

但是,文件没有完全更新完毕的时候,B来了,读入存放token的文件。因为token文件中数据没有更新完整,B读到的数据就会产生错误。

另外还有可能是A和B同时在更新文件内容,这样就会产生数据混乱,也会导致错误发生。

如何规避这个错误呢?

文件锁机制可以完成。

在PHP中提供了 flock()函数,可以对文件使用锁定机制(锁定或释放文件)。当一个进程在访问文件时加上锁,其他进程要想对该文件进行访问,则必须等到锁定被释放以后。这样就可以避免在并发访问同一个文件时破坏数据。

函数原型如下:

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

  • handle

    文件系统指针,是典型地由 fopen() 创建的 resource(资源)。

  • operation

  • operation 可以是以下值之一:

    LOCK_SH取得共享锁定(读取的程序)。

    LOCK_EX 取得独占锁定(写入的程序)。

    LOCK_UN 释放锁定(无论共享或独占)。

    LOCK_NB附加锁定(Windows 上还不支持)。

  • wouldblock

  • 如果锁定会堵塞的话(EWOULDBLOCK 错误码情况下),可选的第三个参数会被设置为 TRUE。(Windows 上不支持)

    demo

    demo1.php

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

    demo2.php

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

    先运行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)['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'];
    }

    热心网友 时间:2022-04-07 06:53

    一般文件锁在解决少量并发的时候是起作用的。
    比如:处理库存的时候作一个标记位, 还有定时任务计划的时候,避免重复。
    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    Linux系统安装FTP服务器 Linux系统的网络文件共享 建筑的七盏明灯的内容简介 面向对象设计七大原则 简单说 交互设计七大定律 交互设计的“根”——七大定律 交互设计原则和理论2——七大定律 七大设计原则 附近的加油站有哪些 附近的加油站有哪些地方 苹果13USB转 闪电连接线能充电吗 苹果转闪电数据线可以插入5w适配器吗? 有线耳机没有声音怎么办 电脑耳机插上亮的但是没声音 2015年大专升本科一般几月份报名,费用是多少 大专毕业以后想升本科该怎么报名? 统招专升本是什么时候报考啊,大二下学期,还是大三呢 职业本科是在2021年专科&#x3629;报考吗 真性包皮过长必须要去手术吗? 大专想升本科怎么考 传统包皮过长手术后,多少天后能洗澡 包皮过长手术后勃起怎么办? 有做过包皮手术的吗?这个手术后当天可以回家吗? 好医保长期保期间没有发生理赔退钱吗? 支付宝那个好医保住院医疗靠谱吗 过去几年都没检查过身体 假如生病了会不会被拒保 包皮过长手术后注意事项有哪些 三十年前痊愈的既往病史,好医保长期医疗保险借口拒赔合理吗? 做完 包皮过长的切割手术后 是不是相当难受呀?求真实体验者回答 好医保住院治疗,出院了还能报吗 男性 包皮过长是怎么回事?潮州包皮手术后要注意什么? 请问糯米酒是怎样做的谢谢 荥阳市都有什么特色小吃 荥阳有什么好吃的? 河南除了枣,还有什么特产呢~~ 郑州市荥阳有什么特产? 货车仪表盘上显示断开助力器是什么意思 呼叫器的作用有哪些? 母乳辅助器是什么 叫号器 什么是电气阀门定位器? 提词器只是辅助,为何《吐槽大会》只有李若彤发声? 李若彤觉得脱口秀有提词器是辅助作用,提词器是不是让脱口秀失去了意义? 事业成功的助推器是什么? 为何助力车警报器乱叫 脸上的痣可以挖掉吗 我脸上有些痣,比较多,影响了我的交际,想问问我能自己抠掉吗?应该怎么去掉呢 脸上痣可以抠掉吗 脸上的痦子可不可以自己把他抠下来 我13岁,想用手抠脸上的痣,痣是圆平的,就是把黑色皮弄破,扯掉,行吗? 请问脸上的痣可以去掉吗?这样会不会对生命有危害?我的脸上以前记得有一颗痣,后来我把那个痣扣烂了,之