Returning array and num rows mysqli prepared - php

I'm a bit new to the mysqli prepared statement and I would like to use fetch_array to return the results AND also return num_rows as an array value.
I have something like this
function getCategories($dbh, $catId)
{
$data = array();
$s = "SELECT id, title FROM categories WHERE parent_id = ?";
if ($stmt = mysqli_prepare($dbh, $s)) {
mysqli_stmt_bind_param($stmt, "i", $catId);
mysqli_stmt_execute($stmt);
if (mysqli_stmt_errno($stmt)) {
exit(mysqli_stmt_error($stmt));
}
mysqli_stmt_store_result($stmt);
$count = mysqli_stmt_num_rows($stmt)) {
if ($count) {
$data['count'] = $count;
$result = mysqli_stmt_get_result($stmt);
while ($r = mysqli_fetch_assoc($result)) {
$data[] = $r;
}
}
return $data;
} else {
exit(mysqli_error($dbh));
}
}
It seems that I cannot use mysqli_stmt_store_result and mysqli_stmt_get_result().
The store_result function seems to give a boolean and then I get this error: "mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given"
Hope this makes sense. Any help would be really appreciated.
Updated:
function getCategories($dbh, $catId)
{
$data = array();
$s = "SELECT id, title FROM categories WHERE parent_id = ?";
if ($stmt = mysqli_prepare($dbh, $s)) {
mysqli_stmt_bind_param($stmt, "i", $catId);
mysqli_stmt_execute($stmt);
if (mysqli_stmt_errno($stmt)) {
exit(mysqli_stmt_error($stmt));
}
$result = mysqli_stmt_get_result($stmt);
$data['count'] = $result->num_rows;
while ($r = mysqli_fetch_assoc($result)) {
$data[] = $r;
}
return $data;
} else {
exit(mysqli_error($dbh));
}
}

According to the PHP docs, mysqli_stmt_get_result returns FALSE on error:
Returns a resultset for successful SELECT queries, or FALSE for other DML queries or on failure. The mysqli_errno() function can be used to distinguish between the two types of failure.
You're then passing that into mysqli_fetch_assoc which complains because you're giving it a bool instead of the resultset it expects.
Do a little more erroring checking at that point and you'll be fine. There's probably something wrong with your SQL query. Call mysqli_errorno to determine if there's an error, as the docs state above.
EDIT:
Use the mysqli_error function to get a description of the mysql error. It would be best to use this everywhere you're checking for failure as having an error message will make debugging much easier than simply failing silently.

Related

Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in PDO Insert Query

I am using PDO to execute a insert query but it is throwing me this error I am not able to understand what the problem is! Please help me out! thank you in advance:)
$count_query_params = [$fromDate, $toDate, $TRNO];
$count_query = "INSERT INTO `$HA_ENTRIES`(`fromDate`, `toDate`, `user_trno`) VALUES (?,?,?)";
$count_row = db_query_all($count_query_params, $count_query);
// DB_Query_ALL function
function db_query_all($arrayParams, $query)
{
global $conn;
$result = $conn->prepare($query);
foreach ($arrayParams as $param) {
$result->execute([$param]);
}
$rows = array();
while ($row = $result->fetch()) {
$rows[] = $row;
}
if (count($rows) < 1) {
$rows = false;
}
return $rows;
}
Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in......
db_query_all(Array, 'INSERT INTO `14...')
#2 {main}.....
On your sample code I think that you must call execute() only once. So, istead of:
foreach ($arrayParams as $param) {
$result->execute([$param]);
}
Try:
$result->execute($arrayParams);
Your query has three placeholders. The array you pass to db_execute() has three variables, but you call $results->execute() once each for the three variables, binding only one variable each time, hence the message.
Change your db_execute() function to call $results->execute() just once, but binding all the passed variables in the array at once:
// Execute Any Query With Params
function db_execute($arrayParams, $query)
{
global $conn;
$results = $conn->prepare($query);
$results->execute($arrayParams);
return $results;
}

mysqli array fetching is not getting data

I have to fetch result in single row but I can't run multiple rows. How can I fix this?
$stmt = $this->conn->prepare("SELECT * from user where id=?");
$stmt->bind_param("s", $id);
if($stmt->execute()){
$result = $stmt->get_result()->fetch_array(MYSQLI_ASSOC);
$stmt->close();
return $result;
}
I Got Result Like Wise This
{"ID":2,"Name":"Anju"}
But i need to get all user result .my code is here
$stmt = $this->conn->prepare("SELECT * from user where id=?");
$stmt->bind_param("s", $id);
if($stmt->execute()){
$result = array();
while ($row = $stmt->get_result()->fetch_array(MYSQLI_ASSOC)) {
$result[] = $row;
}
$stmt->close();
return $result;
}
I got the error
Fatal error: Call to a member function fetch_array() on a non-object in line 5
The line is:
while ($row = $stmt->get_result()->fetch_array(MYSQLI_ASSOC))
my expecting result is
{"ID":1,"Name":"Obi"}, {"ID":3,"Name":"Oman"}, {"ID":4,"Name":"Anju"}
$stmt = $this->conn->prepare("SELECT * from user where id=?");
$stmt->bindValue(1, $id);
Try that way
And try to fetchAll instead of fetch_array
You could make following correction.
Change
$rows->fetch_assoc(MYSQLI_ASSOC)
to
$rows->fetch_assoc()
It should look like
if ($stmt->execute()) {
$rows = $stmt->get_result();
$result = array();
while ($row = $rows->fetch_assoc()){
$result[] = $row;
}
$stmt->close();
return $result;
} else {
return NULL;
}
Suggestion : Always specify the list of columns in your SELECT, which makes query execution faster.
Please read php manual

Cannot bind multiple parameters using call_user_func_array()

I know they're many, many questions already about this, but I have no idea why mine doesn't work.
If I just use the following, my code works fine:
$this->stmt->bind_param("ii", $params[0], $params[1]);
But if I use the call_user_func_array, it breaks. One suggestion I got was passing the $parameters array by reference, but adding an & before the variable also broke my code...
Any help is greatly recieved!
Here's my code:
DB class:
function selectQuery($sql, $paramTypes = false, $params = false) {
//Prepare statement
$this->stmt = $this->conn->prepare($sql);
if($this->stmt === false) {
//We have an error
echo 'Wrong SQL: ' . $sql . ' Error: ' . $this->conn->error;
}
//This part doesn't work...
// if ($params) {
// //Bind an unknown number of parameters
// $parameters = array_merge(array($paramTypes), $params);
// call_user_func_array(array($this->stmt, 'bind_param'), $parameters);
// }
//This works.
$this->stmt->bind_param("ii", $params[0], $params[1]);
//Execute statement
$this->stmt->execute();
if ($this->stmt->error) {
echo $this->stmt->error;
return false;
}
//Get the results
$result = $this->stmt->get_result();
$data = $result->fetch_all(MYSQLI_ASSOC);
//Close statement
$this->stmt->close();
//Return the results
return $data;
}
Test page:
<?php
require_once('DatabaseAccess.php');
$db = new DB();
$sql = "SELECT * FROM table WHERE id = ? OR id = ?";
echo "Fetching data....<br>";
$result = $db->selectQuery($sql, "ii", array(1, 2));
foreach($result as $r) {
echo "<pre>".print_r($r, 1)."</pre>";
}
?>
Decided to add more information:
I'll be using this function to pass in the parameter types and parameters, but the amount will vary. When I looked up how to do this everyone suggested the call_user_func thing, but each time I try it (tried a few different ways) it won't work. Read through many threads, but it never seems to work. If I just use the bind_params function directly it works and I get the correct data returned.
Using the call_user_func thing I was getting the no data for the ? mysqli error, which is when I tried passing by reference and the code just broke completely...
Put it before call_user_func_array()
$res = array();
foreach($parameters as $key => $value) {
$res[$key] = &$parameters[$key];
}

mysqli: PHP Fatal error: Call to a member function fetch_array()

I am having some trouble with prepared statements. Basically, this query is returning no rows, even though I know for a fact that this query should return multiple rows. I thought this was just a problem due to SQL injections, but maybe I'm doing something else wrong here, I don't know. If I take out the check for how many rows there are, I get an error:
PHP Fatal error: Call to a member function fetch_array()
Any help would be appreciated!
$stmt = $mysqli->prepare("SELECT sid from SDS WHERE uid=? AND dst=?");
$stmt->bind_param('ss',$username,$structureType);
$stmt->execute();
$stmt->bind_result($results);
$stmt->fetch();
if ($results) {
if($results->num_rows == 0) {
print("No results here.");
return 0;
}
$recordnames = array();
while ($next_row = $results->fetch_array()) {
$recordnames[] = $next_row['sid'];
}
return $recordnames;
}
When you use $stmt->bind_result($result); you are binding the sid from the database to the variable $results. So you cannot perform operations like :
if($results->num_rows == 0) { //... }
or
$results->fetch_array();
This is how I would do it :
<?php
$stmt = $mysqli->prepare("SELECT sid from SDS WHERE uid=? AND dst=?");
$stmt->bind_param('ss', $username, $structureType);
$stmt->execute();
$stmt->bind_result($sid);
$stmt->store_result();
if ($stmt->num_rows == 0)
{
print("No results here.");
$stmt->close();
return 0;
}
else
{
$recordnames = array();
while($stmt->fetch())
{
$recordnames[] = $sid;
}
return $recordnames;
}
?>
This way uses a different logic, check if the row count is 0, if so display "No results here", if not put results into the array.

using mysqli to extract custom data

I am using a function in php for all select queries so that i can dynamically retrieve data from my database ..... I just wanted to know that is my code secure and efficient or if their is a better way to do this, if so please point me to the right direction...thanks
class mysql {
private $conn;
function __construct(){
$this->conn= new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME);
if( mysqli_connect_errno() )
{
trigger_error('Error connecting to host. '.$this->connections[$connection_id]->error, E_USER_ERROR);
}
}
function extracting_data($table, $fields,$condition,$order,$limit){
$query="SELECT ".$fields."
FROM ".$table."
WHERE id =".$this->sql_quote($condition)."
ORDER BY ".$order."
LIMIT ".$limit." ";
//echo $query;
if($stmt = $this->conn->prepare($query)) {
$stmt->execute();
$row = array_pad(array(), $stmt->field_count, '');
$params = array();
foreach($row as $k=>$v) {
$params[] = &$row[$k];
}
call_user_func_array(array($stmt,'bind_result'),$params);
$result = array();
while($stmt->fetch()) {
foreach ($row as $b=>$elem) {
$vals[$b]=$row[$b];
}
$result[]=$vals;
}
$stmt->close();
return $result;
}
}
function sql_quote( $value )
{
if( get_magic_quotes_gpc() )
{
$value = stripslashes( $value );
}
//check if this function exists
if( function_exists( "mysql_real_escape_string" ) )
{
$value = mysql_real_escape_string( $value );
}
//for PHP version < 4.3.0 use addslashes
else
{
$value = addslashes( $value );
}
return $value;
}
}
Now to call the function I am using ::>
$connection=New mysql();
$extract=$connection->extracting_data("tablename","id,name,points","$_GET['id']","date desc","0,10");
The function returns a multi-dimensional array in $result and stores it in $extract ,depending on the data I want to extract..
Any improvements or other suggestions would be appreciated ...
Instead of binding the results and having to do loads of looping, you could simply use mysqli::query() and mysqli_result::fetch_all().
if($stmt = $this->conn->query($query)) {
$result = $stmt->fetch_all(MYSQLI_ASSOC);
$stmt->close();
return $result;
}
You would be better off binding your input variables rather than building up an SQL string containing them, but that may not be feasible using your current approach.
Edit
Sorry, I was an idiot and didn't notice that fetch_all() is only in PHP >= 5.3. You can still do this though which is simpler:
if($stmt = $this->conn->query($query)) {
$result = array();
while ($row = $stmt->fetch_assoc()) {
$result[] = $row;
}
$stmt->close();
return $result;
}
You should watch where the parameters for your function come from. If they come from an unreliable source, then it's very insecure.
If someone passes something like 1 ; DROP TABLE tablename ; SELECT * FROM dual WHERE 1 in the $condition parameter, you'll get the Little Bobby Tables scenario.
Your query will look like the following:
SELECT id, name, points
FROM tablename
WHERE id
ORDER BY
DATE DESC
LIMIT 0, 10
The id here will be casted to BOOLEAN, and the query will select all ids except 0 and NULL.
Is it really what you want?
You probably want to change your $condition to 'id = $id' or something like that.
Do you really need this level of abstraction: generating queries from uknown tables with unknown fields but with predefined SELECT / FROM / ORDER BY / LIMIT stucture?

Categories