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()
{ ... }
}
Related
I have been adapting an older abstraction layer to use PDO but I am running into user x has more than 'max_user_connections' active connections SQLSTATE[HY000] [1203] errors when looping through large sets. I have been reading on http://php.net/manual/en/pdo.connections.php but all of my attempts to unset the $dbh from within the loops result in errors from having ended the connection.
Base class looks like
class DB {
public $pdo;
private $host = DB_HOST;
private $user = DB_USER;
private $pass = DB_PASS;
private $dbname = DB_NAME;
public function __construct()
{
$this->connect();
}
private function connect()
{
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
$this->pdo = new PDO("mysql:host=$this->host;dbname=$this->dbname;charset=utf8;", $this->user, $this->pass, $options);
} catch(PDOException $e) {
echo $e->getMessage();
}
}
public function __sleep()
{
return array('dsn', 'username', 'password');
}
public function __wakeup()
{
$this->connect();
}
public function __destruct()
{
$this->connection = null;
$this->pdo = null;
unset($this->pdo);
}
// CRUD methods follow including
function retrieve($where, $groupBy='', $order_by='') {
$query = "SELECT * FROM `$this->table` $where $groupBy $order_by";
$q = $this->pdo->prepare($query);
$q->execute();
$result = $q->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE,get_class($this));
// was $result = $q->fetchAll(PDO::FETCH_CLASS,get_class($this));
$this->query_log($query);
$q = null;
if ($result == 'NULL') {
return false;
} else {
return $result;
}
} // retrieve()
And an example that has the errors would be
if (in_array($_GET['type'], $types)) {
$type = $_GET['type'];
$rsObj = new ReservedSlug;
if ($type == 'artist') {
$obj = new CalendarArtist;
$slugfield = 'urlSlug';
$namefield = 'name';
} else if ($type == 'event') {
$obj = new CalendarEvent;
$slugfield = 'urlSlug';
$namefield = 'name';
} else if ($type == 'location') {
$obj = new Location;
$slugfield = 'UrlSlug';
$namefield = 'LocationName1';
}
$needslug = $obj->retrieve("TRIM(`$namefield`) != '' AND (`$slugfield` = '' OR `$slugfield` IS NULL) LIMIT 0,400");
if ($needslug) {
foreach ($needslug as $ns) {
$testslug = slugify($ns->$namefield);
list($reserved) = $rsObj->retrieve("`slug` = '$testslug' AND `type` = '$type'");
if (!$reserved) {
list($test) = $obj->retrieve("`$slugfield` = '$testslug'");
if ($test) {
for ($i = 2; $i < 26; $i++) {
list($test) = $obj->retrieve("`$slugfield` = '$testslug-$i'");
if (!$test) {
$slug = $testslug . '-' . $i;
}
}
} else { // not found in table
$slug = $testslug;
}
} else { // was reserved
$slug = false;
}
echo $ns->$namefield . " gets $slug<p>";
} // foreach needslug
} // if needslug
} // type found in array
So I need to understand how to not create new connections when an active connection is available and how to properly __destruct() these child objects. Where am I going wrong?
This question already has answers here:
Reference - What does this error mean in PHP?
(38 answers)
Closed 2 years ago.
I keep getting the following error:
Fatal error: Call to a member function execute() on null in /home/[sitename]/public_html/fc/includes/class_db_handle.php on line 130
This is from the u-Auctions script and I honestly am extremely noob to PDO
please help in "DUMMIE TERMS".
if (!defined('InuAuctions')) exit('Access denied');
class db_handle
{
// database
private $pdo;
private $DBPrefix;
private $CHARSET;
private $lastquery;
private $fetchquery;
private $error;
public $PDOerror;
public function connect($DbHost, $DbUser, $DbPassword, $DbDatabase, $DBPrefix, $CHARSET)
{
$this->DBPrefix = $DBPrefix;
$this->CHARSET = $CHARSET;
try {
// MySQL with PDO_MYSQL
$this->pdo = new PDO("mysql:host=$DbHost;dbname=$DbDatabase;charset =$CHARSET", $DbUser, $DbPassword);
// set error reporting up
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// actually use prepared statements
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
// to run a direct query
public function direct_query($query)
{
try {
$this->lastquery = $this->pdo->query($query);
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
// put together the quert ready for running
/*
$query must be given like SELECT * FROM table WHERE this = :that AND where = :here
then $params would holds the values for :that and :here, $table would hold the vlue for :table
$params = array(
array(':that', 'that value', PDO::PARAM_STR),
array(':here', 'here value', PDO::PARAM_INT),
);
last value can be left blank more info http://php.net/manual/en/pdostatement.bindparam.php
*/
public function query($query, $params = array())
{
try {
//$query = $this->build_query($query, $table);
$params = $this->build_params($params);
$params = $this->clean_params($query, $params);
$this->lastquery = $this->pdo->prepare($query);
//$this->lastquery->bindParam(':table', $this->DBPrefix . $table, PDO::PARAM_STR); // must always be set
foreach ($params as $val)
{
$this->lastquery->bindParam($val[0], $val[1], #$val[2], #$val[3], #$val[4]);
}
$this->lasta->execute();
//$this->lastquery->debugDumpParams();
}
catch(PDOException $e) {
//$this->lastquery->debugDumpParams();
$this->trigger_error($e->getMessage());
}
//$this->lastquery->rowCount(); // rows affected
}
// put together the quert ready for running
public function fetch($method = 'FETCH_ASSOC')
{
try {
// set fetchquery
if ($this->fetchquery == NULL)
{
$this->fetchquery = $this->lastquery;
}
if ($method == 'FETCH_ASSOC') $result = $this->fetchquery->fetch(PDO::FETCH_ASSOC);
if ($method == 'FETCH_BOTH') $result = $this->fetchquery->fetch(PDO::FETCH_BOTH);
if ($method == 'FETCH_NUM') $result = $this->fetchquery->fetch(PDO::FETCH_NUM);
// clear fetch query
if ($result == false)
{
$this->fetchquery = NULL;
}
return $result;
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
// put together the quert ready for running + get all results
public function fetchall($method = 'FETCH_ASSOC')
{
try {
// set fetchquery
if ($this->fetchquery == NULL)
{
$this->fetchquery = $this->lastquery;
}
if ($method == 'FETCH_ASSOC') $result = $this->fetchquery->fetchAll(PDO::FETCH_ASSOC);
if ($method == 'FETCH_BOTH') $result = $this->fetchquery->fetchAll(PDO::FETCH_BOTH);
if ($method == 'FETCH_NUM') $result = $this->fetchquery->fetchAll(PDO::FETCH_NUM);
// clear fetch query
if ($result == false)
{
$this->fetchquery = NULL;
}
return $result;
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
public function result($column = NULL)
{
$data = $this->lastquery->fetch(PDO::FETCH_BOTH);
if (empty($column) || $column == NULL)
{
return $data;
}
else
{
return $data[$column];
}
}
public function numrows()
{
try {
return $this->lastquery->rowCount();
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
public function lastInsertId()
{
try {
return $this->pdo->lastInsertId();
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
private function clean_params($query, $params)
{
// find the vars set in the query
preg_match_all("(:[a-zA-Z_]+)", $query, $set_params);
//print_r("params" . $query);
//print_r($params);
//print_r("set_params");
//print_r($set_params);
$new_params = array();
foreach ($set_params[0] as $val)
{
$key = $this->find_key($params, $val);
$new_params[] = $params[$key];
}
//print_r("new_params");
//print_r($new_params);
return $new_params;
}
private function find_key($params, $val)
{
foreach ($params as $k => $v)
{
if ($v[0] == $val)
return $k;
}
}
private function build_params($params)
{
$PDO_constants = array(
'int' => PDO::PARAM_INT,
'str' => PDO::PARAM_STR,
'bool' => PDO::PARAM_BOOL,
'float' => PDO::PARAM_STR
);
// set PDO values to params
for ($i = 0; $i < count($params); $i++)
{
// force float
if ($params[$i][2] == 'float')
{
$params[$i][1] = floatval($params[$i][1]);
}
$params[$i][2] = $PDO_constants[$params[$i][2]];
}
return $params;
}
private function trigger_error($error)
{
// DO SOMETHING
//$this->error = $error;
$this->PDOerror = $error;
}
// close everything down
public function __destruct()
{
// close database connection
$this->pdo = null;
}
}
You call $this->lasta->execute(); but you have no field lasta
Try this
$this->lastquery->execute();
I would try extending the db_handle class and modifying/creating some methods like so:
<?php
// Make sure the db_handle is included and loaded before hand so it can be extended
class QueryEngine extends db_handle
{
private $bind;
public function connect($host, $username, $password, $database)
{
// One note, I removed:
// $this->DBPrefix = $DBPrefix;
// $this->CHARSET = $CHARSET;
// You can add those back in if you want
try {
// Create connection
$opts = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
$this->pdo = new PDO('mysql:host='.$host.';dbname='.$database, $username, $password,$opts);
}
catch(PDOException $e) {
die($e->getMessage());
}
}
public function query($query, $params = false)
{
if(!empty($params))
$this->bindVals($params);
try {
if(!empty($this->bind)) {
$this->lastquery = $this->pdo->prepare($query);
$this->lastquery->execute($this->bind);
}
else
$this->lastquery = $this->pdo->query($query);
}
catch(PDOException $e) {
die($e->getMessage());
}
return $this;
}
public function fetch()
{
while($row = $this->lastquery->fetch())
$result[] = $row;
return (!empty($result))? $result : 0;
}
private function bindVals($params = false)
{
$this->bind = false;
if(empty($params) || !is_array($params))
return $this;
$i = 0;
foreach($params as $values) {
$this->bind[':'.$i] = $values;
$i++;
}
return $this;
}
}
To use our new class:
$dbEngine = new QueryEngine();
$dbEngine->connect($host,$username,$password,$database);
print_r($dbEngine->query("select * from users where ID = :0",array("1"))->fetch());
This would give you something like (in my db obviously, the table and columns will be different for you):
Array
(
[0] => Array
(
[ID] => 1
[unique_id] => 20150203190700523616
[username] => tester
[password] => $2a$12$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[first_name] => Ras
[last_name] => Clatt
[email] => ras#clatt.com
[usergroup] => 3
[user_status] => on
[reset_password] => $2y$10$xxxxxxxxxxxxxxxxxxx
[timestamp] => 2015-09-25 08:35:09
)
)
This class library you are using is similar to mine so what I have added is parts of the class I use. I tested this extended class out and it works with my database, so hopefully it works with yours!
I want to make a sendmail function on my program. But first, I want to store the information: send_to, subject, and message in a table in another database(mes) where automail is performed. The problem is data fetched from another database(pqap) are not being added on the table(email_queue) in database(mes).
In this code, I have a table where all databases in the server are stored. I made a query to select a specific database.
$sql5 = "SELECT pl.database, pl.name FROM product_line pl WHERE visible = 1 AND name='PQ AP'";
$dbh = db_connect("mes");
$stmt5 = $dbh->prepare($sql5);
$stmt5->execute();
$data = $stmt5->fetchAll(PDO::FETCH_ASSOC);
$dbh=null;
Then after selecting the database,it has a query for selecting the information in the table on the selected database. Here's the code.
foreach ($data as $row5) GenerateEmail($row5['database'], $row5['name']);
Then this is part (I think) is not working. I don't know what's the problem.
function GenerateEmail($database, $line) {
$sql6 = "SELECT * FROM invalid_invoice WHERE ID=:id6";
$dbh = db_connect($database);
$stmt6 = $dbh->prepare($sql6);
$stmt6->bindParam(':id6', $_POST['idtxt'], PDO::PARAM_INT);
$stmt6->execute();
$data = $stmt6->fetchAll(PDO::FETCH_ASSOC);
$dbh=null;
foreach ($data as $row6) {
$invnumb=$row6['Invoice_Number'];
$partnumb=$row6['Part_Number'];
$issue=$row6['Issues'];
$pic=$row6['PIC_Comments'];
$emailadd= $row6['PersoninCharge'];
if($row6['Status']=="Open") {
$message = "<html><b>Invoice Number: {$invnumb}.</b><br><br>";
$message .= "<b>Part Number:</b><br><xmp>{$partnumb}</xmp><br><br>";
$message .= "<b>Issues:</b><br><xmp>{$issue}</xmp><br>";
$message .= "<b>{$pic}<b><br>";
$message .= "</html>";
if(!empty($emailadd)) {
dbInsertEmailMessage($emailadd, "Invoice Number: {$invnumb} - {$issue}.", $message);
$dbh=null;
}
}
}
}
function dbInsertEmailMessage($send_to, $subject, $message) {
$sql7 = "INSERT INTO email_queue (Send_to, Subject, Message) VALUES (:send_to, :subject, :message)";
$dbh = db_connect("mes");
$stmt7 = $dbh->prepare($sql7);
$stmt7->bindParam(':send_to', $send_to, PDO::PARAM_STR);
$stmt7->bindParam(':subject', $subject, PDO::PARAM_STR);
$stmt7->bindParam(':message', $message, PDO::PARAM_STR);
$stmt7->execute();
$dbh=null;
}
Here's my db connection:
function db_connect($DATABASE) {
session_start();
// Connection data (server_address, database, username, password)
$servername = '*****';
//$namedb = '****';
$userdb = '*****';
$passdb = '*****';
// Display message if successfully connect, otherwise retains and outputs the potential error
try {
$dbh = new PDO("mysql:host=$servername; dbname=$DATABASE", $userdb, $passdb, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
return $dbh;
//echo 'Connected to database';
}
catch(PDOException $e) {
echo $e->getMessage();
}
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
There are a couple things that may help with your failed inserts. See if this is what you are looking for, I have notated important points to consider:
<?php
// take session_start() out of your database connection function
// it draws an error when you call it more than once
session_start();
// Create a connection class
class DBConnect
{
public function connect($settings = false)
{
$host = (!empty($settings['host']))? $settings['host'] : false;
$username = (!empty($settings['username']))? $settings['username'] : false;
$password = (!empty($settings['password']))? $settings['password'] : false;
$database = (!empty($settings['database']))? $settings['database'] : false;
try {
$dbh = new PDO("mysql:host=$host; dbname=$database", $username, $password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
// You return the connection before it hits that setting
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}
catch(PDOException $e) {
// Only return the error if an admin is logged in
// you may reveal too much about your database on failure
return false;
//echo $e->getMessage();
}
}
}
// Make a specific connection selector
// Put in your database credentials for all your connections
function use_db($database = false)
{
$con = new DBConnect();
if($database == 'mes')
return $con->connect(array("database"=>"db1","username"=>"u1","password"=>"p1","host"=>"localhost"));
else
return $con->connect(array("database"=>"db2","username"=>"u2","password"=>"p2","host"=>"localhost"));
}
// Create a query class to return selects
function query($con,$sql,$bind=false)
{
if(empty($bind))
$query = $con->query($sql);
else {
foreach($bind as $key => $value) {
$kBind = ":{$key}";
$bindVals[$kBind] = $value;
}
$query = $con->prepare($sql);
$query->execute($bindVals);
}
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row;
}
return (!empty($result))? $result:0;
}
// Create a write function that will write to database
function write($con,$sql,$bind=false)
{
if(empty($bind))
$query = $con->query($sql);
else {
foreach($bind as $key => $value) {
$kBind = ":{$key}";
$bindVals[$kBind] = $value;
}
$query = $con->prepare($sql);
$query->execute($bindVals);
}
}
// Do not create connections in your function(s), rather pass them into the functions
// so you can use the same db in and out of functions
// Also do not null the connections out
function GenerateEmail($con,$conMes,$line = false)
{
if(empty($_POST['idtxt']) || (!empty($_POST['idtxt']) && !is_numeric($_POST['idtxt'])))
return false;
$data = query($con,"SELECT * FROM `invalid_invoice` WHERE `ID` = :0", array($_POST['idtxt']));
if($data == 0)
return false;
// Instead of creating a bunch of inserts, instead create an array
// to build multiple rows, then insert only once
$i = 0;
foreach ($data as $row) {
$invnumb = $row['Invoice_Number'];
$partnumb = $row['Part_Number'];
$issue = $row['Issues'];
$pic = $row['PIC_Comments'];
$emailadd = $row['PersoninCharge'];
if($row['Status']=="Open") {
ob_start();
?><html>
<b>Invoice Number: <?php echo $invnumb;?></b><br><br>
<b>Part Number:</b><br><xmp><?php echo $partnumb; ?></xmp><br><br>
<b>Issues:</b><br><xmp><?php echo $issue; ?></xmp><br>
<b><?php echo $pic; ?><b><br>
</html>
<?php
$message = ob_get_contents();
ob_end_clean();
if(!empty($emailadd)) {
$bind["{$i}to"] = $emailadd;
$bind["{$i}subj"] = "Invoice Number: {$invnumb} - {$issue}.";
$bind["{$i}msg"] = htmlspecialchars($message,ENT_QUOTES);
$sql[] = "(:{$i}to, :{$i}subj, :{$i}msg)";
}
}
$i++;
}
if(!empty($sql))
return dbInsertEmailMessage($conMes,$sql,$bind);
return false;
}
function dbInsertEmailMessage($con,$sql_array,$bind)
{
if(!is_array($sql_array))
return false;
write($con,"INSERT INTO `email_queue` (`Send_to`, `Subject`, `Message`) VALUES ".implode(", ",$sql_array),$bind);
return true;
}
// Create connections
$con = use_db();
$conMes = use_db('mes');
GenerateEmail($con,$conMes);
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;
}
}
I have been using the old mysql api in PHP for a long time and want to start using mysqli for both speed and security with a new project I'm working on. I've looked through the manual and read several tutorials, but I'm finding a lot of conflicting and somewhat confusing information on how to do prepared statements in mysql.
Is there anything in this code that doesn't need to be there, and is there anything that is missing? Also, is this the easiest way to do something simple like this (seems somewhat involved for such a simple task)?
Procedural:
// build prepared statement
$query = mysqli_prepare($link, "SELECT email FROM users WHERE id = ?");
// bind parameters to statement
mysqli_stmt_bind_param($query, 's', $_GET['id']);
// execute statement
mysqli_stmt_execute($query);
// bind the variables to the result
mysqli_stmt_bind_result($query, $email);
// print the results
while (mysqli_stmt_fetch($query)) {
echo $email;
}
// close the statement
mysqli_stmt_close($query);
// close connection
mysqli_close($link);
Object-Oriented:
// build prepared statement
$query = $link->prepare("SELECT email FROM users WHERE id = ?");
// bind parameters to statement
$query->bind_param('s', $_GET['id']);
// execute statement
$query->execute();
// bind the variables to the result
$query->bind_result($email);
// print the results
while ($query->fetch()) {
echo $email;
}
// close the statement
$query->close();
// close connection
$link->close();
Here's the guts of a semi-self-explanatory class that encapsulates mysqli, including prepared statements, which are quite tricky. It's pretty well tested - I've been using it for a year now without change.
It only implements prepared statements to Execute SQL commands because they change data and often require nasty encoding tricks otherwise. If you want SELECTs, it's left as an exercise for the reader - it's easier. :)
<?php
class Db
{
var $_mysqli;
var $_result;
var $_error_msg;
public function __construct($server, $user, $password, $name)
{
$this->_mysqli = new mysqli("p:".$server, $user,
$password, $name);
if($this->_mysqli->connect_errno)
{
$this->_error_msg = $this->_mysqli->connect_error;
}
}
public function __destruct()
{
}
private function sql_select($sql)
{
$this->_mysqli->query("SET NAMES 'utf8'"); // a little help for UTF8 io
$this->_result = $this->_mysqli->query($sql);
}
private function sql_close()
{
$this->_mysqli->close();
}
public function ErrorMessage()
{
return $this->_error_msg;
}
public function SqlRows($sql)
{
$rows = array();
$result = $this->sql_select($sql);
if($this->IsError())
{
return $rows;
}
while($row = $result->fetch_array())
{
$rows[] = $row;
}
$result->free();
return $rows;
}
public function SqlObjects($sql)
{
$objects = array();
$result = $this->sql_select($sql);
while($object = $this->_result->fetch_object())
{
$objects[] = $object;
}
$result->free();
return $objects;
}
public function SqlOneObject($sql)
{
$result = $this->sql_select($sql);
$obj = $result->fetch_object();
$result->free();
return $obj;
}
public function SqlOneRow($sql)
{
$result = $this->sql_select($sql);
if(! is_object($result))
return null;
if($result->num_rows > 0)
$row = $result->fetch_array();
else
$row = null;
$result->free();
return $row;
}
public function SqlOneValue($sql)
{
$result = $this->sql_select($sql);
if(!empty($result))
{
$row = $result->fetch_array();
}
$result->free();
return empty($row) ? null : $row[0] ;
}
// returns number of affected rows
public function SqlExecute($sql)
{
$this->_result = $this->_mysqli->query($sql);
return $this->affected_rows();
}
private function affected_rows()
{
return $this->_mysqli->affected_rows;
}
private function IsError()
{
if(empty($this->_mysqli))
return false;
return !empty($this->_mysqli->error);
}
// arguments are sql and an array of
// argument references (not values).
public function SqlExecutePS($sql, $args)
{
$stmt = $this->_mysqli->prepare($sql);
// make the type-string
$typestr = make_typestring($args);
$params = array($typestr);
$params = array_merge($params, $args);
call_user_func_array(array($stmt, 'bind_param'), $params);
$stmt->execute();
$ret = $this->affected_rows();
$stmt->close();
return $ret;
}
public function SqlExists($sql)
{
$result = $this->SqlOneRow($sql);
return !empty($result[0]);
}
function make_typestring($args)
{
assert(is_array($args));
$ret = "";
foreach($args as $arg)
{
switch(gettype($arg))
{
case "boolean":
case "integer":
$ret .= "i";
break;
case "double":
$ret .= "d";
break;
case "string":
$ret .= "s";
break;
case "array":
case "object":
case "resource":
case "NULL":
default:
// call it a blob and hope
// you know what you're doing.
$ret .= "b";
break;
}
}
return $ret;
}
}
?>