PHP文件锁定机制flock()

zxh5566  2016-08-23 05:24   Hits: 

文件系统操作是在网络环境下完成的,可能有多个客户端用户在同一个时刻对服务器上的同一个文件访问,当这种并发访问发生时,很可能会破坏文件中的数据,例如,一个用户正向文件中写入数据,当还没写完,其他用户在这一时刻也向这个文件中写入数据,就会造成数据写入混乱,还有,当用户没有将数据写完时,其他用户就去获取这个文件中的内容,也会得到残缺的数据。

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

该函数第一个参数handle必须是一个已经打开的文件资源,第二个参数operation也是必需的,规定使用哪种锁定类型,operation可以是以下值

LOCK_SH取得共享锁定(从文件中读取数据时使用)
LOCK_EX取得独占锁定(向文件中写入数据时使用)
LOCK_UN释放锁定(无论共享或独占,都用它释放)
LOCK_NB附加锁定(如果不希望flock()锁定时阻塞,则应在上述锁定后加上该锁)

如果锁定会阻塞的话,已经被锁定的文件,再次加锁,flock()函数会被挂起,这时称为堵塞,也可以将可选的第三个参数设置为1,则当进行锁定时会阻挡其他进程,锁定操作也可以被fclose()函数释放,为了让flock()函数发挥作用,在所有访问文件的程序中都必须使用相同的方式锁定文件。该函数如果成功则返回true,失败反复false

在下面的示例中,通过编写一个网络留言板的模型,应用一下flock()函数,首先创建一个包含表单内容的脚本,在表单中允许输入用户名,标题以及留言内容三部分,并在脚本中接受表单提交的内容,存储到文本文件text_data.txt中,文件以追加方式打开,文本文件存储规则为每次提交存储一行。例如"王小二||我要吃饭||哪里有饭店<|>",每部分之间使用两个竖线分隔,每行以<|>结束,并将读取存储的文本文件text_data.txt中的数据,以html方式输出


<?php
$filename = "text_data.txt";
if(isset($_POST['sub'])){
$message = $_POST['username'].'||'$_POST['title'].'||'$_POST['mess'].'<|>';
writeMessage($filename,$message);
}

if(file_exists($filename)){
readMessage($filename);
}

function writeMessage($filename,$message){
$fp = fopen($filename,'a');
if(flock($fp,LOCK_EX)){
fwrite($fp,$message);
flock($fp,LOCK_UN);
}else{
echo"不能锁定文件";
}
fclose($fp);
}

function readMessage($filename){
$fp = fopen($filename,'r');
flock($fp,LOCK_SH);
$buffer = '';
while(!feof($fp)){
$buffer.=fread($fp,1024);
}
$data=exlolde('<|>',$buffer);
foreach($data as $line){
list($username,$title,$message)=explode("||",$line);
if($username!=''&&$title!=''&& $message!=''){
echo $usrname.'说:';
echo $title;
echo $message.'<hr>';
}
}
flock($fp,LOCK_UN);
fclose($fp);
}

?>
上面留言板程序中,在对文件的读取和写入时,都是使用flock()函数对文件加锁和释放锁,一个文件可以同时存在很多个共享锁定LOCK_SH,这意味着多个用户可以在同一时刻拥有对该文件的读取访问权限,而一个独占锁定LOCK_EX中允许一个用户拥有一次,通常被用于文件的写入操作,如果不希望出现锁定堵塞发生,可以附加LOCK_NB

<?php
$file = fopen("test.txt","w+");
flock($file,LOCK_EX+LOCK_NB);
fwrite($file,"www.txxwl.net");
flock($file,LOCK_UN+LOCK_NB);
fclose($file);
?>

上一篇:PHP读取文件fread()、file_get_contents()、fgets()、file
下一篇:文件指针ftell()、fseek()、rewind()