flash-tool · master
Docs · Configuration

The project config file

Every option in a project's php-baremetal.config.toml — the file phpflash init writes and the other commands read: the portable header (name, type, PHP source and version, extensions, env, store, web-server) and the [esp32] backend block (board, toolchain, storage, network, security and power). Plus the local override and how paths and versions resolve.

Every project is a php-baremetal.config.toml plus a project-src/ folder. The config is backend-neutral: a portable header (name, type, [php], [extensions.*], [env], [store], [web-server]) describes the app itself, and a backend block carries everything specific to building it for a given chip family. Today the only backend block is [esp32]; the same project could grow an [stm32]/[nxp] block later, and only the matching backend's tool reads its block. phpflash init writes this file interactively; build, flash and monitor read it. If you scaffold with init you rarely touch it by hand, but this is the full picture — every key, its type and default.

Everything except the name, an execution type and a board has a default and can be omitted. A minimal file is two lines and a table:

toml php-baremetal.config.toml — minimal
name         = "my-project"
type         = "init-loop"

[esp32]
target = "esp32-p4-pico"
storage_type = "microsd"

The sections below cover the portable header first, then the [esp32] backend block and its subtables.

phpflash holds no hard-coded hardware knowledge

The boards, the storage and execution modes, the PHP versions, and the extensions with their settings all come from the installed php-esp32 firmware, read at runtime from its manifest and board descriptors. This page documents the shape of the config; which values are valid for your install is decided by the firmware — see the php-esp32 manifest.

Top level (portable header)

The portable keys describe the app and mean the same for any backend.

Key Type Default Meaning
name string the directory name The project name. Cosmetic; used in scaffolding and messages.
type string init-loop The execution model: init-loop (run the script, then setup() once and loop($tick) repeatedly), web-server (an HTTP server runs PHP per request; needs a networked board), or event-driven (reserved).

The rest of the portable header is the [php], [extensions.*], [env], [store] and [web-server] tables documented below. Extensions are the app's intent — a backend provides each through its own HAL and validates which it can supply; the pins a driver needs are passed at runtime from PHP, so they stay portable too.

[esp32] — the ESP32 backend

The board, how phpflash reaches it over serial, where the source lives on the chip, and the security/power switches. Everything in this block (and its [esp32.*] subtables) is specific to building for Espressif chips.

Key Type Default Meaning
preset string — A vendor-model preset over a chip/mode, for example waveshare-esp32-s3-eth. Selects the board and its wiring; phpflash discover helps pick one.
family string — Alternative to preset: a chip/mode's generic preset, for example esp32-s3/octal.
target string esp32-p4-pico Legacy board key, for example esp32-p4-pico, esp32-p4-eth. Used when neither preset nor family is set. phpflash discover prints the key for a connected board.
port string "" (autodetect) Serial port for flash and monitor, for example /dev/ttyACM0. Empty means autodetect at flash time. Best kept in the local override, not the committed config.
cpu_freq_mhz int 0 (board default) Override the CPU clock, passed to the firmware as -DPHP_CPU_FREQ_MHZ. 0 or absent uses the board default (360 MHz on the P4). On a P4 the choices are 360 and 400; 400 on a pre-3.0 chip is experimental and can be unstable.
storage_type string microsd Where the PHP source lives: microsd (read from a FAT card) or embedded (baked into a read-only flash image). Limited to what the board supports — a -Zero board (no card slot) offers only embedded.
power_save bool false Enable esp_pm automatic light sleep (the event-driven reactor sleeps between events).
secure bool false Flash Encryption (dev mode): the flash image is unreadable off the chip.
secure_boot bool false Secure Boot v2: only firmware signed with your per-unit key boots. The build auto-provisions a signing key at secure_boot_keys_dir/<MAC>.pem.
secure_boot_keys_dir string ./deploys Where the per-unit signing keys live. Keys are secrets — keep them out of version control.

storage_type and type are orthogonal, and both are drawn from php-esp32: a mode is offered only when it is both implemented by the firmware and supported by the chosen board. That is why a board with no network never offers web-server.

Port autodetection order

When port is empty and no -p flag is given, phpflash picks the first serial device that exists — /dev/ttyACM* before /dev/ttyUSB* — without opening it, and falls back to letting ESP-IDF autodetect. Because it never opens the port, detection cannot hang on or disturb a device that is not the board.

[esp32.idf] and [esp32.sdk]

Where the toolchain and the firmware sources live, and which version to use. Both keys of both tables can be empty, in which case the default applies. See Path and version resolution below for the full precedence.

Table Key Type Default Meaning
[esp32.idf] path string ~/esp/esp-idf The ESP-IDF checkout.
[esp32.idf] version string the version php-esp32 targets A git ref (for example v5.5.5) system-setup checks out.
[esp32.sdk] path string ~/esp/php-esp32 The php-esp32 firmware checkout.
[esp32.sdk] version string the default branch A git ref for the firmware.

[esp32.storage]

microsd and reserve_kb are only meaningful for an embedded project, and written by init only in that case; a microsd project always has the card. The SD wiring keys apply to any project that mounts a card, and override the preset's [storage.microsd] one field at a time.

Key Type Default Meaning
microsd bool false For an embedded project, also mount a microSD for writable data alongside the baked-in source. Off means the SD drivers are not even compiled in.
reserve_kb int 0 (just fit the source) Pads the embedded storage partition: the firmware sizes it to the source plus FAT overhead and adds this many KB on top. Headroom for a larger source, not runtime growth — the image is read-only.
mode string the preset's "spi" or "sdio"; must be one the chip supports.
cs, sclk, mosi, miso int the preset's, else the board default SD pins (GPIO). cs/mosi/miso are SPI-only; sclk is the clock in either mode.
pwr_en int the preset's (none) GPIO switching the card's VDD, driven low to power it.

Removing a pin takes effect only after build --clean: CMake keeps the previous value in its cache.

[esp32.network]

For a board with a network. Optional.

Key Type Default Meaning
dns list of strings [] (use DHCP) Static DNS servers the firmware applies after DHCP, for example ["1.1.1.1", "8.8.8.8"]. Empty means use whatever DHCP hands out. Relevant when a name lookup is needed, such as the HTTPS client. Emitted to the build as -DPHP_NET_DNS.

[web-server]

For a web-server project. Optional.

Key Type Default Meaning
init string "" (none) A PHP script within [php] src the firmware runs once, before the HTTP server starts, for one-time setup shared across requests — bringing hardware up through a C extension, or seeding the in-RAM mem_* / persistent store_* stores. Its output goes to the console; a failure is logged but non-fatal. A no-op for non-web-server projects.

[php]

The PHP source folder, its entry point, and the language version to build.

Key Type Default Meaning
src string project-src The folder holding the PHP source. This is the deployable: copied to the card, or baked into the embedded image.
entry string index.php The entry file within src. A framework points this at its front controller, for example public/index.php.
version string "" (repo default) The PHP language version to build, one of the directories under components/php/versions/ (for example 8.5.9). Empty follows default_version in the repo's php-esp32.toml. init offers the installed versions when there is more than one, and pins this only when you pick a non-default one. An unknown version fails the build with the list of what is installed.

[extensions.<name>]

One table per enabled optional extension. The always-on extensions (standard, pcre, hash, json, spl, reflection, random, gpio) are always compiled and are not listed here. Each table carries enabled = true plus any settings that extension declares — a bool per toggle, a string per path:

toml php-baremetal.config.toml — extension tables
[extensions.mbstring]
enabled = true
onig    = true          # a bool setting

[extensions.openssl]
enabled      = true
full         = true     # a bool setting
tls          = true     # a bool setting
certs_source = "/etc/ssl/certs/ca-certificates.crt"   # a string setting

An extension that declares requires pulls its dependencies in automatically. Enabling one that needs an external library (SQLite, oniguruma, OpenSSL) makes build fetch the sources the first time.

Two kinds of setting

phpflash reads a bool setting (like onig or in_memory) into the extension's flag set, and a string setting (like certs_source or config_path) into a separate string map. Both live in the same [extensions.<name>] table as enabled. Only the settings the manifest declares for that extension are meaningful; anything else is ignored.

Optional extensions and their settings

The full set the firmware ships today. A blank Setting row means the extension has no settings — just enabled = true.

Extension Setting Type Default Meaning
ctype Character-class checks (ctype_alpha, ctype_digit).
filter filter_var() validation and sanitization.
tokenizer token_get_all(), PhpToken, the T_* constants.
session session_start(), $_SESSION, save handlers. Needs a writable dir (a microSD) for the files handler.
sqlite PDO with the SQLite driver (pdo plus pdo_sqlite).
date The real ext/date: DateTime and the date/time API.
date minimal_tz bool false Ship a UTC-only timezone database instead of the full one; about 350 KB smaller, no named zones.
mbstring Multibyte strings. Built without mb_ereg unless onig is on.
mbstring no_cjk bool false Drop the legacy CJK codecs (Shift-JIS, EUC, Big5, GB18030); about 755 KB smaller.
mbstring onig bool false Build the mb_ereg and mb_split family (bundles oniguruma); about 445 KB.
opcache Zend OPcache, no JIT. File cache on the microSD by default.
opcache in_memory bool false Keep the bytecode cache in PSRAM instead of on the card. Fastest after warm-up, but the bytecode plus the per-request heap must fit in PSRAM. Small apps only.
openssl The openssl_* functions. Default is the mbedTLS-backed symmetric subset.
openssl full bool false Build the real ext/openssl on a ported OpenSSL 3.0 (RSA, EC, X.509); about 2 MB.
openssl tls bool false Full build only: build the ssl:// and tls:// transport so PHP can do HTTPS. Needs a networked board.
openssl no_load_config bool false Full build only: do not read an openssl.cnf at startup.
openssl certs_path string certs/ca-bundle.crt Where the CA bundle is shipped (relative to the source folder, or an absolute on-device path you manage). Used by the TLS client.
openssl certs_source string auto-detected system store The host trust store to copy into certs_path.
openssl config_path string openssl.cnf Full build only: where the openssl.cnf is shipped and read. Relative is written under the source folder; absolute is a path you provide.

The full openssl reference — the two config modes and the TLS-client requirements — is in the firmware's openssl.md; the per-extension flash cost is in footprint.md. OPcache's two cache modes have their own page in OPcache.

[env] and [store]

Two optional tables the scaffold leaves commented, each with its own dedicated page. [env] controls baking a project .env into the firmware as $_ENV / getenv(); [store] sizes the reboot-persistent key-value store.

Table Key Type Default Meaning
[env] enabled bool unset → on when .env exists false turns baking off even when the file is present.
[env] file string ".env" Path to the env file, relative to the project.
[store] size_kb int 0 (no persistence) Add a dedicated NVS partition of this size; 0 or no [store] section means store_available() is false.

The full behaviour is on the build-time environment and persistent store pages. The volatile in-RAM store (mem_*) needs no config at all.

Local overrides: php-baremetal.config.local.toml

If a php-baremetal.config.local.toml sits next to the config, every command overlays it: keys it sets win, everything else keeps the committed value. init never creates it, the scaffolded .gitignore lists it, and it is for machine-specific tweaks that should not be committed — typically the serial port or a local toolchain path.

toml php-baremetal.config.local.toml
[esp32]
port = "/dev/ttyACM1"

[esp32.idf]
path = "/opt/esp-idf"

The overlay is a straight TOML decode of the local file over the already-loaded base config, so it sets only the fields the local file actually defines. That gives override semantics for scalar and table keys, and for the extra bool/string keys inside an [extensions.<name>] table.

Path and version resolution

For the [esp32.idf] and [esp32.sdk] paths and versions, the highest available source wins:

  1. 01

    CLI flag

    — --idf-path, --php-esp32-path, --idf-version, --php-esp32-version.

  2. 02

    `php-baremetal.config.toml`

    — the path and version keys above (a local.toml overlays these).

  3. 03

    Environment

    — IDF_PATH, PHP_ESP32_DIR.

  4. 04

    Default

    — ~/esp/esp-idf and ~/esp/php-esp32.

The first non-empty value in that order is used, so an empty key falls through to the next source rather than blanking it.

A full example

Every option at once, for reference. Real configs are much shorter, since almost everything defaults.

toml php-baremetal.config.toml — annotated
name         = "sensor-gateway"
type         = "web-server"       # init-loop | web-server | event-driven

[esp32]
target       = "esp32-s3-eth"     # board key; its family sets the ESP-IDF target
port         = ""                 # empty = autodetect at flash time
cpu_freq_mhz = 0                  # 0 = board default
storage_type = "microsd"          # microsd | embedded

[esp32.idf]
path    = ""                      # empty = ~/esp/esp-idf
version = "v5.5.5"                # git ref system-setup checks out

[esp32.sdk]
path    = ""                      # empty = ~/esp/php-esp32
version = ""                      # empty = the default branch

[esp32.network]
dns = ["1.1.1.1", "8.8.8.8"]      # static DNS applied after DHCP

[web-server]
init = "init.php"                 # run once before the HTTP server starts

[extensions.ctype]
enabled = true

[extensions.mbstring]
enabled = true
onig    = true                    # build mb_ereg (bundles oniguruma)

[extensions.session]
enabled = true

[extensions.opcache]
enabled = true                    # file cache on the microSD by default

[extensions.openssl]
enabled      = true
full         = true               # real ext/openssl on OpenSSL 3.0
tls          = true               # ssl:// and tls:// transports
certs_source = "/etc/ssl/certs/ca-certificates.crt"

[php]
src     = "project-src"
entry   = "public/index.php"      # a framework's front controller
version = "8.5.9"                 # omit or leave empty to follow the repo default