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) 分享
分享
取消