0

我有一个简单的脚本,只计算点击链接的次数,当点击链接时,一个 php 脚本读取链​​接ID/URL/Label/Count的“counter.txt”文件,然后在计数上加 1,写入“counter.txt”文件。 txt”,然后重定向。

计数器.txt:

Label 1|1|http://google.com|1
Label 2|2|http://google.us|1
Label 3|3|http://google.uk|1

链接.php:

<?php

//gets the content from "counter.txt"
$filecontent = file_get_contents('counter.txt');

//separates the contents of counter.txt by "\n" (spaces)
$filelines = explode("\n", $filecontent);

$url_array = null;

$new_file_content = "";

//for each $filelines variable, assign it as $fileline and execute code
foreach ($filelines AS $fileline)
{
//separates the contents of $fileline by "|"
    $filelines_exploded = explode("|", $fileline);

    //assigns counter.txt label to a variable
    $label       = $filelines_exploded[0];
    //assigns counter.txt id's to a variable
    $click_id    = $filelines_exploded[1];
    //assigns counter.txt url's to a variable
    $click_url   = $filelines_exploded[2];
    //assigns counter.txt click count to a variable
    $click_count = $filelines_exploded[3];

    if ($_REQUEST["id"] == $click_id)
    {
        //$url_array contains all of the variables in an array
        $url_array = $filelines_exploded;
        //string to rebuild the counter.txt file
        $new_file_content .= $label . "|" . $click_id . "|" . $click_url . "|" . ((int) $click_count + 1);
    }
    else

    {
        $new_file_content .= $fileline;
    }
    //adds a line break when rebuilding the counter.txt
    $new_file_content .= "\n";
}
//file_put_contents to rewrite the file
file_put_contents('counter.txt', trim($new_file_content));
//redirects to the link gathered from the counter.txt file
header("HTTP/1.1 301 Moved Permanently"); 
header('Location: ' . $url_array[2]);
exit;
?>

脚本工作,但有时,counter.txt 变为空白,丢失所有数据,我不知道为什么,请看看我的代码有什么问题。

谢谢/

4

1 回答 1

2

这可能发生在两个访问者几乎同时单击您的链接的竞争条件下,导致第二个实例读取您的文件,就像第一个实例在写入之前将其清除一样。这导致实例 2 写入一个空白文件。

对于初学者,您可以通过在 file_put_contents 中使用标志 FILE_APPEND 来减少这个问题,这样您只需将的点击附加到文件的末尾,而不是完全重写。

接下来,您可以尝试使用 PHP 的函数flock() 来尝试获取相关文件的写锁。如果您的脚本获得并遵守flock() 文件锁定,您可以阻止竞争条件的发生,代价是所有线程都阻塞,直到它们可以轮到文件。

不过在我看来……如果你不得不开始担心这样的竞争条件,你可能已经准备好将这个系统转移到你的数据库中,在那里你不必担心同时写入新的点击行,或者担心关于同时重新计算 sumstats,即使你这样做了——在大多数数据库引擎中锁定表很容易(有时在某些配置中,flock() 似乎不可靠)。

于 2016-06-27T06:01:20.517 回答