I have a very common mysqli class to provide database connections for the rest of the application:
class IabDB extends mysqli {
private static $instance = null;
// db connection config vars
private $user = "xxx-lit";
private $pass = "xxx";
private $dbName = "xxx";
private $dbHost = "xxx";
private function __construct() {
parent::__construct($this->dbHost, $this->user, $this->pass, $this->dbName);
if (mysqli_connect_error()) {
exit('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
mysqli_set_charset($this, "utf8");
}
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
In my model I retrive data like this which works nicely:
$db = IabDB::getInstance();
$query = $db->query("SELECT status, username, email, id FROM " . $table);
$items = $query->fetch_all();
EDIT
But when I try to get another instance for another query I get the error message: Call to a member function fetch_all() on null.
Believe me: I tried it back and forth. Both queries are valid and both return a result if only either one of them is used. Just for the sake of completeness here is the second one with the model around:
class Model {
public static function getItems($table) {
$db = IabDB::getInstance();
$query = $db->query("SELECT * FROM lit_veranstaltungen");
$items = $query->fetch_all();
$db->close();
var_dump($items);
}
}
So it seems the second connection is disturbed somehow!?
Bonus question: from my knowledge the obviously now mostly laughed upon singleton pattern seems to be of good use for this purpose?
Any help and optionions are greatly appreciated!
Your code works for me, whatever number of instances I get:
$db = IabDB::getInstance();
$query = $db->query("SELECT name FROM users limit 1");
$items = $query->fetch_all();
var_export($items);
$db = IabDB::getInstance();
$query = $db->query("SELECT name FROM users limit 1,1");
$items = $query->fetch_all();
var_export($items);
returns
array ( 0 => array ( 0 => 'John', ), )
array ( 0 => array ( 0 => 'Mike', ), )
So I suppose there is an error with particular query you run. Therefore you need just better error reporting for your queries. Change your constructor to this
private function __construct() {
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
parent::__construct($this->dbHost, $this->user, $this->pass, $this->dbName);
$this->set_charset("utf8");
}
Then make sure your PHP is configured like this
error_reporting(E_ALL);
ini_set('display_errors',1);
and then run your code again.
It will either report an error or return an empty array. In the latter case it means that there are no rows in the database to match your second query conditions. E.g., for a code like this
$db = IabDB::getInstance();
$query = $db->query("SELECT name FROM users WHERE 1=0");
$items = $query->fetch_all();
var_export($items);
$db = IabDB::getInstance();
$query = $db->query("SELECT name FOrM users");
$items = $query->fetch_all();
var_export($items);
it will return an empty array for the first snippet and error for the second:
array ()
Fatal error: Uncaught exception 'mysqli_sql_exception' with message 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'users' at line 1'
Also, let me suggest you to add a function like this
public function query_params($query, $params, $types = NULL)
{
$statement = $this->prepare($query);
$types = $types ?: str_repeat('s', count($params));
$statement->bind_param($types, ...$params);
$statement->execute();
return $statement->get_result();
}
that will let you to use prepared statements as easily as with PDO:
$user = $db->query_params("SELECT * FROM users WHERE name = ?", ['Mike'])->fetch_assoc();
Regarding singleton, if you're using old style procedural PHP, then singleton is all right. If you're using OOP, then better implement a Dependency Injection based approach.
You cannot make singleton from class which extends mysqli (or PDO) since mysqli (and PDO) class constructor is public. You cannot override public parent's constructor and make it private in inherited child class! Try it and you will get the following error:
Fatal error: Access level to DataBase::__construct() must be public (as in class mysqli)
Try to use $query->close(); after you executed the query.
For this case, a singleton is not a bad idea. But more commonly, you have something like a "connection manager", which creates a mysqli object on first use, and then returns that object on consecutive calls, with the ability to have multiple connections to multiple databases or with differen users.
Something like this:
class DBConnection {
protected static $connections = array();
public static function getConnection($connection_name = 'default') {
if (!isset(static::$connections[$connection_name])) {
static::$connections[$connection_name] = // setup connection
// ... error handling and stuff
}
return static::$connections[$connection_name];
}
}
Btw.: In your constructor, I would use the mysqli object's properties for errorhandling:
http://php.net/manual/de/mysqli.connect-error.php
http://php.net/manual/de/mysqli.connect-errno.php
and
http://php.net/mysqli_set_charset
Related
I have one quick question. I have that class written in mysql extension my question is how can I migrate that class from mysql to mysqli object oriented style not procedural.
I'm new at this mysqli extension.
<?php
class DBController {
private $host = "";
private $user = "";
private $password = "";
private $database = "";
function __construct() {
$conn = $this->connectDB();
if(!empty($conn)) {
$this->selectDB($conn);
}
}
function connectDB() {
$conn = mysql_connect($this->host,$this->user,$this->password);
return $conn;
}
function selectDB($conn) {
mysql_select_db($this->database,$conn);
}
function runQuery($query) {
$result = mysql_query($query);
while($row=mysql_fetch_assoc($result)) {
$resultset[] = $row;
}
if(!empty($resultset))
return $resultset;
}
function numRows($query) {
$result = mysql_query($query);
$rowcount = mysql_num_rows($result);
return $rowcount;
}
}
?>
Having such class is a really good idea, but unfortunately moving from mysql_* API to mysqli class is not so simple. It requires a large code rewrite and change in thinking.
If you are planning the upgrade from mysql_* API it probably means you were using PHP 4 until now. If you were using PHP 5, you were using PHP 4 way of thinking. PHP has come a long way since then. We now have proper classes, namespacing, better error reporting, etc. When it comes to database interactions we now have two new extensions: mysqli and PDO. Out of these two you should be using PDO. However, if you are using a wrapper class like the one you are trying to create changing from mysqli to PDO should be very easy. For this reason alone such a wrapper class is a good idea.
The primary reason for mysqli extension was to keep a familiar syntax of the old extension and add necessary new features such as prepared statements and proper error reporting. If you were used to putting PHP variables directly into SQL queries, you must change your way of thinking. You should now use parameterized queries and bind the values separately.
A simple example of what your improved class could look like is this:
<?php
class DBController {
/**
* mysqli instance
*
* #var \mysqli
*/
private $mysqli;
public function __construct(
$host = null,
$username = null,
$passwd = null,
$dbname = null,
$charset = 'utf8mb4',
$port = null,
$socket = null
) {
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$this->mysqli = new \mysqli($host, $username, $passwd, $dbname, $port, $socket);
$this->mysqli->set_charset($charset);
}
public function runQuery(string $sql, array $params = []): ?array {
$stmt = $this->mysqli->prepare($sql);
if ($params) {
$stmt->bind_param(str_repeat("s", count($params)), ...$params);
}
$stmt->execute();
if ($result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_BOTH);
}
return null;
}
}
Warning: This is not a full implementation of such wrapper class. You most likely need to implement other methods and add more logic as per your needs. This is only for demonstration purposes.
First, in the construct method, we should execute 3 steps. Enable error reporting, create an instance of the mysqli class and set the correct charset (use utf8mb4 which was added in MySQL 5.5 and is now the standard charset).
Your runQuery() method now accepts 2 arguments. The first one is your SQL query with placeholders instead of interpolated values, and the second one is an array of the values to be bound.
Most likely you do not need selectDB() and you definitely do not need numRows(). If you want to know the number of rows in your retrieved array, you can count them in PHP using count().
Using such class is very simple.
$db = new DBController('localhost', 'username', 'password', 'db_name');
$result = $db->runQuery('SELECT Id, Name FROM table1 WHERE uuid=?', ['myuuid']);
if ($result) {
// Get the name of found record
echo $result[0]['Name'];
} else {
echo 'No records found';
}
If you wanted to switch the implementation to PDO, you can replace the class without changing the way you use it.
class DBController {
/**
* PDO instance
*
* #var \PDO
*/
private $pdo;
public function __construct(
$host = null,
$username = null,
$passwd = null,
$dbname = null,
$charset = 'utf8mb4',
$port = null,
$socket = null
) {
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset;port=$port;socket=$socket";
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$this->pdo = new PDO($dsn, $username, $passwd, $options);
}
public function runQuery(string $sql, array $params = []): ?array {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
}
Warning: This is not a full implementation of such wrapper class. You most likely need to implement other methods and add more logic as per your needs. This is only for demonstration purposes.
Until recently all the database queries from my PHP app were going through a single function that put everything into an insecure "mysqli_query". I wanted to move away from this for obvious reasons and convert to PDO to prevent injection.
A helpful user provided this PDO class/function as an alternative:
class DatabaseConfig
{
private static $singleton;
public function __construct()
{
if(empty(self::$singleton))
self::$singleton = $this->connect();
return self::$singleton;
}
public function connect($host = "localhost", $username = "username", $password = "password", $database = "database")
{
// Create connection
$opts = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
$conn = new PDO('mysql:host='.$host.';dbname='.$database, $username, $password,$opts);
return $conn;
}
}
// This is a query class that will run your sqls
class QueryEngine
{
private $results;
private static $singleton;
public function __construct()
{
if(empty(self::$singleton))
self::$singleton = $this;
return self::$singleton;
}
public function query($sql = false,$bind = false)
{
$this->results = 0;
$db = new DatabaseConfig();
try {
if(!empty($bind)) {
$query = $db ->connect()
->prepare($sql);
$query->execute($bind);
}
else {
$query = $db ->connect()
->query($sql);
}
$this->results = $query;
}
catch (PDOException $e)
{
die($e->getMessage());
}
return $this;
}
public function fetch()
{
while($row = $this->results->fetch())
$result[] = $row;
return (!empty($result))? $result : 0;
}
}
function dbcommand($req,$bind = false)
{
// Create query instance
$qEngine = new QueryEngine();
// Run the query
$qEngine->query($req,$bind);
// If select, fetch array
if(strpos(strtoupper($req), 'SELECT') === 0)
return $qEngine->fetch();
// The query already ran, so you can return whatever you want
// For ease I am just returning true
elseif(strpos($req, 'INSERT INTO') === 0)
return true;
}
The above code works great but the issue is that I can still SQL inject into statements that I'm not filtering prior to using dbcommand. I was under the impression PDO automatically resolves injection issues but I'm obviously adopting it incorrectly. Can anyone englighten me?
This "dbcommand" function is intended to be used this way:
$row = dbcommand("SELECT * FROM users WHERE id=?", [$id]);
Here you have to substitute all the variables in the query with question marks, while sending variables as a second parameter, in the form of array.
Or you can use named placeholders and associative array:
$update = [
'name' => $_POST['name'],
'id' => $_POST['id'],
]
dbcommand("UPDATE users SET name=:name WHERE id=:id", $update);
Only when variables are substituted with placeholders PDO will protect your queries.
On a side note, although this function is a good intention by itself, it severely reduces the usability of the vanilla PDO. For example, for the large datasets, it is not advised to fetch all the data at once, but this function offer no option for this. Or this function won't let you get the number of affected rows. To make a simple PDO wrapper usable, one should make it return a PDOStatement instance. It is essential, because there is way too much functionality in this class to be simply dismissed.
For a class that lets you use all the great power of PDO, refer to my Simple yet efficient PDO wrapper, especially "Examples" section. All examples can be run without any prior setup, save for setting database credentials.
Just for the clarification: a list of possible use cases from the link above which your class doesn't support:
Prepared statement multiple execution
Getting the insert id
Getting rows in a loop one by one
Getting one row
Getting single field value
Getting array of rows in all the dozens of predefined formats supported by PDO
Getting the number of affected rows
I have just started learning the concept of Object oriented programming and I've written this class with functions.
It works fine, but I'm interested in knowing if I have done this correctly...
Here is my code:
class Database{
const DB_HOSTNAME = 'localhost';
const DB_USERNAME = 'root';
const DB_PASSWORD = 'password';
const DB_NAME = 'shop';
protected $_db_connect;
protected $_sql;
protected $_result;
protected $_row;
function db_connect(){
$this->_db_connect = mysql_connect(self::DB_HOSTNAME,self::DB_USERNAME,self::DB_PASSWORD) or die(mysql_error());
}
function slect_db(){
mysql_select_db(self::DB_NAME) or die(mysql_error());
}
function sql(){
$this->_sql = 'SELECT * FROM users';
}
function query(){
$this->_result = mysql_query($this->_sql);
}
function fetch_array(){
while($this->_row = mysql_fetch_array($this->_result)){
$username = $this->_row['user_USERNAME'];
echo "<ul>";
echo "<li>".$username."</li>";
echo "</ul>";
}
}
function db_close(){
mysql_close($this->_db_connect);
}
}
$database = new Database();
$database->db_connect();
$database->slect_db();
$database->sql();
$database->query();
$database->fetch_array();
$database->db_close();
Please use PDO or MySQLi as it's more secure and mysql_* functions are deprecated as stated above, I've provided some generic code using PDO to help you with that new venture. As stated in the comments, you really shouldn't be echoing out the data if you're looking for an object oriented design, what you should be doing is after you do the query, return the rows that you fetched and from there use something such as a foreach loop to then display your data. Doing your database class this way will also make sure that multiple database connections aren't open at once! Note, this code is just for you to reference, and should be tested before use in production or anything live.
config.php:
<?php
//Enter your database connection details here.
$host = 'localhost'; //HOST NAME.
$db_name = 'databasename'; //Database Name
$db_username = 'root'; //Database Username
$db_password = ''; //Database Password
try
{
$pdo = new PDO('mysql:host='. $host .';dbname='.$db_name, $db_username, $db_password);
}
catch (PDOException $e)
{
exit('Error Connecting To DataBase');
}
?>
database.class.php:
<?php
class database
{
function __construct($pdo)
{
$this->pdo = $pdo;
}
function getData()
{
$query = $this->pdo->prepare('SELECT * FROM database');
$query->execute();
return $query->fetchAll();
}
}
?>
index.php:
<?php
require_once 'config.php';
require_once 'database.class.php';
$db = new database($pdo);
$rows = $db->getData();
?>
It is possible to improve the way you connect to databases using autoloading and dependency injection containers. Here is a way of using Auryn to connect to your database while being sure there is only one connection opened and not having to manually require files throughout your application.
I will cover only PDO and Auryn here. There are other dependency injection containers and notably the mysqli extension to connect to database, but the content should help you using another container if you wish to do so.
The database class
Having a database class is superfluous. The \PDO class is already providing all necessary methods to query the database. Having a database class makes you repeat the functions it provides and limits your actions (or makes you create many functions) when you want to for example use multiple different fetch styles depending on your needs in a specific method.
Dependency Injection
If you haven't already, have a read on dependency injection. The point is that when a class needs to access the database, it should not have to bother constructing the \PDO object, it should be constructed with it:
class Mapper {
private $pdo;
public function __construct(\PDO $pdo) {
$this->pdo = $pdo;
}
public function createFromId($id) {
$stmt = $this->pdo->prepare("SELECT name FROM foo WHERE id=:id");
$stmt->execute([
":id" => $id,
]);
return $stmt->fetchObject();
}
}
Notice that I directly pass the \PDO object, not a wrapper class. That way, I always have access to all of its capabilities, not only a subset of user-defined functions.
Dependency Injection Container
A dependency injection container helps build your classes, giving them the objects they need, and giving you great flexibility on how to actually build those objects. Here I'll only focus on configuring and sharing a \PDO object through the use of Auryn.
I assume you have installed the required Auryn class, the easier way is using composer. This is out of the scope of this answer, there are multiple resources on how to use it.
Create the injector
$injector = new \Auryn\Injector();
Define the \PDO class parameters
$injector->define("PDO", [
":dsn" => "mysql:host=localhost;charset=utf8;dbname=dbname",
":username" => "user",
":passwd" => "passwd",
":options" => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
],
]);
You can either write the configuration parameters directly here, or get them from a config file. I like having a config.ini file and using parse_ini_file() to get my configuration options, as I can easily switch databases by editing a config file.
Share the \PDO object
$injector->share("PDO");
This part is really important. This lines makes the injector give the same \PDO object every time it is tasked with constructing a class that needs a connection. Note that the order of the lines is not important, you can share the class before defining it, only make sure to create you database needing classes after writing both those lines.
Create your objects
$mapper = $injector->make("Mapper");
That's it. The injector will create your mapper object, creating the \PDO object if it haven't already been, passing the existing instance if it has.
Autoloading
Assuming you have used composer, you can make use of its great autoloader. Otherwise you can also roll you own autoloader.
The point here is to stop having require() everywhere in your code, especially if you have complex class hierarchies, which you should have in a single responsibility compliant class system.
Wrapping up
With this set up, you now can use the \PDO object in your classes while being assured there will only be one instance per request, without the need to require files everywhere, and without using a singleton anti-pattern.
$database = new Connection();
class Connection
{
function __construct()
{
switch($_SERVER['DOCUMENT_ROOT'])
{
case 'path':
$this->host = 'hostname';
$this->user = 'username';
$this->passwd = 'password';
$this->database = 'dbname';
break;
default :
$this->host = 'localhost';
$this->user = 'root';
$this->passwd = 'root';
$this->database = 'dbname';
break;
}
$this->clink = #mysql_connect($this->host,$this->user,$this->passwd);
#mysql_select_db($this->database,$this->clink);
}
}
$objConn = new mysqlconnect();
$Conn = $objConn->setobjConnect("localhost","root","P#ssw0rd");
class Database{
var $last_query; //Saved result of the last query made
var $last_result; //Results of the last query made
var $func_call; //A textual description of the last query/get_row/get_var call
var $link; //database link
var $lastquery; //last query
var $result; //query result
// Connect to MySQL database
function database() {
$this->link=mysql_connect(DB_HOST, DB_USER, DB_PASS) or die('Server connexion not possible.');
//Set All Charsets to UTF8
mysql_query("SET character_set_results=utf8 , character_set_client=utf8 , character_set_connection=utf8 , character_set_database=utf8 , character_set_server=utf8");
mysql_select_db(DB_NAME) or die('Database connection not possible.');
}
/** Query the database.
* #param $query The query.
* #return The result of the query into $lastquery, to use with fetchNextObject().
*/
function query( $query ){
$this->lastquery=$query;
$this->result=#mysql_query( $query, $this->link );
return $this->result;
}
/** Do the same as query() but do not return nor store result.
* Should be used for INSERT, UPDATE, DELETE...
* #param $query The query.
* #param $debug If true, it output the query and the resulting table.
*/
function execute($query)
{
#mysql_query($query);
}
/** Convenient method for mysql_fetch_object().
* #param $result The ressource returned by query().
* #return An ARRAY representing a data row.
*/
function fetchArray($result){
if ($result == NULL)
$result = $this->result;
if ($result == NULL || mysql_num_rows($result) < 1)
return NULL;
else
return mysql_fetch_assoc($result);
}
/** Close the connecion with the database server.
* It's usually unneeded since PHP do it automatically at script end.
*/
function close()
{
mysql_close($this->link);
}
/** Get the number of rows of a query.
* #param $result The ressource returned by query(). If NULL, the last result returned by query() will be used.
* #return The number of rows of the query (0 or more).
*/
function numRows($result = NULL)
{
if ($result == NULL)
return #mysql_num_rows($this->result);
else
return mysql_num_rows($result);
}
}
![<?php
class mysqlconnect{
private $server=null;private $user=null;private $password=null;private $objConnect=null;
function setobjConnect($s,$u,$p){
$this->server = $s;
$this->user = $u;
$this->password = $p;
return $this->objConnect = mysql_connect($this->server,$this->user,$this->password);
}
}
$objConn = new mysqlconnect();
$Conn = $objConn->setobjConnect("localhost","root","P#ssw0rd");
if($Conn)
{
echo "Database Connect";
}
else
{
echo "Database Connect Failed.";
}
mysql_close($Conn);
?>]
1
It's the first time i'm using PDO just for testing purpose.
But a strange error occurred and googling it, it seems to be weird.
Here's my database testing class
class db extends PDO
{
# Our instance.
private static $db = NULL;
# Calling the connector.
public static function connect()
{
if (self::$db === NULL)
{
$class = __CLASS__;
self::$db = new $class();
}
return self::$db;
}
# Connector.
public function __construct()
{
$dns = 'mysql:dbname='.reg::get('db-name').';host='.reg::get('db-host');
self::$db = new PDO($dns, reg::get('db-username'), reg::get('db-password'));
reg::delete('db-password');
}
# Quick reporting
public function reportError($array)
{
if ($this->db != NULL) { echo 'Myself getting horny'; } // Just for testing, i'm not getting horny because of a mysql database connection!
}
}
Then executing the following code:
$db = new db();
$row = $db->prepare('SELECT * FROM test WHERE id = :id')->execute(array('id' => 1));
echo $row['value'];
It shows me the following error:
Warning: PDO::prepare() [pdo.prepare]: SQLSTATE[00000]: No error: PDO constructor was not called in myfile.php on line 39
Considering line 39 as
$row = $db->prepare('SELECT * FROM test WHERE id = :id')->execute(array('id' => 1));
You code is a mess, it's probably because you're so horny...
connect() method - why is it there?:
if ($db === NULL)
should be:
if (self::$db === NULL)
self::$db = new $class();
So, if $class == __CLASS__ == db, you are doing self::$db = new db();, doesn't seem right.
You can't use PDO to prepare an identifier, like a table or a column.
$db->prepare('SELECT * FROM :table WHERE id = :id')->execute(array('table' => 'test', 'id' => 1));
Should be:
$db->prepare('SELECT * FROM `test` WHERE id = :id')->execute(array('id' => 1));
Try this:
class db extends PDO
{
private static $db = null;
public static function singleton()
{
if (is_null(self::$db) === true)
{
self::$db = new PDO('mysql:dbname='.reg::get('db-name').';host='.reg::get('db-host'), reg::get('db-username'), reg::get('db-password'));
}
return self::$db;
}
}
Like this:
$result = db::singleton()->prepare('SELECT * FROM `test` WHERE id = :id')->execute(array('id' => 1));
var_dump($result);
I'm not entirely sure if this is your answer, as it seems to be unrelated to the error message, but I do not think you can pass in a table name as a bound parameter. What happens if you put a hard-coded table name in the place of :table?
You have a static 'connect' constructor, that makes a db-object in (static), and returns it. But you also make a new db() yourself.
The prepare statement uses self::$db, so tries to call the static made variable. I'm not really sure how your code is supposed to work, combining some sort of singleton/static form with an object form.
But that seems to be the trouble
Your singleton pattern is all wrong. Your constructor should be private and you should use static instances of $db. Refer to this singleton example.
Fatal error: Call to a member function prepare() on a non-object
Is what I am getting when I try to do:
$sql = $connect->prepare ("SELECT id, pwd, firstname, lastname, approved, user_level FROM users WHERE $user_cond AND banned = 0"); // SELECT
$sql->execute ();
$sql->setFetchMode(PDO::FETCH_ASSOC);
$num = $connect->rowCount();
Im holding on rewriting my system, taking out all mysql_* and make use of pdo instead.
This is what was before:
$result = mysql_query("SELECT `id`,`pwd`,`firstname`,`lastname`,`approved`,`user_level` FROM users WHERE
$user_cond
AND `banned` = '0'
") or die (mysql_error());
$num = mysql_num_rows($result);
What have I done wrong?
And with list() I have:
list($id,$pwd,$firstname,$lastname,$approved,$user_level) = mysql_fetch_row($result);
instead of mysql_fetch_row($result); what should I do in PDO?
My PDO object/connection:
try{
$connect = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset:UTF-8", DB_USER, DB_PASS, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
catch(PDOException $pe)
{
die('Could connect to the database because: ' .$pe->getMessage());
}
Fatal error: Call to a member function
prepare() on a non-object
usually means that something failed and your variable is not what you expect it to be. $connection is probably false.
PDOStatement::fetch
list($id,$pwd,$firstname,$lastname,$approved,$user_level) = $sql->fetch();
Also call rowCount on the statement, not on the connection:
$sql->rowCount();
Since you using prepare, you should make the $cond a named parameter and then do this:
in this example the condition is just user_id, but you can have multiple conditions and multiple named parameters, just bind() each one the same way
$sth = $pdo->prepare ("SELECT id, pwd, firstname, lastname, approved, user_level FROM users WHERE user_id = :cond AND banned = 0");
$sth->bindParam(':cond', $some_user_id);
$sth->execute ();
$a = $sth->fetch( PDO::FETCH_ASSOC );
The $a will be your assiciate array, print_r($a) to see what's in it
Looks like a scope issue.
Are you assigning $connect within a function, class, namespace or are you running prepare in a function, class or namespace ?
if your assigning $connect within a function then that function should return the PDO Connection. I would introduce a static instance like so:
class Database extends PDO
{
private $instance = null;
public static function Instance()
{
if(self::$instance == null)
{
self::$instance = new Database();
}
return self::$instance;
}
private function __construct(){}
private function __connect()
{
try
{
parent::__construct("mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset:UTF-8", DB_USER, DB_PASS, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION))
}catch(PDOException $e)
{
die($e->getMessage());
}
}
}
then use like so:
$Database = Database::Instnace();
$Database->prepare("...");
The error is most likely due to the MySQL connection failing - therefor $connect is not a valid PDO object - so as the error says, you're trying to call a method on an object which doesn't support it. What does your connection handling code look like? Did you check if a connection was successfully created?