Mysqli prepared statement num_rows with multiple parameters - php

I have the following script:
<?php
$mysqli = new mysqli('localhost', 'user', 'password', 'database');
$statement = $mysqli->stmt_init();
$query = 'SELECT * FROM table WHERE id = ? AND active = 1';
$statement->prepare($query);
$parameters = array('i');
$inputParameters = array(10);
foreach ($inputParameters as $param) {
$parameters[] =& $param;
}
call_user_func_array(array($statement, 'bind_param'), $parameters);
$statement->execute();
$statement->store_result();
echo $statement->num_rows;
?>
Which returns exactly the right number of rows.
But when I change the script to:
<?php
$mysqli = new mysqli('localhost', 'user', 'password', 'database');
$statement = $mysqli->stmt_init();
$query = 'SELECT * FROM table WHERE id = ? AND active = ?';
$statement->prepare($query);
$parameters = array('ii');
$inputParameters = array(10, 1);
foreach ($inputParameters as $param) {
$parameters[] =& $param;
}
call_user_func_array(array($statement, 'bind_param'), $parameters);
$statement->execute();
$statement->store_result();
echo $statement->num_rows;
?>
It returns 0. Does anyone have an explanation for that? To me it looks like num_rows stops working as soon as you have more than 1 param bound to the statement.
p.s: in the full script there's a reason to use call_user_func_array here, not using call_user_func_array gives the same result.

I found the answer after a lot of debugging: $parameters will be array('ii', 1, 1) in the second code. This is because of the reference used there. Changing foreach ($inputParameters as $param) { to foreach ($inputParameters as &$param) { fixed the problem

Related

Switching Object Oriented mysqli to Procedural

function build_calendar($month, $year){
$mysqli = new mysqli('localhost', 'root', '', 'ems');
$stmt = $mysqli->prepare("SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
$stmt->bind_param('ss', $month, $year);
$bookings = array();
if($stmt->execute()){
$result = $stmt->get_result();
if($result->num_rows>0){
while($row = $result->fetch_assoc()){
$bookings[] = $row['event_date'];
}
$stmt->close();
}
}
I wrote out this code as a fix for fetching booked dates from my database and displaying them on my calendar but I'm not an OOP guy yet and I'd love to have this syntax in Procedural format which I still understand better.
I already tried
$connection = mysqli_connect('localhost', 'root', '', 'ems');
$query = "SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?";
$get_dates = mysqli_query($connection, $query);
while($row = mysqli_fetch_assoc($get_dates)){
$booked_dates[] = $row['event_date'];
}
But this returns an error:
Fatal error: Uncaught TypeError: mysqli_fetch_assoc(): Argument #1 ($result) must be of type mysqli_result
Don't do that. There's absolutely no reason to use procedural mysqli style. It was designed only to help people migrate from PHP 4 code. You should not use it in a new code base.
Besides, using mysqli in OO-style does not make your code OOP and you don't even need to know OOP to use mysqli in OO-style.
If you want to know what is the difference between procedural and OO-style mysqli, it's only the different name of the function and you must pass the object as the first argument.
This means that these are equivalent:
$stmt = $mysqli->prepare("SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
$stmt = mysqli_prepare($mysqli, "SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
Your function converted to procedural mysqli still looks the same:
function build_calendar($month, $year)
{
$mysqli = mysqli_connect('localhost', 'root', '', 'ems');
$stmt = mysqli_prepare($mysqli, "SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
mysqli_stmt_bind_param($stmt, 'ss', $month, $year);
$bookings = array();
if (mysqli_stmt_execute($stmt)) {
$result = mysqli_stmt_get_result($stmt);
if (mysqli_num_rows($result) > 0) {
while ($row = mysqli_fetch_assoc($result)) {
$bookings[] = $row['event_date'];
}
mysqli_stmt_close($stmt);
}
}
}
However, by learning mysqli you are learning a lot of bad practice due to the bad tutorials out there. I would highly recommend learning PDO. If you really want to suffer with mysqli then you can at least simplify the code:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'root', '', 'ems');
function build_calendar(mysqli $mysqli, $month, $year): array
{
$stmt = $mysqli->prepare("SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
$stmt->bind_param('ss', $month, $year);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
}
$bookings = build_calendar($mysqli, 1, 2020);

how to store posted parameter in array using slimframework 3

i want to store the posted parameters to my function in an array,
i am using slim 3
My question
is the request->getparam('') how i should get the parameters
posted ?
should i bind them ? if so to what should i bind them since i am
not using :Adminusera :Adminuserb :Adminuserc anywhere
is there a way i could place for example this in my array value :Adminusera instead of $userA ?
my code:
//IS THIS HOW I GET THE POSTED PARAMETERS To My Function ?
$userA = $request->getParam('usera');
$userB = $request->getParam('userb');
$userC = $request->getParam('userc');
$sql = "SELECT *FROM admins";
try {
$db = new db();
$db = $db->connect();
$stmt = $db->prepare($sql);
$stmt->bindParam(':Adminusera', $userA);
$stmt->bindParam(':Adminuserb', $userB);
$stmt->bindParam(':Adminuserc', $userC);
$stmt->execute();
$admin = $stmt->fetch(PDO::FETCH_OBJ);
$db = null;
if(!empty($admin)){
$newUsers = array('a' => $userA, 'b' => $userB, 'c' => $userC);
print_r($newUsers);
}
}
Turns out i don't need to use bindparam i could just do it like this
$userA = $request->getParam('usera');
$userB = $request->getParam('userb');
$userC = $request->getParam('userc');
$sql = "SELECT *FROM admins";
try {
$db = new db();
$db = $db->connect();
$stmt = $db->prepare($sql);
$stmt->execute();
$admin = $stmt->fetch(PDO::FETCH_OBJ);
$db = null;
if(!empty($admin)){
$newUsers = array('a' => $userA, 'b' => $userB, 'c' => $userC);
print_r($newUsers);
}
}
thus i need to send the post request to my function using x-www-form-urlencoded

retrieve data from db using function pdo

here is the code before implementing the function,
try {
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5');
$stmt->execute(array(':published' => 'published'));
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$contents = $result['content'];
$title = $result['title'];
....
this works fine. Then i moved db connecting commands to separate php file(functions.php). and created this function,
function run_db($sqlcom,$exe){
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
$data_db = $stmt->fetch(PDO::FETCH_ASSOC) ;
return $data_db;
}
Then i changed first mentioned code like this,
try {
$data_db=run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
while ($result = $data_db) {
$contents = $result['content'];
$title = $result['title'];
Then all i got was one post repeating infinitely. Can anyone tell me how to correct this?
Change the function to this:
function run_db($sqlcom,$exe){
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt;
}
and the call to that function to:
try {
$stmt = run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$contents = $result['content'];
$title = $result['title'];
EDIT: Better solution is the one that jeroen advices - to return all the fetched objects at once:
function run_db($sqlcom,$exe){
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Then calling this way:
try {
$data = run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
foreach($data as $result) {
$contents = $result['content'];
$title = $result['title'];
EDIT 2: Anyway - wrapping such a logic into one function is not very good idea. now You are limited with executing of only SELECT queries and the resulting array containing always only record's associative array. What if You would like to (for any reason) retrieve the array of objects, or even only one single value? What if You would like to execute INSERT, UPDATE, DELETE queries???
If You for sure want to go this way, then I'd suppose creating a class with functions like this:
class MyPDO {
private $connection;
static $instance;
function __construct() {
$this->connection = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
static function getInstance() {
return self::$instance ? : self::$instance = new MyPDO;
}
// retrieves array of associative arrays
function getAssoc($sqlcom, $exe) {
$stmt = $this->connection->prepare($sqlcom);
$stmt->execute($exe);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// retrieves array of objects
function getObj($sqlcom, $exe) {
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt->fetchAll(PDO::FETCH_OBJ);
}
// retireves one single value, like for SELECT 1 FROM table WHERE column = true
function getOne($sqlcom, $exe) {
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt->fetchColumn();
}
// just executes the query, for INSERT, UPDATE, DELETE, CREATE ...
function exec($sqlcom, $exe){
$stmt = $conn->prepare($sqlcom);
return $stmt->execute($exe);
}
}
Then You can call it this way:
try {
$pdo = MyPDO::getInstance();
foreach($pdo->getAssoc('MySQL QUERY'), array($param, $param)) as $result) {
print_r($result);
}
} catch(\Exception $e) {
// ...
}
Just return the statement:
function run_db($sqlcom,$exe){
static $conn;
if ($conn == NULL)
{
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt;
}
try {
$stmt=run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$contents = $result['content'];
$title = $result['title'];
And you could also set the default fecth mode on the connection.
An alternative to the correct answers that return $stmt from the function, would be to fetch all rows in the function and use a foreach in your main code:
In function:
...
$data_db = $stmt->fetchAll(PDO::FETCH_ASSOC) ;
return $data_db;
Outside of function:
$data_db=run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
foreach ($data_db as $result) {
$contents = $result['content'];
$title = $result['title'];
...
There are two essential problems with your code.
It connects every time it runs a query.
It returns data in only one format, while PDO can return results in dozens different formats.
Accepted answer makes it wrong, as it is just trying to reinvent PDO features, but very dirty way, with a lot of duplicated code and still failing to make it as good as with vanilla PDO.
As it said in xdazz's answer, you have to return the statement. And then use PDO's native fetch mode to get the result in desired format, using method chaining.
Also, you shouldn't add try to your code.

mysqli get_result alternative with multiple parameters

SELECT * FROM `ware_house_indents` WHERE `has_cancel` = ? AND `eid`= ?
i need to get result above query in mysqli. but i cant use get_result() function because it is not working in server.i have found this below function and it is working fine.but that function not possible to pass multiple parameters.please help me to solve this problem.
function db_bind_array($stmt, &$row)
{
$md = $stmt->result_metadata();
$params = array();
while($field = $md->fetch_field()) {
$params[] = &$row[$field->name];
}
return call_user_func_array(array($stmt, 'bind_result'), $params);
}
function db_query($db, $query, $types, $params)
{
$stmt = $db->prepare($query);
$bindRet = call_user_func_array(array($stmt,'bind_param'),
array_merge(array($types), $params));
$stmt->execute();
$result = array();
if (db_bind_array($stmt, $result) !== FALSE) {
return array($stmt, $result);
}
$stmt->close();
return FALSE;
}
if (($qryRes = db_query($mysqli, $sql, 'i', array(&$var))) !== FALSE) {
$stmt = $qryRes[0];
$row = $qryRes[1];
while ($stmt->fetch()) {
print_r($row);
}
$stmt->close();
}
Let me suggest you a quite indirect solution.
You'd do yourself a huge favor if start using PDO instead of mysqli
It has no mysqli disadvantages when dealing with prepared statements as it has a way better implementation of above functions out of the box. So, it will let you to get your data in a few lines:
$sql = "SELECT * FROM ware_house_indents WHERE has_cancel = ? AND eid= ?";
$stm = $pdo->prepare($sql);
$stm->execute(array($cancel,$eid));
$data = $stm->fetchAll(); // or fetch() if you need only one row
that's all

Getting "wrong parameter count..." error with prepared statement

I have been trying to learn prepared statements so that we can start implementing them thoughout our PHP sites. This function takes values (or none) from text boxes on a search form using the $_POST transfer method then uses the names and values of those textboxes to add criteria to the WHERE clause. The function worked previously ut I can't seem to get the prepared statement to function.
Researching several scripts I started using the one below and worked out a few bugs. now when I run it I get the error Wrong parameter count for mysqli_stmt::bind_param()
After this query runs I want to export the values into a table and was working before attempting the prepared statement.
Here is the code I have so far:
<?php
$db = mysqli_connec("ip_address", "loginname", "password", "database");
$refs = array('sssss');
foreach ($_POST as $key => $value)
{
$refs[] =& $_POST[$key];
}
$query = "SELECT col1, col2, col3, col4, col5 FROM tbl_name WHERE 1=1";
foreach ($_POST as $k => $v)
{
if(!empty($v)) {
$query .= " AND $k = ?";
$params[$k] = $v;
}
}
$results = $db->prepare($query);
call_user_func_array(array($results, 'bind_param'), $refs);
$results->execute();
?>
Parameters passed to mysqli_stmt::bind_param must be passed by reference, and only variables can be passed by reference, so you cannot pass the result of a function directly into call_user_func_array in this case. Also, the first parameter passed to bind_param is a string list of the variable types. Instead, try this:
// Change to whatever types are relevant
$refs = array('sss');
foreach ($arr as $key => $value)
{
$refs[] =& $arr[$key];
}
call_user_func_array(array($results, 'bind_param'), $refs);
Edit
This line is wrong:
$results = $mysqli->prepare($query);
Should be
$results = $db->prepare($query);
Ok, the way I solved this was to scrap everything and start over, which is always fun...but the new script that works for what I need is here
<?php
$dbhost = "ip_address";
$dbname = "db_name";
$dbuser = "db_login";
$dbpass = "db_pass";
$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass);
$query = "SELECT * FROM tbl_name WHERE 1=1";
foreach ($_POST as $k => $v)
{
if(!empty($v)) {
$query .= " AND $k LIKE ?";
$params[] = $v;
}
}
$results = $conn->prepare($query);
$results->execute($params);
$results->bindColumn(1, $no);
$results->bindColumn(2, $date);
$results->bindColumn(3, $name);
$results->bindColumn(4, $id);
$results->bindColumn(5, $path);
?>

Categories