prepared statement method.. confused - php

I don't know what's missing or why it isn't displaying data. My code is working if I'm not using prepared statements. When I used prepared statements, it seems that code is not working anymore.
db.php
Class Database{
public $mysqli;
public function __construct($db_host, $db_user, $db_password, $db_name){
$this->con = new mysqli($db_host, $db_user, $db_password, $db_name);
}
public function selectUserInfo($id){
$stmt = $this->con->prepare("SELECT * FROM users WHERE os_id = ?");
$stmt->bind_param("s", $id);
if($stmt->execute() == FALSE){
trigger_error($stmt->error, E_USER_ERROR);
}else{
$data = array();
while($row = $stmt->fetch()){
$data[] = $row;
}
return $data;
}
}
}
config.php
define("DBHOST","somehost");
define("DBUSER","someroot");
define("DBPASS","somepassword");
define("DB","my_database");
this is how I would displayed it at my page.
require 'global/db.php';
require_once 'config.php';
$db = new Database(DBHOST, DBUSER, DBPASS, DB);
$data = $db->selectUserInfo($_GET['name']);
foreach ($data as $key) {
# code...
echo $key['os_fname'];
}

As we have defined, that the issue was with your foreach.
What is wrong is with how you're reading it, fetch does not have associative properties so need to use the bind_result.
Here is a hack that is also suggested at the fetch manual:
public function selectUserInfo($id)
{
$stmt = $this->con->prepare("SELECT * FROM users WHERE os_id=?");
$stmt->bind_param('i', $id);
if(!$stmt->execute())
{
trigger_error($stmt->error, E_USER_ERROR);
}
else
{
$bindVarArray = array();
$data = array();
$result;
$meta = $stmt->result_metadata();
while ($column = $meta->fetch_field())
{
$columnName = str_replace(' ', '_', $column->name);
$bindVarArray[] = &$result[$columnName];
}
call_user_func_array(array($stmt, 'bind_result'), $bindVarArray);
$index = 0;
while ($stmt->fetch() != null)
{
foreach ($result as $k => $v)
{
$data[$index][$k] = $v;
}
$index++;
}
return $data;
}
}
Then you can use your foreach to read it like this:
foreach ($data as $result)
{
echo $result['os_fname'], ' => ', $result['os_lname'], "\n";
}
And you can always use print_r to see how your resulting array is:
print_r($data);

your od_id type in DB is string or integer? if a integer
public function selectUserInfo($id){
$stmt = $this->con->prepare("SELECT * FROM users WHERE os_id = ?");
$stmt->bind_param("i", $id);//use 'i' instead of 's'
if($stmt->execute() == FALSE){
trigger_error($stmt->error, E_USER_ERROR);
}else{
$data = array();
while($row = $stmt->fetch()){
$data[] = $row;
}
return $data;
}
}

Related

Fatal Error while running a CMS program

i get this error while running my program.
Fatal error: Uncaught Error: Call to undefined method
CarModel::InsertCar() in
C:\xampp\htdocs\CoffeeWebsite\Controller\CarController.php:119 Stack
trace: #0 C:\xampp\htdocs\CoffeeWebsite\CarAdd.php(43):
CarController->InsertCar() #1 {main} thrown in
C:\xampp\htdocs\CoffeeWebsite\Controller\CarController.php on line 119
//Source code for CarModel and CarController
<?php
require ("Entities/CarEntity.php");
//Contains database related code for the Car page.
class CarModel {
//Get all car types from the database and return them in an array.
function GetCarTypes() {
require 'Credentials.php';
//Open connection and Select database.
$con = mysqli_connect($host, $user, $passwd) or die(mysqli_error($con));
$sql = mysqli_select_db($con,$database);
$result = mysqli_query($con,"SELECT DISTINCT type FROM car") or die(mysqli_error($con));
$types = array();
//Get data from database.
while ($row = mysqli_fetch_array($result)) {
array_push($types, $row[0]);
}
//Close connection and return result.
mysqli_close($con);
return $types;
}
//Get carEntity objects from the database and return them in an array.
function GetCarByType($type) {
require 'Credentials.php';
//Open connection and Select database.
$con = mysqli_connect($host, $user, $passwd) or die(mysqli_error($con));
$sql = mysqli_select_db($con,$database);
$query = "SELECT * FROM car WHERE type LIKE '$type'";
$result = mysqli_query($con,$query) or die(mysqli_error($con));
$carArray = array();
//Get data from database.
while ($row = mysqli_fetch_array($result)) {
$name = $row[1];
$type = $row[2];
$price = $row[3];
$colour = $row[4];
$details = $row[5];
$image = $row[6];
$review = $row[7];
//Create car objects and store them in an array.
$car = new CarEntity(-1, $name, $type, $price, $colour, $details, $image, $review);
array_push($carArray, $car);
}
//Close connection and return result
mysqli_close($con);
return $carArray;
}
function GetCarByID($id)
{
require 'Credentials.php';
//Open connection and Select database.
$con = mysqli_connect($host, $user, $passwd) or die(mysqli_error($con));
$sql = mysqli_select_db($con,$database);
$query = "SELECT * FROM car WHERE id=$id";
$result = mysqli_query($con,$query) or die(mysqli_error($con));
//Get data from database.
while ($row = mysqli_fetch_array($result)) {
$name = $row[1];
$type = $row[2];
$price = $row[3];
$colour = $row[4];
$details = $row[5];
$image = $row[6];
$review = $row[7];
//Create car
$car = new CarEntity($id, $name, $type, $price, $colour, $details, $image, $review);
}
//Close connection and return result
mysqli_close($con);
return $car;
}
}
function InsertCar(CarEntity $car) {
$query = sprintf("INSERT INTO car
(name, type, price,colour,details,image,review)
VALUES
('%s','%s','%s','%s','%s','%s','%s')",
mysqli_real_escape_string($car->name),
mysqli_real_escape_string($car->type),
mysqli_real_escape_string($car->price),
mysqli_real_escape_string($car->colour),
mysqli_real_escape_string($car->details),
mysqli_real_escape_string("Images/Coffee/" . $car->image),
mysqli_real_escape_string($car->review));
$this->PerformQuery($query);
}
function UpdateCar($id, CarEntity $car) {
$query = sprintf("UPDATE car
SET name = '%s', type = '%s', price = '%s', colour = '%s',
details = '%s', image = '%s', review = '%s'
WHERE id = $id",
mysqli_real_escape_string($car->name),
mysqli_real_escape_string($car->type),
mysqli_real_escape_string($car->price),
mysqli_real_escape_string($car->colour),
mysqli_real_escape_string($car->details),
mysqli_real_escape_string("Images/Coffee/" . $car->image),
mysqli_real_escape_string($car->review));
$this->PerformQuery($query);
}
function DeleteCar($id) {
$query = "DELETE FROM car WHERE id = $id";
$this->PerformQuery($query);
}
function PerformQuery($query) {
require ('Credentials.php');
$con=mysqli_connect($host, $user, $passwd) or die(mysqli_error($con));
mysqli_select_db($con,$database);
//Execute query and close connection
mysqli_query($query) or die(mysqli_error($con));
mysqli_close($con);
}
?>
<?php
require ("Model/CarModel.php");
//Contains non-database related function for the Coffee page
class CarController {
function CreateCarDropdownList() {
$carModel = new CarModel();
$result = "<form action = '' method = 'post' width = '200px'>
Please select a type:
<select name = 'types' >
<option value = '%' >All</option>
" . $this->CreateOptionValues($carModel->GetCarTypes()) .
"</select>
<input type = 'submit' value = 'Search' />
</form>";
return $result;
}
function CreateOptionValues(array $valueArray) {
$result = "";
foreach ($valueArray as $value) {
$result = $result . "<option value='$value'>$value</option>";
}
return $result;
}
function CreateCarTables($types)
{
$carModel = new CarModel();
$carArray = $carModel->GetCarByType($types);
$result = "";
//Generate a carTable for each carEntity in array
foreach ($carArray as $key => $car)
{
$result = $result .
"<table class = 'carTable'>
<tr>
<th rowspan='6' width = '150px' ><img runat = 'server' src = '$car->image' /></th>
<th width = '75px' >Name: </th>
<td>$car->name</td>
</tr>
<tr>
<th>Type: </th>
<td>$car->type</td>
</tr>
<tr>
<th>Price: </th>
<td>$car->price</td>
</tr>
<tr>
<th>Colour: </th>
<td>$car->colour</td>
</tr>
<tr>
<th>Details: </th>
<td>$car->details</td>
</tr>
<tr>
<th>Review: </th>
<td colspan='2' >$car->review</td>
</tr>
</table>";
}
return $result;
}
function GetImages() {
//Select folder to scan
$handle = opendir("Images/Coffee");
//Read all files and store names in array
while ($image = readdir($handle)) {
$images[] = $image;
}
closedir($handle);
//Exclude all filenames where filename length < 3
$imageArray = array();
foreach ($images as $image) {
if (strlen($image) > 2) {
array_push($imageArray, $image);
}
}
//Create <select><option> Values and return result
$result = $this->CreateOptionValues($imageArray);
return $result;
}
//<editor-fold desc="Set Methods">
function InsertCar() {
$name = $_POST["txtName"];
$type = $_POST["ddlType"];
$price = $_POST["txtPrice"];
$colour = $_POST["txtColour"];
$details = $_POST["txtDetails"];
$image = $_POST["ddlImage"];
$review = $_POST["txtReview"];
$car = new CarEntity(-1, $name, $type, $price, $colour, $details, $image, $review);
$carModel = new CarModel();
$carModel->InsertCar($car);
}
function UpdateCar($id) {
}
function DeleteCar($id) {
}
//</editor-fold>
//<editor-fold desc="Get Methods">
function GetCarById($id) {
$carModel = new CarModel();
return $carModel->GetCarById($id);
}
function GetCarByType($type) {
$carModel = new CarModel();
return $carModel->GetCarByType($type);
}
function GetCarTypes() {
$carModel = new CarModel();
return $carModel->GetCarTypes();
}
//</editor-fold>
}
?>
To elaborate on my comment.
First you want to use Prepared statements. Here is an example:
/* Connection */
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* Check connection */
if ($mysqli->connect_errno)
{
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
if($stmt = $mysqli->prepare("UPDATE..."))
{
/* Bind your params */
$stmt->bind_param('ss', $username, $password);
/* Error handling if execute failed */
if (!$stmt->execute())
{
die('execute() failed: ' . htmlspecialchars($stmt->error));
}
}
else
{
/* Error handling if Prepare failed */
die('prepare() failed: ' . htmlspecialchars($DBConnect->error));
}
$stmt->close();
Read more about returning result here
Now since you want to pass in args from your functions which are unknown to the PerformQuery function, you'll want to dynamically generate the Bind Params for use of using prepared statements. I've done something similar for dynamically generating the Bind Params using Reflection.
If you pass an Args value into the PerformQuery function you could have a function that looks like this:
public function PerformQuery($sql, $args = null)
{
/* Connection */
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* Check connection */
if ($mysqli->connect_errno)
{
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
if($stmt = $mysqli->prepare($sql))
{
/* Bind your params dynamically */
if (isset($args))
{
$method = new \ReflectionMethod('mysqli_stmt', 'bind_param');
$method->invokeArgs($stmt, $this->refValues($args));
}
/* Error handling if execute failed */
if (!$stmt->execute())
{
die('execute() failed: ' . htmlspecialchars($stmt->error));
}
}
else
{
/* Error handling if Prepare failed */
die('prepare() failed: ' . htmlspecialchars($mysqli->error));
}
$stmt->close();
}
For the dynamic binding to work you'll also need the following function
private function refValues($arr)
{
if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+
{
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
return $arr;
}
Now from your other methods, for example DeleteCar you'd pass in the query and args as follows:
public function DeleteCar($id)
{
$query = "DELETE FROM car WHERE id = ?"; // ? to show where mysqli will bind
$args = array('i', $id); // i means an int
$this->PerformQuery($query, args);
}
Using prepared statements will make your code much more secure and dynamically binding the variants in the Preform Query function means that you don't have to completely refactor your code to pass a connection around so you can use mysqli_real_escape_string.
Good luck :)

PHP database connection class bind_param

I would like to write a database connection class and I dont understand how I have to write the select method with bind_param-s. Here is the full code. And here the part of the code where I need the help:
public function select($sql){
$db = $this->connect(); //This methos connect to the DB
$stmt = $db->prepare($sql);
if($stmt === false){ //If the prepare faild
trigger_error("Wrong SQL", E_USER_ERROR);
}
$error = $stmt->bind_param("i", $id);
if($error){
return "Error: ".$stmt->error, $stmt->errno;
}
$err = $stmt->execute();
if($error){
return "Error: ".$stmt->error, $stmt->errno;
}
$result = $stmt->bind_result($id);
$stmt->close();
$dbConnection->closeConnection($db);
return $result;
}
I need to got it parameters or how can I slove it?
You need to pass your values into this function too. And eventually bind them into prepared statement.
Optionally you can pass string with types, but by default all "s" will do.
Also remember that you should connect only ONCE per script execution. and then use one single connection all the way throughout your code.
And get rid of all these error checks. Set mysqli in exception mode instead.
public function q($sql, $values = array(), $types = NULL)
{
$stm = $this->mysql->prepare($sql);
if (!$types)
{
$types = str_repeat("s", count($values));
}
if (strnatcmp(phpversion(),'5.3') >= 0)
{
$bind = array();
foreach($values as $key => $val)
{
$bind[$key] = &$values[$key];
}
} else {
$bind = $values;
}
array_unshift($bind, $types);
call_user_func_array(array($stm, 'bind_param'), $bind);
$stm->execute();
return $stm->get_result();
}
so it can be used like this
$res = $db->q("SELECT name FROM users WHERE id=?", [$id]);
or
$res = $db->q("SELECT name FROM users WHERE id=?", [$id], "i");
your other functions have to be changed as well.
class DB{
public $con;
function __construct()
{
$this->con = new mysqli("localhost", "root", "", "proba_fferenc");
}
public function select(...)
{
// as shown above
}
}

bind_param() on a non object error

I have the following function:
public function detail($detail, $table, $column, $value) {
if(is_array($detail)) {
$data = array();
foreach($detail as $key) {
$stmt = $this->mysqli->prepare("SELECT `$key` FROM `$table` WHERE `$column` = ?");
if(is_numeric($value)) {
$stmt->bind_param('i', $value);
} else {
$stmt->bind_param('s', $value);
}
$stmt->execute();
$stmt->bind_result($detail);
$stmt->fetch();
$data[] = $detail;
}
return $data;
} else {
$stmt = $this->mysqli->prepare("SELECT `$detail` FROM `$table` WHERE `$column` = ?");
if(is_numeric($value)) {
$stmt->bind_param('i', $value);
} else {
$stmt->bind_param('s', $value);
}
$stmt->execute();
$stmt->bind_result($detail);
$stmt->fetch();
return $detail;
}
}
This functions works well untill I use an array. The way to use this function is something like this: $db->detail('username', 'users', 'id', 1) This would return the username from users where the id is 1 (this works fine). Like I said the problem starts when I use an array so for example:
$details = array('username', 'active', 'registered');
$details = $db->detail($details, 'users', 'id', 1);
print_r($details);
The error is pointing to $stmt->bind_param('i', $value); in the if(is_array()). I already tried the answer of: bind_param on a non-object but that didn't help me; I still get the same error.
I hope someone knows how to fix the Fatal error: Call to a member function bind_param() on a non-object error for me.
Thanks in advance.
Try to unset the $stmt variable in the loop:
public function detail($detail, $table, $column, $value) {
if(is_array($detail)) {
$data = array();
foreach($detail as $key) {
$stmt = $this->mysqli->prepare("SELECT `$key` FROM `$table` WHERE `$column` = ?");
if(is_numeric($value)) {
$stmt->bind_param('i', $value);
} else {
$stmt->bind_param('s', $value);
}
$stmt->execute();
$stmt->bind_result($detail);
$stmt->fetch();
$data[] = $detail;
$stmt = null;
}
return $data;
} else {
$stmt = $this->mysqli->prepare("SELECT `$detail` FROM `$table` WHERE `$column` = ?");
if(is_numeric($value)) {
$stmt->bind_param('i', $value);
} else {
$stmt->bind_param('s', $value);
}
$stmt->execute();
$stmt->bind_result($detail);
$stmt->fetch();
return $detail;
}
}
This should help.
I think the efficient way to prepare query without using loop is too implode values in the array instead of looping and preparing the query statement.
For eg:- if the query is
SELECT `username`,`active`,`register` FROM users WHERE ID = 1 //username,active and register can be used in single prepare statement by imploding the array
if(is_array($detail)) {
$data = array();
$stmt = $this->mysqli->prepare("SELECT ".implode(", ",$detail)." FROM `$table` WHERE `$column` = ?");
if(is_numeric($value)) {
$stmt->bind_param('i', $value);
} else {
$stmt->bind_param('s', $value);
}
$stmt->execute();
$stmt->bind_result($detail);
$stmt->fetch();
$data[] = $detail;
$stmt = null;
return $data;
}

php mysqli_bind_param function issues. Trying to implement prepared statements

I am trying to establish a data connection to the MySql and create prepared statements, where the query_f function takes in any number of parameters, where the first parameter is the sql statement, and the other parameters are the values that would be substituted in the prepared statement.
Here is what I have. The first error I got is when I am trying to bind the values to the statement.
function query_f(/* query, [...] */){
$user = "root";
$pass = "root";
$host = "localhost";
$database = "mcnair";
$conn = mysqli_connect($host,$user,$pass);
if(!$conn)
{
echo "Cannot connect to Database";
}
else
{
mysqli_select_db($conn, $database);
}
// store query
$query = func_get_arg(0);
$parameters = array_slice(func_get_args(), 1);
$param = "'".implode("','",$parameters)."'";
// Prepare the statement
$stmt = mysqli_prepare($conn, $query);
if ($stmt == false)
{
echo "The statement could not be created";
exit;
}
// Bind the parameters
$bind = mysqli_stmt_bind_param($stmt, 's', $param);
echo mysqli_stmt_error($stmt);
if ($bind == false)
{
echo "Could not bind";
}
else
{
echo "Bind successful";
}
// Execute the statement
$execute = mysqli_stmt_execute($stmt);
if ($execute = false)
{
echo "Could not execute";
}
// fetch the data
$fetch = mysqli_stmt_fetch($stmt)
if ($fetch == false)
{
echo "Could not fetch data";
}
else
{
return $fetch;
}
}
And the function call I am using is:
query_f("SELECT Hash FROM alumni WHERE Username = '?'", "zm123");
How about using a class (instead of a function) and using mysqli in the OO way and not in the procedural way?
This is a simplified version of what I use. Not perfect, so if anyone would like to suggest improvements, I'm all ears.
class Connection {
private $connection;
public function __construct()
{
//better yet - move these to a different file
$dbhost = '';
$dbuname = '';
$dbpass = '';
$dbname = '';
$this->connection = new mysqli($dbhost, $dbuname, $dbpass, $dbname);
}
/*
* This is the main function.
*
* #param $arrayParams = array (0 => array('s' => 'Example string'), 1 => array('s' => 'Another string'), 2 => array('i' => 2), 3 => array('d' => 3.5) )
*/
public function executePrepared($sql, $arrayParams)
{
$statement = $this->prepareStatement($sql);
if ($statement) {
$this->bindParameter($statement, $arrayParams);
$this->executePreparedStatement($statement);
$result = $this->getArrayResultFromPreparedStatement($statement);
//only close if you are done with the statement
//$this->closePreparedStatement($statement);
} else {
$result = false;
}
return $result;
}
public function prepareStatement($sql)
{
$statement = $this->connection->prepare($sql) or $this->throwSqlError($this->connection->error);
return $statement;
}
public function bindParameter(&$statement, $arrayTypeValues)
{
$stringTypes = '';
$arrayParameters = array();
$arrayParameters[] = $stringTypes;
foreach ($arrayTypeValues as $currentTypeVale) {
foreach ($currentTypeVale as $type => $value) {
$stringTypes .= $type;
$arrayParameters[] = &$value;
}
}
$arrayParameters[0] = $stringTypes;
call_user_func_array(array($statement, "bind_param"), $arrayParameters);
}
public function getArrayResultFromPreparedStatement(&$statement)
{
$statement->store_result();
$variables = array();
$data = array();
$meta = $statement->result_metadata();
while($field = $meta->fetch_field())
$variables[] = &$data[$field->name]; // pass by reference
call_user_func_array(array($statement, 'bind_result'), $variables);
$i = 0;
$arrayResults = array();
while($statement->fetch())
{
$arrayResults[$i] = array();
foreach($data as $k=>$v)
{
$arrayResults[$i][$k] = $v;
}
$i++;
}
return $arrayResults;
}
public function executePreparedStatement($statement)
{
$result = $statement->execute() or $this->throwSqlError($statement->error);
return $result;
}
public function closePreparedStatement($statement)
{
$statement->close();
}
public function throwSqlError()
{ ... }
}

Converting MySQL connector to PDO

After taking some advice from people on here in a previous thread, I'm trying to convert my MySQL to PDO, but am running into some issues.
Here is my original MySQL connection class:
class DbConnector {
public static function getInstance() {
static $instance = null;
if ($instance === null) {
$instance = new DbConnector();
}
return $instance;
}
protected $theQuery;
private $link;
function DbConnector() {
$host = 'localhost';
$db = '';
$user = '';
$pass = '';
// connect to the db
$this->link = mysql_connect($host, $user, $pass);
mysql_select_db($db);
register_shutdown_function(array(&$this, 'close'));
}
public function find($query) {
$ret = mysql_query($query, $this->link);
if (mysql_num_rows($ret) == 0)
return array();
$retArray = array();
while ($row = mysql_fetch_array($ret))
$retArray[] = $row;
return $retArray;
}
public function insert($query) {
$ret = mysql_query($query, $this->link);
if (mysql_affected_rows() < 1)
return false;
return true;
}
public function query($query) {
$this->theQuery = $query;
return mysql_query($query, $this->link);
}
public function fetchArray($result) {
return mysql_fetch_array($result);
}
public function close() {
mysql_close($this->link);
}
public function exists($query) {
$ret = mysql_query($query, $this->link);
if (mysql_num_rows($ret) == 0)
return false;
}
public function last_id($query) {
return mysql_insert_id($query);
}
}
Here is the function that I'm writing:
function getRandomSubmission() {
global $db;
if(!empty($_GET['id'])){
$submission_id = $_GET['id'];
$query = $db->find("
SELECT
*
FROM
`submissions`
WHERE id = '{$submission_id}'
LIMIT 1
");
}
else {
$query = $db->find("
SELECT
*
FROM
`submissions`
ORDER BY RAND()
LIMIT 1
");
}
if($query) {
return $query[0];
}
else {
$query = $db->find("
SELECT
*
FROM
`submissions`
ORDER BY RAND()
LIMIT 1
");
}
}
Here is the PDO connector:
$host = 'localhost';
$username = '';
$pass = '';
$db = '';
try {
$dbh = new PDO("mysql:host=$host;dbname=$db", $username, $pass);
} catch (PDOException $e) {
echo $e->getMessage();
}
Here is what I've tried to convert it to, but it's just plain wrong. I think I need to be returning a PDO associative array in the 2nd if statement, but am not sure.
function getRandomSubmission() {
global $dbh;
if(!empty($_GET['id'])){
$submission_id = $_GET['id'];
$stmt = $dbh->prepare('
SELECT
*
FROM
`submissions`
WHERE
`id` = ?
LIMIT 1
');
$stmt->bindParam(1, $submission_id, PDO::PARAM_INT);
$stmt->execute();
}
else {
$stmt = $dbh->prepare('
SELECT
*
FROM
`submissions`
ORDER BY RAND()
LIMIT 1
');
$stmt->execute();
}
if($stmt) {
return $stmt[0];
}
else {
$stmt = $dbh->prepare('
SELECT
*
FROM
`submissions`
ORDER BY RAND()
LIMIT 1
');
$stmt->execute();
}
}
The original one works as intended, however (I realize I left the connection details blank).
You need to call fetch method of the PDOStatement object:
return $stmt->fetch()
Read about the fetch style, really you don't need FETCH_BOTH ;-)

Categories