Jump to content

Recommended Posts

Hello,

I'm looking to log the last logged in IP address from my users' accounts and their IP address used on registration. I would prefer to store the IP addresses in my database (`last_ip`) and (`registered_ip`)

As far as I'm aware, the best way to store an IP address in MySQL is VARBINARY(16) for IPV6 and VARBINARY(4) for IPV4.

Login.php

<?php
// Initialize the session
session_start();
 
// Check if the user is already logged in, if yes then redirect to dashboard
if(isset($_SESSION["loggedin"]) && $_SESSION["loggedin"] === true){
    header("location: dashboard.php");
    exit;
}

// Include ShareX config file
$config = include('../i/cfg/config.php');

// Include ASE config file
include_once('../ase/cfg/config.php');

// Define variables and initialize with empty values
$username = $password = "";
$username_err = $password_err = $login_err = "";

// Processing form data when form is submitted
if ($_SERVER["REQUEST_METHOD"] == "POST")
{

    // Check if username is empty
    if (empty(trim($_POST["username"])))
    {
        $username_err = "Please enter your username.";
    }
    else
    {
        $username = trim($_POST["username"]);
    }

    // Check if password is empty
    if (empty(trim($_POST["password"])))
    {
        $password_err = "Please enter your password.";
    }
    else
    {
        $password = trim($_POST["password"]);
    }

    // Validate credentials
    if (empty($username_err) && empty($password_err))
    {
        // Prepare a select statement
        $sql = "SELECT userID, username, password FROM users WHERE username = ?";

        if ($stmt = mysqli_prepare($link, $sql))
        {
            // Bind variables to the prepared statement as parameters
            mysqli_stmt_bind_param($stmt, "s", $param_username);

            // Set parameters
            $param_username = $username;

            // Attempt to execute the prepared statement
            if (mysqli_stmt_execute($stmt))
            {
                // Store result
                mysqli_stmt_store_result($stmt);

                // Check if username exists, if yes then verify password
                if (mysqli_stmt_num_rows($stmt) == 1)
                {
                    // Bind result variables
                    mysqli_stmt_bind_result($stmt, $userID, $username, $hashed_password);
                    if (mysqli_stmt_fetch($stmt))
                    {
                        if (password_verify($password, $hashed_password))
                        {
                            // Password is correct, so start a new session
                            session_start();

                            // Store data in session variables
                            $_SESSION["loggedin"] = true;
                            $_SESSION["userID"] = $userID;
                            $_SESSION["username"] = $username;

                            // Redirect user to welcome page
                            header("location: dashboard.php");
                        }
                        else
                        {
                            // Password is not valid, display a generic error message
                            $login_err = "Invalid username or password.";
                        }
                    }
                }
                else
                {
                    // Username doesn't exist, display a generic error message
                    $login_err = "Invalid username or password.";
                }
            }
            else
            {
                echo "Oops! Something went wrong. Please try again later.";
            }

            // Close statement
            mysqli_stmt_close($stmt);
        }
    }

    // Close connection
    mysqli_close($link);
}
?>

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
        <meta name="description" content="Personal image hosting powered by ShareX" />
        <meta name="author" content="" />
        <title>ASE - Login</title>
        <link rel="icon" href="assets/img/favicon.ico" type="image/x-icon">
        <link href="css/styles.css" rel="stylesheet" />
        <script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
    </head>
    <body class="bg-primary">
        <div id="layoutAuthentication">
            <div id="layoutAuthentication_content">
                <main>
                    <div class="container">
                        <div class="row justify-content-center">
                            <div class="col-lg-5">
                                <div class="card shadow-lg border-0 rounded-lg mt-5">
                                    <div class="card-header"><h3 class="text-center font-weight-light my-4">All Seeing Eye</h3></div>
                                    <div class="card-body">
                                        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="POST" class="my-login-validation" novalidate="">
                                            <!-- Username -->
                                            <div class="form-floating mb-3">
                                                <input id="username" type="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>" name="username" required>
                                                <label for="username">Username</label>
                                                <div class="invalid-feedback">
                                                <?php echo $username_err; ?>
                                                </div>
                                            </div>
                                            <!-- Password -->
                                            <div class="form-floating mb-3">
                                                <input id="password" type="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>" name="password" required>
                                                <label for="password">Password</label>
                                                <div class="invalid-feedback">
                                                <?php echo $password_err; ?>
                                                </div>
                                            </div>
                                            <!-- Remember Me -->
                                            <div class="form-check mb-3">
                                                <input class="form-check-input" id="rememberMe" type="checkbox" value="lsRememberMe" required />
                                                <label class="form-check-label" for="rememberMe">Remember Password</label>
                                            </div>
                                            <!-- Forgot Password -->
                                            <div class="d-flex align-items-center justify-content-between mt-4 mb-0">
                                                <a class="small" href="#">Forgot Password?</a>
                                                <input type="submit" value="Login" class="btn btn-primary btn-block" onclick="lsRememberMe()"></input>
                                            </div>
                                        </form>
                                    </div>
                                    <div class="card-footer text-center py-3">
                                        <div class="small">Need an account? <a href="register.php">Create One</a></div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </main>
            </div>
            <!-- Footer -->
            <div id="layoutAuthentication_footer">
                <footer class="py-4 bg-light mt-auto">
                    <div class="container-fluid px-4">
                        <div class="d-flex align-items-center justify-content-between small">
                            <div class="text-muted">Copyright &copy; 2025 &mdash;</div>
                            <div>
                                <a href="#">Privacy Policy</a>
                                &middot;
                                <a href="#">Terms &amp; Conditions</a>
                            </div>
                        </div>
                    </div>
                </footer>
            </div>
        </div>
        <!-- JavaScript -->
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
        <script src="js/scripts.js"></script>
        <script src="js/rememberme.js"></script>
    </body>
</html>

Register.php

<?php
// Include ShareX config file
include('../i/cfg/config.php');

// Include ASE config file
require_once "../ase/cfg/config.php";

// Define variables and initialize with empty values
$username = $email = $password = $confirm_password = "";
$username_err = $email_err = $password_err = $confirm_password_err = "";

// Processing form data when form is submitted
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
    // Validate username
    if (empty(trim($_POST["username"])))
    {
        $username_err = "Please enter a username.";
    }
    elseif (!preg_match('/^[a-zA-Z0-9_]{3,}$/', trim($_POST["username"])))
    {
        $username_err = "Username must contain the following:<br/><li>Minimum 3 characters long.</li><li>Only letters, numbers, and underscores.";
    }
    else
    {
        // Prepare a select statement
        $sql = "SELECT userID FROM users WHERE username = ?";

        if ($stmt = mysqli_prepare($link, $sql))
        {
            // Bind variables to the prepared statement as parameters
            mysqli_stmt_bind_param($stmt, "s", $param_username);

            // Set parameters
            $param_username = trim($_POST["username"]);

            // Attempt to execute the prepared statement
            if (mysqli_stmt_execute($stmt))
            {
                /* Store result */
                mysqli_stmt_store_result($stmt);

                if (mysqli_stmt_num_rows($stmt) == 1)
                {
                    $username_err = "This username is already taken.";
                }
                else
                {
                    $username = trim($_POST["username"]);
                }
            }
            else
            {
                echo "Oops! Something went wrong. Please try again later.";
            }

            // Close statement
            mysqli_stmt_close($stmt);
        }
    }

        if (empty(trim($_POST["email"])))
    {
        $email_err = "Please enter your email address.";
    }
    elseif (!filter_var(trim($_POST["email"]), FILTER_VALIDATE_EMAIL))
    {
        $email_err = "Please enter a valid email address.";
    }
    else
    {
        // Prepare a select statement
        $sql = "SELECT userID FROM users WHERE email = ?";

        if ($stmt = mysqli_prepare($link, $sql))
        {
            // Bind variables to the prepared statement as parameters
            mysqli_stmt_bind_param($stmt, "s", $param_email);

            // Set parameters
            $param_email = trim($_POST["email"]);

            // Attempt to execute the prepared statement
            if (mysqli_stmt_execute($stmt))
            {
                mysqli_stmt_store_result($stmt);

                if (mysqli_stmt_num_rows($stmt) == 1)
                {
                    $email_err = "This email address is already taken.";
                }
                else
                {
                    $email = trim($_POST["email"]);
                }
            }
            else
            {
                echo "Oops! Something went wrong. Please try again later.";
            }

            mysqli_stmt_close($stmt);
        }
    }

    // Validate password
    if (empty(trim($_POST["password"]))) {
        $password_err = "Please enter a password.";
    } elseif (!preg_match('/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&_-])[A-Za-z\d@$!%*?&_-]{8,}$/', trim($_POST["password"]))) {
        $password_err = "Password must contain the following sequence:";
    } else {
        $password = trim($_POST["password"]);
    }

    // Validate confirm password
    if (empty(trim($_POST["confirm_password"]))) {
        $confirm_password_err = "Please confirm your password.";
    } else {
        $confirm_password = trim($_POST["confirm_password"]);
        if (empty($password_err) && $password != $confirm_password) {
            $confirm_password_err = "Password did not match.";
        }
    }

    // Check input errors before inserting in database
     if (empty($username_err) && empty($email_err) && empty($password_err) && empty($confirm_password_err))
    {
        // Prepare an insert statement
        $sql = "INSERT INTO users (username, email, password) VALUES (?, ?, ?)";


        if ($stmt = mysqli_prepare($link, $sql))
        {
            // Bind variables to the prepared statement as parameters
            mysqli_stmt_bind_param($stmt, "sss", $param_username, $param_email, $param_password);
            // Set parameters
            $param_username = $username;
            $param_email = $email;
            $param_password = password_hash($password, PASSWORD_BCRYPT); // BCRYPT hashing
            // Attempt to execute the prepared statement
            if (mysqli_stmt_execute($stmt))
            {
                // Redirect to login page
                header("location: index.php");
            }
            else
            {
                echo "Oops! Something went wrong. Please try again later.";
            }

            // Close statement
            mysqli_stmt_close($stmt);
        }
    }

    // Close connection
    mysqli_close($link);
}

?>

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
        <meta name="description" content="Personal image hosting powered by ShareX" />
        <meta name="author" content="" />
        <link rel="icon" href="assets/img/favicon.ico" type="image/x-icon">
        <title>ASE - Register</title>
        <link href="css/styles.css" rel="stylesheet" />
        <script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
    </head> 
    <body class="bg-primary">
        <div id="layoutAuthentication">
            <div id="layoutAuthentication_content">
                <main>
                    <div class="container">
                        <div class="row justify-content-center">
                            <div class="col-lg-7">
                                <div class="card shadow-lg border-0 rounded-lg mt-5">
                                    <div class="card-header"><h3 class="text-center font-weight-light my-4">Create Account</h3></div>
                                    <div class="card-body">
                                        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="POST" class="my-login-validation" novalidate="" id="registration_form">
                                            <!-- Username -->
                                            <div class="form-floating mb-3">
                                                <input id="username" type="text" class="form-control <?php echo !empty($username_err) ? "is-invalid" : ""; ?>" value="<?php echo $username; ?>" name="username" required autofocus>
                                                <label for="username">Username</label>
                                                <div class="invalid-feedback">
                                                <?php echo $username_err; ?>
                                            </div>
                                            </div>
                                            <!-- Email -->
                                            <div class="form-floating mb-3">
                                                <input id="email" type="text" class="form-control <?php echo !empty($email_err) ? "is-invalid" : ""; ?>" value="<?php echo $email; ?>" name="email" required autofocus>
                                                <label for="email">Email Address</label>
                                                <div class="invalid-feedback">
                                                <?php echo $email_err; ?>
                                            </div>
                                            </div>
                                            <!-- Password -->
                                            <div class="row mb-3">
                                                <div class="col-md-6">
                                                    <div class="form-floating mb-3 mb-md-0">
                                                        <input id="password" type="password" class="form-control <?php echo !empty($password_err) ? "is-invalid" : ""; ?>" value="<?php echo $password; ?>" name="password" required data-eye oninput="validatePassword(this.value)" minlength="8">
                                                        <label for="password">Password</label>
                                                        <div class="invalid-feedback">
                                                        <?php echo $password_err; ?>
                                                    </div>
                                                <!-- Password Strength Meter -->
                                                <div class="form-group">
                                                    <span id="errorMessage" class="font-weight-bold text-danger" style="font-style: italic;"></span>
                                                <ul>
                                                    <li id="minLength"><i class="fas fa-times text-danger"></i> Minimum 8 characters</li>
                                                    <li id="uppercase"><i class="fas fa-times text-danger"></i> At least one uppercase letter</li>
                                                    <li id="lowercase"><i class="fas fa-times text-danger"></i> At least one lowercase letter</li>
                                                    <li id="symbol"><i class="fas fa-times text-danger"></i> At least one symbol (@$!%*?&_-)</li>
                                                </ul>
                                                </div>
                                                    </div>
                                                </div>
                                                <!-- Confirm Password -->
                                                <div class="col-md-6">
                                                    <div class="form-floating mb-3 mb-md-0">
                                                        <input id="confirm_password" type="password" class="form-control <?php echo !empty($confirm_password_err) ? "is-invalid" : ""; ?>" value="<?php echo $confirm_password; ?>" name="confirm_password" required data-eye minlength="8">
                                                        <label for="confirm_password">Confirm Password</label>
                                                        <div class="invalid-feedback">
                                                        <?php echo $confirm_password_err; ?>
                                                        </div>
                                                    </div>
                                                </div>
                                                <!-- reCaptcha -->
                                                <div class="form-group">
                                                    <div class="g-recaptcha" data-sitekey="6LdSlSAUAAAAAM3UIiPUhr9zSF8OgTT7uzQBSOcU" data-callback="verifyRecaptchaCallback" data-expired-callback="expiredRecaptchaCallback"></div>
                                                        <input class="form-control d-none" data-recaptcha="true" required data-error="Please complete the Captcha">
                                                    <div class="help-block with-errors"></div>
                                                </div>
                                            </div>
                                            <!-- T&C's -->
                                            <div class="form-group">
                                                <div class="custom-checkbox custom-control">
                                                <input type="checkbox" name="agree" id="agree" class="custom-control-input" required="">
                                                <label for="agree" class="custom-control-label">I agree to the <a href="#">Terms and Conditions</a></label>
                                            <div class="invalid-feedback">
                                            You must agree with our Terms and Conditions.
                                        </div>
                                    </div>
                                        </div>
                                            <!-- Submit Form -->
                                            <div class="mt-4 mb-0">
                                                <div class="d-grid">
                                                    <input type="submit" name="register-btn" class="btn btn-primary" value="Login"></input>
                                                </div>
                                                    <!-- <button type="button" class="btn btn-danger btn-block">Registration is Closed</button></div> -->
                                            </div>
                                        </form>
                                    </div>
                                    <div class="card-footer text-center py-3">
                                        <div class="small">Already have an account? <a href="index.php"> Sign In</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </main>
            </div>
            <!-- Footer -->
            <div id="layoutAuthentication_footer">
                <footer class="py-4 bg-light mt-auto">
                    <div class="container-fluid px-4">
                        <div class="d-flex align-items-center justify-content-between small">
                            <div class="text-muted">Copyright &copy; 2025 &mdash;</div>
                            <div>
                                <a href="#">Privacy Policy</a>
                                &middot;
                                <a href="#">Terms &amp; Conditions</a>
                            </div>
                        </div>
                    </div>
                </footer>
            </div>
        </div>
        <!-- JavaScript -->
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
        <script src="js/scripts.js"></script>
        <script src="js/password-strength.js"></script>
        <script src='https://www.google.com/recaptcha/api.js' async defer></script>
    </body>
</html>

 

You've got three basic options for storage: a string, a number, or as binary

A string is the obvious choice because human beings think of IP addresses as strings. You can support IPv4 and IPv6 easily because it's just a string. You can do exact searches because it's just a string, but CIDR-ranged searches are hard.
A number is another choice, as an IP address is essentially a number. That's fine for IPv4 addresses, but the IPv6 is too large to support. Exact and CIDR searches are easy.
There's also binary, which is probably the least convenient form to work with. It has the strengths of strings (variable-width) but its own disadvantages (binary data, inefficient ranged searches), as well as the strength of numbers (efficient storage) as well as their disadvantages (need to convert to/from string format).

If you don't need ranged searches then use strings, if you think you need ranged searches then think again because you probably don't. Because this is one of those times where you can get lost overthinking the problem.

Besides that,

Don't store just the last IP address. Store all of them. Since you're dealing with user accounts you'll also have a session, and in there you can remember the IP address, and that means you can know if it changes (which would mostly mean a mobile device switching networks, but even that isn't especially common these days).
Fun side effect of this is that you're more likely to think about session security, like how you should reauthenticate a user if a request comes from the "wrong" IP address...

 

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.