2

I have a simple download page that receives a file URL, download counter .TXT file url, and a redirect link for after the download. This is all sent through PHP arguments. Problem is, someone has been spamming the downloaders and messing up the count. I want to put a cap on the download counter so it will only count 3 hits from each address, per downloadable item.

I need to be able to do this with only PHP, and without a MySQL database. I do have reasoning for this, my database server is trash and unreliable, I can't have the counter going down.

This is my current downloader PHP file. Further information, this PHP file is in its own folder at /counter with a /counter/data directory for each download counting TXT file. These files store just a single integer value.

<?
    //Retrieve downloadable file URL
    $c_url = urldecode($_GET['url']);

    //retrieve redirect page URL
    $c_page = urldecode($_GET['page']);

    //Retrieve download counter TXT URL
    $c_file = "../" . $_GET['file'];
?>

<!-- Set up simple styles -->
<head>
    <style type="text/css">
        body{
            background: url("../images/background.png");
            color: #ffffff;
        }
    </style>
</head>

<!-- Creates download file URL in hidden iFrame -->
<iframe src="<?echo $c_url;?>" id="hiddenFrm" style="display:none;" frameborder="0"></iframe>

<body>
<center>
    <h1>Your download is starting</h1><br>
    <p>You should be redirected momentarily...<br>

    <?
    <br><br>

    if (file_exists($c_file))
    {
        //Add one value to the counter file
        file_put_contents($c_file, ((int) file_get_contents($c_file)) + 1);

        //Set an automatic redirect for the page (Return home)
        ?>
        <meta http-equiv="refresh" content="0;url=<?echo $c_page;?>" />
        <?

        //Display information about the download, and alternate exits to the page
        if ($c_url != "") 
        {?>
            <b><a href="<?echo $c_url?>">Click here</a> if the download did not start.<br><br>
            <a href="<?echo $c_page?>">Click here</a> if this page does not close after your download.</b></p>
        <?} 
        else 
        {
        ?>
            <b><a href="<?echo $c_page?>">Click here</a> if you are not redirected automatically</b></p>
        <?
        }
    }
    else
    {
        //In case our counter file is improperly specified
        echo "<br><br><br>Error, the counter file was not found!";
    }
    ?>
    </center>
</body>

My question simplified: How can I store IP addresses of people who download each product and prevent the download counter from counting more than 3 downloads from that address using only PHP and no databases?

Help is much appreciated.

EDIT: As I said above, I can't use databases. Also, I am interested in two solutions but not sure how to make them work (I am looking for code examples), one being cookies, and the other being text-files acting as databases.

Bit Fracture
  • 651
  • 1
  • 9
  • 24
  • Refer this link http://stackoverflow.com/questions/15579620/how-to-block-100-000-individual-ip-addresses may be it will help.. – Yogesh Suthar Apr 07 '13 at 16:30
  • The time it will take you to write a fast hash to store the IPS and hit counts and even update them efficiently, it will already be less beneficial than to fix that `trash and unreliable` database server and help yourself avoid some headache later. If your web server can serve sites, it should be able to run a database too for this – Hanky Panky Apr 07 '13 at 16:30
  • Have you tried a cache? – kdazzle Apr 07 '13 at 16:37
  • I want to cache data in text files, my problem is that I want just two efficient functions. One to check whether or not that address exists 3 times, and another to add an address to the data cache in some way. I am not very experienced in data handling outside of game engine programming. – Bit Fracture Apr 07 '13 at 17:13

3 Answers3

2

Without using any database at all it would be pretty tough. I'd be surprised if you can't use MySQL at all, but maybe something even simpler like SQLite might work. Other than that there are two solutions I can think of: the file system and cookies.

The problem with cookies are that they are transient, and if you have bots spamming you they will probably reject the cookie setting anyway.

What you can do is maintain a file of

IP    download-count    last-download-time

If the file is small enough you can load it into memory with file and search for the IP address with preg_grep and update the count that way.

Note that IP Address may not be the best bet either because some valid and invalid users may share mobile routers and IP Addresses can potentially be spoofed by use of a proxy, etc. Your best bet would be some sort of user authentication system, but that would be prohibitively difficult without a DB

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • I like the mention of cookies. That actually would be a much better system because I can then get a good accurate count, and no "I hope there aren't more than 3 machines at that address." My problem is not bots, thankfully. It is human work I am dealing with. Thanks for you help, but could you maybe explain how I could set up a cookie system? – Bit Fracture Apr 07 '13 at 17:16
  • 1
    @BitFracture you could just have one or two cookies. One that has the download number and the last download time, or one that has both. Checking and setting cookies is very simple with PHP's `setcookie` and `$_COOKIE` mechanisms. You don't even have to consider IP address in that case – Explosion Pills Apr 07 '13 at 17:29
  • This is a lot easier than I thought! Thank you! – Bit Fracture Apr 07 '13 at 17:39
  • What if the user deletes the cookie every 3 downloads? – kdazzle Apr 07 '13 at 18:29
  • I understand the problem, but my users aren't that smart. For now, simply as a solution to my problem, this will work fine. Question though, I get some sort of header modification error or something when I call this: `setcookie($c_title, true, time()+(60));`. Yes it is just a test, and the cookie is set to expire in a minute, but I keep getting an error. Let me go grab the exact text. – Bit Fracture Apr 07 '13 at 18:40
  • `Cannot modify header information - headers already sent by...` (Redirect thingy I did set the header first) but I don't see how this has anything to do with header setting... Just like this guy: http://stackoverflow.com/questions/2658083/setcookie-cannot-modify-header-information-headers-already-sent So nvm :D – Bit Fracture Apr 07 '13 at 18:43
1

I would use Memcache. You can see PHP's docs here: http://php.net/manual/en/book.memcache.php

You can use a string of the IP address as the key, and then on each download request, you would attempt to do a $memcache->get($key). If that doesn't exist, you would do a $memcache->set($key, $downloadCount). If the key does exist, you would increment the downloadCount.

kdazzle
  • 4,190
  • 3
  • 24
  • 27
  • This might be exactly what I am looking for, I will test it out and get back to you. – Bit Fracture Apr 07 '13 at 17:18
  • This appears like I must have access to the server directly. Where my website is hosted I have absolutely no control over the servers (Or that unreliable database) so I really need a way to use what the PHP came with. Is this included in PHP normally? I will try it out still. It appears like it uses a database. – Bit Fracture Apr 07 '13 at 17:25
  • 1
    Some providers already have memcache setup for you. Memcache is designed to minimize database calls, so I'm almost positive it's just an in-memory hash table. – kdazzle Apr 07 '13 at 17:34
  • If I end up needing another solution to my problem, I will consider this. But since my problem does not include bots, a simple cookie will do what I need done. – Bit Fracture Apr 07 '13 at 17:41
0

The data has to be stored somewhere since PHP always 'starts from the scratch'. How about a text file to represent the database?