Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>First of all: This is not the way I would write a click counter.</p> <p>That said, 100 users hitting your server at the same time (with initial clicks at 0) might result in a recorded number of 1..100 with low (=wrong) values being prominent.</p> <ul> <li>If you want to count in a text file, lock as in @lanzz's answer and be prepared for a major performance hit - you are effectivly serializing the requests.</li> <li>If you want to count in any file, consider SQlite and prepare for a manageable performance hit</li> <li>If you just want to count, consider a real DB with a very small performance hit</li> </ul> <p><strong>EDIT: Implementations</strong></p> <p>I created the below implementations for a file counter in a text file, SQLite and MySQL</p> <p>Please do not flame me for using the <code>mysql_*()</code> function family - as allways the code is meant to be instructive, not productive: instructive in the sense of concentrating on the issue at hand, not the surrounding layers.</p> <p><strong>counter-file.php:</strong></p> <pre><code>&lt;?php //acquire file handle $fd=fopen('counter.txt','c+b'); if (!$fd) die("Can't acquire file handle"); //lock the file - we must do this BEFORE reading, as not to read an outdated value if (!flock($fd,LOCK_EX)) die("Can't lock file"); //read and sanitize the counter value $counter=fgets($fd,10); if ($counter===false) die("Can't read file"); if (!is_numeric($counter)) { flock($fd,LOCK_UN); die("Value in file '$counter' is not numeric"); } //increase counter and reconvert to string $counter++; $counter="$counter"; //Write to file if (!rewind($fd)) { flock($fd,LOCK_UN); die("Can't rewind file handle"); } $num=fwrite($fd,$counter); if ($num!=strlen($counter)) { flock($fd,LOCK_UN); die("Error writing file"); } //Unlock the file and close file handle flock($fd,LOCK_UN); fclose($fd); printf ("Counter is now %05d",$counter); ?&gt; </code></pre> <p><strong>counter-sqlite.php:</strong></p> <pre><code>&lt;?php //counter.sqlite3 was created with //CREATE TABLE counter (counter NUMERIC) //INSERT INTO counter VALUES (0) //Open database $dsn='sqlite:'.dirname(__FILE__).'/counter.sqlite3'; $db=new PDO($dsn); if (!$db) die("Can't open SQlite database via DBO"); //Make exclusive $sql="BEGIN EXCLUSIVE TRANSACTION"; if ($db-&gt;exec($sql)===false) die("Error starting exclusive transaction"); //Update counter $sql="UPDATE counter SET counter=counter+1"; if (!$db-&gt;exec($sql)) die("Error inserting into database"); //Read value $sql="SELECT counter FROM counter"; $result=$db-&gt;query($sql); if (!$result) die("Error querying database"); foreach ($result as $row) $counter=$row['counter']; //Commit $sql="COMMIT TRANSACTION"; if (!$db-&gt;exec($sql)) die("Error committing to database"); //Print result printf("Counter is now %05d",$counter); ?&gt; </code></pre> <p><strong>counter-mysql.php:</strong></p> <pre><code>&lt;?php //mysql database was created with //CREATE TABLE counter (counter INT NOT NULL) //INSERT INTO counter VALUES (0) //Open database connection and select database $db=mysql_pconnect('127.0.0.1','redacted','redacted'); if (!$db) die("Can't open database"); if (!mysql_select_db('redacted', $db)) die("Can't select database"); //Update counter $sql="UPDATE counter SET counter=counter+1"; $qry=mysql_query($sql,$db); if (!$qry) die("Error updating database"); //Read value $sql="SELECT counter FROM counter"; $qry=mysql_query($sql,$db); if (!$qry) die("Error reading from database"); $counter=mysql_fetch_array($qry,MYSQL_ASSOC); if (!$counter) die("Error reading result"); //Print result printf("Counter is now %05d",$counter['counter']); ?&gt; </code></pre> <p>As for the performance: <strong>I stand corrected.</strong> The SQLite implementation is 100 times slower than the two others - this is because I had to accept, that nothing else than <code>START EXCLUSIVE TRANSACTION</code> would end a test of <code>ab -n 1000 -c 50 http://127.0.0.1/stackoverflow/counter/counter-sqlite.php</code> with 1000 clicks counted.</p> <p>My recommendation for the OP is to use the MySQL version - it is fast and will reliably save the counter over an OS crash. The file version has nearly the same performance characteristics, but it can quite easily be destroyed by an OS crash.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload