php Prepared Statement giving me JSON Malformed - php

My php code works fine when it is not a prepared statement - however when it is a prepared statement it is giving me a json malformed error. After debugging my code for some time I have realised that there is something wrong with my if statement and that it should be different when it is a prepared statement. I am not sure what to change but this is my code:
$statement = "SELECT userID, forename, surname, email, age FROM employees WHERE forename = ?"
$outcome = $conn -> prepare($statement);
$outcome->bind_param('s', $forename);
$outcome->execute();
$outcome->close();
$outcomearray = array();
echo json_encode("It works as of now"); // This bit works and the message is echoed
// From this point, it is giving me errors and problems
if(mysqli_num_rows($outcome)){
while($line = mysqli_fetch_assoc($outcome)){
$outcomearray[] = array
(
"userID" => $line["userID"],
"forename" => $line["forename"],
"surname" => $line["surname"],
"username" => $line["username"],
"email" => $line["email"],
"age" => $line["age"]
);
}
echo json_encode($outcomearray);
}
It is the following two lines:
if(mysqli_num_rows($outcome)){
while($line = mysqli_fetch_assoc($outcome)){
that I believe are giving the errors.
How do I fix this?

$stmt = $conn->prepare(
"SELECT userID, forename, surname, email, age FROM employees WHERE forename = ?"
);
$stmt->bind_param('s', $forename);
$stmt->execute();
$rows = array();
$result = $stmt->get_result();
while($line = $result->fetch_assoc()){
$rows[] = $line;
}
print json_encode($rows);
$conn->close();
Note that this is the typical pattern when you are returning JSON resonses. If there is no match you render an empty array - thus there is no real need to check the number of rows.
If you for whatever reason needed to you can get the number of rows from the num_rows property on the mysqli_result object:
$result = $stmt->get_result();
if ((bool) $result->num_rows) {
}
Also note that the whole point of fetch_assoc is to get an associative array. So if your column names line up with the JSON you want to produce there is no need to map the keys one by one.
http://php.net/manual/en/class.mysqli-result.php

Try use
$outcome->num_rows;
OR
mysqli_stmt_num_rows($outcome);
Also use
$outcome->bind_result('userID','email', 'age', 'surname', 'forename');
$outcome->fetch()
instead
mysqli_assoc_fetch()

Related

Why is the echo not returning an ID after the SQL query in php?

I have the following code in some php:
$stmt = $connection->prepare("SELECT * FROM users where email = ?");
$stmt->bind_param('s', $email);
if($stmt->execute()){
$result = $stmt->get_result();
$isUserFound = $result->num_rows == 1;
if(isUserFound){
$row = $result->fetch_row();
echo "<br>id: " . $row["id"];
}
I know that the user is found because the code inside the second if executes and I have done a manual check also to make sure. Is there something wrong with the syntax I have used? The echo returns just "id: " with no id from the database even though the user exists.
I have tried using single quotes for the id and also tried in capital letters, all return nothing.
According to the documentation, fetch_row() is used to "get a result row as an enumerated array." This will result in an array like this:
$row = [
0 => "2342",
1 => "user#example.com",
2 => "User",
];
Instead use fetch_assoc() which will "fetch a result row as an associative array" and give you something like this:
$row = [
"id" => "2342",
"email" => "user#example.com",
"name" => "User",
];
Note that if you enabled some error reporting in your development environment you would have seen "undefined index" notices that might have helped you solve this issue.

why am I getting foreach error when posting with Android Volley to my php?

In my Android app I am using volley to echo my response which should be of the form:
[
{
"category":"whatever",
"name":"whatever",
"phone":"whatever",
"comment":"whatever",
"reviewid":32
},
{
"category":"whatever",
"name":"whatever",
"phone":"whatever",
"comment":"whatever",
"reviewid":76
}
]
Instead I am getting as the response:
Warning: Invalid argument supplied for foreach() in php file on line 13
I don't know if I'm posting it wrong from java or if the problem is with my php.
In my app I have:
selectOwnUserReviews = Arrays.toString(category.getUserReviewIds());
When I toast selectOwnUserReviews I can see selectOwnUserReviews is of the format like:
[63,59,42] or [234] or [34,29] etc...
I am trying to post the selectOwnUserReviews array with volley to my php with:
#Override
//post info to php
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
//KEY_REVIEWID_USER is reviewiduser
params.put(KEY_REVIEWID_USER, selectOwnUserReviews);
return params;
}
Here's my php:
<?php
require('file.php');
$ReviewID = $_POST['reviewiduser'];
$results = array();
foreach($ReviewIDs as $ReviewID) {
$sql2 = "SELECT * FROM review WHERE review_id = ?";
$stmt2 = $con->prepare($sql2) or die(mysqli_error($con));
$stmt2->bind_param('i', $ReviewID) or die ("MySQLi-stmt binding failed ".$stmt2->error);
$stmt2->execute() or die ("MySQLi-stmt execute failed ".$stmt2->error);
$result2 = $stmt2->get_result();
//if user_id has reviews in the db
while($row = mysqli_fetch_array($result2)) {
//make an array called $results
$results[] = array(
'category' => $row['cat_name'],
'name' => $row['name'],
'phone' => $row['phone'],
'comment' => $row['comment'],
'reviewid' => $row['review_id'],
);
}
}
$json = json_encode($results);
echo $json;
?>
Line 13 in my php code is:
foreach($ReviewIDs as $ReviewID) {
Different variable names!
$ReviewID = $_POST['reviewiduser']; //without final s
foreach($ReviewIDs as $ReviewID) { //with final s.
/* ^ */
Edit:
You say you're still having problems.
Probably your $_POST is a string. Try:
$reviewIDs = json_decode($_POST['reviewiduser']);
that will probably make $reviewIDs a proper array to work with foreach.
You're getting the foreach error when posting with Android Volley to your php b/c all input values are strings in PHP and you can not foreach a string.
You perhaps first want to decode the string into an array which you then can foreach over. But if that is inteded by you or not was not clear to me from your question so I can not be very specific about that w/ my answer and only provide this as a general hint. It is often common to decode JSON, but please that must not be the case in your case: http://php.net/json_decode.
Next to that also take care you are using actually the correct variables, as others have pointed out and I'm with them, you need to use the exactly correctly written variable name, even one character off will give you a different variable name which will evaluate to NULL in PHP which you can't foreach over as well like w/ the string.
I was posting from Java to Php as a string and treating it in php like it was an array.
In Java I was posting selectOwnUserReviews which was of the format like "[1,34,78]". It looked like an array but was all treated as one unit. And even if I tried operations in php I was doing it on [1 and 34 and 78], not on 1 and 34 and 78.
So in Java I did:
//convert [56,23,87] to a string
selectOwnUserReviews = Arrays.toString(category.getUserReviewIds());
//remove [ and ] so we have a string of 56,23,87
selectOwnUserReviews = selectOwnUserReviews.substring(1,selectOwnUserReviews.length()-1);
Now I have the string 56,23,87 and I post this string to my php. In my php I use explode to get the individual values, my complete code looking like:
<?php
require('file.php');
$ReviewID = $_POST['reviewiduser'];
$ReviewID = explode(",",$ReviewID);
$results = array();
foreach($ReviewID as $ReviewID) {
$sql2 = "SELECT * FROM review WHERE review_id = ?";
$stmt2 = $con->prepare($sql2) or die(mysqli_error($con));
$stmt2->bind_param('i', $ReviewID) or die ("MySQLi-stmt binding failed ".$stmt2->error);
$stmt2->execute() or die ("MySQLi-stmt execute failed ".$stmt2->error);
$result2 = $stmt2->get_result();
while($row = mysqli_fetch_array($result2)) {//make an array called $results
$results[] = array(
'category' => $row['cat_name'],
'name' => $row['name'],
'phone' => $row['phone'],
'comment' => $row['comment'],
'reviewid' => $row['review_id'],
);
}
}
echo json_encode($results);
?>
Job done.
To expand on the other answers and give a more complete response based on the comments.
As you noted var_dump($_POST) results in the following:
array(1) {
["reviewiduser"]=>
string(4) "[63]"
}
Meaning that your post value is being received as a string of 4 characters, in the format of an array. Rather than the desired array of integers. However you can use json_decode on the value to parse the string into the desired array of integers.
Example: https://3v4l.org/64v30
Since we should never trust the data from the end user, especially cross-platform/site, you should sanitize and validate the data prior to processing it.
Additionally you have a mix of procedural and object oriented uses of mysqli with some missing controls of where mysql can return false or null. It is best to only utilize one style to ensure that your code is cohesive/coherent. As well as cover all cases where a function/method call may return a value other than what is desired, to be better anticipate the desired behavior or failure.
<?php
require __DIR__ . '/file.php';
//ensure the desired post key exists otherwise set a default value
if (!array_key_exists('reviewiduser', $_POST)) {
$_POST['reviewiduser'] = '[]';
}
//ensure json decode returns as the desired data type
$ReviewIDs = json_decode($_POST['reviewiduser']);
if (!is_array($ReviewIDs)) {
$ReviewIDs = [];
}
//declare results for use with json_encode
$results = [];
//declare ReviewID as a variable for use with bind_param
$ReviewID = null;
//prepare the database query for multiple executions
$sql2 = 'SELECT cat_name AS category, name, phone, comment, review_id AS reviewid FROM review WHERE review_id = ?';
//create a statement for use with prepare
$stmt2 = $con->stmt_init();
$stmt2->prepare($sql2) or die($con->error);
//bind ReviewID by reference so that it changes for each execute iteration
$stmt2->bind_param('i', $ReviewID) or die ('MySQLi-stmt binding failed ' . $stmt2->error);
//iterate over ReviewIDs
foreach ($ReviewIDs as $ReviewID) {
//validate the value is of the desired type
if (!is_numeric($ReviewID)) {
continue;
}
$stmt2->execute() or die ('MySQLi-stmt execute failed ' . $stmt2->error);
$result2 = $stmt2->get_result() or die('MySQLi-smt get_result failed' . $smt2->error);
//ensure a result is retrieved from the database
if ($row = $result2->fetch_assoc()) {
$results[] = $row;
}
}
$stmt2->close();
echo json_encode($results);
exit;

Fetch multiple rows in mysql single query in php with different id

I have different id's, i am getting the values of these id from users
$id=array();
$id[0]=$_GET["id0"];
$id[1]=$_GET["id1"];
$id[2]=$_GET["id2"];
now to fetch data from database i am using following query:
for($j=0;$j<count($id);$j++)
{
$res=mysql_query("SELECT * FROM mutable WHERE id='$id[$j]'")
while($row=mysql_fetch_array($res))
{
$row[]=array("email"=>$row[2],"name"=>$row[3],"address"=>$row[5]);
echo JSON_encode($row);
}
}
now i am getting proper result from this query using for loop but the result is not in proper JSON format, is there any way to do it more efficentyly and getting proper result in JSON array and JSON object format
Place json_encode() outside of your loops.
Let's modernize and refine things...
*Unfortunately prepared statements that use an IN clause suffer from convolution. pdo does not suffer in the same fashion.
Code: (untested)
if(isset($_GET['id0'],$_GET['id1'],$_GET['id2'])){
$params=[$_GET['id0'],$_GET['id1'],$_GET['id2']]; // array of ids (validation/filtering can be done here)
$count=count($params); // number of ids
$csph=implode(',',array_fill(0,$count,'?')); // comma-separated placeholders
$query="SELECT * FROM mutable WHERE id IN ($csph)";
$stmt=$mysqli->prepare($query); // for security reasons
array_unshift($params,str_repeat('s',$count)); // prepend the type values string
$ref=[]; // add references
foreach($params as $i=>$v){
$ref[$i]=&$params[$i]; // pass by reference as required/advised by the manual
}
call_user_func_array([$stmt,'bind_param'],$ref);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_array(MYSQLI_NUM))
$rows=["email"=>$row[2],"name"=>$row[3],"address"=>$row[5]];
}
$stmt->close();
echo json_encode($rows);
}
Three things:
Always, always, always used prepared statements and bound parameters when dealing with untrusted (i.e., $_GET) input. Just do it.
As regards your problem with JSON, you only need to run json_encode once:
$results = [];
for($j=0;$j<count($id);$j++) {
...
while($row=mysql_fetch_array($res)) {
results[] = ...
}
}
json_encode( $results );
Use a single SQL statement, since you have a known number of IDs to collect:
$dbh = new PDO($dsn, $user, $password);
$sql = "SELECT * FROM mutable WHERE id IN (?, ?, ?)";
$sth = $dbh->prepare( $sql );
foreach ( $sth->execute( [$_GET['id0'], $_GET['id1'], $_GET['id2']] ) as $row ) {
...
This is more efficient then multiple round trips to the database. For this contrived case it probably doesn't matter, but getting into good habits now will serve you in the long run.
you have used $row wrongly, declare array variable outside of loop like
$json_response = array();
for($j=0;$j<count($id);$j++) {
$res=mysql_query("SELECT * FROM mutable WHERE id='$id[$j]'")
while($row=mysql_fetch_array($res)) {
$json_response[]=array("email"=>$row[2],"name"=>$row[3],"address"=>$row[5]);
echo json_encode($json_response); // not good to echo here
}
}
// echo json_encode($json_response); // ideally echo should be here

return array of results from select query php

I'm trying to implement search suggestions for an app and need to search a database table that contains a list of users. I need the script to return an array of with the details of all the users that fit the criteria (i.e if the user searches 'Jo' it'll return users named 'John' 'Joe' etc.). I've had a go at doing this using parts of some of my other scripts but I can't get the mysqli_fetch_array method to work properly.
I'm using an onTextChangedListener to query the script every time the user types something, I believe this is the right way to go about doing it. I'll post my code below, if there's any more info needed just let me know.
$con = mysqli_connect(database details);
$name = $_POST["name"];
$statement = mysqli_prepare($con, "SELECT user_id, name, email FROM users WHERE name = ?");
mysqli_stmt_bind_param($statement, "s", $name);
mysqli_stmt_execute($statement);
mysqli_stmt_store_result($statement);
mysqli_stmt_bind_result($statement, $user_id, $name, $email);
$response = mysqli_fetch_array($statement, MYSQLI_ASSOC);
echo json_encode($response);
mysqli_close($con);
Within android studio I'm getting the error: mysqli_fetch_array() expects parameter 1 to be mysqli_result.
Try changint the mysqli_fetch array for the following loop:
while (mysqli_stmt_fetch($statement)) {
$response[] = [
"user_id" => $user_id,
"name" => $name,
"email" => $email,
]; //assign each data to response array
}

Getting elements of the array MySQLi + PHP

Trying to get array from using MySQLi and PHP, so that I could work with each element of the array (like $array[0], array[1])
$titlesquery = $db->prepare("SELECT title FROM books WHERE id = ?");
$titlesquery->bind_param('i', $id);
$titlesquery->execute();
$titlesquery->bind_result($returned_title);
$json = $titlesquery->fetch($returned_title, MYSQLI_ASSOC);
echo json_encode($json);
This doesn't work. I get such warning:
mysqli_stmt::fetch() expects exactly 0 parameters, 2 given
If it helps, just $titlesquery->fetch(); works fine but I get not a kind of array(?) structure, just single element for that column. What is my mistake?
Like what exactly says on the error message, it needs no parameters:
http://php.net/manual/en/mysqli-stmt.fetch.php
bool mysqli_stmt::fetch ( void )
$titlesquery->bind_result($returned_title);
$titlesquery->fetch();
$json = array('title' => $returned_title);
After you have invoked ->bind_result(), this already binds results from your prepared statement.
If you want an array row fetching and this is available to you (needs mysqlnd), use ->get_result() instead.
$titlesquery = $db->prepare("SELECT title FROM books WHERE id = ?");
$titlesquery->bind_param('i', $id);
$titlesquery->execute();
$result = $titlesquery->get_result();
$json = $result->fetch_assoc();
echo json_encode($json);

Categories