Skip to content

Bundle default PHP binary#3554

Merged
bcotrim merged 4 commits into
trunkfrom
ship-default-php-binary
May 20, 2026
Merged

Bundle default PHP binary#3554
bcotrim merged 4 commits into
trunkfrom
ship-default-php-binary

Conversation

@bcotrim
Copy link
Copy Markdown
Contributor

@bcotrim bcotrim commented May 20, 2026

Related issues

  • N/A

How AI was used in this PR

Codex helped implement and review the packaging/runtime changes. I reviewed the diff and manually smoke-tested the packaged app behavior.

Proposed Changes

  • Download the recommended PHP binary during Studio packaging and include it as an app resource.
  • Teach the CLI to copy the bundled PHP binary into ~/.studio/php-bin/<patch> before falling back to CDN download.
  • Keep the existing writable PHP install layout so php.ini, ca-bundle.crt, and runtime files are managed in the user config directory.
  • Add focused tests for bundled PHP path resolution and first-use bundled install behavior.
  • Update the native PHP binaries design doc and ignore the generated packaging artifact directory.

Testing Instructions

macOS packaged-app smoke test:

  • Build/package the app:
    • Apple Silicon: npm run make:macos-arm64
    • Intel: npm run make:macos-x64
  • Verify the packaged app includes PHP:
    • find apps/studio/out -path '*/Studio.app/Contents/Resources/php-bin/*/php' -type f -ls
    • Expected: a path like apps/studio/out/Studio-darwin-arm64/Studio.app/Contents/Resources/php-bin/8.4.21/php.
  • Launch the packaged app with a clean config and native PHP enabled:
    • export DEV_CONFIG_DIR="$(mktemp -d)"
    • export STUDIO_RUNTIME=native-php
    • apps/studio/out/Studio-darwin-arm64/Studio.app/Contents/MacOS/Studio
  • In Studio, create or start a site.
  • Verify PHP was copied from the app bundle into the writable config directory:
    • find "$DEV_CONFIG_DIR/php-bin" -maxdepth 3 -type f | sort
    • Expected files include php-bin/8.4.21/php, php-bin/8.4.21/php.ini, php-bin/8.4.21/ca-bundle.crt, php-bin/8.4.21/runtime.json, and php-bin/8.4.21/ext/xdebug.so.
  • Confirm the copied binary runs:
    • "$DEV_CONFIG_DIR/php-bin/8.4.21/php" -v

Windows packaged-app smoke test:

  • Build/package the app:
    • x64: npm run make:windows-x64
    • ARM64: npm run make:windows-arm64
  • Verify the packaged app includes PHP:
    • Get-ChildItem .\apps\studio\out -Recurse -Filter php.exe | Where-Object { $_.FullName -like '*\resources\php-bin\*\php.exe' } | Select-Object -ExpandProperty FullName
    • Expected: a path like apps\studio\out\Studio-win32-x64\resources\php-bin\8.4.21\php.exe.
  • Launch the packaged app with a clean config and native PHP enabled:
    • $env:DEV_CONFIG_DIR = Join-Path $env:TEMP ("studio-test-" + [guid]::NewGuid())
    • New-Item -ItemType Directory -Path $env:DEV_CONFIG_DIR | Out-Null
    • $env:STUDIO_RUNTIME = "native-php"
    • .\apps\studio\out\Studio-win32-x64\Studio.exe
  • In Studio, create or start a site.
  • Verify PHP was copied from the app bundle into the writable config directory:
    • Get-ChildItem "$env:DEV_CONFIG_DIR\php-bin" -Recurse -File | Sort-Object FullName | Select-Object -ExpandProperty FullName
    • Expected files include php-bin\8.4.21\php.exe, php-bin\8.4.21\php.ini, php-bin\8.4.21\ca-bundle.crt, php-bin\8.4.21\runtime.json, and extension DLLs under php-bin\8.4.21\ext\.
  • Confirm the copied binary runs:
    • & (Get-ChildItem "$env:DEV_CONFIG_DIR\php-bin" -Recurse -Filter php.exe | Select-Object -First 1).FullName -v

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

@bcotrim bcotrim self-assigned this May 20, 2026
@bcotrim bcotrim requested a review from fredrikekelund May 20, 2026 13:06
@wpmobilebot
Copy link
Copy Markdown
Collaborator

wpmobilebot commented May 20, 2026

📊 Performance Test Results

Comparing 87dfc0c vs trunk

app-size

Metric trunk 87dfc0c Diff Change
App Size (Mac) 1376.63 MB 1487.03 MB +110.40 MB 🔴 8.0%

site-editor

Metric trunk 87dfc0c Diff Change
load 1466 ms 1505 ms +39 ms ⚪ 0.0%

site-startup

Metric trunk 87dfc0c Diff Change
siteCreation 8627 ms 8566 ms 61 ms 🟢 -0.7%
siteStartup 4936 ms 4929 ms 7 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

Copy link
Copy Markdown
Contributor

@fredrikekelund fredrikekelund left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 I left a few comments that would be nice to address, but the fundamentals look solid

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this script was there before this PR, but it strikes me now that we should maybe say that it downloads a PHP package rather than a binary, because it's not just that single binary on Windows.

Comment thread scripts/download-php-binary.ts Outdated
const binaryName = isWindows ? 'php.exe' : 'php';
const platformKey = `${ args.platform }-${ effectiveArch }`;
const phpBinaryRoot =
process.env.STUDIO_PHP_BINARY_INSTALL_ROOT ?? path.join( getConfigDirectory(), 'php-bin' );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

STUDIO_PHP_BINARY_INSTALL_ROOT could be an option passed to the script instead of an environment variable.

Comment thread docs/design-docs/native-php-binaries.md Outdated
Comment on lines +99 to +102
destination patch folder does not exist. For non-bundled PHP versions, Studio downloads the
tracked patch for the current platform and architecture, then verifies the
checked-in SHA-256 before extracting the archive. If metadata is missing for the
requested device, native PHP install fails for that version.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
destination patch folder does not exist. For non-bundled PHP versions, Studio downloads the
tracked patch for the current platform and architecture, then verifies the
checked-in SHA-256 before extracting the archive. If metadata is missing for the
requested device, native PHP install fails for that version.
destination patch folder does not exist. Studio downloads other PHP versions
on demand from manifest URLs, then verifies the checked-in SHA-256 before
extracting the archive. If metadata is missing for the requested device, native
PHP install fails for that version.

Doesn't have to be exactly like this, but I think we can make it clearer that we ship with one PHP version and the other ones are downloaded on demand.

return fs.existsSync( getBundledDefaultPhpPath() );
}

export const installBundledDefaultPhp: Migration = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a comment that explains what this migration does.

Comment on lines +41 to +43
if ( ! bundledDefaultPhpExists() || fs.existsSync( getDefaultPhpDestinationDir() ) ) {
return;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we're repeating needsToRun() here

@bcotrim bcotrim enabled auto-merge (squash) May 20, 2026 14:47
@bcotrim bcotrim merged commit e538a41 into trunk May 20, 2026
9 of 11 checks passed
@bcotrim bcotrim deleted the ship-default-php-binary branch May 20, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants