使用flock的PHP问题 - 文件锁定
Posted
技术标签:
【中文标题】使用flock的PHP问题 - 文件锁定【英文标题】:PHP issues using flock - file locking 【发布时间】:2013-05-23 10:26:11 【问题描述】:我在使用 php flock()
函数时遇到问题。我需要编写两个不同的变量($O
和 $o
),但通常它不会写入第二个变量($o
),可能是因为该文件连续写入两次。
代码如下:
include_once "changevar.php";
changevar("O",$seguimedia,$filename,0);
changevar("o",$offerta,$filename,0);
$seguimedia
、$filename
和 $offerta
设置正确。
changevar.php:
function changevar($varname,$newval,$filename,$type)
while(!$fp=fopen($filename,"c+"))
usleep(100000);
while(!flock($fp,LOCK_EX))
usleep(100000);
while(!include($filename))
usleep(100000);
ftruncate($fp,0);
rewind($fp);
$$varname=$newval;
if($type==0)
foreach(array("u","p","t","d") as $v)$$v=str_replace("\\","\\\\",$$v);
$text="<?\$o=$o;\$u=\"$u\";\$c=$c;\$m=$m;\$p=\"$p\";\$C=$C;\$id=\"$id\";\$t=\"$t\";\$d=\"$d\";\$O=$O;?>";
else
$text="<?\$impressions=$impressions;\$clickunici=$clickunici;\$clicknulli=$clicknulli;\$creditiguadagnati=$creditiguadagnati;\$creditiacquistati=$creditiacquistati;\$creditiutilizzati=$creditiutilizzati;?>";
fwrite($fp,$text);
flock($fp,LOCK_UN);
fclose($fp);
PHP flock()
是避免此类问题的好方法吗?
我需要使用哪种语言/功能?
【问题讨论】:
我不知道您的目标是什么,但是编写和重新读取 php 文件并不是一个好的解决方案,不仅因为大量的 i/o 流量。可能有更快更好的解决方案,memcache、sqlite、mongodb,甚至ini/csv文件都更好处理 【参考方案1】:如果您在同一个脚本中编写两次并不重要。 但事实上,当您从两个不同的进程尝试此操作并使用文件锁定时...
无论如何,你的 changevar() 函数实际上每次都会截断文件,所以我猜这就是为什么它“似乎”只写了一个 var。
【讨论】:
【参考方案2】:问题其实出在fopen()
调用中。
您正在以c+
模式打开文件。这意味着文件指针位于文件的开头,这将导致任何写入覆盖已经存在的内容。
雪上加霜,你打电话给ftruncate()
,在写入之前将文件截断为0字节——因此,在每次写入之前,你都在手动擦除整个文件。因此,该代码保证只保留最后一次写入文件的内容,手动清除其他所有内容。
fopen()
调用应使用模式a+
,ftruncate()
和rewind()
都需要去(后者还有将文件指针放在开头的效果)。
【讨论】:
【参考方案3】:老实说,我真的认为读取和写入 PHP 文件是一个非常非常非常糟糕的想法。如果您正在查看配置,请使用 ini
或 json
。
如果你真的想读写文件,那么它可以很简单:
$file = __DIR__ . "/include/config.json";
$var = new FileVar($file);
$var['o'] = "Small o";
$var['O'] = "Big O";
$var->name = "Simple json";
echo file_get_contents($file);
输出
"o": "Small o",
"O": "Big O",
"name": "Simple json"
另一个例子
// To remove
unset($var['O']);
// to update
$var['o'] = "Smaller o";
输出
"o": "Smaller o",
"name": "Simple json"
请注意,包含文件夹包含此.htaccess
<Files "*">
Order Deny,Allow
Deny from all
</Files>
为了测试这个lock
是否真的有效,我使用pthreads 来模拟竞争条件
for($i = 0; $i < 100; $i ++)
$ts = array();
// Generate Thread
foreach(range("A", "E") as $letter)
$ts[] = new T($file, $letter);
// Write all files at the same time
foreach($ts as $t)
$t->start();
// Wait for all files to finish
foreach($ts as $t)
$t->join();
// What do we have
echo file_get_contents($file);
主类
class FileVar implements ArrayAccess
private $file;
private $data;
private $timeout = 5;
function __construct($file)
touch($file);
$this->file = $file;
$this->data = json_decode(file_get_contents($file), true);
public function __get($offset)
return $this->offsetGet($offset);
public function __set($offset, $value)
$this->offsetSet($offset, $value);
public function offsetSet($offset, $value)
if (is_null($offset))
$this->data[] = $value;
else
$this->data[$offset] = $value;
$this->update();
public function offsetExists($offset)
return isset($this->data[$offset]);
public function offsetUnset($offset)
unset($this->data[$offset]);
$this->update();
public function offsetGet($offset)
return isset($this->data[$offset]) ? $this->data[$offset] : null;
private function update()
// Open file with locking
$time = time();
while(! $fp = fopen($this->file, "c+"))
if (time() - $time > $this->timeout)
throw new Exception("File can not be accessed");
usleep(100000);
// Lock the file for writing
flock($fp, LOCK_EX);
// Overwrite the old data
ftruncate($fp, 0);
rewind($fp);
// Write the new array to file
fwrite($fp, json_encode($this->data, 128));
// Unlock the file
flock($fp, LOCK_UN);
// Close the file
fclose($fp);
测试类
class T extends Thread
function __construct($file, $name)
$this->file = $file;
$this->name = $name;
function run()
$var = new FileVar($this->file);
$var[$this->name] = sprintf("Letter %s", $this->name);
【讨论】:
以上是关于使用flock的PHP问题 - 文件锁定的主要内容,如果未能解决你的问题,请参考以下文章