I'm in the process of creating a game for myself and I have been using the MySQLi extension. This is really my first "big" project using it and so far I don't mind it too much, though I do find it very... verbose. Anyway, so far so good except this one issue I have run into regarding inserting a value into one of my tables. I have created a function to insert a user into the users table but it's failing and I am getting several PHP warnings. The following is the function.

/**
 * Inserts a user into the user table.
 *
 * @param mysqli $conn The database connection object.
 * @param string $email The user's email address.
 * @param string $password The user's hashed password.
 * @param string $salt The user's unique salt.
 * @param int $country The user's country.
 * @return bool Returns true if the user was inserted successfully or false if not.
 */
function insert_user($conn, $email, $password, $salt, $country)
{
	$query = "INSERT INTO users (user_email, user_pass, user_salt, country_id)
			VALUES (?, ?, ?, ?)";

//Prepare the query
$statement = mysqli_prepare($conn, $query);

//Bind the parameters
mysqli_stmt_bind_param($statement, 'sssi', $email, $password, $salt, $country);

//Execute the query
mysqli_stmt_execute($statement);

//Close the statement	
mysqli_stmt_close($statement);

return (mysqli_affected_rows($statement)) ? true : false;
}

The messages I am getting:

Warning: mysqli_stmt_bind_param() expects parameter 1 to be mysqli_stmt, boolean given in F:\Web\airline\api\registration.php on line 148

Warning: mysqli_stmt_execute() expects parameter 1 to be mysqli_stmt, boolean given in F:\Web\airline\api\registration.php on line 151

Warning: mysqli_stmt_close() expects parameter 1 to be mysqli_stmt, boolean given in F:\Web\airline\api\registration.php on line 154

Warning: mysqli_affected_rows() expects parameter 1 to be mysqli, boolean given in F:\Web\airline\api\registration.php on line 156

These error messages seem pretty straightforward and easily fixable if you read the manual for the specific functions (while I am transitioning to MySQLi I prefer to stick with a procedural approach). It seems obvious that my mistake is mysqli_prepare() does not return a statement object but a boolean instead. Silly me. But I also have the following function which works as expected:

/**
 * Checks if the email address is unique.
 *
 * @param mysqli $conn The database connection object.
 * @param string $email The email to check.
 * @return bool Returs true if the email address is unique or false if not.
 */
function unique_email($conn, $email)
{
	$query = "SELECT user_email
			FROM users
			WHERE user_email = ?";

//Prepare the query
$statement = mysqli_prepare($conn, $query);

//Bind the parameters
mysqli_stmt_bind_param($statement, 's', $email);

//Execute the statement
mysqli_stmt_execute($statement);

//Bind the result set
mysqli_stmt_bind_result($statement, $result);

//Fetch the result set
mysqli_stmt_fetch($statement);

//Close the statement
mysqli_stmt_close($statement);	

return (NULL == $result) ? true : false;
}

According to the manual, this should not work, but it does. It was only going back and rereading the manual did I notice this discrepancy (I haven't gone back and changed this function yet).

Anyway, I have noticed in a lot of the examples in the manual they use mysqli_stmt_init(), which does return a mysqli_stmt object. So I tried using that (removed some of the irrelevant code):

//Initialize a prepared statement
$statement = mysqli_stmt_init($conn);

//Prepare the query
mysqli_prepare($statement, $query);

//Bind the parameters
mysqli_stmt_bind_param($statement, 'sssi', $email, $password, $salt, $country);

//Execute the query
mysqli_stmt_execute($statement);

//Close the statement	
mysqli_stmt_close($statement);

return (mysqli_affected_rows($statement)) ? true : false;

But this also produces errors:

Warning: mysqli_prepare() expects parameter 1 to be mysqli, object given in F:\Web\airline\api\registration.php on line 148

Warning: mysqli_stmt_bind_param(): invalid object or resource mysqli_stmt in F:\Web\airline\api\registration.php on line 151

Warning: mysqli_stmt_execute(): invalid object or resource mysqli_stmt in F:\Web\airline\api\registration.php on line 154

Warning: mysqli_stmt_close(): invalid object or resource mysqli_stmt in F:\Web\airline\api\registration.php on line 157

Warning: mysqli_affected_rows() expects parameter 1 to be mysqli, object given in F:\Web\airline\api\registration.php on line 159

Notably it says that mysqli_prepare() expects the first parameter to mysqli, but the manual page for [man]mysqli_prepare/man specifically states that it returns a mysqli_statement object for mysqli_prepare().

If I try to echo out mysqli_stmt_error() or mysqli_error() I get an empty string.

I figured it must be my $conn variable that has an issue but I printed it out and I got the following (not sure what to expect so the problem may be evident here):

mysqli Object
(
    [affected_rows] => -1
    [client_info] => mysqlnd 5.0.10 - 20111026 - $Id: b0b3b15c693b7f6aeb3aa66b646fee339f175e39 $
    [client_version] => 50010
    [connect_errno] => 0
    [connect_error] => 
    [errno] => 0
    [error] => 
    [error_list] => Array
        (
        )

[field_count] => 1
[host_info] => localhost via TCP/IP
[info] => 
[insert_id] => 0
[server_info] => 5.5.25a
[server_version] => 50525
[stat] => Uptime: 413269  Threads: 2  Questions: 19489  Slow queries: 0  Opens: 392  Flush tables: 1  Open tables: 2  Queries per second avg: 0.047
[sqlstate] => 00000
[protocol_version] => 10
[thread_id] => 1046
[warning_count] => 0
)

You could say I am quite confused on how this all works. I am sure my mistake is obvious but I have been looking at this for so long that I cannot see it, which is why I hope another pair of eyes will notice my mistake. Sorry for the long post; I just wanted to present as much information as I could.

Thanks in advance!

    If MySQL is able to successfully parse and process the prepare query string, then the prepare function returns the statement object; but if MySQL figurative chokes on it for some reason, then the PHP function returns a Boolean false. Therefore, you need to check first that it's not false before trying to use it, and if it is false, log/output some debug info. A quick-and-dirty way:

    	//Prepare the query
    	$statement = mysqli_prepare($conn, $query);
    	if($statement == false) {
    		die("<pre>".mysqli_error($conn).PHP_EOL.$query."</pre>");
    	}
    

      Thanks NogDog for the insight!

      I added an if statement testing for false but it was never executing, nor was mysqli_error() ever printing anything. Eventually I got it to insert but I was still receiving a warning telling me that mysqli_affected_rows() required a mysqli and not a mysqli_stmt object, which at that point I noticed I was using the incorrect function and should have been using mysqlistmtaffected_rows().

        Write a Reply...