I have this class called dataBase . Looks like this
class dataBase
{
private $conexion;
private $paisConexion;
var $db;
function __construct($db='default')
{
$this->db = $db;
include '../settings/variables.php';
if(isset($bbdd)){
$conexion = mysql_connect($bbdd["server"], $pais[0]['user'], $pais[0]['pass']) or die('No se pudo conectar: '.mysql_error());
// Seleccionamos la base de datos
mysql_select_db($x[0]['database']) or die('No se pudo seleccionar la base de datos');
if($conexion)
{
$paisConexion = mysql_connect($bbdd["server"], $pais[$this->db]['user'], $pais[$this->db]['pass']) or die('No se pudo conectar: '.mysql_error());
mysql_select_db($pais[$this->db]['database']) or die('No se pudo seleccionar la base de datos');
}
}
else{
echo 'El sistema no se pudo conectar a la base de datos.';
exit;
}
}
public function execute($sql)
{
$result = mysql_query($sql) or die("ERROR: Ejecución de consulta: $sql<br>\n");
return $result;
}
}
I am trying to make two connection to two different database using the variable $conexion and $paisConexion .
My question is is it possible to do something like this .
I mean suppose I am creating an object for the class like this
$obj = new dataBase(1);
$res = obj->execute($sql);
So how the the class will decide which of the connection it has to use ? .
I think I am doing this wrong way . If any one has any idea please let me know
Thanks in Advance
It is possible to do something like this, but the approach you have suggested seems very limited to me, so I have taken the liberty to write an alternative using PDO since the mysql_* functions are deprecated. Mysql_* functions official documentation here
By using the PDO class provided by PHP you gain the benefit of parameterized queries and transactions. PDO documentation here
To make it easier for you to add other connections in the future I have written a small class containing the absolutely bare bones. I have left many things such as error handling out for simplicity as this only serves as demonstration.
/*
* DO NOT USE THIS IN PRODUCTION
*/
class DatabaseConnectionManager {
private $connections = [];
public function __construct(array $credentials) {
foreach($credentials as $identifier => $information) {
$this->connections[$identifier] = $this->openConnection(
$information['host'],
$information['database'],
$information['username'],
$information['password']
);
}
}
public function __destruct() {
/* If the object is destroyed before the script closes or is disrupted (fatal errors), we
* destroy all database connections as good practice.
*/
$this->connections = [];
}
public function getConnection($identifier) {
if(!array_key_exists($identifier, $this->connections)) {
throw new LogicException('Unknown database connection: ' . $identifier);
}
return $this->connections[$identifier];
}
private function openConnection($host, $database, $username, $password) {
$dsn = "mysql:host{$host};dbname={$database}";
return new PDO($dsn, $username, $password);
}
}
With this you can supply an array of different database connection information. The usage is like the following.
$credentials = [
'primary' => [
'host' => 'localhost',
'database' => 'number1',
'username' => 'awesome',
'password' => 'secret'
],
];
$connections = new DatabaseConnectionManager($credentials);
To get a connection (PDO object) which can perform different database related task, simply specify a connection identifier with the getConnection() method.
$db = $connections->getConnection('primary');
IMPORTANT
This code is no where near production ready and serve only for demonstration purpose. There is next to no error checking or error handling. If an array with insufficient required parameters is provided you will get an error.
At the same time it is impossible at the current moment to provide options to the PDO object without hard-coding them.
Hope this can help you in the right direction.
You can't create one class for both databases. Unless you pass some parameter that specifies witch connection to use. Also than you must use two different variables for different connections. And don't use deprecated mysql_* functions
class DataBase {
// only private variables accessed by functions
private $localDb, $remoteDb;
// Always use constants instead of magic numbers
const LOCAL = 1, REMOTE = 2
public function _construct() {
$this->localDb= new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$this->remoteDb= new PDO('mysql:host=remore;dbname=test2', 'username', 'password');
}
// Can't use constants in function header - - - - -v
public function execute($queryString, $params = [], $useDb = 1) {
// static:: will take variable from this class and not from parent class (if extends something)
if ($useDb == static::LOCAL) {
$db = $this->local;
} elseif ($useDb == static::REMOTE) {
$db = $this->remote;
}
$query = $db->prepare($queryString);
// Usage of prepared statement
return $query->execute($params);
}
}
$db = new DataBase();
$db->execute(
'SELECT * FROM table WHERE column = :columnVal', // named placeholders instead of tons of '?'
[':columnVal' => 5], // some parameters
DataBase::LOCAL // Constant from class
);
Save connection to private field and use it in execute:
function __construct($db='default')
{
...
$this->paisConexion = mysql_connect(...
...
}
public function execute($sql)
{
$result = mysql_query($sql, $this->paisConexion);
return $result;
}
Related
I'm dealing with a PHP application with what seems to have a peculiarity: One of its files (helpers.php) has a couple of functions that includes another file, and the included file (db_connection.php) includes the file that originally included it.
helpers.php:
<?php
function lineBreak()
{
return "\n<br>\n";
}
function saveScoreToDB($score)
{
//session_start(); // Already started
$usuario_id = $_SESSION["usuario_id"];
$etapa = $_SESSION["etapa"];
try
{
$query_etapa = "SELECT id FROM etapas WHERE numero = $etapa";
require_once "db_connection.php";
// `$db_link` works perfectly fine here:
$etapa_id = $db_link->query($query_etapa)->fetchColumn();
$query_score = "INSERT INTO score
(
usuario_id,
etapa_id,
pontos
)
VALUES
(
$usuario_id,
$etapa_id,
$score
)";
$db_link->query($query_score);
}
catch (Exception $e)
{
$_SESSION["error_message"] = $e->getMessage();
header("Location: erro.php");
}
}
function completeTest($redirectTo)
{
unset($_SESSION["etapa"]);
$usuarioId = $_SESSION["usuario_id"];
// TODO: try/catch
try
{
$queryEmailUsuario = "SELECT email FROM usuarios WHERE id = $usuarioId";
$queryNomeUsuario = "SELECT nome FROM usuarios WHERE id = $usuarioId";
require_once "db_connection.php";
// `$db_link` does *not* work here. Why?
$emailUsuario = $db_link->query($queryEmailUsuario)->fetchColumn();
$nomeUsuario = $db_link->query($queryNomeUsuario)->fetchColumn();
// Routine to send email using the variables above
}
catch (Exception $ex)
{
// TODO
}
}
db_connection.php:
<?php
require_once "db_credentials.php";
require_once "helpers.php";
// Variables used here come from `db_credentials.php`
$dsn = "mysql:host=$host;dbname=$dbname;port=3307;charset=utf8;";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
];
try
{
$db_link = new PDO($dsn, $user, $pass, $options);
}
catch (PDOException $e)
{
echo "Error connecting to the database.";
echo lineBreak();
echo $e->getMessage();
echo lineBreak();
echo lineBreak();
}
Notice how in the first script variable $db_link is used in two different functions, both of which include the file where this variable is defined. Within the first function (saveScoreToDB), the variable is available and the function works fine; but within the second (completeTest) it is not available and I get an undefined variable error.
Why is that? How to make it work?
The first require_once() works because that's the "once", but it's only in-scope in that single function call, so $db_link gets tossed out at the end of the function call and is never seen again. You can change that to require(), but creating a new connection for every single function call is... not going to work out well in the long run.
Ideally you create the connection once and then pass it in via parameters where it is needed, eg:
require_once('db_credentials.php');
saveScoreToDB($score, $db_link);
completeTest($redirectTo, $db_link)
But that might get a bit tedious, right? Well this is where classes become useful.
class MyThing {
protected $db;
public function __construct(\PDO $db) {
$this->db = $db;
}
public function saveScoreToDB($score) {
$this->db->prepare(...);
}
public function completeTest($redirectTo) {
$this->db->prepare(...);
}
}
$thing = new Mything($db_link);
$thing->saveScoreToDB(42);
$thing->completeTest('yes');
I am having a strange error while creating objects. While I create an objects in chronological orders as classed defined, it is going on good. But when I change the order or object creation, it gives error.
The classes I am using are as follows:
<?php
class dbClass{
private $dbHost, $dbUser, $dbPass, $dbName, $connection;
function __construct(){
require_once("system/configuration.php");
$this->dbHost = $database_host;
$this->dbUser = $database_username;
$this->dbPass = $database_password;
$this->dbName = $database_name;
}
function __destruct(){
if(!$this->connection){
} else{
mysql_close($this->connection);
}
}
function mysqlConnect(){
$this->connection = mysql_connect($this->dbHost, $this->dbUser, $this->dbPass) or die("MySQL connection failed!");
mysql_select_db($this->dbName,$this->connection);
}
function mysqlClose(){
if(!$this->connection){
} else{
mysql_close($this->connection);
}
}
}
class siteInfo{
private $wTitle, $wName, $wUrl;
function __construct(){
require_once("system/configuration.php");
$this->wTitle = $website_title;
$this->wName = $website_name;
$this->wUrl = $website_url;
}
function __destruct(){
}
function showInfo($keyword){
if($keyword=="wTitle"){
return $this->wTitle;
}
if($keyword=="wName"){
return $this->wName;
}
if($keyword=="wUrl"){
return $this->wUrl;
}
}
}
?>
The problem is when I create objects in the following order, it is working perfectly:
include("system/systemClass.php");
$dbConnection = new dbClass();
$dbConnection -> mysqlConnect();
$siteInfo = new siteInfo();
But if I change the order to following
include("system/systemClass.php");
$siteInfo = new siteInfo();
$dbConnection = new dbClass();
$dbConnection -> mysqlConnect();
It gives error!
Warning: mysql_connect() [function.mysql-connect]: Access denied for user '#####'#'localhost' (using password: NO) in /home/#####/public_html/#####/system/systemClass.php on line 19
MySQL connection failed!
Your problem comes from the unconventional use of a configuration file that is read ONCE, but should be used in all classes.
When you instantiate the dbclass first, the configuration is read, probably variables get assigned, and you use these in the constructor.
After that, instantiating siteinfo will not read that file again, which is less harmful, because you only end up with an empty object that does return a lot of null, but does work.
The other way round, you get a siteinfo object with all the info, but a nonworking dbclass.
My advice: Don't use a configuration file that way.
First step: Remove the require_once - you need that file to be read multiple times.
Second step: Don't read the file in the constructor. Add one or more parameters to the constructor function and pass the values you want to be used from the outside.
Info: You can use PHP code files that configure stuff, but you shouldn't define variables in them that get used outside. This will work equally well:
// configuration.php
return array(
'database_host' => "127.0.0.1",
'database_user' => "root",
// ...
);
// using it:
$config = require('configuration.php'); // the variable now has the returned array
So, I'm working on a project that requires a database connection. I've chosen to use PDO for its versatility and need to figure out how to set up the connection. Currently I'm going for something like this:
class Database {
private static $db;
static function initDB() {
if(!is_object(self::$db) || get_class(self::$db) != 'PDO') {
include('core/db.php');
try {
$db = new PDO($database, $username, $password);
} catch(PDOException $e) {
print("<br />Could not establish database connection. Error message: ".$e->getMessage()."<br />");
die();
}
}
//Try the transaction
/*
if($transaction = $db::query(PDO::quote($value)))
$db::query(PDO::quote("INSERT INTO log VALUES ('".Authorization::$user."','".PDO::quote($value)."', 'Success')"));
else
$db::query(PDO::quote("INSERT INTO log VALUES ('".Authorization::$user."','".PDO::quote($value)."', 'Failure')"));*/
}
}
So, this pretty much reveals one of the concepts I don't really know: singletons and static classes/objects. Any way to set up a database connection using OO best practices that initializes with the script via some kind of __construct method?
A database connection should not be either static or a singleton. This merely introduces another form of global state, which is bad for unit-testing and does hide obvious dependencies.
The right way here would be is to inject an instance of PDO into the classes that need it. You adhere the Single-Responsibility Principle and Dependency Injection.
Note, you should never log errors and do include() inside PDOAdapter constructor because its masked violation of the Single-Responsibility Principle
So, this would look like this:
final class PDO_Provider extends PDO
{
/**
* Constructor. Inits PDO
*
* #param array $params
* #return void
*/
public function __construct(array $params)
{
try {
extract($params);
parent::__construct(sprintf('mysql: host=%s; dbname=%s', $host, $database), $user, $password);
$this->setAttribute(parent::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES UTF8');
$this->setAttribute(parent::ATTR_ERRMODE, parent::ERRMODE_EXCEPTION);
$this->setAttribute(parent::ATTR_EMULATE_PREPARES, false);
$this->setAttribute(parent::ATTR_DEFAULT_FETCH_MODE, parent::FETCH_ASSOC);
} catch(PDOException $e) {
die($e->getMessage());
}
}
}
And you would use it like this,
<?php
$sql_config = array(
'host' => 'localhost',
'user' => 'root',
'password' => '',
'database' => '_DB_NAME_',
);
// <- Or you can include that, like
$sql_config = include(__DIR__ . '/core/db_params.php');
$pdoProvider = new PDO_Provider($sql_config);
$user = new User_Login($pdoProvider); // the point here is to inject an instance of $pdoProvider. User_Login is actually irrelevant
if you want to use a normal object instead of sigleton, try something like this:
class PDOConnector{
protected $connection;
function __construct($host, $user, $pass, $db_name)
{
//create database connection
try{
$this->connection = new PDO('mysql:host='.$this->host.';dbname='.$this->db_name.';charset=utf8', $this->user, $this->pass,array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
catch(PDOException $ex) {
echo "An Error occured : ".$ex->getMessage();
}
}
}
Hi i am trying to move from MySQL to MySQLi in my PHP script, i had this system class with the function that connects to the database that i call whenever i need, with a simple method like this:
Sys::database_connect();
the actual code of the function is:
function database_connect(){
require 'conf.php';//configuration file with database variables (sql_)
mysql_connect($sql_serv, $sql_user, $sql_pw) OR die('ERRO!!! não ligou a base de dados');
mysql_select_db($sql_bd);
}
after calling the function i can query the database without problem.
But I cant do the same with mysqli if I put this in the sys class:
function database_connect(){
require 'conf.php';
$mysqli = new mysqli($sql_serv, $sql_user, $sql_pw, $sql_bd);
if (mysqli_connect_errno()) {
printf("Ligação à Base de dados falhou: %s\n", mysqli_connect_error());
exit();
}
}
When I call
Sys::database_connect();
it connects to the database but i can't query has i used to what i would like would be a simple method as I have done with normal MySQL, if somebody can explain what am I doing wrong or why exactly I cannot do it like that...
Thank you in advance;
Fernando Andrade.
Your later queries have to use the mysqli connection identifier, you create when connecting to the database. So save this to a property of your system class and use it later on.
function database_connect(){
require 'conf.php';
$mysqli = new mysqli($sql_serv, $sql_user, $sql_pw, $sql_bd);
if (mysqli_connect_errno()) {
printf("Ligação à Base de dados falhou: %s\n", mysqli_connect_error());
exit();
}
Sys::$dbConn = $mysqli;
}
and then later on
function query( $sql ) {
Sys::$dbConn->query( $sql );
// error handling etc.
}
I wrote an extend for the mysqli database class
class database extends mysqli {
function __construct() {
parent::__construct('host', 'user', 'password', 'database');
if(mysqli_connect_error()) {
die('Connect error ('.mysqli_connect_errno().')'.mysqli_connect_error());
}
parent::query("SET NAMES 'utf8'");
}
function query($query) {
$result = parent::query($query);
if(!$result) {
echo "<strong>MySQL error</strong>: ".$this->error."<br />QUERY: ".$query;
die();
}
if(!is_object($result)) {
$result = new mysqli_result($this);
}
return $result;
}
}
So connecting to database is $db = new database()
Executing a query is $db->query(YOUR QUERY);
Hey guys I have a connection class I found for pdo. I am calling the connection method on the page that the file is included on. The problem is that within functions the $conn variable is not defined even though I stated the method was public, and I was wondering if anyone had an elegant solution other then using global in every function. Any suggestions are greatly appreciated.
CONNECTION
class PDOConnectionFactory{
// receives the connection
public $con = null;
// swich database?
public $dbType = "mysql";
// connection parameters
// when it will not be necessary leaves blank only with the double quotations marks ""
public $host = "localhost";
public $user = "user";
public $senha = "password";
public $db = "database";
// arrow the persistence of the connection
public $persistent = false;
// new PDOConnectionFactory( true ) <--- persistent connection
// new PDOConnectionFactory() <--- no persistent connection
public function PDOConnectionFactory( $persistent=false ){
// it verifies the persistence of the connection
if( $persistent != false){ $this->persistent = true; }
}
public function getConnection(){
try{
// it carries through the connection
$this->con = new PDO($this->dbType.":host=".$this->host.";dbname=".$this->db, $this->user, $this->senha,
array( PDO::ATTR_PERSISTENT => $this->persistent ) );
// carried through successfully, it returns connected
return $this->con;
// in case that an error occurs, it returns the error;
}catch ( PDOException $ex ){ echo "We are currently experiencing technical difficulties. We have a bunch of monkies working really hard to fix the problem. Check back soon: ".$ex->getMessage(); }
}
// close connection
public function Close(){
if( $this->con != null )
$this->con = null;
}
}
PAGE USED ON
include("includes/connection.php");
$db = new PDOConnectionFactory();
$conn = $db->getConnection();
function test(){
try{
$sql = 'SELECT * FROM topic';
$stmt = $conn->prepare($sql);
$result=$stmt->execute();
}
catch(PDOException $e){ echo $e->getMessage(); }
}
test();
You can declarate database class where you carrying conn pdo class, then you don't must duplicates instaces of this. And all database operations you can doing by this class. I mean my answer is what you searching.
But i see, you using only PDO hadle class in Product Factory pattern. You can use normal full database support class under PDO (includes queryies execution from one function) and without this design pattern when you don't want to use many database connectors engines.