问题
I checked my code by replacing all the statements inside IF with a echo statement and its working fine..
if($rows==1){
echo "Record exists in DB";
}
I don't know why $result = mysqli_stmt_get_result($stmt); returning false and I am getting error as
Warning: mysqli_fetch_array() expects parameter 1 to be mysqli_result, boolean given in E:\xampp\htdocs\jq\login_system_sql_injection_proof\loginprocess.php on line 57
I Wasted more than a day for searching Solution over Internet but did not find any. I will be very Thankful if someone help me. I expect Solution in Procedural way. Thanks In Advance
<?php require("dbconnect.php"); ?>
<?php
$uname = $pass = "";
if($_SERVER['REQUEST_METHOD']=='POST'){
if(empty($_POST['uname'])){
header("location:loginform.php?error=".urlencode("Please enter your username"));
exit();
//$unameErr = "Please enter username";
}
else{
$uname = test_input($_POST["uname"]);
$uexp = "/^[a-zA-Z]*$/";
if(!preg_match($uexp,$uname)){
header("location:loginform.php?error=".urlencode("username should contaion only Alphabetic chars"));
exit();
//$unameErr = "only alphabets are allowed";
}
else $uname = mysqli_real_escape_string($con,$uname);
}
if(empty($_POST['pass'])){
header("location:loginform.php?error=".urlencode("Please enter your password"));
exit();
//$passErr = "Please enter password";
}
else{
$pass = test_input($_POST["pass"]);
$pass = mysqli_real_escape_string($con,$pass);
}
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
<?php
$query = "SELECT *FROM user WHERE user.username = ? AND user.password = ?";
$stmt = mysqli_prepare($con,$query);
if($stmt){
mysqli_stmt_bind_param($stmt,'ss',$uname,$pass);
$run = mysqli_stmt_execute($stmt);
if($run){
mysqli_stmt_store_result($stmt);
$rows = mysqli_stmt_num_rows($stmt);
if($rows==1){
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
echo $row['username'];
//session_start();
//$_SESSION['uid'] = $row['username'];
//header('location:welcome.php');
}
else{
header('location:loginform.php?error="Invalid username/password.. Please check and re-try login"');
}
}
else{
echo "Query Execution Failed";
}
}
else{
echo "Failed to Prepare Sql Statement";
}
?>
回答1:
Even if you've maybe found a solution, I'd like to present it myself to you too (tested with your code).
I'll begin with telling you, that your problem is actually that you don't use exception handling. If you would have done this, you would have discovered the real exception/error thrown by your php/mysqli. I recommend you to always apply exception handling, at least when you're querying databases. I'll present you the solution(s) encapsulated in a complete exception handling code. Feel free to ask me anything, if you need further explanations.
First let's see your code (just the second, querying part is relevant), edited by me and brought in my form.
Your code (error-prone):
<?php
/*
* Tested on table "user":
*
* ------------------------
* id username password
* ------------------------
* 1 John Smith
* 2 John Mark
*/
try {
// Your received POST values.
$uname = 'John';
$pass = 'Smith';
//---------------------------------------------------------
// Connect to db.
//---------------------------------------------------------
$con = mysqli_connect('<server>', '<user>', '<pass>', '<db>');
if (!$con) {
throw new Exception('Connect error:<br/><br/>' . mysqli_connect_errno() . ' - ' . mysqli_connect_error());
}
//---------------------------------------------------------
// Sql statement.
//---------------------------------------------------------
$query = "SELECT * FROM user WHERE user.username = ? AND user.password = ?";
//---------------------------------------------------------
// Prepare sql statement.
//---------------------------------------------------------
$stmt = mysqli_prepare($con, $query);
if (!$stmt) {
throw new Exception('The sql statement can not be prepared!');
}
//---------------------------------------------------------
// Binds variables to the prepared statement as parameters.
//---------------------------------------------------------
$bound = mysqli_stmt_bind_param($stmt, 'ss', $uname, $pass);
if (!$bound) {
throw new Exception('The variables could not be bound to the prepared statement!');
}
//---------------------------------------------------------
// Execute the prepared statement.
//---------------------------------------------------------
$executed = mysqli_stmt_execute($stmt);
if (!$executed) {
throw new Exception('The prepared statement could not be executed!');
}
//---------------------------------------------------------
// Transfers the result set from the prepared statement.
//---------------------------------------------------------
$stored = mysqli_stmt_store_result($stmt);
if (!$stored) {
throw new Exception('The result set from the prepared statement could not be transfered!');
}
//---------------------------------------------------------
// Get the number of rows in statements result set.
//---------------------------------------------------------
$rows = mysqli_stmt_num_rows($stmt);
if ($rows == 1) {
//---------------------------------------------------------
// Get the result set from the prepared statement.
//---------------------------------------------------------
$result = mysqli_stmt_get_result($stmt);
if (!$result) {
throw new Exception(mysqli_error($con));
//----------------------------------------------------------------
// OR:
//----------------------------------------------------------------
// Get a list of errors from the last command executed.
// Each error displayed as an associative array containing the
// errno, error, and sqlstate.
// Because array returned, then no exception thrown, just display.
//----------------------------------------------------------------
// $errorList = mysqli_error_list($con);
// echo '<pre>' . 'Error retrieving result set:<br/></br>' . print_r($errorList, true) . '</pre>';
// exit();
//----------------------------------------------------------------
}
//---------------------------------------------------------
// Read the result set.
//---------------------------------------------------------
$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
if (!isset($row)) {
echo 'No records returned!';
exit();
}
echo 'Returned username is: ' . $row['username'];
} else {
echo 'Invalid username/password. Please check and retry login';
}
//-----------------------------------------------------------
// Frees stored result memory for the given statement handle.
//-----------------------------------------------------------
mysqli_stmt_free_result($stmt);
//---------------------------------------------------------
// Close db connection.
//---------------------------------------------------------
$closed = mysqli_close($con);
if (!$closed) {
throw new Exception('The database connection can not be closed!');
}
} catch (Exception $exception) {
echo '<pre>' . print_r($exception, true) . '</pre>';
exit();
}
If you run this code which is using mysqli_stmt_store_result() together with mysqli_stmt_get_result() you'll get the
Error:
Exception Object
(
[message:protected] => Commands out of sync; you can't run this command now
[string:Exception:private] =>
[code:protected] => 0
[file:protected] => [...]/index.php
[line:protected] => 63
[trace:Exception:private] => Array
(
)
[previous:Exception:private] =>
[xdebug_message] => ( ! ) Exception: Commands out of sync; you can't run this command now in [...]/index.php on line 63
Call Stack
#TimeMemoryFunctionLocation
10.2170368808{main}( ).../index.php:0
)
Or in this form (see my code):
Error retrieving result set:
Array
(
[0] => Array
(
[errno] => 2014
[sqlstate] => HY000
[error] => Commands out of sync; you can't run this command now
)
)
This exception (Commands out of sync; you can't run this command now) states, that you can't run two simultaneous queries. For details, please see this answer for example.
The warning you showed in the question is telling you actually the effect: that you are not getting any mysqli_result from your call to
$result = mysqli_stmt_get_result($stmt);
Therefore your
$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
receives FALSE as argument (for $result) and raises (to you) the warning
Warning: mysqli_fetch_array() expects parameter 1 to be mysqli_result, boolean given in E:\xampp\htdocs\jq\login_system_sql_injection_proof\loginprocess.php on line 57
In order to resolve this, I'll give you two solutions.
Solution 1:
Use only mysqli_stmt_get_result() with mysqli_fetch_array():
<?php
/*
* Tested on table "user":
*
* ------------------------
* id username password
* ------------------------
* 1 John Smith
* 2 John Mark
*/
try {
$uname = 'John';
$pass = 'Smith';
//---------------------------------------------------------
// Connect to db.
//---------------------------------------------------------
$con = mysqli_connect('<server>', '<user>', '<pass>', '<db>');
if (!$con) {
throw new Exception('Connect error:<br/><br/>' . mysqli_connect_errno() . ' - ' . mysqli_connect_error());
}
//---------------------------------------------------------
// Sql statement.
//---------------------------------------------------------
$query = "SELECT * FROM user WHERE user.username = ? AND user.password = ?";
//---------------------------------------------------------
// Prepare sql statement.
//---------------------------------------------------------
$stmt = mysqli_prepare($con, $query);
if (!$stmt) {
throw new Exception('The sql statement can not be prepared!');
}
//---------------------------------------------------------
// Binds variables to the prepared statement as parameters.
//---------------------------------------------------------
$bound = mysqli_stmt_bind_param($stmt, 'ss', $uname, $pass);
if (!$bound) {
throw new Exception('The variables could not be bound to the prepared statement!');
}
//---------------------------------------------------------
// Execute the prepared statement.
//---------------------------------------------------------
$executed = mysqli_stmt_execute($stmt);
if (!$executed) {
throw new Exception('The prepared statement could not be executed!');
}
//---------------------------------------------------------
// Get the result set from the prepared statement.
//---------------------------------------------------------
$result = mysqli_stmt_get_result($stmt);
if (!$result) {
throw new Exception(mysqli_error($con));
}
//---------------------------------------------------------
// Get the number of rows in statements result set.
//---------------------------------------------------------
$rows = mysqli_num_rows($result);
if ($rows == 1) {
//---------------------------------------------------------
// Read the result set.
//---------------------------------------------------------
$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
if (!isset($row)) {
echo 'No records returned!';
exit();
}
echo 'Returned username is: ' . $row['username'];
} else {
echo 'Invalid username/password. Please check and retry login';
}
//-----------------------------------------------------------
// Frees stored result memory for the given statement handle.
//-----------------------------------------------------------
mysqli_stmt_free_result($stmt);
//---------------------------------------------------------
// Close db connection.
//---------------------------------------------------------
$closed = mysqli_close($con);
if (!$closed) {
throw new Exception('The database connection can not be closed!');
}
} catch (Exception $exception) {
echo '<pre>' . print_r($exception, true) . '</pre>';
exit();
}
Solution 2:
Use mysqli_stmt_store_result() together with mysqli_stmt_bind_result() and mysqli_stmt_fetch():
<?php
/*
* Tested on table "user":
*
* ------------------------
* id username password
* ------------------------
* 1 John Smith
* 2 John Mark
*/
try {
$uname = 'John';
$pass = 'Smith';
//---------------------------------------------------------
// Connect to db.
//---------------------------------------------------------
$con = mysqli_connect('<server>', '<user>', '<pass>', '<db>');
if (!$con) {
throw new Exception('Connect error:<br/><br/>' . mysqli_connect_errno() . ' - ' . mysqli_connect_error());
}
//---------------------------------------------------------
// Sql statement.
//---------------------------------------------------------
$query = "SELECT * FROM user WHERE user.username = ? AND user.password = ?";
//---------------------------------------------------------
// Prepare sql statement.
//---------------------------------------------------------
$stmt = mysqli_prepare($con, $query);
if (!$stmt) {
throw new Exception('The sql statement can not be prepared!');
}
//---------------------------------------------------------
// Binds variables to the prepared statement as parameters.
//---------------------------------------------------------
$bound = mysqli_stmt_bind_param($stmt, 'ss', $uname, $pass);
if (!$bound) {
throw new Exception('The variables could not be bound to the prepared statement!');
}
//---------------------------------------------------------
// Execute the prepared statement.
//---------------------------------------------------------
$executed = mysqli_stmt_execute($stmt);
if (!$executed) {
throw new Exception('The prepared statement could not be executed!');
}
//---------------------------------------------------------
// Transfers the result set from the prepared statement.
//---------------------------------------------------------
$stored = mysqli_stmt_store_result($stmt);
if (!$stored) {
throw new Exception('The result set from the prepared statement could not be transfered!');
}
//---------------------------------------------------------
// Get the number of rows in statements result set.
//---------------------------------------------------------
$rows = mysqli_stmt_num_rows($stmt);
if ($rows == 1) {
//---------------------------------------------------------
// Bind result set columns to variables.
//---------------------------------------------------------
$bound = mysqli_stmt_bind_result($stmt, $resId, $resUsername, $resPassword);
if (!$bound) {
throw new Exception('The result set columns could not be bound to the variables');
}
//--------------------------------------------------------------------
// Fetch results from the prepared statement into the bound variables.
//--------------------------------------------------------------------
while (mysqli_stmt_fetch($stmt)) {
echo 'Successfully returned data:<br/><br/>';
echo 'ID is: ' . $resId . '<br/>';
echo 'Username is: ' . $resUsername . '<br/>';
echo 'Password is: ' . $resPassword . '<br/>';
}
} else {
echo 'Invalid username/password. Please check and retry login';
}
//-----------------------------------------------------------
// Frees stored result memory for the given statement handle.
//-----------------------------------------------------------
mysqli_stmt_free_result($stmt);
//---------------------------------------------------------
// Close db connection.
//---------------------------------------------------------
$closed = mysqli_close($con);
if (!$closed) {
throw new Exception('The database connection can not be closed!');
}
} catch (Exception $exception) {
echo '<pre>' . print_r($exception, true) . '</pre>';
exit();
}
In addition to your code I've added exception handling and the mysqli_stmt_free_result($stmt) function to free the memory occupied by the result set.
Good luck.
来源:https://stackoverflow.com/questions/44200833/login-using-mysqli-prepared-statement