【问题标题】:How to reset a persistent counter at a particular value?如何将持久计数器重置为特定值?
【发布时间】:2011-03-09 20:02:39
【问题描述】:

我之前问过一个问题(How to keep this counter from reseting at 100,000?),现在有一个后续问题。

我有另一个版本的计数器,可以被告知在某个数字处重置,我想确保第二个版本与第一个版本没有相同的问题。

我现在编码的是:

$reset = '10';

$filename4 = "$some_variable/$filename3.txt";  

// Open our file in append-or-create mode.
$fh = fopen($filename4, "a+");

if (!$fh)
    die("unable to create file");

if ($reset == 'default'){        
    // Before doing anything else, get an exclusive lock on the file.
    // This will prevent anybody else from reading or writing to it.
    flock($fh, LOCK_EX);

    // Place the pointer at the start of the file.
    fseek($fh, 0);

    // Read one line from the file, then increment the number.
    // There should only ever be one line.
    $current = 1 + intval(trim(fgets($fh)));

    // Now we can reset the pointer again, and truncate the file to zero length.
    fseek($fh, 0);

    ftruncate($fh, 0);

    // Now we can write out our line.
    fwrite($fh, $current . "\n");

    // And we're done.  Closing the file will also release the lock.
    fclose($fh);                
}
else {        
    $current = trim(file_get_contents($filename4)) + 1;

    if($current >= $reset) {            
        $new = '0';            
        fwrite(fopen($filename4, 'w'), $new);                        
    }
    else {            
        fwrite(fopen($filec, 'w'), $current);                        
    }               
}

echo $current;

我不想假设我知道要对此代码进行哪些更改,所以我发布了另一个问题。编辑-如果 $reset 不等于默认值,我应该在此处进行哪些更改以避免在文件上没有获得独占锁定?对此进行编码的正确方法是什么?这行得通吗?:

$filename4 = "$some_variable/$filename3.txt";  

// Open our file in append-or-create mode.
$fh = fopen($filename4, "a+");

if (!$fh)
die("unable to create file");


// Before doing anything else, get an exclusive lock on the file.
// This will prevent anybody else from reading or writing to it.
flock($fh, LOCK_EX);

// Place the pointer at the start of the file.
fseek($fh, 0);



if ($reset == 'default'){

// Read one line from the file, then increment the number.
// There should only ever be one line.
$current = 1 + intval(trim(fgets($fh)));

} else {
// Read one line from the file, then increment the number.
// There should only ever be one line.
$current = 1 + intval(trim(fgets($fh)));

if($current >= $reset) {            
    $current = '0';            
}
else {            
// Read one line from the file, then increment the number.
// There should only ever be one line.
$current = 1 + intval(trim(fgets($fh)));

} 
}
// Now we can reset the pointer again, and truncate the file to zero length.
fseek($fh, 0);

ftruncate($fh, 0);

// Now we can write out our line.
fwrite($fh, $current . "\n");

// And we're done.  Closing the file will also release the lock.
fclose($fh);                


echo $current;

编辑 - 这似乎对我有用:

$reset = "default";
$filename4 = "counter.txt";  

// Open our file in append-or-create mode.
$fh = fopen($filename4, "a+");

if (!$fh)
die("unable to create file");


// Before doing anything else, get an exclusive lock on the file.
// This will prevent anybody else from reading or writing to it.
flock($fh, LOCK_EX);

// Place the pointer at the start of the file.
fseek($fh, 0);

// Read one line from the file, then increment the number.
// There should only ever be one line.
$current = 1 + intval(trim(fgets($fh)));

if ($reset == 'default'){
$new = $current;
} else {
if($current >= ($reset + '1')) {            
$new = '1';            
}
else {            
$new = $current;
} 
}
// Now we can reset the pointer again, and truncate the file to zero length.
fseek($fh, 0);

ftruncate($fh, 0);

// Now we can write out our line.
fwrite($fh, $new . "\n");

// And we're done.  Closing the file will also release the lock.
fclose($fh);                


echo $new;

这看起来对吗?

【问题讨论】:

  • 抱歉缩进。整洁从来不是我的天分……
  • $reset 的值从何而来?这段代码基本上是说“如果 $reset = default,将文件中的值增加 1”。 "否则,如果文件中的当前值大于$reset,则将当前值设置为0。
  • @David 没错。 $reset 会在页面源代码的前面设置。
  • @Mario 如上所述,“我应该在此处进行哪些更改?”
  • 那么,你想要任意代码建议吗?或者建议的更改是否应该有特定的结果?

标签: php hitcounter


【解决方案1】:
    if($current >= $reset) {
        // here is where you are setting the counter back to zero. comment out
        // these lines.
        //$new = '0';            
        //fwrite(fopen($filename4, 'w'), $new);                        
    }

如果您只是想要一个不会重置的计数器,请尝试:

$filename4 = "counter.txt";  

// Open our file in append-or-create mode.
$fh = fopen($filename4, "a+");

if (!$fh)
die("unable to create file");


// Before doing anything else, get an exclusive lock on the file.
// This will prevent anybody else from reading or writing to it.
flock($fh, LOCK_EX);

// Place the pointer at the start of the file.
fseek($fh, 0);

// Read one line from the file to get current count.
// There should only ever be one line.
$current = intval(trim(fgets($fh)));

// Increment
$new = $current++;

// Now we can reset the pointer again, and truncate the file to zero length.
fseek($fh, 0);

ftruncate($fh, 0);

// Now we can write out our line.
fwrite($fh, $new . "\n");

// And we're done.  Closing the file will also release the lock.
fclose($fh);

echo $new;                

【讨论】:

  • 接近尾声,您将 $current 与 $reset 进行比较。如果 $current 大于 10,在这种情况下,您将文件中的任何数字设置回 0。通过注释掉这些行(或者更好的是删除整个 if 块),您不会将该值重置为 0 .
  • @David 我不确定我是否理解这将如何解决。你的解释能更清楚吗?我可以在这里给其他会员发私信吗?
  • 我们又见面了。 @大卫。我认为他想在这种情况下将其重置为 0。如果这就是意图,那么代码大部分是正确的。
  • @frostymarvelous 很高兴在这里见到你!是的!你知道这段代码是干什么用的。这是我的意图。
  • 文本文件的主要处理我没有看,但是你检查条件和重置的部分是正确的。
【解决方案2】:

我认为最好的方法是使用非独占锁打开文件以进行读取。然后您可以执行所需的检查,如果计数超过 $reset 值,您可以关闭文件,再次打开它,但这次使用排他锁进行写入。 另一种方法就是不使用排他锁。 您可以查看已经测试过锁定机制的非常好的平面文件类。

【讨论】:

  • 您能举个例子吗?我将研究那些平面文件类。你能链接你最喜欢的吗?
  • 我会在 xtgem 上给你。以后我要搬家了。
【解决方案3】:

file_put_contents 已经是原子的了。不需要十行文件锁定代码。

<?php

    $fn = "$filename3.txt"; 

    $reset = 0;        // 0 is equivalent to "default"
    //$reset = 10000000;  

    $count = file_get_contents($fn);        
    $count = ($reset && ($count >= $reset)) ? (0) : ($count + 1);
    file_put_contents($fn, $count, LOCK_EX);

    echo $count;

不知道这是否有帮助,因为您的问题仍然不透明。我不会回答cmets。

【讨论】:

  • 关于file_put_contents 的第三个参数。也就是说,OP 正遭受需要锁定的大量并发问题。看看他链接的原始问题。虽然您的代码不应该遭受导致完全数据丢失的竞争条件,但您的代码仍然容易在多个并发请求期间丢失数据。
  • @Charles:是的,这是一种非常不精确的方法。如果他想要一些极其原子的东西,那么file_put_contents("$fn", "*", FILE_APPEND)filesize($fn) 就可以了(当然会浪费相应的磁盘空间)。从最初的问题来看,我认为这是更关键的逻辑问题。
  • @mobilestimulus,这个答案非常适合仅用于重置代码
  • @Charles - 我编辑了我的问题帖子以反映我当前的代码和状态。这看起来可以接受吗?
猜你喜欢
  • 1970-01-01
  • 2011-05-14
  • 1970-01-01
  • 1970-01-01
  • 2015-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-22
相关资源
最近更新 更多