PHP并发下安全读写文件函数

    admin 千秋月 关注 管理组 LV20
    发表于程序代码版块 技术杂文

    在高并发场景下,PHP 直接对同一文件进行读写操作时,极易出现文件内容丢失、数据错乱等问题。究其原因,是多个进程同时操作文件时缺乏原子性控制,因此需要通过文件锁机制来规避这类风险,核心思路是借助 flock 函数对文件加锁,确保同一时间只有一个进程能读写文件。

    接下来要分享的这个文件操作函数,源自知名无数据库轻量级云存储系统 —— 可道云(KodCloud)的核心代码(原版位于 /app/function/file.function.php 第 729 行附近)。可道云全程依赖文件存储配置数据,因此该函数经过了海量场景的验证,其安全性、稳定性和普适性均有保障,可放心集成到各类 PHP 项目中。


    原版函数存在一个小局限:当目标文件不存在时,会直接返回 false 导致写入失败。我对这一逻辑做了优化 —— 若写入的目标文件不存在,函数会自动创建文件并完成内容写入,进一步提升了函数的易用性和场景适配性。


    可道云源码下载地址:


    https://pan.quark.cn/s/8b02f9ebfbda


    以下是完整的优化后代码:


    <?php
     
    /**
     * @link http://kodcloud.com/
     * @author warlee | e-mail:kodcloud@qq.com
     * @copyright warlee 2014.(Shanghai)Co.,Ltd
     * @license http://kodcloud.com/tools/license/license.txt
     */
     
     
    /**
     * 安全读取文件,避免并发下读取数据为空
     * 
     * @param $file 要读取的文件路径
     * @param $timeout 读取超时时间 
     * @return 读取到的文件内容 | false - 读取失败
     */
    function file_read_safe($file, $timeout = 5) {
        if (!$file || !file_exists($file)) return false;
        $fp = @fopen($file, 'r');
        if (!$fp) return false;
        $startTime = microtime(true);
        
        // 在指定时间内完成对文件的独占锁定
        do {
            $locked = flock($fp, LOCK_EX | LOCK_NB);
            if (!$locked) {
                usleep(mt_rand(1, 50) * 1000);     // 随机等待1~50ms再试
            }
        }
        while ((!$locked) && ((microtime(true) - $startTime) < $timeout));
        
        if ($locked && filesize($file) >= 0) {
            $result = @fread($fp, filesize($file));
            flock($fp, LOCK_UN);
            fclose($fp);
            if (filesize($file) == 0) {
                return '';
            }
            return $result;
        } else {
            flock($fp, LOCK_UN);
            fclose($fp);
            return false;
        }
    }
     
    /**
     * 安全写文件,避免并发下写入数据为空
     * 
     * @param $file 要写入的文件路径
     * @param $buffer 要写入的文件二进制流(文件内容)
     * @param $timeout 写入超时时间 
     * @return 写入的字符数 | false - 写入失败
     */
    function file_write_safe($file, $buffer, $timeout = 5) {
        clearstatcache();
        if (strlen($file) == 0 || !$file) return false;
        
        // 文件不存在则创建
        if (!file_exists($file)) {
            @file_put_contents($file, '');
        }
        if(!is_writeable($file)) return false;    // 不可写
        
        // 在指定时间内完成对文件的独占锁定
        $fp = fopen($file, 'r+');
        $startTime = microtime(true);
        do {
            $locked = flock($fp, LOCK_EX); 
            if (!$locked) {
                usleep(mt_rand(1, 50) * 1000);   // 随机等待1~50ms再试
            }
        }
        while ((!$locked) && ((microtime(true) - $startTime) < $timeout));    
        
        if ($locked) {
            $tempFile = $file.'.temp';
            $result = file_put_contents($tempFile, $buffer, LOCK_EX);
            
            if (!$result || !file_exists($tempFile)) {
                flock($fp, LOCK_UN);
                fclose($fp);
                return false;
            }
            @unlink($tempFile);
            
            ftruncate($fp, 0);
            rewind($fp);
            $result = fwrite($fp, $buffer);
            flock($fp, LOCK_UN);
            fclose($fp);
            clearstatcache();
            return $result;
        } else {
            flock($fp, LOCK_UN);
            fclose($fp);
            return false;
        }
    }


    本文章最后由 admin2026-02-08 17:50 编辑
    评论列表 评论
    发布评论

    评论: PHP并发下安全读写文件函数



    2026全面升级!对接公众号万级资源池 + 智能AI双驱动,速来体验! 外卖党必看!你吃外卖我买单!欢迎报名下单! AI人脸替换工具离线版,免费下载~ Image


    免责声明
    本站资源,均来自网络,版权归原作者,所有资源和文章仅限用于学习和研究目的 。 不得用于商业或非法用途,否则,一切责任由该用户承担 !

    请求资源或报告无效资源,请点击[反馈中心>>]

    电脑不给力运行不了?试试[高配云电脑>>]

    常见问题一站式解决方案,点击进入解答区,随时为您解答![进入>>]


    侵权删除请致信 E-Mail:2309931055@qq.com
    已有0次打赏
    (0) 分享
    分享
    取消