flash-tool · v0.8.x
Docs · Getting started

Your first project

Go from nothing to PHP running on the board: install the toolchain once, scaffold a project, then build, flash, and monitor. A project is just a config file and a project-src/ folder.

This page takes a board from nothing to running your own PHP: install the toolchain once, scaffold a project, then build, flash, and watch it boot. It assumes phpflash is already on your PATH — if not, start with Installation.

The mental model

A project is two things: a config file, php-esp32.config.toml, and a project-src/ folder that holds your PHP. The config picks the board, where the code lives, how it runs, and which extensions to compile; project-src/ is the deployable — it is what gets copied to a microSD card or baked into the firmware image. phpflash init writes both for you, plus a .gitignore.

text tree — what init scaffolds
my-project/
├── php-esp32.config.toml   the project config
├── .gitignore              ignores build/, sdkconfig, vendor/, the local override, .env
└── project-src/
    └── index.php           your entry script (the chosen starter)

The whole sequence

  1. 01

    Install the toolchain

    phpflash system-setup, once per machine. It installs ESP-IDF and the php-esp32 firmware sources.

  2. 02

    Scaffold a project

    phpflash init my-project answers a short series of prompts and writes the config plus a starter project-src/index.php.

  3. 03

    Enter the project

    cd my-project.

  4. 04

    Write your PHP

    — edit project-src/index.php (or point [php] entry at a front controller).

  5. 05

    Build

    phpflash build turns the enabled extensions into build flags and drives ESP-IDF into the project's own build/.

  6. 06

    Flash

    phpflash flash builds if needed, checks the connected chip matches the project's board, then writes it.

  7. 07

    Monitor

    phpflash monitor opens the serial console. Watch the boot log; leave with Ctrl-].

1. Install the toolchain (once)

Before the first project, install the cross-toolchain and the firmware sources. This is a one-time step per machine:

bash terminal — system-setup
phpflash system-setup

It clones ESP-IDF and runs its installer, then clones php-esp32 and runs scripts/fetch-php.sh to download and patch the PHP source. It is idempotent — safe to re-run. Everything lands under ~/esp by default.

2. Scaffold a project

bash terminal — init
phpflash init my-project

init is interactive, with a default at every step, and it reads your installed php-esp32 so it only offers what the firmware can actually build. In order, it asks:

  1. 01

    Project name

    — defaults to the directory name.

  2. 02

    Chip family, then board

    — the family list and the boards within it come from php-esp32's boards/. Picking the board fixes the ESP-IDF target for you.

  3. 03

    Storage type

    microsd or embedded, limited to what the selected board supports.

  4. 04

    Project type

    — the execution model: init-loop, web-server, or event-driven, limited to what the board supports.

  5. 05

    PHP version

    — offered only when more than one version is installed. Choosing the default leaves the config's version empty (the project follows the repo default); picking another pins it.

  6. 06

    Optional extensions

    — a multi-select of the extensions optional for the chosen project type. Each one you enable then asks, one by one, about its own settings.

  7. 07

    Serial port

    — leave it empty to autodetect at flash time.

  8. 08

    Starter

    — a hello page or a blink sketch to place in project-src/index.php.

The flags let you skip or steer the prompts: --yes accepts every default and asks nothing, --board <id> preselects a board, --name <name> sets the project name, and --force overwrites an existing php-esp32.config.toml.

If php-esp32 is not installed yet

When init cannot find an installed php-esp32, it prints note: php-esp32 not installed; board and extensions default -- configure after system-setup and skips the board and extension prompts. Run system-setup first, or fill those keys into the config by hand afterward.

The two starters

The final prompt seeds project-src/index.php with one of two templates:

A minimal linear script that runs once and prints to the serial console.

php project-src/index.php — hello
<?php
echo "Hello from PHP on ESP32\n";

An Arduino-style setup()/loop() sketch that blinks an LED on GPIO2. The firmware calls setup() once at boot, then loop($tick) repeatedly with an incrementing tick; delay() paces it in milliseconds.

php project-src/index.php — blink
<?php
// setup()/loop() sketch: blink an LED on GPIO2.
function setup() {
    gpio_mode(2, GPIO_OUTPUT);
}
function loop($tick) {
    gpio_write(2, $tick % 2);
    delay(500);
}

The config it writes

init writes php-esp32.config.toml. It is meant to be read and edited — a short one looks like this:

toml php-esp32.config.toml
name = "my-project"
storage_type = "microsd"   # where the PHP source lives
type = "init-loop"         # execution model

[board]
target = "esp32-p4-pico"
port   = ""                # empty = autodetect at flash time

[php]
src     = "project-src"    # PHP source folder (copied to the microSD / embedded)
entry   = "index.php"      # entry file within src
version = ""               # PHP version to build; empty = the repo default

An enabled optional extension gets its own [extensions.<name>] table with enabled = true and any settings you turned on. The scaffold also leaves [esp-idf] and [php-esp32] tables (each with path and version) so a project can pin a specific toolchain or firmware checkout.

Keep machine-specific settings out of git

A sibling php-esp32.config.local.toml, if present, is overlaid on top of the main config for machine-specific tweaks such as a serial port or a local toolchain path. The scaffolded .gitignore already excludes it, along with build/, sdkconfig, project-src/vendor/, and .env.

3. Enter the project and write your PHP

bash terminal — cd and edit
cd my-project
$EDITOR project-src/index.php

Edit the starter, or replace it entirely. For a framework, point [php] entry at the front controller (for example public/index.php) instead of the top-level index.php.

4. Build

bash terminal — build
phpflash build

build reads the config, turns the enabled extensions into a deterministic -D<flag>=ON/OFF list, runs any fetch scripts an enabled extension needs, then drives ESP-IDF into a build tree under the project's own build/. Because that tree and its sdkconfig are per project, several projects can share one php-esp32 install with isolated, side-by-side builds. On success it prints Build complete. Next: phpflash flash.

5. Flash

bash terminal — flash
phpflash flash

flash builds first if needed, then runs two guardrails around the write. It probes the connected chip and refuses if its target does not match the project board's family — an S3 image with a P4 plugged in, say — with --force to override. And after a microsd flash it erases the board's storage partition, so a leftover embedded image from an earlier build cannot mount and shadow the card. The port comes from -p, then the config's [board].port, then the first serial device it finds.

6. Monitor

bash terminal — monitor
phpflash monitor

monitor opens the serial console. Watch the board boot and print your script's output; leave with Ctrl-]. On a networked board the boot log prints the address it came up on, which is where you point a browser or curl for a web-server project.

Where to go next

For every flag and the full behaviour of each step, see the command reference — starting with phpflash init. For writing PHP for the board, the extensions, and the porting details, see the php-esp32 docs.