0

I am doing updation of table using following prepared statements as follows:

 $query = " UPDATE signup SET name=?,password=?,verify_key=? WHERE email=? ";
 $stmt=$conn->prepare($query);
 $stmt->bind_param("ssss",$dname,$password,$verify_key,$email);
 $stmt->execute();
 $stmt->close();

But it is giving error on which I am stuck for long time:

Fatal error: Call to a member function bind_param() on boolean in somefile.php on line 75

Structure of table in database is as follow:

mysql> desc signup;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| sid        | int(11)      | NO   | PRI | NULL    | auto_increment |
| name       | varchar(100) | NO   |     | NULL    |                |
| email      | varchar(100) | NO   | UNI | NULL    |                |
| password   | varchar(255) | NO   |     | NULL    |                |
| verify_key | varchar(255) | NO   |     | NULL    |                |
| active     | bit(1)       | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

Note : I printed $dname,$password,$verify_key,$email. All printed correct string values.

Entire PHP code:

<?php
session_start();
ob_start();
require_once("connection.php");

$dname=$_POST['dname'];
$email=$_POST['email'];
$password=$_POST['password'];

if(empty($dname) || empty($email) || empty($password))
  die("Enter correct details.");

$password = password_hash($password,PASSWORD_DEFAULT); // generate hash for password
$verify_key = password_hash(RandomString(),PASSWORD_DEFAULT); // generate hash for verification key

/* RandomString() generates random string */
function RandomString($length = 32) {
      $randstr;
      //our array add all letters and numbers if you wish
      $chars = array(
          'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'p',
          'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5',
          '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
          'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');
      for ($rand = 0; $rand <= $length; $rand++) {
          $random = rand(0, count($chars) - 1);
          $randstr .= $chars[$random];
      }
      return $randstr;
}  // function RandomString()  over

/*  Mail Sending Code */
function sendMail($email,$verify_key){
$to = $email;
$subject = 'Something';
$mail_link='https://127.0.0.1/rs/signupCheck.php?email='.$email.'&key='.$verify_key;
$message = "
<html>
<head>
  <title></title>
</head>
<body>
<p>
<a href='> Click this link to verify your account </a>
</p>
</body>
</html>
";

// To send HTML mail, the Content-type header must be set
$headers[] = 'MIME-Version: 1.0';
$headers[] = 'Content-type: text/html; charset=iso-8859-1';
$headers[] = 'From: Something <Something>';
$res = mail($to, $subject, $message, implode("\r\n", $headers));
return $res;  //check officially mail is sent or not
}  // function sendMain() ends


// check if email already exists in database
$query = " SELECT active FROM signup WHERE email=?";
$stmt = $conn->prepare($query);
$stmt->bind_param("s",$email);
$stmt->execute();
$stmt->bind_result($dbactive);
if($stmt->fetch()){     // email is present in DB
if($dbactive==1){        // status=1
  $stmt->close();
  die("Account already created. Try forget passwod if you can't access it.");
}
else{
  /* Record is already present with status=0 , override all the details */
  if(sendMail($email,$verify_key)) {  // send mail first then update DB
     $query = " UPDATE `signup` SET `name`=?,`password`=?,`verify_key`=? WHERE `email`=? ";
     $stmt=$conn->prepare($query);
     $stmt->bind_param("ssss",$dname,$password,$verify_key,$email);
     $stmt->execute();
     $stmt->close();
     die("We sent you verification link on mail. Click it to verify !!!");
  }
  else {
    die("Mail sending failed. Try again !!!");
  }
}
}      // email already present with either status=1 or status=0
else { // Insert account details in DB , nothing is present in DB for user
     if(sendMail($email,$verify_key)) {  // send mail first then update DB
       $query = "INSERT INTO signup (sid,name,email,password,verify_key,active)VALUES(?,?,?,?,?,?)";
       $stmt = $conn->prepare($query);
       $stmt->bind_param("issssi",$fixed_sid='',$dname,$email,$password,$verify_key,$fixed_active=0);
        /* Notice $fixed_sid and $fixed_active , it is needed
           you can't have fixed values in bind_param
        */
       $stmt->execute();
       $stmt->close();
       die("We sent you verification link on mail. Click it to verify !!!");
     }
     else {
       die("Mail sending failed. Try again !!!");
     }
}    // first time data entry in DB
?>
14
  • 2
    You prepare statment return false .. could be you have some wrong column name .. check for error .. Commented Apr 9, 2017 at 16:55
  • You need to pass the variables by reference. Commented Apr 9, 2017 at 16:56
  • @cybermonkey problem is in prepare not in bind_param. Commented Apr 9, 2017 at 16:57
  • @u_mulder I know, the variables still need to be passed by reference regardless. The query should also be properly formatted to prevent MySQLi interpreting table/column names as reserved words. Commented Apr 9, 2017 at 16:57
  • And what reserved word do you see here? Commented Apr 9, 2017 at 17:03

2 Answers 2

4

Add $stmt->close(); before your next mysqli interaction.

if(sendMail($email,$verify_key)) {  // send mail first then update DB
    $stmt->close();
    $query = " UPDATE `signup` SET `name`=?,`password`=?,`verify_key`=? WHERE `email`=? ";

or you might just always want to execute the close after you're finished with your previous mysql interaction.

e.g.:

$query = " SELECT active FROM signup WHERE email=?";
$stmt = $conn->prepare($query);
$stmt->bind_param("s",$email);
$stmt->execute();
$stmt->bind_result($dbactive);
$stmt->close();

and remove the $stmt->close(); from the if. I've never seen official documentation on this but I've seen other threads were this was an underlying issue. The manual page itself actual almost states the opposite:

So, while explicitly closing open connections and freeing result sets is optional, doing so is recommended.

that is optional is false (... in my experience, I also primarily use PDO).

Sign up to request clarification or add additional context in comments.

Comments

1

I had an issue in my query and this line of code help me to diagnose my error

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

here is reference may be it help you
https://websitebeaver.com/prepared-statements-in-php-mysqli-to-prevent-sql-injection

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.