Using connection method constructed in other class doesn't work - php

I have been recently toying with dynamic PDO connection methods. However I run into some problems when I started to use other classes.
Why can't I connect to database in Admin class with method that has been constructed in Server class?
I have tried many solutions. This one seemed most logical to me ...
How do I make it work so that I wouldn't have to construct connection in every class?
class Server
{
private $hostdb = 'blah';
private $namedb = 'blah';
private $userdb = 'blah';
private $passdb = 'blah';
public static $conn;
public $errorMessage = 'If you read this text, contact web administrator and tell him about your problem.';
public function __construct()
{
$this->connect();
}
public function connect()
{
try {
$this->conn = new PDO("mysql:host=$this->hostdb; dbname=$this->namedb", $this->userdb, $this->passdb, array(PDO::ATTR_PERSISTENT => true));
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->conn->exec("SET CHARACTER SET utf8");
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
}
}
And the Admin class:
class Admin extends User
{
function someFunction($table)
{
try {
$sql = "SELECT * FROM $table";
//I want to change this line so that my connection would work
$result = Server::$conn->query($sql);
while ($row = $result->fetch(PDO::FETCH_NUM)) {
//Do something
}
} catch (PDOException $e) {
//Show when debugging
//echo $e->getMessage();
echo Server::errorMessage;
}
}
}
I have instantiated both Server, User and Admin class in config.req.php file.
When I changed "Server::$conn->" to "static::$conn->" it still gave me an error.

Make sure you have instantiated Server at least once in the Request. Otherwise, connect() will never be called. Also, $this->conn will create a new public instance property. Static properties need to be set with static::$conn or self::$conn.
So change your connect() method to
public function connect()
{
try {
self::$conn = new PDO("arguments …"));
self::$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$conn->exec("SET CHARACTER SET utf8");
// … shortened for brevity
On a side note, why not just use Dependency Injection? That makes for more maintainable and testable designs, e.g. keep the $this->conn and remove all the static stuff instead (in addition to the constructor) for something like
class Server
{
private $hostdb = 'blah';
private $namedb = 'blah';
private $userdb = 'blah';
private $passdb = 'blah';
private $conn;
public function getConnection()
{
if (!isset($this->conn)) {
$this->connect();
}
return $this->connection;
}
And then for your Admin class:
class Admin extends User
{
private $server;
public function __construct(Server $server)
{
$this->server = $server;
}
function someFunction($table)
{
try {
$sql = "SELECT * FROM $table";
$result = $this->server->getConnection()->query($sql);
On another side note:
$sql = "SELECT * FROM $table"
Interpolating strings into a query makes you open to SQL Injection attacks. Use prepared statements instead.

Related

PHP Out of class pdo connection fails

I can not make the PDO connection outside the class. Browser gives 500 error. I want to write PDO codes in out class. I am doing global change, but it is not.
try {
$pas = new PDO('mysql:host=localhost; dbname=tets', 'root', '123');
$pas->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$pas->exec("SET CHARACTER SET utf8"); // return all sql requests as UTF-8
} catch (Exception $e) {
echo $e->getMessage();
}
/**
User Avatar Check
**/
class Usercheck
{
public $sql , $paso;
public function __construct()
{
global $pas;
$this->paso =& $pas;
}
public function smf_members($whatid)
{
$this->sql = $this->paso->query("SELECT * FROM smf_members WHERE id_member = $whatid");
}
public function fetchcheck(){
if ($this->sql) {
return $this->sql->fetch(PDO::FETCH_BOTH);
}
}
}
$memberuser = new Usercheck();
$memberuser->smf_members('1');
It is not a good practice to use $global. There are many solutions to achieve what you want to do, and here is my approach.
1) Create a Connection Class to handle the PDO connectivity.
use PDO;
/**
* PDO Connection Classes
* Used by Database wrapper class to ensure that there is only one connection
*/
class Connection
{
private $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME. ';charset=' . DB_CHARSET;
private $conn;
private $error;
public function __construct()
{
try
{
$this->conn = new PDO($this->dsn, DB_USER, DB_PASSWORD);
}
catch(PDOException $e)
{
$this->error = $e->getMessage();
}
}
public function getConnection()
{
return $this->conn;
}
}
2) Establish the PDO connection via your wrapper class __construct(), the __construct() also ensure that there is only one PDO connection is instantiated.
use PDO;
class UserCheck
{
private $conn;
private $db;
public function __construct()
{
if (!$this->db) {
$conn = new Connection();
$this->db = $conn->getConnection();
}
}
}
I'm highly recommend that you read this PDO tutorial on how to use PDO and many best practice tips.

PHP OOP and PDO

My first real foray into using PHP OOP and PDO extensively. I have finally gotten the script to work, but as you notice in order to do it I had to move the PDO connect into the login function - originally it was just in the __construct(). I do not want to have to open a new PDO connect and this is sloppy. How can I maintain the same connection throughout the whole class?
<?php
class user{
public $id;
public $name;
public $email;
private $password;
public function __construct() {
$DBH = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function login($email,$password,$type){
$DBH = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$password_hash = sha1($password);
try{
if ($type != "actives") {
throw new Exception("Type Handling Error");
}
$STH = $DBH->query("SELECT id, email, password FROM $type WHERE email='$email' AND password='$password_hash'");
$STH->setFetchMode(PDO::FETCH_ASSOC);
$row_count = $STH->rowCount();
$row = $STH->fetch();
if($row_count == 1){
session_start();
session_regenerate_id();
$_SESSION['id'] == $row[id];
return true;
}
else{
return false;
}
}
catch (Exception $e) {
echo $e->getMessage();
}
}
public function loggout(){
session_destroy();
setcookie(session_name(), session_id(), 1, '/');
}
Make the database handle a private member within the class:
class user
{
public $id;
public $name;
public $email;
private $password;
private $dbh;
public function __construct(PDO $dbh)
{
$this->dbh = $dbh;
}
public function login($email, $password, $type)
{
$dbh = $this->dbh;
...
}
Usage:
$pdo = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = new User($pdo);
Sooner or later, you may need the PDO connection object somewhere else in your code(outside your user object). Therefore,
I would suggest to use one class which will provide static method as below to get the PDO connection object everywhere you want.
class Database{
private static $datasource='mysql:host=HOST dbname=DB';
private static $username='USER';
private static $password='PASS';
private static $db;
//make the constructor private and empty so that no code will create an object of this class.
private function __construct(){}
//the main public function which will return the required PDO object
public static function getDB(){
if(!isset(self::$db)){
try{
self::$db=new PDO(self::$datasoure,self::$username,self::$password);
}
catch(PDOExceptin $e)
{
$error=$e->getMessage(); //variable $error can be used in the database_error.php file
//display database error file.
include('database_error.php');
exit();
}
}
return self::$db;
}
}
Then you can use the static method like below any time you want PDO connection
$conn=Database::getDB();
Use ceejayoz' proposal or add a global function which is responsible for establishing the database connection. The function is written as to connect to the database at most 1 time per HTTP request:
function getPDOConnection() {
// Thanks to the static-specifier, this variable will be initialized only once.
static $conn = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
return $conn;
}
This enables you to maintain the same connection in your whole application (but of course you don't have to use the function everywhere). Basically, this is a very simple application of the Singleton pattern. See the documentation of the static specifier/keyword and try to get familiar with the Singleton pattern.
Add your database connection as a parameter in the constructor, So you when you create a new instance from the user class it automatically runs across the instantiated object
The variable $DBH needs to be a member variable of your class.
Below private $password;, add private $DBH; and you're good to go with deleting the new-connection code from your login function.

How to use $db instead of $GLOBALS['db'] in my classes?

I need to use $GLOBALS['db'] in my classes ($db is defined in my index.php), but I don't want to use $GLOBALS['db'] when I have to call it.
I wrote this code at the beginning of my classes :
class ClassName
{
var $db;
public function __construct()
{
$this->db = $GLOBALS['db'];
}
public function test()
{
$val = $this->db->oneValue('SELECT first_name FROM users LIMIT 0, 1');
echo $val->first_name;
}
}
But I'm not enjoying this; I prefer to use directly $db in my code. Is there a solution to be able to call $GLOBALS['db'] by $db?
Simples, just inject in the constructor or a setter method: (I'm assuming $db is an object here, not an array of connection parameters etc)
class ClassName
{
protected $db;
public function __construct($db)
{
$this->setConnection($db);
//Any other constructor things you want to happen...
}
/*
* This is just here for convenience, this could be protected if you only want to set
* the db connection via the constructor
*/
public function setConnection($db)
{
$this->db = $db;
}
public function test()
{
$val = $this->db->oneValue('SELECT first_name FROM users LIMIT 0, 1');
echo $val->first_name;
}
}
As mentioned in some comments above, this is a form of dependency injection which will give you more ability to re-use code inside your project (A Good Thing TM).
I prefer using singleton pattern for databases.
this is the DB class i am using for my app.
class Database {
protected static $_dbh;
const HOST = 'localhost';
const DATABASE = 'dbname';
const USERNAME = 'username';
const PASSWORD = 'password';
private function __construct() { }
public static function getInstance() {
if(!isset($_dbh)) {
try {
#Connection String.
self::$_dbh = new PDO('mysql:host='.self::HOST.';dbname='.self::DATABASE,self::USERNAME,self::PASSWORD);
self::$_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
#Print Errors.
echo $e->getMessage();
}
}
return self::$_dbh;
}
}
as i am using singleton pattern the connection will be re-used. you can now use the connection everywhere in your app by calling static connection method i.e
class ClassName
{
protected static $_dbh;
public function __construct() {
self::$_dbh = Database::getInstance();
}
public function test() {
$sth = self::$_dbh->query('SELECT first_name FROM users LIMIT 0, 1');
$row = $sth->fetchAll(PDO::FETCH_ASSOC);
echo $row['first_name'];
}
}

PHP - multiple different databases dependency injected class

I've spent the last several hours trying to find an answer to the "best", most logical, etc way to write a php database class to simultaneously connect to one postgresql db and one mysql db. Also, I'd like to adopt a Dependency Injection design but am new to that whole concept.
So far I've come up with...
class Database {
public function PgSqlConnect() {
/* Connect to database */
$host = 'localhost';
$dbname = '---';
$user = '---';
$pass = '---';
$timeout = 5; /* seconds */
try {
$pgsql_dbh = new PDO("pgsql:host=$host; dbname=$dbname", $user, $pass);
$pgsql_dbh->setAttribute( PDO::ATTR_TIMEOUT, $timeout );
$pgsql_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $pgsql_dbh;
} catch( PDOException $e ) {
echo 'Unable to connect to database: ' . $e->getMessage();
}
}
public function MySqlConnect() {
/* Connect to database */
$host = 'localhost';
$dbname = '---';
$user = '---';
$pass = '---';
$timeout = 5; /* seconds */
try {
$mysql_dbh = new PDO("mysql:host=$host; dbname=$dbname", $user, $pass);
$mysql_dbh->setAttribute( PDO::ATTR_TIMEOUT, $timeout );
$mysql_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $mysql_dbh;
} catch( PDOException $e ) {
echo 'Unable to connect to database: ' . $e->getMessage();
}
}
}
Obviously the duplicated code violates the DRY approach. I know and have seen many examples of multiple db connections, but most deal with same driver and don't provide DI capability.
I should also add that I've considered placing the connection details into the Database class constructor as...
$driver = 'mysql';
...
$mysqldb = new Database($driver,$un,$pw,...);
$driver = 'pgsql';
...
$pgsqldb = new Database($driver,$un,$pw,...);
but I don't know if that is really a good idea nor how well it would work with DI.
Many thanks!
You should create an interface first for all the DB operations.
interface IDatabase
{
function connect();
function query();
...
}
Then have different driver classes implementing this interface
class MySQLDB implements IDatabase
{
}
class PGSQLDB implements IDatabase
{
}
This way you can easily use dependency injection.
class Test
{
private $db;
function __construct(IDatabase $db)
{
$this->db = $db;
}
}
You can call it as:
$mysqldb = new MySQLDB();
$test = new Test($mysqldb);
or
$pgsqldb = new PGSQLDB();
$test = new Test($pgsqldb);
To avoid duplicated code you can extend an abstract class
abstract class AbstractDb {
public function connect() {
// common code to avoid duplication
echo 'connected!';
}
abstract public function escapeField();
abstract public function escapeValue();
}
class MySQL extends AbstractDb {
public function escapeField() {
// Db-specific method
}
public function escapeValue() {
// Db-specific method
}
}
$db = new MySQL;
$db->connect();
Or use composition, and let the Db class use a different driver for db-specific methods
interface IDriver {
public function escapeField();
public function escapeValue();
}
class MySQLDriver implements IDriver {
public function escapeField() {
// Db-specific method
}
public function escapeValue() {
// Db-specific method
}
}
class Db {
public function __construct($driver) {
$this->driver = $driver;
}
public function connect() {
// common code here ? idk, it's just an example
echo 'connect!';
}
// this method is db-specific, so we call the driver
public function escapeField($field) {
return $this->driver->escapeField($field);
}
public function escapeValue() {
// same here
}
}
$db = new Db(new MySQLDriver);
$db->connect();
In php 5.4 there will be traits, so there will be more approaches to avoid code duplication.

Establishing database connection in php using singleton class

Can anybody please guide me with a sample code to establish a database connection in php using singleton class.
class DatabaseSingleton
{
// [Singleton]
private static $instance = null;
public static function getInstance()
{
if (!self::$instance)
{
self::$instance = new self();
}
return self::$instance;
}
private function __clone(){}
// [/Singleton]
private $connection = null;
private function __construct()
{
$this->connection = mysql_connect('localhost','root','admin');
if ($this->connection)
{
mysql_select_db('my_database');
}
}
//
// crud operations go here.
//
}
$db = DatabaseSingleton::getInstance();
$db->SomeCRUDOperation();
Something like that perhaps? Very basic, but should give you a starting point.
That's how a singleton-pattern looks like:
<?php
class SingletonClass
{
static private $instance = null;
static public function getInstance()
{
if (null === self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
private function __construct(){}
private function __clone(){}
}
$singletonClass = SingletonClass::getInstance();
Now you can put random functions and parameters in there that handle your DB-stuff. I hope that answers your question.
See the manual for an example on how to implement the Singleton pattern: http://www.php.net/manual/en/language.oop5.patterns.php
Then just establish the database connection in your class constructor.
I use something like this:
class DBConn
{
static private $_db = null; // The same PDO will persist from one call to the next
private function __construct() {} // disallow calling the class via new DBConn
private function __clone() {} // disallow cloning the class
/**
* Establishes a PDO connection if one doesn't exist,
* or simply returns the already existing connection.
* #return PDO A working PDO connection
*/
static public function getConnection()
{
if (self::$_db == null) { // No PDO exists yet, so make one and send it back.
try {
self::$_db = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PASS);
} catch (PDOException $e) {
// Use next line for debugging only, remove or comment out before going live.
// echo 'PDO says: ' . $e->getMessage() . '<br />';
// This is all the end user should see if the connection fails.
die('<h1>Sorry. The Database connection is temporarily unavailable.</h1>');
} // end PDO connection try/catch
return self::$_db;
} else { // There is already a PDO, so just send it back.
return self::$_db;
} // end PDO exists if/else
} // end function getConnection
} // end class DBConn
/**
* And you can use it as such in a class
* */
class Post {
public function __construct(){
$this->db = DBConn::getConnection();
}
public function getPosts()
{
try {
/*** The SQL SELECT statement ***/
$sql = "SELECT * FROM posts";
foreach ($this->_dbh->query($sql) as $row) {
var_dump($row);
}
/*** close the database connection ***/
$this->_dbh = null;
} catch (PDOException $e) {
echo $e->getMessage();
}
}
}
I am using something like below
class Database
{
private $_connection;
private static $_instance; //The single instance
private $_host = "HOST";
private $_username = "USERNAME";
private $_password = "PASSWORd";
private $_database = "DATABASE";
public static function getInstance() {
if(!self::$_instance) { // If no instance then make one
self::$_instance = new self();
}
return self::$_instance;
}
private function __construct() {
$this->_connection = new mysqli($this->_host, $this->_username,
$this->_password, $this->_database);
// Error handling
if(mysqli_connect_error()) {
trigger_error("Failed to conencto to MySQL: " . mysqli_connect_error(),
E_USER_ERROR);
}
}
// Magic method clone is for prevent duplication of connection
private function __clone() { }
public function getConnection() {
return $this->_connection;
}
}
$db = Database::getInstance();
$mysqli = $db->getConnection();
$sql_query = "SELECT foo FROM etc";
$result = $mysqli->query($sql_query);

Categories