NotSoSmart
NotSoSmart

Reputation: 89

Modify a line with "KEY - AMOUNT" of a file in PHP

this has been bugging me for ages now but i can't figure it out..

Basically i'm using a hit counter which stores unique IP address in a file. But what i'm trying to do is get it to count how many hits each IP address has made.

So instead of the file reading:

222.111.111.111  
222.111.111.112  
222.111.111.113  

I want it to read:

222.111.111.111 - 5  
222.111.111.112 - 9  
222.111.111.113 - 41  

This is the code i'm using:

    $file = "stats.php";  
    $ip_list = file($file);  
    $visitors = count($ip_list);  

    if (!in_array($_SERVER['REMOTE_ADDR'] . "\n", $ip_list))  
    {  
    $fp = fopen($file,"a");  
    fwrite($fp, $_SERVER['REMOTE_ADDR'] . "\n");  
    fclose($fp);  
    $visitors++;  
    }

What i was trying to do is change it to:

    if (!in_array($_SERVER['REMOTE_ADDR'] . " - [ANY NUMBER] \n", $ip_list))  
    {  
    $fp = fopen($file,"a");  
    fwrite($fp, $_SERVER['REMOTE_ADDR'] . " - 1 \n");  
    fclose($fp);  
    $visitors++;  
    }

    else if (in_array($_SERVER['REMOTE_ADDR'] . " - [ANY NUMBER] \n", $ip_list))  
    {  
    CHANGE [ANY NUMBER] TO [ANY NUMBER]+1
    }

I think i can figure out the last adding part, but how do i represent the [ANY NUMBER] part so that it finds the IP whatever the following number is?

I realise i'm probably going about this all wrong but if someone could give me a clue i'd really appreciate it.

Thanks.

Upvotes: 0

Views: 77

Answers (3)

Marc B
Marc B

Reputation: 360702

in_array() simply does a basic a string match. it will NOT look for substrings. Ignoring how bad an idea it is to use a flat file for data storage, what you want is preg_grep, which allows you to use regexes

$ip_list = file('ips.txt');
$matches = preg_replace('/^\d+\.\d+\.\d+\.\d+ - \d+$/', $ip_list);

of course, this is a very basic and very broken IP address match, and will not help you actually CHANGE the value in $ip_list, because you don't get the actual index(es) of the matched lines.

Upvotes: 0

Toote
Toote

Reputation: 3413

What you are doing is a very bad idea

But lets first answer the actual question you are asking.

To be able to do that you will have to actually process the file first in some kind of data structure that allows for that to be done. I'd presonally recommend an array in the form of IP => AMOUNT.

For example (untested code):

$fd = file($file);
$ip_list = array();
for ($fd as $line) {
   list($ip, $amount) = explode("-", $line);
   $ip_list[$ip] = $amount;
}

Note that the code is not perfect as it would leave a space at the end of $ip and another in front of $amount due to the nature of your original data. But it works good enough just to point you in the right direction. A more "accurate" solution would involve regular expressions or modifying the original data source to a more convenient format.


Now the real answer to your actual problem

Your process will quickly become a performance bottleneck as you would have to open up that file, process it and write it all back again afterwards (not sure if you can do in-line editing of an open file) for every request.

As you are trying to do some kind of per-IP hit count, there are a lot of better solutions to your problem:

  • Use an existing solution for it (like piwik)
  • Use an actual database for your data
  • Keep your file simple with just a list of IPs and post-process it off-line periodically to make it be the format you want
  • You can avoid writing that file altogether if you have access to your webserver's logs (and they are setup to log every request with the originating IP) and you can post-process that file instead

Upvotes: 0

jamjam
jamjam

Reputation: 3269

This is bad idea, don't do it this way.

Its normal to store website statics in the file-system but not with pre-aggregation applied to it.

If you going to use the file-system then do post-aggregation on the data otherwise use a database.

Upvotes: 1

Related Questions