2
\$\begingroup\$

To enable my PHP scripts to access my MySQL database, I have a configuration file containing the name of the MySQL database, usernames, etc.

In order to keep that information secure, I'm storing it outside of the web root on the server. I WAS setting an environment variable in httpd.conf to the file path of the .ini file so that PHP could access it and then parse the config file.

However, for the purposes of demonstration I'm deploying this database and front end on a shared server which will not give me access to httpd.conf. This is the alternative I worked out:

<?php
 if(!isset($GLOBALS['config'])){
 $nonPublic = explode("/",$_SERVER['DOCUMENT_ROOT']);
 array_pop($nonPublic);
 $nonPublic = implode("/",$nonPublic);
 $GLOBALS['config'] = parse_ini_file($nonPublic."/configs/JCDBconfig.ini");
 }
?>

The theory is that I make sure the 'configs' folder is just above DOCUMENT_ROOT, grab all but the last part of the DOCUMENT_ROOT path, and the PHP script should be able to find the config file stored there.

My question is: Is this a good idea, or sloppy? Is $_SERVER['DOCUMENT_ROOT'] reliable enough that, should I deploy this on a dedicated server in the future, it will still work?

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Apr 28, 2017 at 6:58
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Does the web server allow you to do this?! In most servers I've worked with you are not allowed to go up from the DOCUMENT_ROOT. \$\endgroup\$ Commented Apr 28, 2017 at 10:12
  • 1
    \$\begingroup\$ The user the web server is being run as will likely not have access to directories or files outside of the web root as holroy has already noted. If you are able to use a customized php.ini file simply add the outside of the web root directory to the include_path variable in php.ini which allows you to simply include or require the file easily and securely. This is actually a common practice since only a very few files have to actually be visible to the web server (namely index.php, style files and JavaScript). \$\endgroup\$ Commented Apr 28, 2017 at 14:04

1 Answer 1

2
\$\begingroup\$

I am assuming that you have a directory structure something like this, which can be common in shared hosting environments:

/path/to/your/directory => your customer directory on the host
/path/to/your/directory/public => the web server document root

Or, if you had full control over your environment it might look like:

/some/nonpublic/directory => non-public directory (possibly in include path)
/var/www => web server document root

So ideally, your application should be able to seamlessly handle both without custom code that changes based on where you deploy the application.

Typically, this is done by configuring constants for file paths in a config file, not by relying on values derived from $_SERVER['DOCUMENT_ROOT'] as this has absolutely no connection to where on a server you may have the ability to place your non-public application code. You may be able to count on this behavior for some specific shared host environment, but this gives you no guarantee that this same behavior would exist in another environment.

So an approach of defining path constants may look like:

define('WEB_ROOT', $_SERVER['DOCUMENT_ROOT']);
define('INCLUDE_DIR', {path to one of non-public directories shown above});
define('CONFIG_DIR', INCLUDE_DIR . '/config');

Then if you wanted to check if your config is set for JCDB, it might look more like:

if(!isset($GLOBALS['config'])){
 $GLOBALS['config'] = parse_ini_file(CONFIG_DIR . '/JCDBconfig.ini');
}

This reduces your problem to only having to figure out how to populate the value into INCLUDE_DIR, not trying to determine this directory when you are at the point of trying to conditionally load configurations for various components in the application.

This could be hard-coded (not ideal) which is quick and dirty, but you might consider an approach that allows you to conditionally determine the include path.

For example, if you control the environment, you could modify your Apache config to inject an environmental variable holding the include path or, if missing, perhaps looks into a file that you specifically deploy onto your shared host to determine how to get to that include path for the host you are on.

So perhaps something like this near the beginning of your application bootstrap process.

define('WEB_ROOT', $_SERVER['DOCUMENT_ROOT']);
if(!empty($_SERVER['APP_INCLUDE_PATH']) {
 define('INCLUDE_DIR', $_SERVER['APP_INCLUDE_PATH']);
} else {
 define('INCLUDE_DIR', require WEB_ROOT . '/appIncludeConfig.php');
}

Where in Apache you have

 SetEnv APP_INCLUDE_PATH /some/nonpublic/directory

Or for shared host, appIncludeConfig.php has a single line of code like:

<?php
return '/path/to/your/directory';

I question why you would want to put a critical dependency like a config setting into a mutable variable in global scope vs. something immutable (like a constant). So perhaps something like this is more appropriate:

if(!defined('JCDB_CONFIG')){
 define('JCDB_CONFIG', parse_ini_file(CONFIG_DIR . '/JCDBconfig.ini'));
}

Note I also changed the naming of the config setting to be something less generic than just config such that it is clear that this value is specific only to this particular configuration value.

answered Apr 28, 2017 at 18:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.