ScreaMyCZE
ScreaMyCZE

Reputation: 65

How to fix mysqli_stmt_close invalid object error?

I was programming my login system, but I got an error that I cannot fix:

Warning: mysqli_stmt_close(): invalid object or resource mysqli_stmt in C:\Users\Acer\Desktop\xampp\htdocs\Login System\includes\signup.inc.php on line 61.

When I save the file and open it, everything works fine until data must be sent to the database. In that moment I get that error and the database is empty.

Here is the code

<?php
if (isset($_POST['signup-submit'])) {
    require 'dbh.inc.php';

    $username = $_POST['uid'];
    $email = $_POST['mail'];
    $password = $_POST['pwd'];
    $passwordrepeat = $_POST['pwd-repeat'];

    if (empty($username) || empty($email) || empty($password) || empty($passwordrepeat)) {
        header("Location: ../signup.php?error=emptyfields&uid=".$username."&mail=".$email);
        exit();
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL) && !preg_match("/^[a-zA-Z0-9]*$/", $username)) {
        header("Location: ../signup.php?error=invalidmailuid");
        exit();
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        header("Location: ../signup.php?error=invalidmail&uid=".$username);
        exit();
    } elseif (!preg_match("/^[a-zA-Z0-9]*$/", $username)) {
        header("Location: ../signup.php?error=invaliduid&mail=".$email);
        exit();
    } elseif ($password !== $passwordrepeat) {
        header("Location: ../signup.php?error=passcheck&uid=".$username."&mail=".$email);
        exit();
    } else {
        $sql = "SELECT uidUsers FROM users WHERE uidUsers=?";
        $stmt = mysqli_stmt_init($conn);
        if (!mysqli_stmt_prepare($stmt, $sql)) {
            header("Location: ../signup.php?error=sqlerror");
            exit();
        }
        else {
        mysqli_stmt_bind_param($stmt, "s", $username);
        mysqli_stmt_execute($stmt);
        mysqli_stmt_store_result($stmt);
        $resultCheck = mysqli_stmt_num_rows($stmt);  
        if ($resultCheck > 0){
        header("Location: ../signup.php?error=usertaken&mail=".$email);
        exit();
        }
        else {
        $sql = "INSERT INTO users (uidUsers, mailUsers, pwdUsers) VALUES (?, ?, ?)";
        $stmt = mysqli_stmt_init($conn);
         if (!mysqli_stmt_prepare($stmt, $sql)) {


         }
         else {
            $hashedPwd = password_hash($password, PASSWORD_DEFAULT);

            mysqli_stmt_bind_param($stmt, "sss", $username, $email, $hashedPwd);
            mysqli_stmt_execute($stmt);
            header("Location: ../signup.php?signup=success");
            exit();
            }
        }
      }


    }
    mysqli_stmt_close($stmt);
    mysqli_close($conn);
}
else {
header("Location: ../signup.php");
exit();
}

Upvotes: 0

Views: 383

Answers (1)

elixenide
elixenide

Reputation: 44831

TL;DR You call mysqli_stmt_close($stmt); in a section of code where $stmt may not be set.

The Problem

Your primary problem here is that you can't tell what code is running before you get to the mysqli_stmt_close(). There are two reasons for this: (1) too much code complexity and (2) bad (no) formatting.

Fixing Your Formatting

The earlier versions of your post included code that wasn't formatted at all (it looks like you have edited it to make it better, but it still has some problems). Formatted properly, your code looks like this:

<?php
if (isset($_POST['signup-submit'])) {
    require 'dbh.inc.php';

    $username = $_POST['uid'];
    $email = $_POST['mail'];
    $password = $_POST['pwd'];
    $passwordrepeat = $_POST['pwd-repeat'];

    if (empty($username) || empty($email) || empty($password) || empty($passwordrepeat)) {
        header("Location: ../signup.php?error=emptyfields&uid=" . $username . "&mail=" . $email);
        exit();
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL) && !preg_match("/^[a-zA-Z0-9]*$/", $username)) {
        header("Location: ../signup.php?error=invalidmailuid");
        exit();
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        header("Location: ../signup.php?error=invalidmail&uid=" . $username);
        exit();
    } elseif (!preg_match("/^[a-zA-Z0-9]*$/", $username)) {
        header("Location: ../signup.php?error=invaliduid&mail=" . $email);
        exit();
    } elseif ($password !== $passwordrepeat) {
        header("Location: ../signup.php?error=passcheck&uid=" . $username . "&mail=" . $email);
        exit();
    } else {
        $sql = "SELECT uidUsers FROM users WHERE uidUsers=?";
        $stmt = mysqli_stmt_init($conn);
        if (!mysqli_stmt_prepare($stmt, $sql)) {
            header("Location: ../signup.php?error=sqlerror");
            exit();
        } else {
            mysqli_stmt_bind_param($stmt, "s", $username);
            mysqli_stmt_execute($stmt);
            mysqli_stmt_store_result($stmt);
            $resultCheck = mysqli_stmt_num_rows($stmt);
            if ($resultCheck > 0) {
                header("Location: ../signup.php?error=usertaken&mail=" . $email);
                exit();
            } else {
                $sql = "INSERT INTO users (uidUsers, mailUsers, pwdUsers) VALUES (?, ?, ?)";
                $stmt = mysqli_stmt_init($conn);
                if (!mysqli_stmt_prepare($stmt, $sql)) {


                } else {
                    $hashedPwd = password_hash($password, PASSWORD_DEFAULT);

                    mysqli_stmt_bind_param($stmt, "sss", $username, $email, $hashedPwd);
                    mysqli_stmt_execute($stmt);
                    header("Location: ../signup.php?signup=success");
                    exit();
                }
            }
        }
    }
    mysqli_stmt_close($stmt);
    mysqli_close($conn);
} else {
    header("Location: ../signup.php");
    exit();
}

In the future, you should use an IDE like PHPStorm, which will help you tremendously with formatting your code and catching obvious errors like this.

Finding the Error

For simplicity, let's just look at the structure of your code (... indicates code I'm leaving out here):

<?php
if (isset($_POST['signup-submit'])) {
    require 'dbh.inc.php';

    $username = $_POST['uid'];
    $email = $_POST['mail'];
    $password = $_POST['pwd'];
    $passwordrepeat = $_POST['pwd-repeat'];

    if (empty($username) || empty($email) || empty($password) || empty($passwordrepeat)) {
        // ...
    } 
    // ... long series of elseif statements here...
    else {
        $sql = "SELECT uidUsers FROM users WHERE uidUsers=?";
        $stmt = mysqli_stmt_init($conn);
        // ...
    }
    mysqli_stmt_close($stmt);
    mysqli_close($conn);
} else {
    // ...
}

As you can see, $stmt is only set in one place, inside an else block. But you try to close it outside that else block, meaning that $stmt might never be set before you try to close it.

The Immediate Fix

Move your mysqli_stmt_close($stmt); inside the else statement where you set and use $stmt.

The Real Fix

This code is what we call "spaghetti code." I don't say that to be rude; it's just the reality of what you have here. To avoid these kinds of problems in the future:

  • Break your code into functions or classes.
  • Avoid deep, complicated if... elseif... else structures. When you have as many elseifs as you do, something has gone wrong.
  • Please learn how to properly format your code.
  • Use an IDE.

You really should read through PHP: The Right Way before you write any more code. It will save you a lot of heartburn.

Please note that you have some other problems in this code that I am not addressing here, such as injecting user input directly into URLs in header("Location:...") without any encoding or filtering. This could be used for, for example, malicious redirects or other nefarious activity. (You also likely have XSS problems on your other pages on your site.)

Upvotes: 2

Related Questions