Problem
I have a simple PHP application that uses a MySQL database to store data. The username and password are currently hard-coded in the PHP code. For example, since the code is also available on a repository, this is a circumstance I dislike.
The only solution I can think of is to move the data from the code to a configuration file (not in the repository) and encrypt it so that it is not immediately readable (obfuscation). Is there a more efficient and user-friendly way to resolve the problem?
$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb');
Goal: I want to provide a solution that is both reliable and simple to use. I want reasonable protection, but I’m not dealing with sensitive information.
Remark: Using the mysql connect functions is no longer encouraged; see the Stack Overflow question Why shouldn’t I use mysql_ functions in PHP?*. I could have altered the code sample, but I didn’t because some commenters mentioned it. The basic nature of the inquiry, however, remains relevant.
Asked by Horst Walter
Solution #1
The simplest method is to utilize a configuration file, like you mentioned.
This is the most typical way of doing things and is used by many frameworks (Zend, CakePHP, Kohana, and so on) (even in a non-PHP environment such as ASP.NET with its web.config files). This also allows you to replicate configuration values from one environment to the next by just copying the site’s files, which is more convenient than relying on server-setup environment variables (which can very quickly be lost and forgotten).
Because it’s not a world-available file, and it surely shouldn’t be online accessible, you shouldn’t have to worry about password obfuscation. This means you’d either a) tell your web server not to serve your configuration file (IIS currently does this with web.config files, serving an HTTP 404.8 status instead of the contents), or b) move it outside of your web served directory. It’s worse than having it in your source code if someone can see your configuration file.
It’s also a good idea to have a basic (empty / default) version of the configuration file and separate it by environments, so you can have separate configuration files for production, development, and testing platforms.
The most frequent technique to distinguish between various environments is to use an environment variable, such as the code below:
// Check if it's been set by the web server
if (!empty($_ENV['ENVIRONMENT'])) {
// Copy from web server to PHP constant
define('ENVIRONMENT', $_ENV['ENVIRONMENT']);
}
if (!defined('ENVIRONMENT')) {
// Default to development
define('ENVIRONMENT', 'development');
}
// Load in default configuration values
require_once 'config.default.php';
// Load in the overridden configuration file for this environment
require_once 'config.' . ENVIRONMENT . '.php';
Another popular method is to utilize an XML configuration file and only read in the values you require as needed (storing a cached copy of the config file in memory). This can easily be controlled to just load specific values rather than allowing arbitrary PHP file inclusion, and is, in my opinion, a preferable solution, but the above should get you started in the correct path.
It’s likely that you’ll want your VCS to disregard the file. On the other hand, you might want to version control a skeleton of the file or one with sensible defaults (this does not apply to login data, of course). One popular solution is to have a checked-in template configuration file, which the installation procedure copies to the real configuration file’s location, where it is altered. This can be done manually or automatically.
(While not directly linked to the primary topic, providing a constant for your environment allows you to do some other nice things like deferring to a fake mail implementation rather than a live SMTP one, but this could also be done using a configuration file.)
Answered by Rudi Visser
Solution #2
If you’re using Apache, one nice solution is to save the information in the virtualhost configuration.
SetEnv MYSQL_USER "xx"
SetEnv MYSQL_PASSWORD "y2wrg435yw8"
The data can be easily retrieved for usage in the code by using $_ENV[].
Answered by hank
Solution #3
Put it in a separate configuration file outside of source control, as others have suggested (obviously this will be mentioned in code which is under source control).
It’s also a good idea to name the file config.php rather than config.ini in case the directory is ever mistakenly exposed, as this will prevent the file from being downloaded and will instead return nothing.
Answered by acutesoftware
Solution #4
If you believe the 12factor approach is beneficial, they advise saving configuration in the environment.
This has the added benefit of allowing you to write the exact same code in a non-production environment whether testing or otherwise. There’s no need to rewrite your code if you want (or need) to change the database or anything else; simply change the environment variables and you’re ready to go.
Answered by Wayne Werner
Solution #5
What I would do is keep only example config files in the repository, such as config.php.dist, and not the actual config.php.
Answered by Serge Kuharev
Post is based on https://stackoverflow.com/questions/15088979/php-and-mysql-how-to-avoid-password-in-source-code