mysqli prepared statement - nested function does not perform - php

Nested function inside of fetch (which is inside of another function) does not perform.
fn_smth1 is nested inside of fn_smth2 and should output result via fn_smth2
Example below is a simplified version.
function fn_smth1 ($id){
global $mysqli;
$stmt = $mysqli->stmt_init();
if ($stmt->prepare("SELECT code FROM at WHERE id = ?")){
$stmt->bind_param("i",$id);
$stmt->execute();
$stmt->bind_result($code);
if ($stmt->fetch()){
$code_displ = $code;
}
}
$stmt->close;
return $code_displ;
}
function fn_smth2($id){
global $mysqli;
$stmt = $mysqli->stmt_init();
if ($stmt->prepare("SELECT idx, name FROM at WHERE id = ?")){
$stmt->bind_param("i",$id);
$stmt->execute();
$stmt->bind_result($idx, $name);
if ($stmt->fetch()){
$code_displ = $name.' === '.fn_smth1($idx);
}
}
$stmt->close;
return $code_displ;
}
echo fn_smth2(1);
//expected
some name here === some code here
//received
some name here === null (function fn_smth1 does not give a value)

You're trying to execute second prepared statement, while the resultset from the first one has not been stored yet. Use mysqli_stmt::store_result() before trying to execute second statement.

Related

php, mysql: want to make a shortcut for stmt query function [duplicate]

I'm trying to create a function for my project. I would like it to handle all the check functions. What I mean with that is before you start inserting a row in your database you check if a row exists with that email address.
To use this function dynamically it needs to be flexible. So I did put my variables in an array, but mysqli_stmt_bind_param can't handle arrays. As a solution, I tried making a foreach loop.
The query:
$sql = "SELECT users_id, users_email FROM users WHERE users_id = ? AND users_email = ?;";
Calling the function:
check_database($sql, array($id, $mail), array("s", "s"), $location);
My original function:
function check_database($sql, $variables, $types, $location)
{
require $_SERVER['DOCUMENT_ROOT'] . '/includes/db/db.inc.php';
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: " . $location . "?error=sqlerror");
exit();
} else {
mysqli_stmt_bind_param($stmt, $types, $variables);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
if (!$row = mysqli_fetch_assoc($result)) {
return true;
}
}
}
I added a foreach to the mysqli_stmt_bind_param like this:
foreach ($types as $index => $type) {
mysqli_stmt_bind_param($stmt, $type, $variables[$index]);
}
This gives me an error and I don't know how to solve it :(
Warning: mysqli_stmt_bind_param(): Number of variables doesn't match number of parameters in prepared statement
You are on a very right track! Such a function should be an everyday companion for the every PHP programmer using mysqli, but strangely, only few ever have an idea of creating one.
I've had an exactly the same idea once and implemented a mysqli helper function of my own:
function prepared_query($mysqli, $sql, $params, $types = "")
{
$types = $types ?: str_repeat("s", count($params));
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($types, ...$params);
$stmt->execute();
return $stmt;
}
Main differences from your approach
the connection is made only once. Your code connects every time it executes a query and this is absolutely NOT what it should do
it can be used for any query, not only SELECT. You can check the versatility of the function in the examples section down in the article
types made optional as most of time you don't care for the type
no bizarre $location variable. Honestly, whatever HTTP stuff should never be a part of a database operation! If you're curious how to properly deal with errors, here is my other article Error reporting in PHP
With your example query it could be used like this
$check = prepared_query($sql, [$id, $mail])->get_result()->fetch_row();
or, if you want a distinct function, you can make it as well
function check_database($mysqli, $sql, $params, $types = "")
{
return prepared_query($mysqli, $sql, $params, $types)->get_result()->fetch_row();
}
and now it can be called as
$check = check_database($sql, [$id, $mail]);

A helper function for mysqli that dynamically binds params in prepared statement?

I'm trying to create a function for my project. I would like it to handle all the check functions. What I mean with that is before you start inserting a row in your database you check if a row exists with that email address.
To use this function dynamically it needs to be flexible. So I did put my variables in an array, but mysqli_stmt_bind_param can't handle arrays. As a solution, I tried making a foreach loop.
The query:
$sql = "SELECT users_id, users_email FROM users WHERE users_id = ? AND users_email = ?;";
Calling the function:
check_database($sql, array($id, $mail), array("s", "s"), $location);
My original function:
function check_database($sql, $variables, $types, $location)
{
require $_SERVER['DOCUMENT_ROOT'] . '/includes/db/db.inc.php';
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: " . $location . "?error=sqlerror");
exit();
} else {
mysqli_stmt_bind_param($stmt, $types, $variables);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
if (!$row = mysqli_fetch_assoc($result)) {
return true;
}
}
}
I added a foreach to the mysqli_stmt_bind_param like this:
foreach ($types as $index => $type) {
mysqli_stmt_bind_param($stmt, $type, $variables[$index]);
}
This gives me an error and I don't know how to solve it :(
Warning: mysqli_stmt_bind_param(): Number of variables doesn't match number of parameters in prepared statement
You are on a very right track! Such a function should be an everyday companion for the every PHP programmer using mysqli, but strangely, only few ever have an idea of creating one.
I've had an exactly the same idea once and implemented a mysqli helper function of my own:
function prepared_query($mysqli, $sql, $params, $types = "")
{
$types = $types ?: str_repeat("s", count($params));
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($types, ...$params);
$stmt->execute();
return $stmt;
}
Main differences from your approach
the connection is made only once. Your code connects every time it executes a query and this is absolutely NOT what it should do
it can be used for any query, not only SELECT. You can check the versatility of the function in the examples section down in the article
types made optional as most of time you don't care for the type
no bizarre $location variable. Honestly, whatever HTTP stuff should never be a part of a database operation! If you're curious how to properly deal with errors, here is my other article Error reporting in PHP
With your example query it could be used like this
$check = prepared_query($sql, [$id, $mail])->get_result()->fetch_row();
or, if you want a distinct function, you can make it as well
function check_database($mysqli, $sql, $params, $types = "")
{
return prepared_query($mysqli, $sql, $params, $types)->get_result()->fetch_row();
}
and now it can be called as
$check = check_database($sql, [$id, $mail]);

Retrieving data from database using prepared statement

I'm having problem retrieving my data from my database. Here's my code:
function login($email, $password) {
$stmt = $this->conn->prepare("SELECT id FROM lms_admin_users WHERE email=?");
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows == 1) {
while ($stmt->fetch()) {
// echo data from table like $data["name"]; <----
}
}
else {
echo "Failed";
}
}
What I want to know is the equivalent of while($data=mysqli_fetch_assoc($result)) to replace my existing code (in OOP way) while ($stmt->fetch()) and make it fetch the datas using $data["name"]
You need to tell PHP in which variable(s) to store the result. There are two ways to do this:
with bind_result, and then fetch on the statement object, or
with get_result, and then fetch_assoc (or other fetch_* variant) on the result object
1. bind_result
With this solution you bind variable(s) to the SELECT list, and while looping with fetch PHP will put the new data in those variable(s):
$stmt = $this->conn->prepare("SELECT id FROM lms_admin_users WHERE email=?");
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($id, $name); // <- Add; #args = #cols in SELECT
if($stmt->num_rows == 1) {
while ($stmt->fetch()) {
echo $id, $name; // <-- then you can do this.
}
}
2. get_result
Instead of bind_result you can use get_result, which will give a result object which you can fetch each row from as an associative array:
//...
// $stmt->store_result(); // <- Remove: does not work together with next statement
$result = $stmt->get_result(); // <--- add this instead
if($result->num_rows == 1) { // <--- change to $result->...!
while ($data = $result->fetch_assoc()) {
echo $data['id'], $data['name']; // <--- available in $data
}
}

which object is missing?

I am unable to understand why this error is popping up. I do know that the obvious reason why these kind of errors come up but I did look and re-look into my code and cannot understand why!
The error is:
Fatal error: Call to a member function prepare() on a non-object
Here are the code snippets.
db_connect.php
<?php
include_once 'psl-config.php'; // As functions.php is not included
$mysqli = new mysqli(HOST, USER, PASSWORD, DATABASE);
customer.php
include_once 'includes/db_connect.php';
include_once 'includes/functions.php';
.
.
.
function myCallBackFunction($array) {
//echo ".";
// print_r($array);
$amount=$array['amount'];
$date=$array['date'];
if(transaction($mysqli, $date, $amount))
{
echo "Transaction table Updated";
}
}
functions.php
//Function to insert transactions
function transaction($mysqli, $date, $amount) {
if($smt = $mysqli->prepare("INSERT INTO `tbltransaction` (entry_date,income) VALUES (?,?)
ON DUPLICATE KEY UPDATE income=income+?;"));
{
$stmt->bind_param('sii', $date, $amount, $amount); // Bind "$date" and "$amount" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
if ($stmt->num_rows == 1) {
return true;
} else {
return false;
}
}
}
tbltransaction
Column Type Null Default Comments MIME
entry_date date No
income int(11) No
P.S: another function in the functions.php file is working just fine, here is the function and the way I am calling it
function
//Function to display notice
function notice($mysqli) {
$notice = null;
if ($stmt = $mysqli->prepare("SELECT notice FROM tblnotice ORDER BY ID DESC LIMIT 1")) {
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($notice);
$stmt->fetch();
return $notice;
}
}
calling the function
<?php echo notice($mysqli); ?>
This is a variable scope issue - you need to pass the $mysqli object in to the myCallBackFunction function as a second parameter or it won't be set inside that function.
Like this:
function myCallBackFunction($array, $mysqli) {
Then where you call that function you'll need to pass in the $mysqli object:
myCallBackFunction($array, $mysqli);
you do alternatively
function notice() {
global $mysqli;
$notice = null;
if ($stmt = $mysqli->prepare("SELECT notice FROM tblnotice ORDER BY ID DESC LIMIT 1")) {
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($notice);
$stmt->fetch();
return $notice;
}
}

Mysql statement inside a function doesn't work

I have a MySQL statement in a function but somehow it doesn't work. I get the following error:
Fatal error: Call to a member function
prepare() on a non-object in
D:\xampp\test.php on line 7
function isloggedin($getcookiedata) {
$data = explode("|", $getcookiedata);
$userid = $data[0];
$md5password = $data[1];
$sql = "SELECT user_id, username, email, newsletter, user_group FROM users WHERE user_id = ? AND md5password = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('ss', $userid, $md5password);
$stmt->execute();
$stmt->bind_result($r_userid, $r_username, $r_email, $r_newsletter, $r_user_group);
$stmt->store_result();
$checker = $stmt->num_rows;
$stmt->fetch();
$stmt->close();
}
When I just do the SQL statement outside a function, it works. But not inside the function.
If $mysqli is a global you're defining somewhere, you need to pull it into your function's scope with:
function isloggedin($getcookiedata) {
global $mysqli;
...
}
See PHP - Variable scope

Categories