tags:

views:

77

answers:

4

How can I make it so when a user clicks on a link on my web page, it writes to a .txt file named "Count.txt", which contains only a number and adds 1 to that number? Thank you.

+3  A: 

If you forego any validity checking you could do it with something as simple as:

file_put_contents($theCounterFile, file_get_contents($theCounterFile)+1);

Addition:

There's talk about concurrency in this thread and it should be noted that it is a good idea to use a database and transactions to deal with concurrency, I'd highly recommend against writing a bunch of plumbing code to do this in a file.

If you've ever had, or think you might ever have two requests for the resource in the same second you should look into PDO with mysql, or PDO with SQLite instead of a file, use transactions (and InnoDB or better if you're going for mysql).

But really, even if you get two requests in the same microsecond (highly unlikely), chances of locking the file are slim as it will not be kept open and the two requests will probably not be handled parallel enough to lock anyway. Reality check: how many hits on the same resource do you get on average in the same minute?...

Kris
This will fail when multiple users connect at the same time, you need locks. See Wim Vandersmissen's answer.
johannes
yes it will fail, if you need something viable for concurrency use a database, not a text file.
Kris
You forgot the specify the filename for `file_put_contents`.
Gumbo
ouch gumbo, you are absolutely correct!
Kris
+1  A: 

Generally this is quite easy:

$count = (int)file_get_contents('/path/to/Count.txt');
file_put_contents('/path/to/Count.txt', $count++, LOCK_EX);

But you'll run into concurrency problems using this code. One way to generate a lock safe from any race condition is:

$countFile = '/path/to/Count.txt';
$countTemp = tempnam(dirname($countFile), basename($countFile));
$countLock = $countFile . '.lock';
$f_lock = fopen($countLock, 'w'); 
if(flock($f_lock, LOCK_EX)) {
    $currentCount = (int)file_get_contents($countFile);
    $f_temp = fopen($countTemp, 'w');
    if(flock($f_temp, LOCK_EX)) {
        fwrite($f_temp, $currentCount++); 
        flock($f_temp, LOCK_UN); 
        fclose($f_temp); 
        if(!rename($countTemp, $countFile)) { 
            unlink($countTemp); 
        } 
    }
    flock($f_lock, LOCK_UN);
    fclose($f_lock); 
}
Stefan Gehrig
+2  A: 

If you decide to do anything more advanced, like say two numbers, you may want to consider using SQLite. It's about as about as fast and as simple as opening and closing a file, but is much more flexible.

brianegge
SQLite is very obviously a much better idea than using a text file.
Kris
+1  A: 

Open the file, lock the file (VERY important), read the number currently in there, add 1 to the number, write number back to file, release the lock and close the file.

ie. something like :

$fp = fopen("count.txt", "r+");

if (flock($fp, LOCK_EX)) { // do an exclusive lock
    $num = fread($fp, 10);
    $num++;
    fseek($fp, 0);
    fwrite($fp, $num);
    flock($fp, LOCK_UN); // release the lock
} else {
    // handle error
}
fclose($fp);

should work (not tested).

wimvds
why on earth would you want to write all that plumbing yourself, just to reqd and write an int?
Kris
Because on a website you will have concurrent access to the file, and your counter will be off or corrupted if you don't lock and unlock the file.
wimvds