PHP并发下安全读写文件函数
众所周知,在高并发的状态下,直接使用 PHP 读写同一个文件时,可能会导致文件内容丢失,于是乎就需要额外的代码来解决这个问题。大致的思路是先使用 flock
函数对原文件进行锁死,再来读写。
下面的这个函数是从大名鼎鼎的可道云的代码中找到的。可道云相信大家都不会陌生,它是一个无数据库的程序,因此配置存储全都是靠这个函数完成的,所以这段代码的安全性和普适性绝对毋庸置疑,可以放心的用于项目中(注意尽量保留原作者的版权信息就行了)。
代码的原版位于可道云的 /app/function/file.function.php
第 729 行左右。原版代码的逻辑是 写文件时如果原文件不存在,则直接返回 false
,我把这一部分稍微修改了一下,改成了 如果目标文件不存在,则创建文件并写入。
不多说了,全部的代码如下:
<?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;
}
}
可道云的代码里其实还有大量的封装好的非常好用的函数,仔细研究研究绝对受益匪浅。
1.本站所有资源收集于互联网和用户上传,如有侵权请联系客服删除;
2.本站不保证所提供下载资源的准确性、安全性和完整性,请自行测试;
3.资源仅供学习交流使用,版权归原作者所有,请在下载后24小时之内删除;
4.如用于商业或非法用途实属个人行为,与本站无关,一切后果由用户自负;
5.本站提供的源码、主题模板、插件等资源,都不包含技术服务,请大家谅解;
6.本站所设置的资源售价只是用于赞助,收取费用仅维持本站的日常运营所需;
7.如果您有好的源码或者教程,请至个人中心发布资源,将有积分奖励和额外收入;
8.本站默认解压密码:www.ittiantang.com,如有链接无法下载,请联系管理员处理。
IT天堂 » PHP并发下安全读写文件函数
2.本站不保证所提供下载资源的准确性、安全性和完整性,请自行测试;
3.资源仅供学习交流使用,版权归原作者所有,请在下载后24小时之内删除;
4.如用于商业或非法用途实属个人行为,与本站无关,一切后果由用户自负;
5.本站提供的源码、主题模板、插件等资源,都不包含技术服务,请大家谅解;
6.本站所设置的资源售价只是用于赞助,收取费用仅维持本站的日常运营所需;
7.如果您有好的源码或者教程,请至个人中心发布资源,将有积分奖励和额外收入;
8.本站默认解压密码:www.ittiantang.com,如有链接无法下载,请联系管理员处理。
IT天堂 » PHP并发下安全读写文件函数
常见问题FAQ
- IT天堂的会员权益只能通过充值获得吗?
- 您可以通过签到功能获得积分,用积分兑换会员权益。
- 网站上的VIP资源只能通过充值购买吗?
- 您可以通过每日签到获得积分,使用积分直接购买VIP资源。