【问题标题】:PHP issues using flock - file locking使用flock的PHP问题 - 文件锁定
【发布时间】: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文件都更好处理

标签: php file flock overwrite


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    问题其实出在fopen()调用中。

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

    fopen() 调用应使用模式a+ftruncate()rewind() 都需要去(后者还有将文件指针放在开头的效果)。

    【讨论】:

      【解决方案3】:

      老实说,我真的认为读取和写入 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);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-10-19
        • 1970-01-01
        • 2012-02-28
        • 2015-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多