How to change different configuration settings between environments in PHP? - php

I have a a few php files which I call via AJAX calls. They all have a URL to my config.php. Now I've the problem that I always have to change the URLs to that config file by hand when I deploy a new version on my server.
Local Path:
define('__ROOT__', $_SERVER["DOCUMENT_ROOT"].'/mywebsite');
Server Path:
define('__ROOT__', $_SERVER["DOCUMENT_ROOT"].'/../dev.my-website.tld/Modules/');
I want to track changes in all of these PHP files. I'm searching for a solution to automatically change this path.
E.g.
This is my current workflow:
Local Environment:
(path version A)
do changes in the code
git add, git commit, git merge, git push to my server
Server:
git reset --hard
change path to version B

You are trying to run different code bases between development and live, which is not recommended -- they should be identical. The way I tackle this is to use an environment variable to specify which of several config files should be loaded.
In my Apache vhost I do something like this:
SetEnv ENVIRONMENT_NAME local
And then I use a function to read the environment name:
function getEnvironmentName()
{
$envKeyName = 'ENVIRONMENT_NAME';
$envName = isset($_SERVER[$envKeyName]) ? $_SERVER[$envKeyName] : null;
if (!$envName)
{
throw new \Exception('No environment name found, cannot proceed');
}
return $envName;
}
That environment name can then be used in a config file to include, or to retrieve values from a single array keyed on environment.
I often keep environment-specific settings in a folder called configs/, but you can store them anywhere it makes sense in your app. So for example you could have this file:
// This is /configs/local.php
return array(
'path' => '/mywebsite',
// As many key-values as you want
);
You can then do this (assuming your front controller is one level deep in your project, e.g. in /web/index.php):
$root = dirname(__DIR__);
$config = include($root . '/configs/' . getEnvironmentName() . '.php');
You'll then have access to the appropriate per-environment settings in $config.

A pure git way to achieve this would be filters. Filters are quite cool but often overlooked. Think of filters as a git way of keyword expansion that you could fully control.
The checked in version of your file would for example look like this:
define('__ROOT__', 'MUST_BE_REPLACED_BY_SMUDGE');
Then set up two filters:
on your local machine, you'd set up a smudge filter that replaces
'MUST_BE_REPLACED_BY_SMUDGE'
with
$_SERVER["DOCUMENT_ROOT"].'/mywebsite'
on your server, you'd set up a smudge filter that replaces
'MUST_BE_REPLACED_BY_SMUDGE'
with
$_SERVER["DOCUMENT_ROOT"].'/../dev.my-website.tld/Modules/'
on both machines, the clean filter would restore the line to be
define('__ROOT__', 'MUST_BE_REPLACED_BY_SMUDGE');
Further information about filters could be found in this answer and in the Git Book.

Related

realpath() doesnt show realpath GitLab ci runner

the code is stored in /var/www/abc -- "CodePath"
when running gitlab-ci (runner), the code is called via /home/gitlab-runner/builds/4v8bC1n9/0/_gitlabgroup_/_gitprojectname_/abc -- "RealPath"
I'm using a local runner and a shell execution.
when I use the realpath() function in my php code, it still shows the "CodePath" when using gitlab ci runner, instead of "RealPath".
How can I get the "RealPath" integrated in my code, or reconfig GitLab to use the "CodePath" instead?
The runner cli options are documented here: https://docs.gitlab.com/runner/executors/shell.html#overview
The path where the job is run and your sources are cloned into is available in the environment variable:
CI_PROJECT_DIR
The full path where the repository is cloned and where the job is run. If the GitLab Runner builds_dir parameter is set, this variable is set relative to the value of builds_dir. For more information, see Advanced configuration for GitLab Runner.
You did no state how you use realpath(path)...
Whilst a path must be supplied, the value can be an empty string. In this case, the value is interpreted as the current directory.
So maybe you hardcode chdir('/var/www/abc'); somewhere?
When you do chdir(getenv('CI_PROJECT_DIR')); before you call realpath() - it should use the CI directory. Assuming you use realpath without a parameter.
Also: maybe you can make some changes and use one of the the built in constants for the current directory: https://www.php.net/manual/en/language.constants.predefined.php
Thanks to madflow's mentioning of the variable I managed to figure out the following:
runners specific configuration files exist and can be configured as described here
I needed to do these things:
specify enable the [runners.custom_build_dir] section in the config.toml
[[runners]]
builds_dir = "/var/www/abc"
[runners.custom_build_dir]
enabled = true
(boolean not in quotes)
specify a variable in my yml
variables:
GIT_CLONE_PATH: $CI_BUILDS_DIR/
on os level there was some privilege setting for the dir required, where I went for quick and dirty 777 on my local machine

Laravel Application Environment - Best practice and security advice

I am planning on building a multi-tenant application in Laravel with a master subdomain holding the relevant public files and a subdomain for each customer who will have their own databases pointing to the 'master' files. I am planning on doing this as automated as possible e.g. you click a button a subdomain is created, a database is created and the relevant config files are set. All this is fine except I'm not sure if my practices are the best to use and whether or not there are any security issues with it.
In the bootstrap/start.php file I have the following:
$env = $app->detectEnvironment(array(
$_SERVER['SERVER_NAME'] => array($_SERVER['SERVER_NAME'])
));
This would essentially mean that the environment for test.example.co.uk is test.example.co.uk. My install script will create a config directory 'test.example.co.uk` in 'app/config' and will add the relevant database config there.
This does all work as I expected so I am just looking for advice, are there any vulnerabilities with this?
Just to Add - Users will not be able to use the installation script, its just for the developers
I don't think there is any security issues with your code. One thing that I notice is that you are limiting youself to just one environment. Here is my env settings:
$env = $app->detectEnvironment(function()
{
return getenv("ENV") ? : "local";
});
Now my environment will be auto detected - on server I did provide "hook"
in the form of getenv function, and on local machine it is local.
Also instead of array, I am sending callback to detectEnvironment - for more flexibility.

What is the right way to maintain a "version for the server" - with only config files changed, in Git?

I sometimes work with Codeigniter, and after I'm done developing on the local site, I need to migrate the files to the server. All the files in the /config/ folder need to be changed to match the Server settings. It's not right to make an entire commit for these changes, do I simply make Git ignore these files altogether, or is there a way to track these changes and apply them with Git at the right moment?
You could keep versioned:
two "value config files", with the right values for each environment
a template config file, with value placeholder in it (for instance, ##PORT_NUMBER##)
a script able to generate the actual config file depending on the current environment
a content filter driver which, on checkout, will trigger the script in order to generate the right config file.
Note: that supposes your template config file has a recognizable content (the filter doesn't have a name or path of the file). See "Git equivalent of subversion's $URL$ keyword expansion" for more on the limitation of git content filter driver).
It depends on Your needs. In my company we use other approach.
We've created several environments (where the asterix is internal project name):
devel - site runs on domain **.local.com*
test - site run on domain test.*.company.com
beta - beta.*.company.com
production - every other domain.
Based on the domain name we switch automatically configurations.
Basicly config file looks like:
<?php
return array(
'_env' => array(
'devel' => array(
// config for devel
),
'production' => array(
// config for production
)
)
);
?>
Some frameworks (AFAIR Zend) set the environment name in Virtual Host config (or .htaccess). You should look at: zend framework auto switch production staging test .. etc
Have You looked at CI documentation? There's a section about it.
Create two folders in the config folder. One is called development and the other is production. Now copy config.php, database.php etc to each of these folders. Now when you are on production server, CodeIgniter will first check the production folder for the files. If it is not there, then it uses the default file in the config folder. And if you are on development environment, CodeIgniter will first check the development folder.
If you want to keep any config file identical to the production and development environment, keep it in config folder.
If you want to set the environment then add the following code in .htaccess file:
#This code for Development Environment
SetEnv CI_ENV development
and
#This code for Production Environment
SetEnv CI_ENV production

Php multiple db environment with git & phpfog

I have a plain(no framework) php app. I want to deploy my app to PhpFog.
The problem is the config(host,dbname) is different.
How to create a db config for development and production environment?
You could use environment variables to do this. PHPFog provides a way to set environment variables in the App Console > Env. Variables tab for your app.
Simply create all the environment variables that you need on both your local machine and on the App Console:
Example:
Local Machine: Edit your .bash_profile
APP_HOST=localhost
APP_DATABASE=mydatabase
PHPfog App Console:
APP_HOST=production.mysqlserver.com
APP_DATABASE=proddatabase
Then access them from your php app:
$db_host = getenv("APP_HOST");
$db_name = getenv("APP_DATABASE");
You can put your config.php in your .gitignore or another solution is to have two branches on your local repository. One to work locally and one to push. Then you define a special merge strategy:
Let's say you want to exclude the file config.php
On branch A:
Create a file named '.gitattributes' in the same dir, with this line:
config.php merge=ours. This tells git what strategy to use when mergin
the file. In this case it always keep your version, ie. the version on
the branch you are merging into.
Add the .gitattributes file and commit
On branch B: repeat steps 1-2
Try merging now. Your file should be left untouched.

Deployment with Capistrano

I am trying to get into PHP app deployment with Capistrano. I have two config files that I need to be "edited" depending on where I deploy it. It's basic stuff like database name and root url (Codeigniter). Can I make Capistrano edit specified automatically? Let's say I want to edit the following in the file /system/config/edit.php:
$test = '';
// edit to
$test = 'Hello World';
Thanks,
Max
What I generally do in this kind of situation (even though I don't use Capistrano) is to have several config files commited to source control.
For instance :
config.php for development machines
this file is the one that's always used by the application
config.testing.php
config.staging.php
config.production.php
And when deploying the application to the server, I just have to copy the file corresponding to the current environment to "config.php" -- as this one is the one that's always used by the application.
It means that I have to do a file copy during the build process, yes, but :
it means there is no need for any search and replace, that can break
it also means every config files are commited to SVN (or whatever source control software you are using)
If your configuration files become too complex, and duplicate lots of stuff, you can think about having one "default" config file, that's always included, and sub-config files that only define what depends on the environment.
What that, what I said before still stands : just include the "default" file at the begining of each other.
My Unix is knowledge isn't quite up to scratch so I can't quite get the syntax perfect for what you want. However, Capistrano allows you to directly use the Unix command-line by invoking :run_method within your configs.
The Capistrano code might look something like the following:
run "grep -R --files-with-matches '$test = "";' /system/config/ | xargs perl -pi~ -e 's/\$test = "";/$test = "Hello World";/'"
I would check up on that find and replace function working as expected before implementing it live though.
If you need any more help, I'd recommend checking out the Capistrano Handbook, it should answer most of your questions.

Categories