PHP-Defcon is a native extension for loading typed configuration values as PHP constants when the engine starts. Version 1.5 reads a compact configuration language, converts each value to a PHP scalar, and registers the result as a persistent, case-sensitive constant for the lifetime of that PHP process.
The process boundary matters. Defcon does not create one shared memory area for an entire cluster or even for all workers of one server. Every CLI process, Apache process, or PHP-FPM worker loads its own configuration during module initialization. The constants then remain available to every request handled by that process without reparsing the file on each request.
The source code and its PHPT test suite are available from the PHP-Defcon repository. The implementation uses the PHP 5 Zend extension API. It can be built for compatible PHP environments, while other PHP versions require the corresponding API adaptations in the extension source.
Runtime Model
Defcon exports no userland functions. Its empty function table is intentional. During PHP_MINIT, the extension reads the system-level INI setting defcon.config-file, whose default is /etc/defcon.conf, parses that file, and calls the PHP 5 constant-registration API with the CONST_CS and CONST_PERSISTENT flags. Application code then accesses the names like ordinary PHP constants:
<?php
var_dump(DB_HOST);
var_dump(FEATURE_AUDIT_LOG); The INI directive is declared as PHP_INI_SYSTEM. It must therefore be configured in a system-level PHP configuration context, not changed by an application after startup.
Configuration Language
A configuration entry starts with a type keyword, followed by a constant name, an equals sign, and a value. A semicolon is accepted but not required at the end of a line. Several definitions of the same type can be separated by commas:
# Database configuration
string DB_HOST = "localhost";
string DB_USER = "app", DB_NAME = "catalog";
int DB_PORT = 3306;
bool FEATURE_AUDIT_LOG = true;
# Reuse an existing constant and concatenate strings
string APP_ROOT = "/srv/example";
string CACHE_DIR = APP_ROOT . "/cache"; Types and aliases
| Resulting PHP type | Accepted keywords | Conversion in version 1.5 |
|---|---|---|
| string | string | Stores the parsed byte string. |
| integer | int, long, short | Calls C atol(). |
| float | float, real, double | Calls C atof(). |
| boolean | bool, boolean, logical | Recognizes true and false case-insensitively; otherwise applies atol(). |
The parser performs conversion, not strict validation. For example, an invalid integer string generally becomes zero through atol(), while a numeric prefix can be accepted and the remainder ignored. Configuration mistakes can therefore produce valid-looking constants instead of a parser error.
Constant names
Names must begin with an ASCII letter or underscore; subsequent characters may also be digits. They are limited to 64 characters and are registered case-sensitively. A name cannot be one of the parser keywords. Prefixing a name with @ suppresses the normal notice when that constant already exists, but it does not overwrite the existing value.
Values, substitution, and concatenation
Unquoted values end at parser punctuation or whitespace. If an unquoted token names a constant that already exists, Defcon substitutes its value. Single-quoted values only provide minimal quote and backslash escaping. Double-quoted values recognize PHP-like backslash escapes but do not interpolate PHP variables. Strings and include paths can be joined with the dot operator.
Each completed value is limited to 4096 bytes. Constant substitution is truncated to fit that buffer. The parser normally reports an overlong literal, but output from a backtick command is silently truncated.
Backticks execute a shell
A backtick-quoted value is not merely another string syntax. Defcon passes its contents to popen(), reads the command output, removes one trailing newline, and stores the result. It has no command allowlist, sandbox, or timeout. This means configuration parsing can execute arbitrary shell commands with the privileges of the PHP worker during module startup.
Do not use backticks with untrusted or application-writable configuration. A modern deployment should avoid this feature entirely and inject dynamic secrets or host data through the process supervisor or a dedicated secrets system.
Including files and directories
require and include can load another file. A missing required file stops the Defcon parsing operation with a fatal error; a missing included file is ignored. Paths can use the same string concatenation syntax as string constants.
string CONFIG_ROOT = "/etc/example";
require CONFIG_ROOT . "/database.conf";
include CONFIG_ROOT . "/local.conf"; If the configured path is a directory, Defcon reads entries ending in .conf in lexical order. A matching directory is traversed recursively. The implementation has no explicit include-cycle detection or path sandbox, so file ownership, permissions, and directory structure are part of the security boundary.
Building the Extension
The extension uses the PHP 5 phpize build layout. Its actual configuration switch comes from config.m4 and is --enable-defcon:
git clone https://github.com/infusion/PHP-Defcon.git
cd PHP-Defcon
phpize
./configure --enable-defcon --with-php-config="$(command -v php-config)"
make
make test PHP_EXECUTABLE=/usr/bin/php5 TEST_PHP_ARGS="-q"
sudo make install After installation, load defcon.so from a system INI file:
extension=defcon.so
defcon.config-file=/etc/defcon.conf config.m4 declares --enable-defcon. Select a PHP development environment compatible with the extension API or port the Zend API calls before building it for another PHP generation.
Security and Deployment Limits
- Constants are global within each PHP process. Any application code running there can read them, so this is not an isolation mechanism between virtual hosts or applications.
- Secrets leave the document root, but they still reside in process memory and remain visible through PHP's constant APIs. Restrictive file permissions are still required.
- Configuration changes take effect only after the relevant PHP workers restart and reload the module.
- A parser or startup error can affect every request assigned to a worker. Rollout and rollback need to be tested before a fleet restart.
- Backtick values add shell injection, startup latency, command failure, and hanging-command risks to the PHP initialization path.
Porting Defcon
A PHP 8 port would need to update hash lookups, zval construction, constant registration, module macros, INI access, and error expectations in all PHPT files. It should also replace deprecated directory APIs, remove or explicitly disable shell execution, add include-cycle detection, use strict numeric parsing, and define deterministic failure semantics before registration begins.
For deployments that use a different PHP extension API, the same configuration model can be retained while updating the integration layer. The parser, startup loading, persistent constant registration, and PHPT suite provide the functional boundaries for such a port.
References
- [Source]PHP-Defcon source repository, version 1.5.
- [PHP Constants]PHP Manual: Constants.
- [phpize]PHP Manual: Compiling shared extensions with phpize.