Knowledge/Tutorials learn something knew perhaps

PHP Environments

Setup your php project for local, staging and production

Some quick tips to setup multiple environments ( local/dev, staging and production )

Note about version/source control

Keeping everything organized can be tedious especially if you have multiple developers working on one project. Even with a single developer, keeping track of what files have been pushed/uploaded to what environment can be troublesome. Therefore you should get familiar with some form of version control. All the rage is around Git, after all, the linux kernel development is managed through Git.

Managing database schema versions

If your project uses a database, you will want to keep track of updates to the schema so that you can apply them uniformally to all your environments ( local/dev, staging and production ). The most straightforward way I've found is to keep a master database schema for all your tables, basically if you were to start a fresh install you would import that sql file to initialize your database. Then as you make changes to the master database schema, create secondary sql/text files containing the alter/update/create statements needed to change the current database schema to line up with the master.

For example, lets say you start out with a simple database table for storing a basic article format.

create table `article` (
	`id` int unsigned not null auto_increment
	
	,`content` text default null
	
	,primary key(`id)
);

You store this in a master sql file ( not accessible to the public ), in a file name like "schema.sql" or "master.sql", whatever your preference might be. You load that into your database to start your application ( cat master.sql | mysql dbname ). You push your application to the staging environment and production. You now realize that you need to add a new field for the article name. Modify your master schema file to read:

create table `article` (
	`id` int unsigned not null auto_increment
	
	,`name` varchar(255) not null default ''
	,`content` text default null
	
	,primary key(`id)
);

You could delete your database and re-initialize it, but you don't want to lose all your test data do you? ( of course not ) So lets get your local database up to snuff with the master schema using an alter table statement.

alter table `article` add `name` varchar(255) not null default '' after `id`;

Now you will want to keep this statement, create a folder named something like "sql_updates" alongside your master schema file. Store this alter statement in that folder, in a file named with a numeric value prefix, like "001_article_name.sql".

This will let you know that you've made one change to the schema since inception, and you added a name field to your article. Using this method, you have now kept track ( in an adhoc manner ) that your database schema is version "001". You can manage these updates by hand, knowing that if on a `git pull` or a `svn up` that if you see a new sql file in the sql_updates folder that you should apply that to your db schema on that environment.

In the future, you can use this information as a primer for doing more advanced things such as Database Migrations. In case you aren't familiar with the term "Database Migrations", basically it's a methodology for versioning your database schema and then applying updates/patches against that schema in the proper order to reach the latest version. You would want to store your schema version in the database itself, then ( using an automated process ) apply the database update scripts that have a number higher than what the version number in the database is, all the way until you reach the last item. If the database version number is the same as the latest update file, then you're up to date and no updates are required. If you are using a framework or database abstraction library on your project, it may have a system for database migrations/versioning.

Configuration files

It's extremely likely that your development environment will not use the same paths and database credential information as your production environment. It's also likely to be different than your staging environment as well. We store this sort of information in a configuration file so that they can be easily changed between installations/environments.

There are many ways to accomplish keeping multiple configuration files and only utilizing the appropriate one per environment. Here are a couple of ways:

  1. Set a variable for the environment in the php.ini, code your configuration to include the production configuration by default otherwise if the environment variable is present from php.ini include a configuration file named by the environment variable
  2. Store a configuration file that is specific for your environment, code your main configuration to include that conf file if present, otherwise default to production. Under this method you would never want to push your conf file that you use for environment specific configuration up to production, or it would be used. So you would want to setup your version control to ignore the environment specific conf file.

Here is a simple implementation for option 1 above. Add to the php.ini in your local development environment under the [php] area:

server_environment = "local"

Setup your files so that you have a conf.php file that is included by your code under all scenarios. Create 3 other conf files using the values of the "server_environment" variable ( conf.local.php, conf.staging.php, conf.production.php ). In your conf.php, you put logic to read the server_environment setting from php.ini and include the appropriate conf file. Example:

$conf_env = get_cfg_var('server_environment');
if ( $conf_env ) include 'conf.'. $conf_env .'.php';
else include 'conf.production.php';

Of course adjust your code as needed for correct include paths, etc.


Copyright © Michael Vandenberghe 2024