Codeigniter alternate database connection if server down - php

I want to use a raw php code in Codeigniter for alternate database connection my raw php code is:
$db = mysql_connect('remote_server', 'username', 'password'); if(!$db){
$db = mysql_connect('localhost', 'username', 'password') ; }
to connect to a backup server if the remote mysql server is down for some reason.
Has anyone done this kind of thing with CodeIgniter? If so, would you mind sharing code or ideas?

UPDATE:
just figured out a better approach.
suppose you have 2 database configuration in database.php, one is the default, the other is the backup
i.e
$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root';
$db['default']['password'] = '';
$db['default']['database'] = 'temp_test1';
//.......
$db['backup']=$db['default'];
$db['backup']['hostname'] = 'localhost1';
$db['backup']['username'] = 'root';
$db['backup']['password'] = '';
$db['backup']['database'] = 'temp_test1';
now, add this to the end of the database.php file
//check to see if you can connect
$conn=#mysql_connect($db['default']['hostname'],$db['default']['username'],$db['default']['password']);
if($conn) //check to see if it's connecting, if it is close this connection
{
mysql_close($conn);
}
else{ //if it isnt
$db['default']=$db['backup']; //replace the default credentials with the backup credentials
}
OLD POST:
there are a lot of approaches you can take.
Your you can check if a particular connection is open via this mysql_ping(), i.e
$conn=mysql_connect(...);
if(mysql_ping($conn)){...};
so you can use this method to decide which database to choose.
For codeigniter, one approach (which is a rather bad one I would say, but an approach none the less), is to mess with the system files. In DB_Driver, in this portion of the code:
$this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
if ( ! $this->conn_id)
{
log_message('error', 'Unable to connect to the database');
if ($this->db_debug)
{
$this->display_error('db_unable_to_connect');
}
return FALSE;
}
is where it tries to connect and checks if connection was successful, and if not gives the error.
I'm not sure how you do exception handling in CI, but basically you should handle an exception and connect to a different database.
Since I dont know exception handling, say I create a database_backup.php file the config folder hostname, username, password, and database variable. Then I would change the code to this
$this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
if ( ! $this->conn_id) //oops, first connection failed
{
//no problem, change the credentials of the database to our backup credentials
$ci=&get_instance();
$ci->load->config('database_backup');
$this->username=$ci->config->item('username');
$this->password=$ci->config->item('password');
$this->database=$ci->config->item('database');
$this->hostname=$ci->config->item('hostname');
//try to connect to database once more
$this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
// No connection resource STILL?nothing we can do now, throw an error
if ( ! $this->conn_id)
{
log_message('error', 'Unable to connect to the database');
if ($this->db_debug)
{
$this->display_error('db_unable_to_connect');
}
return FALSE;
}
}

take a look at system/database/drivers/mysql/mysql_driver.php
find the function function db_connect() [or function db_pconnect() depending upon which one you using]
there is the connection code:
return #mysql_connect($this->hostname, $this->username, $this->password, TRUE);
change the logic to suit your need.
by the way, prefere to use the PDO driver instead as by default, codeigniter uses mysql_* of whose depreciation process started.

Related

Connecting to Oracle database from PHP

I have an Oracle database that I am trying to connect to.
For some reason when I try the following code:
<?php
include "header.php";
// simply attempt to connect to the database
/* If you are connecting to the Oracle database, the credentials are as follows:
* Username: ********
* Password: ********
* Hostname: **********
* Port: 1521
* Service name: ***********
*/
$oracleConnect = true;
if ($oracleConnect)
{
echo 'Attempting connection...<br>';
$connection = null;
try
{
$connection = oci_connect('user',
'pass',
'user#//hostname:1521/dbname');
}
catch (Exception $e)
{
echo $e->getMessage();
}
if (!$connection)
{
echo '<p>Something is wrong.</p>';
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
// if the connection has been established
else
{
// tell the user and close it (this is a test)
echo 'Connection established!!';
oci_close($connection);
}
}
else
{
$connection = new mysqli('host', 'user', 'password', 'database');
echo ($connection) ? 'Database connection successful!' : 'Could not connect.';
}
include "footer.php";
?>
When I try the above code, I get the "Attempting connection..." to print, but nothing else. It is supposed to print something else regardless. What could possibly be going wrong?
I think the problem is the user# part of your connection string. I dont think thats necessary as oci_connect has a user name parameter. I could be wrong, ive never used oracle from php before, but the docs on oci connections would also seem to indicate that:
To use the Easy Connect naming method, PHP must be linked with Oracle 10g or greater Client libraries. The Easy Connect string for Oracle 10g is of the form: [//]host_name[:port][/service_name]. From Oracle 11g, the syntax is: [//]host_name[:port][/service_name][:server_type][/instance_name]. Service names can be found by running the Oracle utility lsnrctl status on the database server machine.
Also oci_connect does not throw an exception as far as i can tell so your try/catch is useless unless you planned on throwing your own when it returns false.

Symfony 1.4 project in SAAS mode - multiple databases

I have a Symfony 1.4 project that I want to use in SAAS mode for multiple customers.
The idea is to have multiple domains and databases but to always use the same code. I also don't want to have to change anything in my project for each new customer : everything must be dynamic.
I've been trying for a few hours now to override the database.yml configuration but it wasn't really a success. I added at the beginning of my ProjectConfiguration.class.php :
require_once '/path/to/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine.php';
spl_autoload_register(array('Doctrine', 'autoload'));
$manager = Doctrine_Manager::getInstance();
$serverName = $_SERVER['SERVER_NAME'];
if(preg_match("#\.saas-domain\.com$#", $serverName))
$dbname = "db-" . preg_replace("#\.saas-domain\.com$#", "", $serverName);
else
$dbname = "db-default";
$dsn = "mysql:dbname=$dbname;host=localhost";
$user = 'dbuser';
$password = 'dbpsw';
try {
$dbh = new PDO($dsn, $user, $password);
$conn = Doctrine_Manager::connection($dbh);
} catch (PDOException $e) {
die("Can't find that database");
}
I tried to put this code at the end of the setup() method, same thing : it doesn't seem to be used.
As you can see I wanted to deduce the database to use from the domain (ServerName in apache).
My very last option is to manually alter each config_database.yml.php file generated in cache (in fact only alter one and use symlinks), but I really would like not to have to do this.
So my questions are :
Is it possible to override the database.yml configuration ?
If not, is there a way I can delete this file or ignore it and set up a manual doctrine configuration ?
Are there any other solutions that I didn't consider ?
EDIT
I managed to come up with a solution (with the help of this article). It's probably not the best way to do it, but at least the result is OK.
The idea is to use Symfony's filters in order to replace the connection created by the database YAML file :
In config/filters.yml add the following :
myDBConnectionFilter:
class: myDBConnectionFilter
Then create this myDBConnectionFilter class and put it anywhere it can be found by Symfony's autoloader (lib in most cases). Below is an example of code you can use in this class :
<?php
class myDBConnectionFilter extends sfFilter
{
public function execute($filterChain){
if ($this->isFirstCall())
{
$serverName = $_SERVER['SERVER_NAME'];
if(preg_match("#\.saas-domain\.com$#", $serverName))
$dbname = "db-" . preg_replace("#\.saas-domain\.com$#", "", $serverName);
else
$dbname = "db-default";
$dsn = "mysql:dbname=$dbname;host=localhost";
$user = 'user';
$password = 'password';
$manager = Doctrine_Manager::getInstance();
try {
$default = $manager->getConnection('dbconnection');
Doctrine_Manager::getInstance()->closeConnection($default);
$dbh = new PDO($dsn, $user, $password);
$conn = Doctrine_Manager::connection($dbh, 'dbconnection');
} catch (Exception $e) {
die("Error : " . $e->getMessage());
}
}
$filterChain->execute();
}
}
You'll then need to clear Symfony's cache.
This code retrieve a connection from Doctrine_Manager, close it, then create a new one with the same name to replace it. In this case, the connection is called dbconnection. The name of the connection is the one used in database.yml.
As I said, it is not the best way to do it as this method makes two connections to the database instead of one. So if anyone has a better solution i would take it !

how to avoid the new PDO(...) line of code to appear too often?

There is something, as a newbie, that a I want to understand about About database connections.
I am starting off from a tutorial on PHP which has this structure:
Connect.php:
<?php
$username = "dbusername";
$password = "dbpassword";
$host = "localhost";
$dbname = "dbname";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
try
{
$db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options);
}
catch(PDOException $ex)
{
die("Failed to connect to the database: " . $ex->getMessage());
}
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
header('Content-Type: text/html; charset=utf-8');
session_start();
?>
Login.php:
<?php
require("connect.php");
// some code not important for this question,
//that handles login with a session…
?>
various_file_in_the_login_system.php:
<?php
require("connect.php");
// some code that checks if user is logged in with session_ …
// some code that does need the database connection to work
?>
All other files also contain that require("connect.php"); line. It works, but I just don’t know what these connection request to the server – I may not be using the right vocabulary -- end up doing to the server. They are superfluous if the connection is not timed out, are they not?
I found a post which talked about doing a singleton for PDO, and a post which makes me feel like never using persistent connections in my life.
Does this design causes excessive connection churning?
Perhaps servers can handle very many request for connection per second, perhaps a server has its own internal persistent connection mode, or implements connection pooling…
Or the PDO object handle the problem of asking connection too often for no reason…
PDO + Singleton : Why using it?
What are the disadvantages of using persistent connection in PDO
This is what I can recommend for your database connection:
Make a class for the connection:
class Database{
private static $link = null ;
public static function getConnection ( ) {
if (self :: $link) {
return self :: $link;
}
$dsn = "mysql:dbname=social_network;host=localhost";
$user = "user";
$password = "pass";
self :: $link = new PDO($dsn, $user, $password);
return self :: $link;
}
}
Then you can get the connection like this:
Database::getConnection();
The Singleton Pattern is hard to scale - However, I think it will probably be fine for your needs. It takes a lot of load off your database.
I don't think you will be able to avoid the multiple includes.
There is a php.ini setting for prepending a file to every script -> http://www.php.net/manual/en/ini.core.php#ini.auto-prepend-file
How about you change to
require_once('connect.php');
in all locations?
Also you should probably remove session_start() and HTTP header logic from a section of code that has to do with establishing a DB connection. This simply does not make sense there.

Detect if mysql or mysqli is being called for connection

is there a way to check which type of mysql connection is being called mysql or mysqli. what I want to do is have a If statement to call mysql or mysqli connection until I can change out all my coding.
this is my current connection file. would just duplicating what's below but with mysqli accomplish what i'm trying to do?
$dbc = mysql_connect ($db_server, $db_user, $db_pass);
mysql_select_db ($db_name) or die(mysql_error());
$g_link = false;
function GetDbConn()
{
global $g_link;
if( $g_link )
return $g_link;
$g_link = mysql_connect( 'localhost', 'username', 'password') or die('Could not connect to server.' );
mysql_select_db('social_db', $g_link) or die('Could not select database.');
return $g_link;
}
function CleanUpDB()
{
global $g_link;
if( $g_link != false )
mysql_close($g_link);
$g_link = false;
}
You can use get_resource_type function:
if(is_resource($g_link) && get_resource_type($g_link)=='mysql link'){
echo 'MYSQL';
}else{
if(is_object($g_link) && get_class($g_link)=='mysqli'){
echo 'MYSQLI';
}
}
Also, it's better to save connection type when you want to create connection and then use it.
There is absolutely no point in checking which type of mysql connection is being called mysql or mysqli.
While changing "all your coding", you have to make use of some sort of db access library, which will be obviously using a new driver as it's underlying level. And as this library obviously have to be written using new api, no verifications ever needed.
While just rewriting old api calls to the new api calls will make no sense.

Codeigniter/PHP check if can connect to database

I'd like to backup my read replica(i.e., slave) database with my master database but this simple boolean I did failed:
$config['hostname'] = "myReadReplicaDatabase.com";
//...$config['other_stuff']; other config stuff...
$db_obj=$CI->load->database($config, TRUE);
if(!$db_obj){
$config['hostname'] = "myMasterDatabase.com";
$db_obj=$CI->load->database($config, TRUE);
}
After terminating my read replica database I expected the boolean to evaluate to FALSE and the script to then use my master database. Unfortunately, instead I got the following PHP error:
Unable to connect to your database server using the provided settings.
Filename: core/Loader.php
All i want is for the connection to return true or false, does anyone know how to do this in Codeigniter?
My question was answered on this thread on Codeigniter forums.
The key is to not autoinitialize the database:
$db['xxx']['autoinit'] = FALSE;
To suppress errors it you can set this
$db['xxx']['db_debug'] = FALSE;
Then in your code that checks the db state, check TRUE/FALSE of the initialize() function:
$db_obj = $this->database->load('xxx',TRUE);
$connected = $db_obj->initialize();
if (!$connected) {
$db_obj = $this->database->load('yyy',TRUE);
}
Here is my entire config file for future reference: https://gist.github.com/3749863.
when you connect to database its returns connection object with connection id on successful condition otherwise return false.
you can check it to make sure that database connection is done or not.
$db_obj=$CI->load->database($config, TRUE);
if($db_obj->conn_id) {
//do something
} else {
echo 'Unable to connect with database with given db details.';
}
try this and let me know, if you have any other issue.
I test all I found and nothing wokrs, the only way I found was with dbutil checking if database exists, something like this:
$this->load->database();
$this->load->dbutil();
// check connection details
if( !$this->dbutil->database_exists('myDatabase'))
echo 'Not connected to a database, or database not exists';
Based on what was said here:
Codeigniter switch to secondary database if primary is down
You can check for the conn_id on the $db_obj
if ($db_obj->conn_id === false) {
$config['db_debug'] = true;
$config['hostname'] = "myMasterDatabase.com";
$db_obj=$CI->load->database($config, TRUE);
}
This should work.
try {
// do database connection
} catch (Exception $e) {
// DO whatever you want with the $e data, it has a default __toString() so just echo $e if you want errors or default it to connect another db, etc.
echo $e->getMessage();
// Connect to secondary DB.
}
For those who downvoted me, you can do this. Exception will catch PDOException.
try {
$pdo = new PDO($dsn, $username, $password);
} catch(PDOException $e) {
mail('webmaster#example.com', 'Database error message', $e->getMessage());
// and finally... attempt your second DB connection.
exit;
}
$readReplica = #$CI->load->database($config, TRUE); // ommit the error
if ($readReplica->call_function('error') !== 0) {
// Failed to connect
}
Im not sure about the error code (not sure if its int/string) and don't have CI nearby to test this out but this principle should work
$this->load->database();
print_r($this->db);
Its work for me
$config['xxx'] = xx;
...
$config['db_debug'] = false;
$db_obj = #$this->load->database($config,true);
if(!#$db_obj->initialize()){
echo "Unable to connect database";
die;
}

Categories