2013-05-28 87 views
1

我在使用PHP flock()函数时遇到问题。我需要编写两个不同的变量($O$o),但通常它不写第二个变量($o),可能是因为该文件连续写入两次。使用flock的PHP问题 - 文件锁定

下面的代码:

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()一个很好的方式,以避免这种问题?
我需要使用哪种语言/功能?

+0

我不知道你的目标是什么,但编写和重新读取php文件不是一个好的解决方案,不仅因为许多I/O流量。可能有更快更好的解决方案,memcache,sqlite,mongodb,甚至ini/csv文件都可以更好地处理 – DanFromGermany

回答

1

如果您从同一个脚本内写入两次,则无关紧要。 但事实上的确很重要,当你尝试这从两个不同的过程和使用文件锁定...

反正你changevar()函数实际上截断每一次文件,所以我想这就是为什么它“似乎”只写了一个var。

3

问题实际上是在fopen()调用中。

您正在以c+模式打开文件。这意味着文件指针位于文件的开头,这会导致任何写入都覆盖已有的文件。 若要添加侮辱伤害,您打电话ftruncate(),在写入之前将文件截断为0字节 - 因此,在每次写入之前,您都要手动擦除整个文件。因此,该代码是保证只有最后一次写入文件将保留,手动注意擦除每一个单独的文件。

fopen()调用应以模式a+制成,并且两个ftruncate()rewind()需要去(后者也有把文件指针开头的效果)。

1

老实说,我真的认为是一个非常非常不好主意读写一个PHP文件。如果您正在查看配置,请使用inijson

如果你真的想读取和写入文件,那么它可以是简单的:

$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); 
    } 
}