Help with very stubborn code validation, I can't figure it out!

Basically, I have an invite system in PHP. A user gets invited and this creates a unique code, and also gathers the invitee’s e-mail and puts it into a DB. They are then sent e-mail with the link and the code in the URL

Now, here’s the tricky part: The script works, but only if the exact code is used, or if the code equals “activated”, then the validation works. If the passed code is anything different, doesn’t exist (not passed, etc.) it throws the following errors repeatedly during testing:

Warning: Undefined array key 0 in /var/www/vhosts/x.com/httpdocs/contact/index.php on line 13

Warning: Trying to access array offset on value of type null in /var/www/vhosts/x.com/httpdocs/contact/index.php on line 13

Warning: Undefined array key 0 in /var/www/vhosts/x.com/httpdocs/contact/index.php on line 19

Warning: Trying to access array offset on value of type null in /var/www/vhosts/x.com/contact/index.php on line 19

Now,the code stiill works besides the warnings, but if you click “Send” (on a simple form) it will work, but seems to just go through the DB adding “activated” to everyone’s user rec in order. Very strange!

I need to have working validation if no code is present, or if the code does not match anything in the DB and is other than “activated”, and I also need to correct the issue where if you submit the form despite the PHP warnings, it oddly starts sticking “activated” in the DB.

Below is the complete code.

Any help would be most appreciated!! :smile:

For the errors, you need to -

  1. Trim, then validate the $_GET[‘code’] input, before using it. If the trimmed value is an empty string, don’t attempt to use it. If the invite codes have a specific format, such as a fixed length, or all numbers/letters, validate that too. Either setup and display an error message that the invite code is invalided or output nothing to the visitor/bot that submitted the wrongly supplied value. You would also want to log the datetime, ip address, and the submitted invite code, so that you have a record of bad requests.
  2. You need to test if a query matched a row of data, before using the result from the query. The fetch statement will return a false value if the query didn’t match any data. You need to test $result before proceeding to use the value in $result. You should also log the datetime, ip address, and submitted invite code when the query doesn’t match a row of data.

Some points about the code -

  1. $_GET is always set, even if it is empty, so the conditional logic starting with if(isset($_GET)) {will always be executed, Why do you have that conditional test in the code?
  2. Why do you have three SELECT queries? The submitted invite code will either exist or it won’t. All you need is one SELECT query.
  3. You should list out the columns you are SELECTing. This makes your code self-documenting, so that anyone you ask to read it can tell what you are trying to accomplish.
  4. When a query is expected to match at most one row of data, don’t use fetch_all(), just fetch the single row of data.
  5. Because you are updating the code column to ‘activated’, your logic testing if a submitted invite code has already been used won’t work. You would need to have a separate status column, that you would update to ‘activated’ and leave the invite code in the code column.

As to your description concerning a form and adding ‘activated’ to everyone’s user record in order, what form? We cannot help with something if we don’t have the code that produces the problem.

1 Like

Another way in verifying a user is to send the validation/activation code to a page and forcing the user to re-enter his/her security credentials and even have them answer a question?

Here’s my Activate page →

<?php
require_once 'assets/config/config.php';
require_once "vendor/autoload.php";

use FanOfLEGO\Register;

try {
    $today = new DateTime('today', new DateTimeZone("America/Detroit"));
} catch (Exception $e) {
}
$data['validation'] = $today->format("Y-m-d H:i:s");

if (($_SERVER['REQUEST_METHOD'] === 'GET') && isset($_GET['confirmation'])) {
    $data['validation'] = htmlspecialchars($_GET['confirmation']);
}

if (($_SERVER['REQUEST_METHOD'] === 'POST') && isset($_POST['submit'])) {

    $username = $_POST['user']['username'];
    $hashed_password = $_POST['user']['hashed_password'];
    $validation = $_POST['user']['validation'];
    $answer = $_POST['user']['answer'];

    $result = Register::activate($username, $hashed_password, $validation, $answer);

    if ($result) {
        header('Location: message.php');
        exit();
    }


}

?>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=yes, initial-scale=1.0">
    <title>Activate</title>
    <link rel="stylesheet" media="all" href="assets/css/styles.css">
</head>
<body class="site">
<header class="headerStyle">

</header>
<?php include_once 'assets/includes/inc.navigation.php'; ?>
<section class="main">
    <form id="activate" class="login" method="post" action="activate.php">
        <input type="hidden" name="user[validation]" value="<?= $data['validation'] ?>">
        <label class="text_username" for="username">Username</label>
        <input id="username" class="io_username" type="text" name="user[username]" value="" required>
        <label class="text_password" for="password">Password</label>
        <input id="password" class="io_password" type="password" name="user[hashed_password]" required>
        <label for="question">What country does LEGO originate from?</label>

        <select id="question" class="select-css" name="user[answer]">
            <option value="Norway" selected>Norway</option>
            <option value="Denmark">Denmark</option>
            <option value="United States">United States</option>
            <option value="Germany">Germany</option>
        </select>

        <button id="submitForm" type="submit" name="submit" value="enter" tabindex="10">Submit</button>
    </form>
</section>
<?php include_once "assets/includes/inc.sidebar.php" ?>
<?php include_once 'assets/includes/inc.footer.php'; ?>

</body>
</html>

Then you just replace the activation string and upgrade their security level -

Just an example -

    public static function activate($username, $hashed_password, $validation, $answer): bool
    {

        static::$searchItem = 'username';
        static::$searchValue = htmlspecialchars($username);
        $sql = "SELECT id, security, hashed_password, validation FROM " . static::$table . " WHERE username =:username LIMIT 1";
        $result = static::fetch_by_column_name($sql);
        if (password_verify($hashed_password, $result['hashed_password'])) {

            unset($result['hashed_password']);
            /*
             * Update General Level to next level
             * which is member status.
             */
            if ($result['validation'] === $validation && $answer === "Denmark") {
                $sql = 'UPDATE admins SET security=:security, validation=:validation WHERE id=:id';
                Database::pdo()->prepare($sql)->execute(['security' => 'member', 'validation' => 'validate', 'id' => $result['id']]);
                return true;
            }
        }

        return false;

    }

It’s not full proof, but I think it’s pretty secure and besides I’m not running a banking website. :rofl:

I always tell people that I know never to use passwords that they use for important transactions on social media websites or my own websites that I develop anyways.

Here’s the active page - Activate

I figure once a person has been activated there’s no need to say already activated if they try again and besides I do send them to a welcoming page for members.

1 Like

Okay, got it. I was comparing the code passed in the URL to itself. I instead used $code2 for the code in the DB and then compared this to the code passed ($code). I also added validation if the code does not exist.

Everything works! Thanks!! :smiley:

A bit complex for what I need. Thank you for your time! :grin:

Strider64,

Hope you got your website fixed.

I’ve checked out your website and it’s looks pretty neat. However, if you want to attract a broader of potential customers, you should make your website responsive for Tablet and Cell Phone users.

There’s allot of responsive web page templates out there that are free and all you have to do is modify it to what you need and your preference.

1 Like
Sponsor our Newsletter | Privacy Policy | Terms of Service