Nesting of MySQLi prepared statements - php

I have two prepared statements (for example) where the second statement is to be executed within the while(stmt1->fetch()){} loop. But, the inner statement (stmt2) doesn't execute within the first while loop:
<?php
$mysqli = new mysqli("localhost","root","","test");
if(mysqli_connect_errno())
{
printf("connection failed: %s\n",mysqli_connect_error());
exit();
}
$stmt1 = $mysqli->prepare("select id from posts");
$stmt2 = $mysqli->prepare("select username from members where id=?");
$stmt1->execute();
$stmt1->bind_result($ID);
while($stmt1->fetch())
{
echo $ID.' ';
/*Inner query*/
$stmt2->bind_param('i',$id);
$id =$ID;
$stmt2->execute();
$stmt2->bind_result($username);
while($stmt2->fetch())
{
echo 'Username: '.$username;
}
/*Inner query ends*/
}
?>
If I cut-paste the inner query part outside the outer while loop, it executes,but it is useless. What should I do to execute it properly?

Why do nested loop on it, when you can do INNER JOIN instead.
<?php
$mysqli = new mysqli("localhost","root","","test");
if(mysqli_connect_errno())
{
printf("connection failed: %s\n",mysqli_connect_error());
exit();
}
if($stmt1 = $mysqli->prepare("SELECT posts.id,members.username FROM posts INNER JOIN members ON posts.id=members.id")){
$stmt1->execute();
$stmt1->bind_result($id,$username);
while($stmt1->fetch()){
printf("ID # %d.<br>Username: %s<br><br>",$id,$username);
}
$stmt1->close();
}
$mysqli->close();
?>

Related

php Password verify for override feature returns false

I am trying to create an override feature where users type in existing login credentials, verify that a result row is returned matching those credentials, and then verifying that the user has the override role assigned to them. If both MySQL statements return true, I want to run the final query to delete a row from the coded table.
With my current code, the program passes the first if statement and runs the second SELECT statement. Then, it appears to run the second if to moved to the third SELECT statement. However, on the third if statement, the DELETE statement isn't successful.
I think I have a few issues:
I don't know if I'm properly comparing the passwords.
Could the problem be caused by the nested if statements?
Is my problem 'if ($result1) {...}' (assuming that result1 will return true as long as the SELECT statement successfully ran with 0 results returned)?
Either way, I'm not entirely sure of the best way to fix the(se) issue(s).
NOTE:: Through testing, I have confirmed that:
My variables are successfully $_POSTing and of the correct datatypes.
With just the first if/else statement, the alerted response was always a "success" result, even with incorrect credentials entered.
All help is appreciated!!
MY CODE:
PHP:
<?php
include('[db connection page]');
if ((isset($_POST['overrideUsername'])) and (isset($_POST['overridePassword'])) and (isset($_POST['overrideUniqueID']))) {
$overrideUsername = $_POST['overrideUsername'];
$overridePassword = $_POST['overridePassword'];
$overrideUniqueID = $_POST['overrideUniqueID'];
//connect to the database
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if(mysqli_connect_errno() ) {
printf('Could not connect: ' . mysqli_connect_error());
exit();
}
$conn->select_db($dbname);
if(! $conn->select_db($dbname) ) {
echo 'Could not select database. '.'<BR>';
}
$sql1 = "SELECT * FROM users WHERE (users.login = \"".mysqli_real_escape_string($overrideUsername)."\") AND (users.password = ENCODE(\"".mysqli_real_escape_string(overridePassword)."\",\"".mysqli_real_escape_string(ENCRYPTION_SEED)."\"))";
$result1 = $conn->query($sql1);
if ($result1) {
$sql2 = "SELECT * FROM users INNER JOIN rolestousers ON (users.id=rolestousers.userid) WHERE (users.login = \"".mysqli_real_escape_string($overrideUsername)."\") AND (users.password =ENCODE(\"".mysqli_real_escape_string(overridePassword)."\",\"".mysqli_real_escape_string(ENCRYPTION_SEED)."\")) AND (rolestousers.roleid = '154')";
$result2 = $conn->query($sql2);
if ($result2) {
$sql3 = "DELETE * FROM locator_time_track_out WHERE locator_time_track_out.uniqueid = '.$overrideUniqueID'";
$result3 = $conn->query($sql3);
if ($result3) {
echo 'Override Successful! Please scan the unit again to close it out.';
} else {
echo 'Could Not Delete Record from the Table.';
}//End $sql3 num_rows if.
} else {
echo 'User does not have override permission. Please contact the IT Department.';
}//End $sql2 num_rows if.
} else {
echo 'Your login information is incorrect. Please try again. If the issue persists, contact the IT Department.';
}//End $sql1 num_romws if.
//Free the result variable.
$result1->free();
$result2->free();
$result3->free();
//Close the Database connection.
$conn->close();
}//End If statement
UPDATE:
This is the code file I was originally using for the override feature. However, it of course fails for an incorrect password...
include('[db connection file name');
if ((isset($_POST['overrideUsername'])) and (isset($_POST['overridePassword'])) and (isset($_POST['overrideUniqueID']))) {
$overrideUsername = $_POST['overrideUsername'];
$overridePassword = $_POST['overridePassword'];
$overrideUniqueID = $_POST['overrideUniqueID'];
//connect to the database
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if(mysqli_connect_errno() ) {
printf('Could not connect: ' . mysqli_connect_error());
exit();
}
$conn->select_db($dbname);
if(! $conn->select_db($dbname) ) {
echo 'Could not select database. '.'<BR>';
}
$sql1 = "SELECT * FROM users WHERE (users.login = ?) AND (users.password = ?)";
$stmt1 = $conn->prepare($sql1);
$stmt1->bind_param('ss', $overrideUsername, $overridePassword);
$stmt1->execute();
$stmt1->store_result();
if ($stmt1->num_rows == 1) {
$sql2 = "SELECT * FROM users INNER JOIN rolestousers ON (users.id=rolestousers.userid) WHERE (users.login = ?) AND (users.password = ?) AND (rolestousers.roleid = '154')";
$stmt2 = $conn->prepare($sql2);
$stmt2->bind_param('ss', $overrideUsername, $overridePassword);
$stmt2->execute();
$stmt2->store_result();
if ($stmt2->num_rows == 1) {
$sql3 = "DELETE * FROM locator_time_track_out WHERE locator_time_track_out.uniqueid = ?";
$stmt3 = $conn->prepare($sql2);
$stmt3->bind_param('s', $overrideUniqueID);
$stmt3->execute();
$stmt3->store_result();
if ($stmt3->num_rows == 1) {
echo 'Override Successful! Please scan the unit again to close it out.';
} else {
echo 'Could Not Delete Record from the Table.';
}//End $sql3 num_rows if.
} else {
echo 'User does not have override permission. Please contact the IT Department at ext. 0102.';
}//End $sql2 num_rows if.
} else {
echo 'Your login information is incorrect. Please try again. If the issue persists, contact the IT Department at ext. 0102.';
}//End $sql1 num_romws if.
//Free the result variable.
$stmt1->free();
$stmt2->free();
$stmt3->free();
//Close the Database connection.
$conn->close();
}//End If statement

PHP MySQLI Object-Oriented with Wildcard

I'm converting to Mysqli object-oriented (or trying to). I have various category pages. I'd like to use a parameter placeholder '?' in the include and then call up the right category on the category page.
This is as far as I've gotten. How do I indicate the category on my page? All works fine if I indicate WHERE category = apples.
I have this include at top of a category page
<?php require_once 'maincats_mysqli.php' ?>
which is below:
<?php
$db = new mysqli('host', 'userName', '', 'dbName');
if ($db->connect_error) {
$error = $db->connect_error;
} else {
$sql = "SELECT pageName, gImage, prodName, prodPrice
FROM tableName
WHERE category = '?'
ORDER BY dtList DESC";
$stmt->bind_param('s', ['$category']);
$result = $db->query($sql);
if ($db->error) {
$error = $db->error;
}
}
function getItem($result) {
return $result->fetch_assoc();
}
?>
Below is part of one category page. How do I indicate which category? Any help would be appreciated.
<?php
if (isset($error)) {
echo "<p>$error</p>";
}
?>
<?php
while ($item = getItem($result)) {
?>
<a href="http://www.example.com/<?php echo $item['pageName']; ?>">
<img src="http://www.example.com/<?php echo $item['gImage']; ?>"</a>
<a href="http://www.example.com/<?php echo $item['pageName']; ?>">
<?php echo $item['prodName']; ?></a>
<?php echo $item['prodPrice']; ?>
<?php
}
?>
First, you don't declare $stmt.
Second, ? is not a wildcard in this case, it's a parameter placeholder. You can use such placeholders when preparing the query, with $mysqli->prepare($sql). See documentation: http://php.net/manual/en/mysqli-stmt.bind-param.php
$sql = "SELECT pageName, gImage, prodName, prodPrice
FROM tableName
WHERE category = ?
ORDER BY dtList DESC";
$stmt = $db->prepare($sql);
Third, you encapsulate your variable in single quotes, so it's a string with a dollar and the name of your variable, not its content. And it must not be in an array:
$stmt->bind_param('s', $category);
Last: where does $category comes from? It's not defined in the script you show us. I guess it's from $_GET, so the previous line should be:
$stmt->bind_param('s', $_GET['category']);
Finally, you need to execute your statement, which contains the query:
$stmt->execute();
EDIT:
To fetch results, you don't need that getItem() function. Just remove it.
$result = $stmt->get_result();
Then you can loop over $result and fetch each row:
while ($item = $result->fetch_assoc()):
// do you stuff
endwhile;
Note that I use here the PHP control structure alternative syntax which is more clear in your case (endwhile is more explicit than just })
You're missing the prepare(). Look at the first example in the PHP manual page:
<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$city = "Amersfoort";
/* create a prepared statement */
$stmt = $mysqli->stmt_init();
if ($stmt->prepare("SELECT District FROM City WHERE Name=?")) {
/* bind parameters for markers */
$stmt->bind_param("s", $city);
/* execute query */
$stmt->execute();
/* bind result variables */
$stmt->bind_result($district);
/* fetch value */
$stmt->fetch();
printf("%s is in district %s\n", $city, $district);
/* close statement */
$stmt->close();
}
/* close connection */
$mysqli->close();
?>
Note that you must not quote binded parameters.

Same statements, the second not working in different if

I'm trying to figure out why a mysqli parepared statement is not working. I can say the page have something like 2 sections, the first one needs $_GET to be empty and the last one needs $_GET['id'] and other to be set (isset). Both "sections" have the same query but in the last section there's a different query first.
Everyting is working fine until the repeated query in the last "section", where nothing is printed.
I have something like this:
if (login_check($mysqli) == true) {
if(empty($_GET)) { //first section
if ($stmt = $mysqli->prepare("SELECT friends.*, members.*, account_type.* FROM friends INNER JOIN members ON members.id = friends.friendID
INNER JOIN account_type ON account_type.name = members.acc_type
WHERE friends.userID = ? AND members.acc_type = ?")) {
$stmt->bind_param('is', $_SESSION['user_id'], $_SESSION['acc_type']);
$stmt->execute();
} else echo $mysqli->error;
$result = $stmt->get_result();
// php/mysqli stuff working as expected ($row[] printing db data)
// no need to close
}
if(isset($_GET['id'], $_SESSION['user_id'])) { // last section
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
/* prepare statement */
if ($stmt = $mysqli->prepare("SELECT COUNT(*) rowCount FROM friends WHERE friendID = ? AND userID = ?")) {
$stmt->bind_param('ii', $_GET['id'], $_SESSION['user_id']);
$stmt->execute();
/* bind variables to prepared statement */
$stmt->bind_result($rowCount);
/* fetch values */
if($stmt->fetch()) {
if ($rowCount > 0) { // This check is working fine, I tested.
$stmt->close(); // close here so no "non-object" error
$stmt = $mysqli->prepare("SELECT friends.*, members.*, account_type.* FROM friends INNER JOIN members ON members.id = friends.friendID
INNER JOIN account_type ON account_type.name = members.acc_type
WHERE friends.friendID = ? AND members.acc_type = ?");
$stmt->bind_param('is', $_GET['id'], $_SESSION['acc_type']);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_array();
// Here I have some $row['columns'] and nothing is printed.
} else{
echo $_SESSION['username'], ', you are not allowed to be here.';
}
}
/* close statement */
$stmt->close();
}
/* close connection */
$mysqli->close();
}
} else {
echo 'Please, log in.';
}
The first query is working fine, the other is a copy/paste.
I don't see where the problem is :(
Thanks!
Edit: sorry the second query should be "WHERE friends.friendID".
for ($i = 1; $i < 13; $i++) {
$month = $row['month' . $i];
if($row[$month] == 1) {
$paid[] = 'Paid';
} else {
$paid[] = 'Not Paid';
}
$bonus = $row['bonus'];
}
The problem is members.monthx and friends.monthx have the same name, but they are not meant to have the same values so I don't know from what table is getting $row['month' . $i]. The value should be taken from friends.monthx. How do I specify that?

Binding results in MySQLi

In the code below if I try to fetch results after two successive executions with different sets of parameters, it shows the same result set(the first one twice), instead of showing both the results with different parameters. What should I do? Also, in the PHP manual $sqli->bind_results() is put after $sqli->execute(), is it always mandatory or is it valid also to put $sqli->bind_results() before $sqli->execute() ?
<?php
$mysqli = new mysqli("localhost","root","","test");
/*check connection*/
if(mysqli_connect_errno())
{
printf("connection failed: %s\n",mysqli_connect_error());
exit();
}
/*create prapared statement*/
$sqli = $mysqli->prepare("select post_id from posts where id=?");
/*bind params*/
$sqli->bind_param('i',$id);
/*set params*/
$id =1;
/*execute prapared statement*/
$sqli->execute();
/*bind results*/
$sqli->bind_result($post_id);
while($sqli->fetch())
{
echo ' '.$post_id;
}
echo '<br/>fetch new record<br/>';
/*set params*/
$id =2;
/*execute prapared statement*/
$sqli->execute();
while($sqli->fetch())
{
echo ' '.$post_id;
}
Executing in loops:*
Scene1: calling bind_result($post_id) repeatedly
<?php
$mysqli = new mysqli("localhost","root","","test");
/*check connection*/
if(mysqli_connect_errno())
{
printf("connection failed: %s\n",mysqli_connect_error());
exit();
}
/*create prapared statement*/
$sqli = $mysqli->prepare("select post_id from posts where id=?");
/*bind params*/
$sqli->bind_param('i',$id);
for($x=0;$x<1000;$x++)
{
$id =$x;
$sqli->execute();
/*****bind results*****/
$sqli->bind_result($post_id);
while($sqli->fetch())
{
echo ' '.$post_id;
}
}
?>
Scene2: calling bind_result($post_id) once
<?php
$mysqli = new mysqli("localhost","root","","test");
/*check connection*/
if(mysqli_connect_errno())
{
printf("connection failed: %s\n",mysqli_connect_error());
exit();
}
/*create prapared statement*/
$sqli = $mysqli->prepare("select post_id from posts where id=?");
/*bind params*/
$sqli->bind_param('i',$id);
/*****bind results*****/
$sqli->bind_result($post_id);
for($x=0;$x<1000;$x++)
{
$id =$x;
$sqli->execute();
while($sqli->fetch())
{
echo ' '.$post_id;
}
}
?>
Now,as par PHP manual bind_result() should be used after execute(),but as shown in the scene1 above this will call "bind_result()" repeatedly whereas in scene2 it is called just once and still it is doing well. Which approach is better? Is scen2 valid?
Yes, you need to run bind_result after each execute.
From the manual...
Note that all columns must be bound after mysqli_stmt_execute() and prior to calling mysqli_stmt_fetch().
So, you're only missing the second (required) call to bind_result...
$id = 2;
$sqli->execute();
$sqli->bind_result($post_id);

PHP - prepared statements and json_encode

I want to create a php script using prepared statements to query a table in my database and return the results in json format. I have a table of doctors and i want to return the doctors of a given speciality. I have a version of the script that doesn't use prepared statements that works fine. But when i use prepared statements my script doesn't work.
Non - prepared statements version:
<?php
// include database constants
require_once("../config/config.php");
// create db connection
$mysqli = new mysqli($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME);
/* check connection */
if ($mysqli->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
$mysqli->set_charset("utf8");
$speciality = $_POST['speciality'];
$query = "SELECT * FROM `doctors` WHERE speciality='$speciality'";
$result = $mysqli->query($query) or die("Error executing the query");
while($row = $result->fetch_assoc()) {
$output[]= $row;
}
print(json_encode($output));
$mysqli->close();
?>
prepared statements version:
<?php
// include database constants
require_once("../config/config.php");
// create db connection
$mysqli = new mysqli($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME);
/* check connection */
if ($mysqli->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
$mysqli->set_charset("utf8");
$speciality = $_POST['speciality'];
$query = "SELECT * FROM `doctors` WHERE speciality=?";
if ($stmt = $mysqli -> prepare($query)){
$stmt -> bind_param("s", $speciality);
$stmt -> execute();
$result = $stmt -> get_result();
while($row = $result -> fetch_assoc()) {
$output[]= $row;
}
print(json_encode($output));
$stmt -> close();
} else {
echo $mysqli->error;
echo "no entry found";
}
$mysqli->close();
?>
What am i doing wrong? I don't get a mysqli error which means that the problem is after the execution of the query but i just don't know what it is.
Edit: What i mean by saying it doens't work is that i don't get anything back. The html body of the page after the execution is completely empty. On the other hand if i use the other script i posted (without prepared statements) i get the expected result.
UPDATED:
Use this:
/* bind result variables */
$stmt->bind_result($col1,$col2,$col3,$col4);
/* fetch values */
while ($stmt->fetch()) {
$output[]=array($col1,$col2,$col3,$col4);
}
Instead. Hope it helps.
anyone please give reason of putting downvote.
ini_set('display_errors',1);
error_reporting(E_ALL);
and then look at HTML body again. Most likely get_result is not supported but I hate to guess.
Make sure your version of PHP is compatible with the method
http://php.net/manual/pt_BR/mysqli-stmt.get-result.php
To get data as associative array you can do as follow:
$stmt->bind_result($col1, $col2);
$rows = [];
while ($stmt->fetch()) {
$rows[]=array("col1"=>$col1, "col2"=>$col2);
}

Categories