Jump to content
roger01

Restrict form usage once per visitor

Recommended Posts

Hello

I want to run a contest on my website and i am asking visitors to post their names and BTC addresses and i'll use random.org's list randomizer to pick one from the list

what i did so far:
 

<?php
if ($_POST) {
        $name = $_POST['commentName'];
        $txt = $_POST['commentBTC'];
        $handle = fopen("comments.html","a");
        fwrite($handle, "<b>" . $name . "</b> : " . $txt . "<br/>");
        fclose($handle);
}
?>


and
 

]                <form action="" method="POST"  onsubmit="return checkform(this);">
                        Some Name:
                        <input type="text" maxlength="10" name="commentName"/><br>
                        BTC Address:
                        <input type="text"  maxlength="34" pattern="^[123][a-km-zA-HJ-NP-Z1-9]{25,34}$" name="commentBTC" required/><br>


so i get a html list, which is great. the problem is that some visitors are signing up multiple times :(

is there a way to check 'comments.html' for 'commentBTC' and if exists, to deny signing up?

i can drop the 'commentName' field if it's easier to have only a bitcoin address list.

help? thank you!

Share this post


Link to post
Share on other sites

Don't store comments in a text file. Get a database. Even a SQLite database will do the job, if you don't have a real one available.

 

Then all you have to do is run a query on the database to see if the BTC address (being the most reliable piece of information you have) has already been entered.

Share this post


Link to post
Share on other sites

... or add a UNIQUE key to the field to make it impossible to add the same one twice

Share this post


Link to post
Share on other sites

thank you for your answers!

 

meanwhile, i got a lot of weird POST submissions so i came up with this (i found the code, actually):

<?php

session_start();

if (isset($_POST['message']))
{
if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token'])
    {
        $message = htmlentities($_POST['message']);
                $ipaddy = $_SERVER['REMOTE_ADDR'];

        $fp = fopen('./btcs.txt', 'a');
        fwrite($fp, "$ipaddy $message <br /> \n");
        fclose($fp);
    }
}

$token = md5(uniqid(rand(), true));
$_SESSION['token'] = $token;

?>

<form method="POST" onsubmit="return checkform(this);">
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" maxlength="34" pattern="^[12][a-km-zA-HJ-NP-Z1-9]{25,34}$" name="message" required><br />
<input type="submit" value="Sign-up!">

i wanted to have the ips stored aswell so i can iptables drop whoever uses post injection or whatever but in don't want to show it on the website so i'm using this:

<?php

$lines = file('btcs.txt');
foreach ($lines as $line) {
    $parts = explode(' ', $line);
    echo isset($parts[1]) ? $parts[1] : 'N/A';
    echo "<br>";
}

?>

i'm just trying to run this for a couple of days so i don't need anything fancy like store it in a sql. however, it would be nice if the last part of the code will remove the duplicate btc addresses  (there still are visitors that post the same btc address over and over again:), anyone knows how to do that?

 

thank you very much!

Share this post


Link to post
Share on other sites

If you want to make use of this forum, it's a good idea to actually listen to the advice you get. Most of us are professional developers, so we know a bit about implementing features like this. When requinix tells you to use an SQL database, he means it.

 

That code you've “found somewhere” is nonsense. You can spend the rest of your time trying to fix it, but you'll still end up with up cheaters sabotaging your contest. This leaves you with two options:

  • You accept that the contest is just a fun project and let users post whatever they want.
  • Or you take this seriously and set it up in a way that it actually works.

Even the cheapest hoster today has MySQL, so I'm sure you already have a database and probably even phpmyadmin (which is a graphical administration tool).

 

Here's the table definition:

CREATE TABLE contest_submissions (
    contest_submission_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    btc_address VARCHAR(35) NOT NULL UNIQUE,
    username VARCHAR(10) NOT NULL,
    ip_address VARCHAR(15) NOT NULL
);

People who try to post a large number of requests can be stopped with CAPTCHAs like reCAPTCHA.

Edited by Jacques1

Share this post


Link to post
Share on other sites

i know you are right. my php knowledge is next to 0 and i was trying to avoid the sql method because i have no idea how to do it and couldn't allow myself to ask here 'hey can someone write up a whole script for me?' so that's why i dogged that answer, not because i don't want to do.

 

thank you for your answer, i've managed to get something really medieval working, getting the btc addresses in a txt and running a crontab every 5 minutes with uniq and awk that txt :D

Share this post


Link to post
Share on other sites

my php knowledge is next to 0

 

That's why we have this forum: To help people solve problems which exceed their current knowledge.

 

While you were busy writing your cronjob hack, I've written the script. It took me ~10 minutes, 2 queries (CREATE and INSERT) and ~50 lines of plain PHP code. That's not exactly rocket science. And unlike your hack, it actually solves the problem.

 

But if you prefer to run a cronjob every 5 minutes, go ahead.

Share this post


Link to post
Share on other sites

If you are intent on using a text file then store it as json encoded data. Take advantage of the fact that an array key must be unique and make the BTC the key.

 

To get the current submissions and put in an array

$submissions = json_decode(file_get_contents('btcs.json'), true);

to add a new submission

if (isset($submissions[$btc]) {
    // error - already exists!
}
else {
    $submissions[$btc] = [  'username' => $username , 'ip' => $ip ];
}

to save the data, reverse the first code

file_put_contents('btcs.json', json_encode($submissions));

However, you really should get to grips with using a database. It has so many advantages and it's a move you'll need to make sometime.

Share this post


Link to post
Share on other sites

That's why we have this forum: To help people solve problems which exceed their current knowledge.

 

While you were busy writing your cronjob hack, I've written the script. It took me ~10 minutes, 2 queries (CREATE and INSERT) and ~50 lines of plain PHP code. That's not exactly rocket science. And unlike your hack, it actually solves the problem.

 

But if you prefer to run a cronjob every 5 minutes, go ahead.

 

well may i have it? :)

Edited by roger01

Share this post


Link to post
Share on other sites

yes, but i only used two columns:

 SELECT * FROM `contest_submissions` ;
+-----------------------+------------------------------------+---------------+
| contest_submission_id | btc_address                        | ip_address    |
+-----------------------+------------------------------------+---------------+
|                     1 | 1KZsSb1ZsQrB1FXzFdnhFL2GuPGTjUKLhi | 192.168.100.3 |
+-----------------------+------------------------------------+---------------+
1 row in set (0.00 sec)

oh, and i made botw btc_address and ip_aadress unique, i hope there won't be problems

Edited by roger01

Share this post


Link to post
Share on other sites

Making the IP address unique is a bad idea, because this will lock out many legitimate users. In fact, the IP address is most definitely shared among many people, be it due to an Internet connection with multiple users, a proxy server, a VPN, Tor etc. Once you've blocked a couple of big services, large parts of the Internet population will be unable to visit your site. At the same time, an actual attacker can easily obtain a new address.

 

If you want to limit abuse, install reCAPCHA. It's much more effective against attackers and much less harmful for legitimate users.

 

The recommend way to access a MySQL database with PHP is via PDO. It should already be installed on the server:

<?php

// database credentials
const DB_HOST = 'localhost';
const DB_USER = '???';
const DB_PASSWORD = '???';
const DB_NAME = '???';
const DB_CHARSET = 'UTF8';

// MySQL error codes
const MYSQL_ER_DUP_ENTRY = 1062;



// establish a database connection
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHARSET;
$database_connection = new PDO($dsn, DB_USER, DB_PASSWORD, [
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

// test connection
var_dump( $database_connection->query('select * from contest_submissions')->fetchAll() );

Share this post


Link to post
Share on other sites

if i understand this correctly, this is for reading the columns, right? i've managed to gather something up to insert into the table by using this in insert.php:

    $ipaddy = mysqli_real_escape_string($link, $_SERVER['REMOTE_ADDR']);
    $btcaddy = mysqli_real_escape_string($link, $_POST['message']);

    $sql = "INSERT INTO contest_submissions (btc_address, ip_address) VALUES ('$ipaddy', '$btcaddy')";
    if(mysqli_query($link, $sql)){
        echo "Records added successfully.";
    } else{
        echo "ERROR: Could not able to execute $sql. " . mysqli_error($link);

and

<form action="insert.php">

but while using the txt file, i had this code writing the file:

if (isset($_POST['message']))
{
if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token'])
    {
        $message = htmlentities($_POST['message']);
                $ipaddy = $_SERVER['REMOTE_ADDR'];

        $fp = fopen('./messages.txt', 'a');
        fwrite($fp, "$ipaddy $message <br /> \n");
        fclose($fp);
    }
}

$token = md5(uniqid(rand(), true));
$_SESSION['token'] = $token;

and i've noticed there weren't any trash POST like

ZAP'
ZAP"
ZAP
ZAP'
ZAP"
ZAP%<br/>
ZAP%'

whatever this was.. :) could it be that the mysql will be flooded upon with that trash if the simple script is used?

Edited by roger01

Share this post


Link to post
Share on other sites

 

$sql = "INSERT INTO contest_submissions (btc_address, ip_address) VALUES ('$ipaddy', '$btcaddy')";

 

The values are the wrong way round. You are putting the $btcaddy into the ip_address column

Share this post


Link to post
Share on other sites

And you need to stop copying and pasting random code from the Internet. mysqli is poor, manual escaping is poor, and printing internal error messages on the screen is really not a good idea.

 

Did you run the PDO code I gave you? Then you need to use a prepared statement and also catch errors which are caused by duplicate Bitcoin addresses:

// process POST request
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $errors = [];

    // TODO: validate the $_POST input

    // try to insert input; if there's a duplicate value, this will fail
    try
    {
        $contest_insert_stmt = $database_connection->prepare('
            INSERT INTO contest_submissions (btc_address, ip_address)
            VALUES (:btc_address, :ip_address)
        ');
        $contest_insert_stmt->execute([
            'btc_address' => $_POST['btc_address'],
            'ip_address' => $_SERVER['REMOTE_ADDR'],
        ]);
    }
    catch (PDOException $contest_insert_exception)
    {
        // was the error caused by a duplicate value?
        if ($contest_insert_exception->errorInfo[1] == MYSQL_ER_DUP_ENTRY)
        {
            $errors[] = 'This Bitcoin address has already been entered.';
        }
        else
        {
            // a different error, rethrow exception
            throw $contest_insert_exception;
        }
    }
}
Edited by Jacques1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.