Override core Magento DB connection using environment variables - php

I am trying to use environment variables that are loaded into my Magento application to override the default database connection credentials.
I've managed to 'almost' get this working using the getenv('MY_CUSTOM_VAR'), however I am trying to use this same method to override the database credentials, so this sensitive data can be stored within the htaccess.
e.g
# .htaccess file
SetEnv DB_USERNAME root
SetEnv DB_PASSWORD password123
SetEnv DB_HOST localhost
My App.php (within app/code/local/Mage/Core/Model/App.php - a copy of the one from the core pool)
// my function that overrides the core one
protected function _initBaseConfig()
{
Varien_Profiler::start('mage::app::init::system_config');
$this->_config->loadBase();
/* Read DB connection config from environment variables */
$connection = $this->_config->getNode('global/resources/default_setup/connection');
$connection->setNode('host', getenv('DB_HOST'));
$connection->setNode('username', getenv('DB_USERNAME'));
$connection->setNode('password', getenv('DB_PASSWORD'));
Varien_Profiler::stop('mage::app::init::system_config');
return $this;
}
I want the $connection just created to be the default global database connection used site-wide, this code should appear to do that but if i enter pure random entries for DB_HOST/DB_PASSWORD etc.. it still connects to the database which suggests that it isn't overriding the default database settings configured with the Magento setup.
Any ideas on how to get this $connection to override and become the 'global' database connection?
P.S Apologies in advance if this question is similar to my previous one, the original question was a bit of a general question whereas this one is much more focused to particular section.
Update...
I have open the local.xml within the app/etc directory and set the 'default setup' database connection to inactive (by changing the active node value to 0) and this as expected returns an error. It would appear the overriding function doesn't seem to like to override the initial db connection.. any ideas guys?

For MySQL db you can do next:
Copy file lib/Zend/Db/Adapter/Mysqli.php to app/code/local/Zend/Db/Adapter/Mysqli.php
Open app/code/local/Zend/Db/Adapter/Mysqli.php and find _connect() function.
In this function near line 317 you'll see:
$_isConnected = #mysqli_real_connect(
$this->_connection,
$this->_config['host'],
$this->_config['username'],
$this->_config['password'],
$this->_config['dbname'],
$port
);
Redefine params:
$this->_config['host'] = getenv('DB_HOST');
$this->_config['username'] = getenv('DB_USERNAME');
$this->_config['password'] = getenv('DB_PASSWORD');
$_isConnected = #mysqli_real_connect(
$this->_connection,
$this->_config['host'],
$this->_config['username'],
$this->_config['password'],
$this->_config['dbname'],
$port
);
Clear cache and restart MySQL. For other databases check files in lib/Zend/Db/Adapter folder (DB2.php, Oracle.php, Sqlsrv.php).

Related

Variable from config file to other files [duplicate]

I want to create a config file for my PHP project, but I'm not sure what the best way to do this is.
I have 3 ideas so far.
1-Use Variable
$config['hostname'] = "localhost";
$config['dbuser'] = "dbuser";
$config['dbpassword'] = "dbpassword";
$config['dbname'] = "dbname";
$config['sitetitle'] = "sitetitle";
2-Use Const
define('DB_NAME', 'test');
define('DB_USER', 'root');
define('DB_PASSWORD', '');
define('DB_HOST', 'localhost');
define('TITLE', 'sitetitle');
3-Use Database
I will be using the config in classes so I'm not sure which way would be the best or if there is a better way.
One simple but elegant way is to create a config.php file (or whatever you call it) that just returns an array:
<?php
return array(
'host' => 'localhost',
'username' => 'root',
);
And then:
$configs = include('config.php');
Use an INI file is a flexible and powerful solution! PHP has a native function to handle it properly. For example, it is possible to create an INI file like this:
app.ini
[database]
db_name = mydatabase
db_user = myuser
db_password = mypassword
[application]
app_email = mailer#myapp.com
app_url = myapp.com
So the only thing you need to do is call:
$ini = parse_ini_file('app.ini');
Then you can access the definitions easily using the $ini array.
echo $ini['db_name']; // mydatabase
echo $ini['db_user']; // myuser
echo $ini['db_password']; // mypassword
echo $ini['app_email']; // mailer#myapp.com
IMPORTANT: For security reasons the INI file must be in a non public folder
I use a slight evolution of #hugo_leonardo 's solution:
<?php
return (object) array(
'host' => 'localhost',
'username' => 'root',
'pass' => 'password',
'database' => 'db'
);
?>
This allows you to use the object syntax when you include the php : $configs->host instead of $configs['host'].
Also, if your app has configs you need on the client side (like for an Angular app), you can have this config.php file contain all your configs (centralized in one file instead of one for JavaScript and one for PHP). The trick would then be to have another PHP file that would echo only the client side info (to avoid showing info you don't want to show like database connection string). Call it say get_app_info.php :
<?php
$configs = include('config.php');
echo json_encode($configs->app_info);
?>
The above assuming your config.php contains an app_info parameter:
<?php
return (object) array(
'host' => 'localhost',
'username' => 'root',
'pass' => 'password',
'database' => 'db',
'app_info' => array(
'appName'=>"App Name",
'appURL'=> "http://yourURL/#/"
)
);
?>
So your database's info stays on the server side, but your app info is accessible from your JavaScript, with for example a $http.get('get_app_info.php').then(...); type of call.
The options I see with relative merits / weaknesses are:
File based mechanisms
These require that your code look in specific locations to find the ini file. This is a difficult problem to solve and one which always crops up in large PHP applications. However you will likely need to solve the problem in order to find the PHP code which gets incorporated / re-used at runtime.
Common approaches to this are to always use relative directories, or to search from the current directory upwards to find a file exclusively named in the base directory of the application.
Common file formats used for config files are PHP code, ini formatted files, JSON, XML, YAML and serialized PHP
PHP code
This provides a huge amount of flexibility for representing different data structures, and (assuming it is processed via include or require) the parsed code will be available from the opcode cache - giving a performance benefit.
The include_path provides a means for abstracting the potential locations of the file without relying on additional code.
On the other hand, one of the main reasons for separating configuration from code is to separate responsibilities. It provides a route for injecting additional code into the runtime.
If the configuration is created from a tool, it may be possible to validate the data in the tool, but there is no standard function to escape data for embedding into PHP code as exists for HTML, URLs, MySQL statements, shell commands....
Serialized data
This is relatively efficient for small amounts of configuration (up to around 200 items) and allows for use of any PHP data structure. It requires very little code to create/parse the data file (so you can instead expend your efforts on ensuring that the file is only written with appropriate authorization).
Escaping of content written to the file is handled automatically.
Since you can serialize objects, it does create an opportunity for invoking code simply by reading the configuration file (the __wakeup magic method).
Structured file
Storing it as a INI file as suggested by Marcel or JSON or XML also provides a simple api to map the file into a PHP data structure (and with the exception of XML, to escape the data and create the file) while eliminating the code invocation vulnerability using serialized PHP data.
It will have similar performance characteristics to the serialized data.
Database storage
This is best considered where you have a huge amount of configuration but are selective in what is needed for the current task - I was surprised to find that at around 150 data items, it was quicker to retrieve the data from a local MySQL instance than to unserialize a datafile.
OTOH its not a good place to store the credentials you use to connect to your database!
The execution environment
You can set values in the execution environment PHP is running in.
This removes any requirement for the PHP code to look in a specific place for the config. OTOH it does not scale well to large amounts of data and is difficult to change universally at runtime.
On the client
One place I've not mentioned for storing configuration data is at the client. Again the network overhead means that this does not scale well to large amounts of configuration. And since the end user has control over the data it must be stored in a format where any tampering is detectable (i.e. with a cryptographic signature) and should not contain any information which is compromised by its disclosure (i.e. reversibly encrypted).
Conversely, this has a lot of benefits for storing sensitive information which is owned by the end user - if you are not storing this on the server, it cannot be stolen from there.
Network Directories
Another interesting place to store configuration information is in DNS / LDAP. This will work for a small number of small pieces of information - but you don't need to stick to 1st normal form - consider, for example SPF.
The infrastucture supports caching, replication and distribution. Hence it works well for very large infrastructures.
Version Control systems
Configuration, like code should be managed and version controlled - hence getting the configuration directly from your VC system is a viable solution. But often this comes with a significant performance overhead hence caching may be advisable.
Well - it would be sort of difficult to store your database configuration data in a database - don't ya think?
But really, this is a pretty heavily opinionated question because any style works really and it's all a matter of preference. Personally, I'd go for a configuration variable rather than constants - generally because I don't like things in the global space unless necessary. None of the functions in my codebase should be able to easily access my database password (except my database connection logic) - so I'd use it there and then likely destroy it.
Edit: to answer your comment - none of the parsing mechanisms would be the fastest (ini, json, etc) - but they're also not the parts of your application that you'd really need to focus on optimizing since the speed difference would be negligible on such small files.
You can create a config class witch static properties
class Config
{
static $dbHost = 'localhost';
static $dbUsername = 'user';
static $dbPassword = 'pass';
}
then you can simple use it:
Config::$dbHost
Sometimes in my projects I use a design pattern SINGLETON to access configuration data. It's very comfortable in use.
Why?
For example you have 2 data source in your project. And you can choose witch of them is enabled.
mysql
json
Somewhere in config file you choose:
$dataSource = 'mysql' // or 'json'
When you change source whole app shoud switch to new data source, work fine and dont need change in code.
Example:
Config:
class Config
{
// ....
static $dataSource = 'mysql';
/ .....
}
Singleton class:
class AppConfig
{
private static $instance;
private $dataSource;
private function __construct()
{
$this->init();
}
private function init()
{
switch (Config::$dataSource)
{
case 'mysql':
$this->dataSource = new StorageMysql();
break;
case 'json':
$this->dataSource = new StorageJson();
break;
default:
$this->dataSource = new StorageMysql();
}
}
public static function getInstance()
{
if (empty(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function getDataSource()
{
return $this->dataSource;
}
}
... and somewhere in your code (eg. in some service class):
$container->getItemsLoader(AppConfig::getInstance()->getDataSource()) // getItemsLoader need Object of specific data source class by dependency injection
We can obtain an AppConfig object from any place in the system and always get the same copy (thanks to static). The init () method of the class is called
In the constructor, which guarantees only one execution. Init() body checks
The value of the config $dataSource, and create new object of specific data source class. Now our script can get object and operate on it, not knowing
even which specific implementation actually exists.
Define will make the constant available everywhere in your class without needing to use global, while the variable requires global in the class, I would use DEFINE. but again, if the db params should change during program execution you might want to stick with variable.
If you think you'll be using more than 1 db for any reason, go with the variable because you'll be able to change one parameter to switch to an entirely different db. I.e. for testing , autobackup, etc.
Here is my way.
<?php
define('DEBUG',0);
define('PRODUCTION',1);
#development_mode : DEBUG / PRODUCTION
$development_mode = PRODUCTION;
#Website root path for links
$app_path = 'http://192.168.0.234/dealer/';
#User interface files path
$ui_path = 'ui/';
#Image gallery path
$gallery_path = 'ui/gallery/';
$mysqlserver = "localhost";
$mysqluser = "root";
$mysqlpass = "";
$mysqldb = "dealer_plus";
?>
Any doubts please comment
One of the simplest form to use config with multiple files is like this:
Files hierarchy:
config
- mail.php
- database.php
mail.php
return [
'smtp_debug' => 0,
];
A helper function:
function config($configFilename, $key)
{
$path = sprintf("config/%s.php", $configFilename);
if (file_exists($path)) {
$config = include sprintf("config/%s.php", $configFilename);
if (isset($config[$key])) {
return $config[$key];
}
}
return '';
}
And you can call it in elegant way:
config('mail','smtp_debug')
I normally end up creating a single conn.php file that has my database connections.
Then i include that file in all files that require database queries.
What about something like this ?
class Configuration
{
private $config;
public function __construct($configIniFilePath)
{
$this->config = parse_ini_file($configIniFilePath, true);
}
/**
* Gets the value for the specified setting name.
*
* #param string $name the setting name
* #param string $section optional, the name of the section containing the
* setting
* #return string|null the value of the setting, or null if it doesn't exist
*/
public function getConfiguration($name, $section = null)
{
$configValue = null;
if ($section === null) {
if (array_key_exists($name, $this->config)) {
$configValue = $this->config[$name];
}
} else {
if (array_key_exists($section, $this->config)) {
$sectionSettings = $this->config[$section];
if (array_key_exists($name, $sectionSettings)) {
$configValue = $sectionSettings[$name];
}
}
}
return $configValue;
}
}
if i have a config file like config.conf (it can be htttp://example.com/config.conf)
user=cacom
version = 2021608
status= true
this is my function:
function readFileConfig($UrlOrFilePath){
$lines = file($UrlOrFilePath);
$config = array();
foreach ($lines as $l) {
preg_match("/^(?P<key>.*)=(\s+)?(?P<value>.*)/", $l, $matches);
if (isset($matches['key'])) {
$config[trim($matches['key'])] = trim($matches['value']);
}
}
return $config;
}
we can use:
$urlRemote = 'http://example.com/default-config.conf';
$localConfigFile = "/home/domain/public_html/config.conf";
$localConfigFile2 = "config.conf";
print_r(readFileConfig($localConfigFile2));
print_r(readFileConfig($localConfigFile));
print_r(readFileConfig($urlRemote));
You can use this simple one:
define('someprop', 0);
and
echo someprop; // output 0
Here it is
<?php
$server = "localhost";
$username = "root";
$password = "";
$db = "your_db_name";
$conn = mysqli_connect($server, $username, $password, $db);
if(!$conn){
die('Error in connecting to server or Database');
}
?>

is my cfg.php connection right?

I have a quick question to you guys, i have created the CFG file which stores my database connection detail in two dimensional array. I then connect it to my PHP class file and make it launch the arrays stated in CFG file. As you can see below in my code:
cfg.php
<?php
$cfg['db']['host'] = 'localhost';
$cfg['db']['user'] = 'root'; //your user name
$cfg['db']['pass'] = ''; //your password
$cfg['db']['db'] = 'db3'; //your database
?>
and my class file :
<?php
require_once(dirname(__FILE__) . 'cfg.php');
class Database {
private $dbConn; //stores the database connection
public function __construct($dbConn)
{
global $cfg;
mysql_connect(DB_HOST,DB_USER,DB_PASSWORD) or die('Could not connect to MySQL server.');
mysql_select_db(DB_DATABASE)or die('Unable to select database: ');
}
}
What i want to ask you is: is this right way of doing this? also what do I need to add in my index to see that it is connected. and the output of the database content. Thank you in advance for taking time and reading my problem. Cheerio.
Edit :
<?php
require_once(dirname(__FILE__) . 'cfg.php');
class Database {
private $dbConn; //stores the database connection
public function __construct($dbConn)
{
global $cfg;
mysqli_connect($cfg['db']['host'], $cfg['db']['user'], $cfg['db']['pass'])
or die('Could not connect to MySQL server.');
mysqli_select_db($dbConn, $cfg['db']['db'])
or die('Unable to select database: ');
}
}
Does this looks better now? If yes. How do i connect it with the index.php file where my forms will be stored. say to output the message of (connected to database). Thank you.
EDIT: changed to mysqli and now when selecting the database it states that i am missing the database name. Not sure where to put that and how to alter it. Thank you.
EDIT: I am on my way to create functions for 'Select' 'Insert' and 'Delete' . If any of you can point me do a great source of information which will help me in my research it will be most appreciated.
You are using constants instead of the actual values from your config in your mysql_connect() function, so that wouldn't work. You would need to do it this way:
mysql_connect($cfg['db']['host'], $cfg['db']['user'], $cfg['db']['pass'])
Aside from that and OO paradigms, it would probably be better if you used PHP's mysqli (as stated here) or PDO, as PHP's mysql_ is pretty outdated.
No you are not doing it correctly. By using this line
require_once(dirname(__FILE__) . 'cfg.php');
in your class file you have introduced a somewhat tight coupling to the config file and you have made it hard to swap it out for other credentials. I.e. you will have to change the file with the Database class in it to change the credentials. So start by dropping that include there.
Another thing you do is using the global keyword which is as far from OOP as you could possibly get. Inject the information the class needs instead.
Also you are using the ancient, deprecated and soon to be removed mysql_* API. You are also calling the execution of your script of something fails (or die()) which makes it impossible to integrate your code in a project and also makes it impossible to correctly handle errors (i.e. custom error page).
When upgrading to a better database API (e.g. PDO) you even don't have the need anymore to use a database class at all.
The above would simply look something like the following:
bootstrap.php
try {
$dbConnection = new \PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $e) {
// nicely handle error here
}
Alternatively you could implement lazy loading for the database connection depending on your requirements.
As you can see now there is no need for an external config file (you can just change the credentials here in the bootstrap file) and there is no need for a database class.

Integrate phpgrid with codeigniter

Im trying to integrate phpgrid with my codeigniter program.
I need a few clarifications on how to use the library function.
I have added the phpgrid files to the application/libraries path and I have loaded the libray using $this->load->library('phpGrid');
Below is the code in the phpgrid conf.php file.
<?php
// mysql example
define('DB_HOSTNAME','localhost'); // database host name
define('DB_USERNAME', 'admin'); // database user name
define('DB_PASSWORD', 'pop3'); // database password
define('DB_NAME', xtra); // database name
define('DB_TYPE', 'mysql'); // database type
define('DB_CHARSET','utf8'); // ex: utf8(for mysql),AL32UTF8 (for oracle), leave blank to use the default charset
define('SERVER_ROOT', '/grid');
/******** DO NOT MODIFY ***********/
require_once('phpGrid.php');
/**********************************/
?>
Can someone please help me how can I reference the define and require_once files to my library path?
Or is there any other way that I can include the phpgrid files to my CI project?
I've just looked at the PHPgrid source files and it appears that they are encrypted so you are limited as to how much you can fully "integrate" with Codeigniters MVC framework.
To work with an external library like this, here's what I would generally do:
Store a separate config.php file (that looks like the PHPgrid one) that defines the db connection constants in the root directory.
Then require this in your Codeigniter config/database.php file and use the constants to set the Codeigniter settings as well. So your Codeigniter database.php would look like:
require_once('config.php');
$db['default']['hostname'] = DB_HOSTNAME;
$db['default']['username'] = DB_USERNAME;
$db['default']['password'] = DB_PASSWORD;
$db['default']['database'] = DB_NAME;
You don't want to be storing database connection details all over the place.
Then include config.php at the top of your phpgrid/conf.php file, and use the constants to fill the details the same way, obviously fill out the other phpgrid constants as well.
Put all the PHPgrid files in a subdir of application/libraries. Now create a new file in your application/libraries file that is called something like ci_phpgrid.php and in it create a new class like below:
<?php
require_once('phpgrid/conf.php');
class CI_phpgrid {
public function example_method($val = '')
{
$dg = new C_DataGrid("SELECT * FROM Orders", $val, "Orders");
return $dg;
}
}
You can now use this to communicate with php grid, leaving the original files intact.
In you controller you would just do something like:
$this->load->library('ci_phpgrid');
$data['phpgrid'] = $this->ci_phpgrid->example_method(3)
$this->load->view('home_page',$data);
And then in the view you can display the table using:
$phpgrid->display()
As I mentioned, I've not used PHPgrid and you'll need to include all the relevant JS for sorting etc but this is generally the way you want to approach external libraries in CI.

Path Inclusion/Global variable not working?

Simply put, my config file includes my database class, and the config file has in it:
global $db;
$db = new database(DB_HOST, DB_NAME, DB_USER, DB_PASS);
That file is root/config.php
Moving on to root/functions/func.newpage.php doesn't have any includes/requires, and uses $db->classfunction since the file I'm working with:
root/newpage.php - requires the config file, as well as func.newpage.php.
However I still come up with: Undefined variable db.
Anything you guys are seeing I'm not? Thanks! Let me know if more details are needed.
Are you doing this global $db inside of a function? If not, remove that line, because global is used to add an existing global variable to the scope of a function.
Anyway, if you want to make sure that you're including the config file, you could add an echo("config") at the top of the config script, and you'll be sure that it was included right.
Good luck!

safest place to store php values for msql_connect?

Were is the safest place to store my values which will be used in mysql_connect also what is the safest way to call these variable would be better using a require , include or something else ?
thanks :)
The best place to store it IMO is in a PHP file (whether you use require or include to fetch it doesn't matter) outside the web root, i.e. not directly accessible in the browser.
<?php
$db_server = "xyz";
$db_user = "def";
$db_password = "abc";
?>
If there is no access outside the web root
#Yacoby wrote this down in his answer. He deleted it since, but it definitely deserves mention.
There are foolish hosting providers who don't allow access outside the web root. In that case, you put the config file in a directory in your web site and protect it using a .htaccess file containing Deny from All. This works on most hosting packacges. Make sure you test it though, you should get a 403 Forbidden when trying to access that file.
This is what I usually do:
Set up the project so the website is a subfolder of the project. That way you can have all PHP classes and config files outside the web root folder.
Have a config.php file with an array of Database credentials. For example:
$databases = array(
"read" => array("host" => "127.0.0.1",
"user" => "read",
"pword"=> "secret",
"dbase"=> "projectName"));
Extend the PDO class (or create a new class) called Database that has a constructor taking one argument.
class Database extends PDO{
function __construct($database){
global $databases;
$db = $databases[$database];
parent::__construct("mysql:dbname=".$db['dbase'].";host=".$db['host'],
$db['user'], $db['pword']);
}
}
Now you can pass the array key to one of the database credentials as an argument to the Database class constructor, and then it will sign in with those details. This means that you can have several users to access the database (one for reading, and one for writing).

Categories