文件写入在Wordpress短代码中多次触发?

I have written a simple hit counter shortcode in Wordpress using a text file and I have found out that it is somehow triggering the file write process multiple times.

function sc_page_counter() {
    $fname = get_stylesheet_directory() . "/counter.txt";

    if (!file_exists($fname)) {
        file_put_contents($fname, "0");
    }

    $ct = file_get_contents($fname);
    file_put_contents($fname, ++$ct);

    return $ct;
}
add_shortcode('page_counter', 'sc_page_counter');

I have put the shortcode call in my footer.php

This site has been visited <?php echo do_shortcode('[page_counter]') ?> times.

Let's say the current content of counter.txt is 20. The shortcode will correctly output "21" but upon checking the counter.txt file. It is now "25". Results vary whether I'm running it locally or in the production server.

I tried testing it further by just appending a character instead of writing the new value and it appended it about 32 times. I'm currently stumped on why this is happening.

First, don't use shortcode for this. Second, write to the database.

Site views:

functions.php of your theme:

function header_stuff()
{
    $site_views = get_option('site_views');
    update_option('site_views', (((preg_match('#^\d+$#', $site_views)) ? $site_views : 0) + 1));
}
add_action('wp_head', 'header_stuff');

footer.php

This site has been visited <?php echo get_option('site_views') ?> times.

Or, if you'd like to see views of single post/page page, you can use the following:

functions.php of your theme:

function header_stuff()
{
    global $post;
    if (is_object($post) && is_singular())
    {
        $post_views = get_post_meta($post->ID, '_views', true);
        update_post_meta($post->ID, '_views', (((preg_match('#^\d+$#', $post_views)) ? $post_views : 0) + 1));
    }
}
add_action('wp_head', 'header_stuff');

Output where you need it:

if (is_object($post) && is_singular())
{
    echo 'Views: ' . get_post_meta($post->ID, '_views', true);
}

Or you can count them both if you need that:

function header_stuff()
{
    //Site view
    $site_views = get_option('site_views');
    update_option('site_views', (((preg_match('#^\d+$#', $site_views)) ? $site_views : 0) + 1));

    //Post view
    global $post;
    if (is_object($post) && is_singular())
    {
        $post_views = get_post_meta($post->ID, '_views', true);
        update_post_meta($post->ID, '_views', (((preg_match('#^\d+$#', $post_views)) ? $post_views : 0) + 1));
    }
}
add_action('wp_head', 'header_stuff');