phpfopenfwriteflockhitcounter

PHP hitcounter adds symbol before digit for each hit


I got stuck in a small problem. I have a php-page:

index.php

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<?php
include( 'counter.php' );
?>
</body>
</html>

And the file counter.php

<?php
$fp = fopen("counter.txt", "r+");

if(!$fp){
    error_log("Could not open counter.txt");
    exit();
}

if(!flock($fp, LOCK_EX)) {  // acquire an exclusive lock
    error_log("Could not lock");
}
else{
    $counter = intval(fread($fp, filesize("counter.txt")));
    $counter++;

    echo $counter;
    ftruncate($fp, 0);      // truncate file
    fwrite($fp, $counter);  // set your data
    fflush($fp);            // flush output before releasing the lock
    flock($fp, LOCK_UN);    // release the lock
}
fclose($fp);
?>

and the file counter.txt, which has the content "0" (0)

After running index.php once, the textfile content becomes ^@^@1, and after that it becomes ^@^@^@1

What I want is the 0 to become 1, and then 2

Is there something wrong the code?

It's running on Ubuntu 18, with Apache, and the files with rights are

-rw-rw-r-- 1 emanuel www-data  559 Feb 13 21:56 counter.php
-rw-rw-r-- 1 emanuel www-data   11 Feb 13 22:51 counter.txt
-rw-rw-r-- 1 emanuel www-data  128 Feb 13 22:50 index.php
drwxrwxr-x 2 emanuel www-data 4096 Feb 12 14:55 software

Answer would be appreciated


Solution

  • Use Rewind after ftruncate (took a bit of work to isolate it)

        ftruncate($fp, 0);      // truncate file
        rewind($fp); //rewind the pointer
    

    Or you can just use rewind instead of ftruncate, which seems to be the cause of the \0 null bytes. It seems somewhat pointless to do both as if you write after doing rewind it wipes the file out anyway (unless you use a+ append) ...

    Looking in the doc's the very first example uses both.

    http://php.net/manual/en/function.ftruncate.php

    From PHP.net

    <?php
    $handle = fopen('output.txt', 'r+');
    
    fwrite($handle, 'Really long sentence.');
    rewind($handle);
    fwrite($handle, 'Foo');
    rewind($handle);
    
    echo fread($handle, filesize('output.txt'));
    
    fclose($handle);
    ?>
    

    Even though the reason why is not explained... I just use rewind() but I am always lazy so I endeavor to write the least amount of code that I need to, as I write a LOT of code.

    Another solution

    Trim the contents of your file before using intval

      $counter = intval(trim(fread($fp, filesize("counter.txt"))));
    

    In notepad++

      [null][null]1
    

    enter image description here

    Anyway that was a fun one... thanks!