1

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

这是代码:

include_once "changevar.php";
changevar("O",$seguimedia,$filename,0);
changevar("o",$offerta,$filename,0);

$seguimedia,$filename并且$offerta设置正确。

更改变量.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);
}

PHPflock()是避免此类问题的好方法吗?
我需要使用哪些语言/功能?

4

3 回答 3

3

问题实际上出在fopen()通话中。

您正在 mode 中打开文件c+。这意味着文件指针位于文件的开头,这将导致任何写入覆盖已经存在的内容。雪上加霜的是,您正在调用ftruncate(),在写入之前将文件截断为 0 字节——因此,在每次写入之前,您都在手动擦除整个文件。因此,该代码保证只保留最后一次写入文件的内容,手动负责擦除其他所有内容。

fopen()调用应该使用 mode ,a+并且两者都ftruncate()需要rewind()go(后者也具有将文件指针放在开头的效果)。

于 2013-06-06T09:43:57.700 回答
1

老实说,我真的认为读写 PHP 文件是一个非常非常糟糕的想法。如果您正在查看配置,请使用inior 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);
    }
}
于 2013-06-08T11:15:41.237 回答
1

如果您在同一个脚本中编写两次并不重要。但实际上,当您从两个不同的进程尝试此操作并使用文件锁定时,这确实很重要......

无论如何,你的 changevar() 函数实际上每次都会截断文件,所以我猜这就是为什么它“似乎”只写了一个 var。

于 2013-06-05T14:55:03.477 回答