Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,29 @@ jobs:
tests:
strategy:
matrix:
ddev_version: [stable, HEAD]
# Each job builds one PHP version, which takes 10-15 minutes
ddev_version: [HEAD]
php: ["8.1", "8.4", "8.5", "8.6"]
runner: [ubuntu-latest]
include:
- ddev_version: stable
php: "8.5"
runner: ubuntu-latest
# Smoke tests on arm64, where users most need to build PHP themselves
- ddev_version: HEAD
php: "8.5"
runner: ubuntu-24.04-arm
- ddev_version: HEAD
php: "8.6"
runner: ubuntu-24.04-arm
fail-fast: false

runs-on: ubuntu-latest
runs-on: ${{ matrix.runner }}

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
STATIC_PHP_TEST_MINOR: ${{ matrix.php }}

steps:
- uses: ddev/github-action-add-on-test@v2
Expand Down
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

This **experimental** add-on tries to address that need, although there are a number of caveats:

1. The build done using this process uses the technique from [static-php-cli](https://github.com/crazywhalecc/static-php-cli) and full details are available there. It supports all the versions supported in the upstream repository, currently PHP 7.3-8.5.
1. The build done using this process uses the technique from [static-php-cli](https://github.com/crazywhalecc/static-php-cli) and full details are available there. It builds PHP 8.1 and later, including PHP 8.6 pre-releases, see [Pre-release versions](#pre-release-versions). static-php-cli doesn't support PHP 7.x, and support for 8.0 and 8.1 is best-effort. The tests cover 8.1, 8.4, 8.5 and 8.6.
2. The build does not match the build done using the official DDEV php packages (which actually come from [deb.sury.org](https://deb.sury.org/).
3. It does not provide Xdebug, so `ddev xdebug` doesn't work. `xhprof` isn't built by default, and `ddev xhprof` hasn't been tested with it. See [extension support](https://static-php.dev/en/guide/extension-notes.html).
4. The resultant PHP binaries built here do not have the exact same extensions as the official DDEV PHP binaries, see [Extensions](#extensions).
Expand All @@ -27,7 +27,7 @@ This **experimental** add-on tries to address that need, although there are a nu
## Installation

```bash
# Set your desired PHP version, when prompted, e.g., 8.0.10
# Set your desired PHP version, when prompted, e.g., 8.4.10
ddev add-on get rfay/ddev-php-patch-build
ddev restart
```
Expand Down Expand Up @@ -65,12 +65,27 @@ These are not available:
* `xdebug`: see the caveats above.
* `xmlrpc`: not supported by static-php-cli.

## Pre-release versions

You can build the current release candidate of a PHP version that isn't released yet, such as `8.6.0RC4`:

```bash
ddev config --php-version=8.6
ddev dotenv set .ddev/.env.php-patch-build --static-php-version=8.6.0RC4
ddev add-on get rfay/ddev-php-patch-build
ddev restart
```

Only the current pre-release listed on [php.net](https://www.php.net/pre-release-builds.php) can be downloaded, so update `--static-php-version` when a new one comes out.

For PHP 8.6, APCu is built from an unreleased commit because the latest APCu release doesn't support PHP 8.6. If your DDEV version doesn't support `php_version: 8.6`, use `8.5`; it only affects which `php.ini` is used.

## Advanced Customization

You can choose a different PHP version with:

```bash
ddev dotenv set .ddev/.env.php-patch-build --static-php-version=8.0.10
ddev dotenv set .ddev/.env.php-patch-build --static-php-version=8.4.10
ddev add-on get rfay/ddev-php-patch-build
ddev restart
```
Expand Down
2 changes: 1 addition & 1 deletion install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pre_install_actions:
post_install_actions:
- |
if [ "${STATIC_PHP_VERSION:-}" = "" ]; then
printf "\n\nPlease enter the PHP patch version you want to use, like 7.4.23 or 8.0.10:"
printf "\n\nPlease enter the PHP patch version you want to use, like 8.4.10 or 8.5.12:"
fi
- |
#ddev-description:Set PHP patch version
Expand Down
49 changes: 41 additions & 8 deletions tests/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
# bats ./tests/test.bats
# To exclude release tests:
# bats ./tests/test.bats --filter-tags '!release'
# To test another PHP minor version (default 8.5), as the CI matrix does:
# STATIC_PHP_TEST_MINOR=8.6 bats ./tests/test.bats
# For debugging:
# bats ./tests/test.bats --show-output-of-passing-tests --verbose-run --print-output-on-failure

Expand Down Expand Up @@ -37,26 +39,51 @@ setup() {
run ddev start -y
assert_success

export CUSTOM_PHP_MINOR_VERSION="8.3.19"
# The PHP minor version to test is set by the CI matrix; build its newest release or pre-release
export STATIC_PHP_TEST_MINOR="${STATIC_PHP_TEST_MINOR:-8.5}"
export STATIC_PHP_TEST_VERSION="$(latest_php_version "${STATIC_PHP_TEST_MINOR}")"
assert [ -n "${STATIC_PHP_TEST_VERSION}" ]
echo "# Testing PHP ${STATIC_PHP_TEST_VERSION}" >&3
printf "<?php\necho phpversion();\n" >index.php
assert_file_exist index.php
printf "<?php\necho ini_get('memory_limit'), ' ', ini_get('upload_max_filesize'), ' ', ini_get('zend.assertions');\n" >ini.php
mkdir -p .ddev/php
printf "upload_max_filesize = 7M\n" >.ddev/php/test.ini
}

# The project's web URL, which includes the router port when it isn't the default
web_url() {
ddev describe -j | jq -r .raw.primary_url
}

# The newest release of a PHP minor version, or its current pre-release if there's no release yet
latest_php_version() {
local version
version="$(curl -fsSL "https://www.php.net/releases/index.php?json&version=$1" | jq -r '.version // empty')"
if [ -z "${version}" ]; then
version="$(curl -fsSL "https://www.php.net/pre-release-builds.php?format=json" | jq -r --arg minor "$1." '.[] | objects | .release | objects | select((.version // "") | startswith($minor)) | .version' | head -n 1)"
fi
echo "${version}"
}

# Match DDEV's php_version to the static PHP so its php.ini and php-fpm configuration are used
set_php_version() {
# DDEV v1.25.4 and older don't support php_version 8.6; 8.5 only changes which php.ini is used
ddev config --php-version="${STATIC_PHP_TEST_MINOR}" >/dev/null 2>&1 || ddev config --php-version=8.5
}

health_checks() {
run ddev php --version
assert_success
assert_output --partial "PHP ${CUSTOM_PHP_MINOR_VERSION}"
assert_output --partial "PHP ${STATIC_PHP_TEST_VERSION}"

run curl -sf https://${PROJNAME}.ddev.site/
run curl -sf "$(web_url)/"
assert_success
assert_output --partial "${CUSTOM_PHP_MINOR_VERSION}"
assert_output --partial "${STATIC_PHP_TEST_VERSION}"

run ddev describe
assert_success
assert_output --partial "Static PHP: ${CUSTOM_PHP_MINOR_VERSION}"
assert_output --partial "Static PHP: ${STATIC_PHP_TEST_VERSION}"

run ddev php -m
assert_success
Expand Down Expand Up @@ -87,7 +114,7 @@ unreleased_checks() {
assert_success
assert_output "-1 7M 1"

run curl -sf https://${PROJNAME}.ddev.site/ini.php
run curl -sf "$(web_url)/ini.php"
assert_success
assert_output "1024M 7M 1"

Expand All @@ -114,7 +141,8 @@ teardown() {
@test "install from directory" {
set -eu -o pipefail

run ddev dotenv set .ddev/.env.php-patch-build --static-php-version="${CUSTOM_PHP_MINOR_VERSION}"
set_php_version
run ddev dotenv set .ddev/.env.php-patch-build --static-php-version="${STATIC_PHP_TEST_VERSION}"
assert_file_exist .ddev/.env.php-patch-build

echo "# ddev add-on get ${DIR} with project ${PROJNAME} in $(pwd)" >&3
Expand All @@ -130,7 +158,12 @@ teardown() {
@test "install from release" {
set -eu -o pipefail

run ddev dotenv set .ddev/.env.php-patch-build --static-php-version="${CUSTOM_PHP_MINOR_VERSION}"
# One release test is enough; the CI matrix runs it only in the default PHP job
if [ "${STATIC_PHP_TEST_MINOR}" != "8.5" ]; then
skip "release test only runs for PHP 8.5"
fi
set_php_version
run ddev dotenv set .ddev/.env.php-patch-build --static-php-version="${STATIC_PHP_TEST_VERSION}"
assert_file_exist .ddev/.env.php-patch-build

echo "# ddev add-on get ${GITHUB_REPO} with project ${PROJNAME} in $(pwd)" >&3
Expand Down
36 changes: 34 additions & 2 deletions web-build/Dockerfile.php-patch-build
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,29 @@ chmod +x bin/spc
bin/spc doctor --auto-fix
rm -rf source/* buildroot/*

PHP_SRC_URL="https://www.php.net/distributions/php-${STATIC_PHP_VERSION}.tar.gz"
if ! curl -fsIL --retry 3 -o /dev/null "${PHP_SRC_URL}"; then
# Pre-release versions like 8.6.0RC4 are on downloads.php.net, listed by php.net
PHP_SRC_URL="$(curl -fsSL --retry 3 "https://www.php.net/pre-release-builds.php?format=json" | jq -r --arg v "${STATIC_PHP_VERSION}" '.[] | objects | .release | objects | select(.version == $v) | .files.gz.path' | head -n 1)"
if [ -z "${PHP_SRC_URL}" ]; then
echo "PHP ${STATIC_PHP_VERSION} not found on php.net, or not the current pre-release" >&2
exit 1
fi
fi

IFS=. read -r PHP_MAJOR PHP_MINOR _ <<<"${STATIC_PHP_VERSION}"
PHP_86_OR_LATER=false
if (( PHP_MAJOR > 8 || (PHP_MAJOR == 8 && PHP_MINOR >= 6) )); then PHP_86_OR_LATER=true; fi

CUSTOM_URLS=(-U "php-src:${PHP_SRC_URL}")
if [ "${PHP_86_OR_LATER}" = true ] && [[ ",${STATIC_PHP_EXTENSIONS}," == *,apcu,* ]]; then
# The latest APCu release (5.1.28) doesn't build with PHP 8.6; this commit does
CUSTOM_URLS+=(-U "apcu:https://github.com/krakjoe/apcu/archive/ebbcd3d153df21eaee3395413de515a30b48ef05.tar.gz")
fi

# Retry because GitHub API release lookups fail intermittently; already-downloaded sources are skipped
for attempt in 1 2 3; do
if bin/spc download --prefer-pre-built --for-extensions="${STATIC_PHP_EXTENSIONS}" -U "php-src:https://www.php.net/distributions/php-${STATIC_PHP_VERSION}.tar.gz"; then
if bin/spc download --prefer-pre-built --for-extensions="${STATIC_PHP_EXTENSIONS}" "${CUSTOM_URLS[@]}"; then
break
fi
if [ "${attempt}" -eq 3 ]; then
Expand All @@ -47,8 +67,20 @@ done
# opcache would normally be here but build fails: https://github.com/crazywhalecc/static-php-cli/issues/192
if [[ ${STATIC_PHP_VERSION} =~ ^[89] ]]; then export STATIC_PHP_EXTENSIONS="${STATIC_PHP_EXTENSIONS},opcache"; fi

# Skip patches for the micro SAPI, which isn't built; static-php-cli applies its PHP 8.0 patches to unknown versions like 8.6
export SPC_MICRO_PATCHES=""

# PHP 8.6 rejects the --with-pic option static-php-cli passes to configure, and needs --enable-pic instead
if [ "${PHP_86_OR_LATER}" = true ]; then
export SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --disable-shared --enable-static --disable-all --disable-phpdbg --enable-pic"
fi

# Scan our own conf.d and the project's .ddev/php directory for additional ini files
bin/spc build "${STATIC_PHP_EXTENSIONS}" --build-cli --build-fpm --with-config-file-scan-dir=/usr/local/etc/php/conf.d:/mnt/ddev_config/php
if ! bin/spc build "${STATIC_PHP_EXTENSIONS}" --build-cli --build-fpm --with-config-file-scan-dir=/usr/local/etc/php/conf.d:/mnt/ddev_config/php; then
# static-php-cli doesn't print the failing command's output, so show it here
tail -n 60 log/spc.shell.log >&2 || true
exit 1
fi

chown -R "${uid}:${gid}" /usr/local/src/static-php-cli
EOF
Expand Down
Loading