Unable to get results php mysqli select with bind - php

I am attempting to return a result set from mysql in php using mysqli. I have attempted several different ways, but they either end in errors, or empty arrays being returned. I know the query is good because I can run it in my db admin client replacing the question mark with the string needed and it returns as expected. Does anyone see something I have missed? Looks like it should be working to me, but obviously something has to be wrong. ¯_(ツ)_/¯
<?php
class db extends mysqli{
function __construct(){
parent::__construct(PUBP_HOST, PUBP_USER, PUBP_PASS, PUBP_DB);
}
/*
--------------------------------------------------------------------------*/
function read_agency_phones($agency_in){
$returnArray = array();
if($stmt = $this->prepare("SELECT firstname, lastname, agency, phonenumber FROM employees WHERE agency = ?")){
try{
$stmt->bind_param('s', $agency_in);
$stmt->execute();
$stmt->bind_result($first, $last, $agency, $phone);
while($stmt->fetch()){
$returnArray[] = array(
'first_name' => $first,
'last_name' => $last,
'agency' => $agency,
'phonenumber' => $phone
);
}
$stmt->free_result();
$stmt->close();
return $returnArray;
} catch (Exception $ex) {
return $ex->getMessage();
}
}
return 'failed001';
}
}
$db = new db();
$results = $db->read_agency_phones("SOME_STRING");
echo '<pre>';
echo var_export($results, true);
echo '</pre>';
die;
The agency field in the database is of type VARCHAR(10).
When running the following query in admin panel, results are returned as expected:
SELECT firstname, lastname, agency, phonenumber FROM employees WHERE agency = "THE-AGENCY"

Related

Pass parameter from URL to a php function in an api php

I have a working API written in PHP, my code works fine but I need to pass a parameters to the API. but it is not working as expected.
In my readOrders function, I am getting all the orders, but now I want to get all orders with ids above a particular number passed on from the url accessing the api.
function getOrders($last_oid){
$stmt = $this->con->prepare("SELECT oid, uid, order_num, create_date, status_date FROM orders WHERE oid > ?");
$stmt->execute($last_oid);
$stmt->bind_result($oid, $uid, $order_num, $create_date, $status_date);
$orders = array();
while($stmt->fetch()){
$order = array();
$order['oid'] = $oid;
$order['uid'] = $uid;
$order['order_num'] = $order_num;
$order['create_date'] = $create_date;
$order['status_date'] = $status_date;
array_push($orders, $order);
}
return $orders;
}
I was getting all the orders when I didn't have a parameter $last_oid. that parameter is to fetch orders with id WHERE id>? and pass the last_id in execute().
And in my API call, I am passing the last_id, it is currently hard coded, after I am done I will use $_GET to get the value and pass it to the function.
//the READ operation
//if the call is get orders
case 'getOrders':
$db = new DbOperation();
$response['error'] = false;
$response['message'] = 'Request orders successfully completed';
$response['orders'] = $db->getOrders(504);
break;
I am not sure what I am not doing right. I am getting an empty json but I could should be getting some few rows.
You have an error in the code. You are executing a "prepared statement" but with the wrong statements. Try it like this:
function getOrders($last_oid)
{
try {
$orders = array();
$stmt = $this->con->prepare("SELECT oid, uid, order_num, create_date, status_date FROM orders WHERE oid > ?");
// I assume $ last_oid is an integer.
$stmt->bind_param("i", $last_oid);
if ($stmt->execute()) {
$result = $stmt->get_result();
// use the while loop to load the result set
while ($row = $result->fetch_assoc()) {
array_push($orders, array(
'oid' => $row['oid'],
'uid' => $row['uid'],
'order_num' => $row['order_num'],
'create_date' => $row['create_date'],
'status_date' => $row['status_date']
));
}
return $orders;
}
} catch (Exception $ex) {
print $ex->getMessage();
}
}

How to organize SQL select functions?

I want to get information by user id, so lets add this to the model:
public function getById ($id)
{
$sql = 'SELECT * FROM users';
return ActualDbHander::run($sql);
}
later, I want to get only some fields:
public function getById ($id, $fields = '*')
{
$sql = 'SELECT '.$fields.' FROM users';
return ActualDbHander::run($sql);
}
another idea, lets add ordering:
public function getById ($id, $fields = '*', $orderBy = '')
{
$sql = 'SELECT '.$fields.' FROM users';
if ($orderBy != '')
{
$sql.= ' ORDER BY '.$orderBy;
}
return ActualDbHander::run($sql);
}
and I see this becaming messy and messy. What if I want to add JOIN-s? What if I want to add detailed WHERE-s? This is when "too generalic" methods born.
I completely agree with mch and Mjh comments, but, only in the case you actually want to have a "BD driver" (and build it yourself) I'd use different names for each query, very specific names, because you need to know exactly what a function will return to you.
So if I were you I would use names like getAllUsers, getUserById, getAllUsersOnlyPersonalData, getUserByIdOnlyPersonalData, getAllUsersOnlyContactData and so on (with fixed fields and filters for each method).
Note that in your examples you are not using at all the $id variable, so you are always receiving a list of users.
Regarding the method to make the queries, there are lots of ways to do it. Personally, I prefer MySQLi Object-Oriented prepared statements, because it's safe, easy and currently very extended, so I will use it just to ilustrate the examples.
Your functions would be something like this:
<?php
class DBDriver{
function openConnection(){
// If you don't always use same credentials, pass them by params
$servername = "localhost";
$username = "username";
$password = "password";
$database = "database";
// Create connection
$conn = new mysqli($servername, $username, $password, $database);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Return conection object
return $conn;
}
function closeConnection($conn){
$conn->close();
}
function getAllUsers (){ // We don't need ids here
$conn = $this->openConnection();
// Array of arrays to store the results
// You can use any other method you want to return them
$resultsArray = [];
$sqlQuery = "SELECT * FROM users";
// In this case it's not neccesary to use prepared statements because we aren't binding any param but we'll use it to unify the method
if ($stmt = $conn->prepare($sqlQuery)) {
// Execute query
$stmt->execute();
// Bind result variables (I don't know your actuall column names)
$stmt->bind_result($id, $name, $email, $phone, $birthdate);
// Fetch values
while ($stmt->fetch()) {
$resultsArray[] = [$id, $name, $email, $phone, $birthdate];
}
// Close statement
$stmt->close();
}
$this->closeConnection($conn);
// If no results, it returns an empty array
return $resultsArray;
}
function getUserByIdOnlyContactData ($userId){
$conn = $this->openConnection();
// Array to store the results (only one row in this case)
$resultsArray = [];
$sqlQuery = "SELECT name, email, phone FROM users WHERE id = ?";
if ($stmt = $conn->prepare($sqlQuery)) {
// Bind parameter $userId to "?" marker in $sqlQuery
$stmt->bind_param("i", $userId);
$stmt->execute();
$stmt->bind_result($name, $email, $phone);
// If id found
if ($stmt->fetch()) {
$resultsArray = [$name, $email, $phone];
}
// Close statement
$stmt->close();
}
$this->closeConnection($conn);
return $resultsArray;
}
function getAllUserOnlyBirthdayDataOrderByBirthday (){
$conn = $this->openConnection();
$resultsArray = [];
$sqlQuery = "SELECT id, name, birthdate FROM users ORDER BY birthdate";
if ($stmt = $conn->prepare($sqlQuery)) {
$stmt->execute();
$stmt->bind_result($id, $name, $birthdate);
while ($stmt->fetch()) {
$resultsArray[] = [$id, $name, $birthdate];
}
// Close statement
$stmt->close();
}
$this->closeConnection($conn);
return $resultsArray;
}
} // Class end
This way it's true you will have lots of functions depending on your requirements but as you can see it's extremely easy to add new ones or modify them (and you won't get mad with many different options in the same function).
Hope this helps you to organize your database driver!

Unable to return database query results

I'm at the early stages of incorporating a search facility on a website, but I've hit a stumbling block. At the moment, I'm just doing some testing, using jQuery AJAX, but the problem definitely lies in my php:
...
$searchq = $_POST['searchq'];
$output = '';
$db = new PDO($dsn, $mysqluser, $mysqlpass, array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
function getData($db){
// Prepare resource query statement
$stmt = $db->query("SELECT * FROM mod_site_content WHERE alias = ':searchq'");
// Bind paremeters
$stmt->bindParam(':searchq', $searchq, PDO::PARAM_STR);
// Execute query
$stmt->execute();
// Grab result
$output = $stmt->fetchAll();
// Return output
done($output);
};
try {
getData($db);
} catch(PDOException $e){
echo $e->getMessage();
}
function done($out){
echo $out;
}
At the moment I'm just passing the results to console.log() in my AJAX .done() method. The above outputs "Array" with nothing in it, regardless of whether I search for something that should be there or not.
If I change the above slightly to:
function getData($db){
...
$output = $stmt->fetchAll();
$result = implode($output,"--");
// Reture output
done($result);
};
I get nothing back whatsoever.
mod_site_content looks like this:
id | type | alias
-------------------------
1 | document | home
2 | document | projects
...
Thanks.
Your issue is here:
$stmt = $db->query("SELECT * FROM mod_site_content WHERE alias = ':searchq'");
replace it by this:
$stmt = $db->prepare("SELECT * FROM mod_site_content WHERE alias = :searchq");
PDO variable i.e. :searchq shouldn't be surrounded by ' or else PDO will consider them as strings, your code should be giving an error when you try to bind searchq
Additionally notice that I used the prepare() not query(), you need to prepare the query first, then bind params then execute
third issue, you should pass $searchq to your getData function
I copied and pasted your code here, and edited, just to clear my head, can you please test it and tell me if it works?
$searchq = $_POST['searchq'];
$output = '';
$db = new PDO($dsn, $mysqluser, $mysqlpass, array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
function getData($db, $searchq){
// Prepare resource query statement
$stmt = $db->prepare("SELECT * FROM mod_site_content WHERE alias = :searchq");
// Bind paremeters
$stmt->bindParam(':searchq', $searchq, PDO::PARAM_STR);
// Execute query
$stmt->execute();
// Grab result
$output = $stmt->fetchAll();
// Return output
done($output);
};
try {
getData($db, $searchq);
} catch(PDOException $e){
echo $e->getMessage();
}
function done($out){
if(is_array($out)){
print_r($out);
} else {
echo $out;
}
}
echo json_encode($out) and make sure you are expecting a json object on the browser.
No idea offhand why imploding the return value and echoing it out failed to return anything, unless ->fetchAll doesn't return an actual array according to implode, in which case it should be kicking out an error somewhere...

Convert mysqli to pdo bind_all

here is my current code
function getUserDetails($username=NULL, $id=NULL) {
if($username!=NULL) {
$column = "user_name";
$data = $username;
}
elseif($id!=NULL) {
$column = "id";
$data = $id;
}
global $db;
$query = $db->prepare("SELECT id, username, permissions, forename, surname, password, email, courseid, choiceid, lastlogin, active FROM users WHERE $column = :column");
$query->bindParam(":column", $data);
$query->execute();
$query->bind_result ($id, $username, $permissions, $forename, $surname, $password, $email, $courseid, $choiceid, $lastlogin, $active);
while ($query->fetch()){
$row = array('id' => $id, 'userlevel' => $permissions, 'username' => $username, 'forename' => $forename, 'surname' => $surname, 'password' => $password, 'email' => $email, 'courseId' => $courseid, 'choiceId' => $choiceId, 'lastlogin' => $lastlogin, 'active'=> $active);
}
return ($row);
}
I have been trying to convert this to pdo, as I've found out bind_result doesn't work with pdo - could anyone help me as to what I should be doing?
I've read arround that I should be using fetch? But i'm getting really confused.
[edit]
ive tried this:
function getUserDetails($username=NULL,$id=NULL) {
if($username!=NULL) {
$column = "user_name";
$data = $username;
}
elseif($id!=NULL) {
$column = "id";
$data = $id;
}
global $db;
$query = $db->prepare("SELECT id, username, permissions, forename, surname, password, email, courseid, choiceid, lastlogin, active FROM users WHERE $column = :column");
$query->bindParam(":column", $data);
$query->execute();
$results = array();
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$results[] = $row;
}
return ($results);
}
is this a step in the right direction ?
[edit2]
updated my code to this:
function getUserDetails($username) {
global $db;
$query = $db->prepare("SELECT * FROM users WHERE username = :username");
$query->bindParam(":username", $username);
return $query->fetch(PDO::FETCH_ASSOC);
}
$username = 'uname';
$result = getUserDetails($username);
print_r($result);
however it prints nothing. the username definitely exists.
ive tried a test database with some dummy data
$data = '2';
$sth = $db->prepare("SELECT * FROM test WHERE id = :id");
$sth->bindParam(":id", $data);
$sth->execute();
$result = $sth->fetch(PDO::FETCH_ASSOC);
print_r($result);
im trying to figure out how i access what is in the printed array:
the array comes out as
Array ( [Id] => 2 [Name] => tom )
how do i (for example) do
$name = $result['name']; //line 67
when i try that code i get
Notice: Undefined index: name in <directory>\test.php on line 67
Figured it out!
function getUserDetails($username) {
global $db;
$sth = $db->prepare("SELECT id, username, permissions, forename, surname, password, email, courseid, choiceid, lastlogin, active FROM users WHERE username = :username");
$sth->bindParam(":username", $username);
$sth->execute();
$result = $sth->fetch(PDO::FETCH_ASSOC);
return $result;
}
$username = 'un';
$userdetails = getUserDetails($username);
echo $userdetails['forename'];
and it gives me the correct answer!
thanks for your help
YES!
It's great step in the right direction.
As you can see, mysqli is absolutely unusable with prepared statements, both in binding placeholders and returning results.
while PDO can solve your problem using dramatically less code.
You don't need useless bind with PDO at all - just get all results with fetchAll():
function getUserDetails($username=NULL,$id=NULL) {
if ($username) {
$column = "user_name";
$data = $username;
} elseif($id) {
$column = "id";
$data = $id;
} else {
return;
}
global $db;
$query = $db->prepare("SELECT * FROM users WHERE $column = ?");
$query->execute(array($data));
return $query->fetchAll();
}
But wait. Why do you want to return an array if it's users details?
It will add just useless dimension to the returned array.
For this very case make it
return $query->fetch();
instead of fetchAll().
But then you need many rows - use this latter method.
On other methods and useful connect options refer to the tag wiki

Why does my code not retrieve/display the PDO record set?

Using the code below, I get the error, "Call to undefined method stdClass::fetchObject()".
function getProdDetails2SaveInInvoice($data) {
global $dbh;
try {
$sth=$dbh->prepare("
SELECT
AES_DECRYPT('alt_id', ?),
AES_DECRYPT('prod_name', ?),
AES_DECRYPT('prod_desc', ?)
FROM
products
WHERE
prod_id = ?
");
$sth->execute($data);
$rs = $sth->query(PDO::FETCH_ASSOC);
return $rs;
}
catch(PDOException $e) {
echo "Something went wrong. Please report this error.\n";
file_put_contents(
$_SERVER['DOCUMENT_ROOT']."/PDOErrors.txt",
"\n\nScript name : ".SCRIPT."\nFunction name : ".__FUNCTION__."\n".
$e->getMessage(), FILE_APPEND);
throw new failedTransaction();
}
}
$data = array(
DBKEY, /* field 1 */
DBKEY, /* field 2 */
DBKEY, /* field 3 */
$prodid /* comparison */
);
$rs = getProdDetails2SaveInInvoice($data);
while ($row = $rs->fetchObject()) {
echo $row->prod_name;
}
Unfortunately, this doesn't work and returns the error mentioned above.
I can confirm that the $dbh database connection is working as it's the same connection working for the inserts and updates. Thanks.
UPDATE
This is how I've amended my code based on the suggestions below, but I'm still getting nothing returned:
try {
$dbh = new PDO("mysql:host=".CO_DB_HOST.";dbname=".CO_DB_NAME, CO_DB_UNAME, CO_DB_PWORD);
$dbh ->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch(PDOException $e) {
echo $e->getMessage();
}
function getProdDetails2SaveInInvoice($data) {
global $dbh;
try {
$sth=$dbh->prepare("
SELECT
AES_DECRYPT('alt_id', ?),
AES_DECRYPT('prod_name', ?),
AES_DECRYPT('prod_desc', ?)
FROM
products
WHERE
prod_id = ?
");
$sth->execute($data);
while ($row = $sth->fetchObject()) {
// PROCESS ROW
$rs = array($row->alt_id, $row->prod_name, $row->prod_desc);
}
return $rs;
}
catch(PDOException $e) {
echo "Something went wrong. Please report this error.\n";
file_put_contents(
$_SERVER['DOCUMENT_ROOT']."/PDOErrors.txt",
"\n\nScript name : ".SCRIPT."\nFunction name : ".__FUNCTION__."\n".
$e->getMessage(), FILE_APPEND);
throw new failedTransaction();
}
}
// Fetch additional info from invoice_products.
$data = array(
DBKEY, /* field 1 */
DBKEY, /* field 2 */
DBKEY, /* field 3 */
$prodid /* comparison */
);
$rs = getProdDetails2SaveInInvoice($data);
print_r($rs);
If I hardcode the 'where' argument (19), it still does not retrieve the result. Ideally I think I should retrieve the result in an object so that it can be streamed, but right now, I'd be happy even if it came in a box!
The data is definitely existing in the database and can be pulled using a traditional query.
This is the output of the print_r($rs):
Array
(
[0] =>
[1] =>
[2] =>
)
You should loop over the prepared statement, and not call query on the prepared statement. Basic usage of prepared statements is as follows:
$sth = $dbh->prepare("YOUR QUERY");
$sth->execute();
$results = array();
while ($row = $sth->fetchObject()) {
$results[] = array(
'alt_id' => $row->alt_id,
'prod_name' => $row->prod_name,
'prod_desc' => $row->prod_desc
);
}
return $result;
As an alternative you could also use $sth->fetchAll() which returns an array with all rows that are the result of your query, see PDOStatement::fetchAll().

Categories