Skip to content

Instantly share code, notes, and snippets.

@EmanueleMinotto
Created January 29, 2015 20:57
Show Gist options
  • Save EmanueleMinotto/e9c80ee5cb3f0fc860ca to your computer and use it in GitHub Desktop.
Save EmanueleMinotto/e9c80ee5cb3f0fc860ca to your computer and use it in GitHub Desktop.
PHP Configuration

Configuration

This configuration system is based on default runtime configuration system.

Difference consists in SAPI access: PHP alone supports .user.ini files only using CGI/FastCGI SAPI, using this version custom configurations can be setted outside main php.ini.

Usage

Suppose to use this project structure

www/
  app/
    .user.ini
    foo.php
    configuration.php
  .user.ini

Configuration files are

; www/app/.user.ini
precision = 13
custom.setting = bar
; www/.user.ini
precision = 12

An application file is

<?php
// www/app/foo.php

var_dump(ini_get('precision')); // 14
var_dump(ini_get('custom.setting')); // false
var_dump(getenv('custom.setting')); // false

require_once 'configuration.php';
// Will be loaded:
// 1. www/app/.user.ini
// 2. www/.user.ini

var_dump(ini_get('precision')); // 12
var_dump(ini_get('custom.setting')); // false
var_dump(getenv('custom.setting')); // "bar"

Precedence

Currently the precedence is defined by .ini file position in the directories structure, more external means more importance.

<?php
// PHP function to include configurations
// http://php.net/manual/en/configuration.file.per-user.php
if (!function_exists('php_sapi_name') || php_sapi_name() != 'cgi-fcgi') {
$root = rtrim(realpath($_SERVER['DOCUMENT_ROOT']), DIRECTORY_SEPARATOR);
$script = realpath($_SERVER['SCRIPT_FILENAME']);
// user_ini.filename sets the name of the file PHP looks for in each directory;
// if set to an empty string, PHP doesn't scan at all. The default is .user.ini.
$filename = ini_get('user_ini.filename') ?: '.user.ini';
// user_ini.cache_ttl controls how often user INI files are re-read.
// The default is 300 seconds (5 minutes).
$cache_ttl = ini_get('user_ini.cache_ttl') ?: 300;
// Cache file
$tmp_file = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
// Does cache exist?
if (file_exists($tmp_file) && time() <= filemtime($tmp_file)) {
$settings = parse_ini_file($tmp_file);
array_walk($settings, function ($v, $k) use (&$final) {
// due to settings as arrays
$final[$k] = $v;
// scalars can exist in .ini files but not in $_ENV
if (!is_scalar($v)) {
$v = serialize($v);
}
// Attention: use `@` if *headers already sent*
if (ini_set($k, $v) === false) {
putenv($k . '=' . $v);
}
});
} elseif (substr_count($script, $root) > 0) {
// used for overwriting
$final = array();
do {
$dir = dirname(isset($dir) ? $dir : $script);
$ini = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
if (file_exists($ini)) {
$settings = parse_ini_file($ini);
array_walk($settings, function ($v, $k) use (&$final) {
// due to settings as arrays
$final[$k] = $v;
// scalars can exist in .ini files but not in $_ENV
if (!is_scalar($v)) {
$v = serialize($v);
}
// Attention: use `@` if *headers already sent*
if (ini_set($k, $v) === false) {
putenv($k . '=' . $v);
}
});
}
} while ($dir != $root);
// Caching
if ((!file_exists($tmp_file) && is_writable(dirname($tmp_file))) || is_writable($tmp_file)) {
$handle = fopen($tmp_file, 'w+');
array_walk($final, function ($v, $k) use ($handle) {
// scalars can exist in .ini files but not in $_ENV
if (is_array($v)) {
$setting = $k;
array_walk($v, function ($v, $k) use ($handle, $setting) {
if (is_numeric($v)) {
fwrite($handle, $setting . '[' . $k . '] = ' . $v . PHP_EOL);
} else {
fwrite($handle, $setting . '[' . $k . '] = ' . '"' . $v . '"' . PHP_EOL);
}
});
} elseif (is_numeric($v)) {
fwrite($handle, $k . ' = ' . $v . PHP_EOL);
} else {
fwrite($handle, $k . ' = "' . $v . '"' . PHP_EOL);
}
});
fclose($handle);
// Edit file modification time
touch($tmp_file, time() + $cache_ttl, time() + $cache_ttl);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment