如何在PHP中锁定文件?

时间:2011-02-05 13:04:49

标签: php apache locking

我正在尝试创建一个PHP文件,如果它已经在运行,它将无法运行。这是我正在使用的代码:

<?php

class Test {
    private $tmpfile;

    public function action_run() {
        $this->die_if_running();
        $this->run();
    }

    private function die_if_running() {
        $this->tmpfile = @fopen('.refresher2.pid', "w");

        $locked = @flock($this->tmpfile, LOCK_EX|LOCK_NB);
        if (! $locked) {
            @fclose($this->tmpfile);
            die("Running 2");
        }
    }

    private function run() {
        echo "NOT RUNNNING";
        sleep(100);
    }
}

$test = new Test();
$test->action_run();

问题是,当我从控制台运行它时,它运行良好。但是当我尝试从浏览器运行它时,许多实例可以同时运行。这是在Windows 7,XAMPP,PHP 5.3.2上。我想操作系统认为它是相同的过程,因此功能下降。是否有一种跨平台的方式来创建这种类型的PHP脚本?

2 个答案:

答案 0 :(得分:0)

没有什么可以承诺的。你不能像这样使用flock。

您可以使用system()启动另一个(php)进程,为您执行锁定。但缺点是:

  • 您需要进行进程间通信。考虑如何告诉其他程序何时释放锁等等。您可以使用stdin进行消息传递并使用3个常量或其他东西。在这种情况下,它仍然很简单
  • 这对性能有害,因为你不断创建昂贵的流程。

另一种方法是启动另一个一直运行的程序。您使用某种IPC连接它(可能只是使用tcp通道,因为它是跨平台的)并允许该程序管理文件访问。该程序也可以是无限循环中的PHP脚本,但用Java或其他支持多线程的语言编写代码可能更简单。

另一种方法是利用现有的资源。为锁创建一个虚拟数据库表,为该文件创建一个条目,然后执行表行锁定。

另一种方法是不使用文件,而是使用数据库。

答案 1 :(得分:0)

前一段时间我遇到过类似的问题。 我需要一个计数器,其中返回的数字是唯一的。 我使用了一个锁文件,只有当这个实例能够创建锁文件时,才允许使用当前编号读取该文件。

也许你可以允许脚本运行,而不是计数。 诀窍是让我们尝试几次(比如5次),中间等待一小段时间。

function GetNextNumber()
{
  $lockFile = "lockFile.txt";
  $lfh = @fopen($lockFile, "x");
  if (!$lfh)
  {
    $lockOkay = false;
    $count = 0;
    $countMax = 5;

    // Try ones every second in 5 seconds
    while (!$lockOkay & $count < $countMax) 
    {
      $lfh = @fopen($lockFile, "x");
      if ($lfh)
      {
        $lockOkay = true;
      }
      else
      {
        $count++;
        sleep(1);
      }
    }
  }

  if ($lfh)
  {
    $fh = fopen($myFile, 'r+') or die("Too many users. ");
    flock($fh, LOCK_EX);
    $O_nextNumber = fread($fh, 15);
    $O_nextNumber = $O_nextNumber + 1;
    rewind($fh);
    fwrite($fh, $O_knr);
    flock($fh, LOCK_UN);  
    fclose($fh);

    unlink($lockFile); // Sletter lockfilen
  }

  return $O_nextNumber;
}