我使用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()
是避免这种问题的好方法吗?
我需要使用哪些语言/函数?
问题实际上是在fopen()
调用。
您正在以c+
模式打开文件。这意味着文件指针位于文件的开头,这将导致任何写操作覆盖已经在那里的内容。雪上加霜的是,您调用ftruncate()
,在写入之前将文件截断为0字节——因此,在每次写入之前,您都要手动擦除整个文件。因此,该代码是,保证只保留对文件的最后一次写入,手动清除其他所有写入。
fopen()
调用应该使用模式a+
,并且ftruncate()
和rewind()
都需要去(后者也具有将文件指针放在开头的效果)。
如果在同一个脚本中编写两次也没关系。但事实上,当您在两个不同的进程中尝试此操作并使用文件锁定时,这确实很重要…
无论如何,你的changevar()函数实际上每次都截断文件,所以我猜这就是为什么它"似乎"只写了一个var。
老实说,我真的认为这是一个非常非常非常坏的主意读取和编写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);
}
}