NativePHPでカスタムPHPバイナリをビルド
はじめに
NativePHPは、PHPとLaravelのスキルを活かしてデスクトップアプリケーションを構築できるフレームワークです。内部的には静的にリンクされたPHPバイナリを使用しており、このバイナリをカスタマイズすることで、デフォルトでは含まれていない拡張機能を追加できます。
本記事では、NativePHP用のカスタムPHPバイナリをビルドする方法を、実際に遭遇したトラブルとその解決策を交えながら解説します。
NativePHPとデータベース接続について
NativePHPの公式ドキュメントでは、データベースアクセスについて以下のように記載されています:
When building a NativePHP mobile application, you can't guarantee a safe, secure, reliable environment (if it's being distributed publicly). So you should have a layer of abstraction in-between your application and the database server. When working with Laravel, this would usually be a REST API.
(訳:NativePHPモバイルアプリケーションを構築する際、公開配布される場合は安全で信頼性の高い環境を保証できません。そのため、アプリケーションとデータベースサーバーの間に抽象化レイヤーを設けるべきです。Laravelの場合、これは通常REST APIになります。)
これはセキュリティ上の観点から、直接MySQL/PostgreSQLに接続するのではなく、API経由でのアクセスを推奨するものです。公開配布するアプリでは、データベース認証情報が漏洩するリスクや、任意のSQLクエリが実行される危険性があるためです。
しかし、私のケースでは現地でローカルネットワークを構築し、インターネットに公開しないクローズドな環境で運用するアプリケーションを開発していました。複数のPCにインストールして同時に動作させる必要があり、さらにNativePHP以外のツールも同じデータベースにアクセスする要件がありました。
このような閉域網環境では、専用のAPIサーバーを別途用意するよりも、各アプリケーションから直接データベースにアクセスする方が運用上合理的です。そのため、mysqli、pgsqlなどのデータベース拡張機能を含むカスタムバイナリが必要になりました。
なぜカスタムバイナリが必要?
NativePHPの公式php-binリポジトリには、一般的な拡張機能が含まれていますが、以下のようなケースではカスタムビルドが必要になります:
-
PostgreSQL対応:
pgsql、pdo_pgsql拡張機能の追加 -
SQL Server対応:
sqlsrv、pdo_sqlsrv拡張機能の追加 -
高速圧縮:
zstd、brotliライブラリの追加 -
HTTP/2対応:
nghttp2ライブラリの追加
プロジェクト構造
ディレクトリ構成
php-bin/
├── .github/
│ └── workflows/
│ ├── build-php.yml # PHPビルドワークフロー
│ └── update-ca-file.yml # CA証明書更新ワークフロー
├── cacert.pem # SSL/TLS証明書バンドル
├── php-extensions.txt # コンパイル対象の拡張機能
└── php-libraries.txt # コンパイル対象のライブラリ
主要ファイルの役割
| ファイル | 役割 |
|---|---|
php-extensions.txt |
ビルドする拡張機能をカンマ区切りで指定 |
php-libraries.txt |
追加するライブラリをカンマ区切りで指定 |
cacert.pem |
HTTPS通信用のCA証明書バンドル |
static-php-cliとは
static-php-cliは、静的にリンクされたPHPバイナリを構築するためのツールです。
特徴
- 自己完結型: 外部ライブラリ依存なしで実行可能
- クロスプラットフォーム: Linux、macOS、Windowsに対応
- 170以上の拡張機能: 幅広い拡張機能をサポート
サポートされているプラットフォーム
| OS | x86_64 | arm64 |
|---|---|---|
| Linux | ✓ | ✓ |
| macOS | ✓ | ✓ |
| Windows | ✓ | ✗ |
サポートされているPHPバージョン
- PHP 8.1, 8.2, 8.3, 8.4
拡張機能とライブラリの設定
拡張機能の設定(php-extensions.txt)
bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,iconv,
mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pdo,pdo_mysql,pdo_pgsql,
pdo_sqlite,pgsql,phar,redis,session,simplexml,soap,sockets,sqlite3,
tokenizer,xml,xmlreader,xmlwriter,zip,zlib,intl,sqlsrv,ssh2,pdo_sqlsrv
ライブラリの設定(php-libraries.txt)
libjpeg,freetype,libwebp,zstd,brotli,nghttp2
拡張機能とライブラリの依存関係
static-php-cliでは、拡張機能には必須とオプションの依存関係があります。
| 拡張機能 | 必須ライブラリ | オプションライブラリ |
|---|---|---|
gd |
zlib, libpng | libjpeg, freetype, libwebp, libavif |
curl |
openssl, zlib | libssh2, brotli, nghttp2, zstd |
redis |
session | igbinary, msgpack, zstd, liblz4 |
intl |
icu | - |
オプションライブラリは --with-libs オプションで明示的に指定する必要があります。
GitHub Actionsでのビルド設定
ワークフローの全体構成
name: Build PHP
permissions:
contents: write
pull-requests: write
on:
workflow_dispatch:
env:
SPC_VERSION: 2.6.1
jobs:
build:
name: ${{ matrix.version }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
max-parallel: 5 # APIレート制限対策
matrix:
version: ["8.1", "8.2", "8.3", "8.4"]
os: ["macos-15-intel", "macos-latest", "ubuntu-latest", "ubuntu-24.04-arm", "windows-latest"]
continue-on-error: true
プラットフォーム別のSPCバイナリ設定
- name: Set SPC URL for macos-15-intel
if: matrix.os == 'macos-15-intel'
run: echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-macos-x86_64.tar.gz" >> $GITHUB_ENV
- name: Set SPC URL for macos-latest
if: matrix.os == 'macos-latest'
run: echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-macos-aarch64.tar.gz" >> $GITHUB_ENV
- name: Set SPC URL for ubuntu-latest
if: matrix.os == 'ubuntu-latest'
run: echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-linux-x86_64.tar.gz" >> $GITHUB_ENV
- name: Set SPC URL for ubuntu-24.04-arm
if: matrix.os == 'ubuntu-24.04-arm'
run: echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-linux-aarch64.tar.gz" >> $GITHUB_ENV
- name: Set SPC URL for windows-latest
if: matrix.os == 'windows-latest'
run: |
echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-windows-x64.exe" >> $GITHUB_ENV
echo "SPC_BINARY=spc.exe" >> $GITHUB_ENV
ビルドコマンド
- name: Build PHP
run: |
cd ../static-php-cli
./bin/spc build --build-cli "${{ env.PHP_EXTENSIONS }}" --with-libs="${{ env.PHP_LIBS }}" --debug
トラブルシューティング
問題1: macOS-13ランナーの廃止
症状
The macOS-13 based runner images are now retired.
原因
GitHub Actionsのmacos-13ランナーが2025年12月に廃止されました。
解決策
macos-13をmacos-15-intelに変更します。
# 変更前
os: ["macos-13", "macos-latest", ...]
# 変更後
os: ["macos-15-intel", "macos-latest", ...]
問題2: Windowsでライブラリが未サポート
症状
[C] library [brotli] is in the lib.json list but not supported to compile
[C] library [zstd] is in the lib.json list but not supported to compile
原因
static-php-cliの一部ライブラリはWindowsでサポートされていません。
| ライブラリ | Linux | macOS | Windows |
|---|---|---|---|
| zstd | ✓ | ✓ | ✗ |
| brotli | ✓ | ✓ | ✗ |
| nghttp2 | ✓ | ✓ | ✗ |
解決策
Windowsビルド時のみ、未サポートライブラリを除外します。
- name: Read PHP libraries from file
shell: bash
run: |
LIBRARIES=$(php -r "echo trim(file_get_contents('php-libraries.txt'));")
# Windowsではzstd, brotli, nghttp2を除外(未サポート)
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
LIBRARIES=$(echo "$LIBRARIES" | sed 's/,zstd//g' | sed 's/,brotli//g' | sed 's/,nghttp2//g')
fi
echo "PHP_LIBS=$LIBRARIES" >> $GITHUB_ENV
問題3: GitHub APIレート制限
症状
curl: (22) The requested URL returned error: 403
Failed to fetch "https://api.github.com/repos/static-php/static-php-cli-hosted/releases"
原因
複数のジョブが同時にGitHub APIにアクセスすると、レート制限に達することがあります。
解決策
max-parallelを設定して同時実行数を制限します。
strategy:
max-parallel: 5 # 同時実行数を5に制限
matrix:
version: ["8.1", "8.2", "8.3", "8.4"]
os: ["macos-15-intel", "macos-latest", "ubuntu-latest", "ubuntu-24.04-arm", "windows-latest"]
max-parallelの動作
| 設定 | 動作 |
|---|---|
| 指定なし | 全20ジョブを同時実行 |
max-parallel: 5 |
最大5ジョブまで同時実行、残りは待機 |
max-parallel: 1 |
1つずつ順番に実行(直列) |
問題4: Windowsでintl拡張機能のビルド失敗
症状
error C2270: 'length': modifiers not allowed on nonmember functions
(compiling source file ext\intl\intl_convertcpp.cpp)
原因
static-php-cliで使用されるICUライブラリとWindowsのコンパイラ間で互換性問題が発生します。
解決策
Windowsビルド時のみ、intl拡張機能を除外します。
- name: Read PHP extensions from file
shell: bash
run: |
EXTENSIONS=$(php -r "echo trim(file_get_contents('php-extensions.txt'));")
# Windowsではintlを除外(ICU互換性問題)
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
EXTENSIONS=$(echo "$EXTENSIONS" | sed 's/,intl//g')
fi
echo "PHP_EXTENSIONS=$EXTENSIONS" >> $GITHUB_ENV
ワークフロー完全版
以下は、プラットフォーム別の除外処理を含む最終的なワークフロー全体です。
name: Build PHP
permissions:
contents: write
pull-requests: write
on:
workflow_dispatch:
env:
SPC_VERSION: 2.6.1
# Temporary workaround. See https://github.com/NativePHP/laravel/issues/522#issuecomment-2736250539
# Remove when updating SPC version
WINBUILD_ACKNOWLEDGE_DEPRECATED: yes
jobs:
build:
name: ${{ matrix.version }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
max-parallel: 5 # APIレート制限対策:同時実行数を制限
matrix:
version: ["8.1", "8.2", "8.3", "8.4"]
os: ["macos-15-intel", "macos-latest", "ubuntu-latest", "ubuntu-24.04-arm", "windows-latest"]
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Set SPC binary name
shell: bash
run: echo "SPC_BINARY=spc" >> $GITHUB_ENV
- name: Set SPC URL for macos-15-intel
shell: bash
if: matrix.os == 'macos-15-intel'
run: echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-macos-x86_64.tar.gz" >> $GITHUB_ENV
- name: Set SPC URL for macos-latest
shell: bash
if: matrix.os == 'macos-latest'
run: echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-macos-aarch64.tar.gz" >> $GITHUB_ENV
- name: Set SPC URL for ubuntu-latest and ubuntu-24.04
shell: bash
if: matrix.os == 'ubuntu-latest'
run: echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-linux-x86_64.tar.gz" >> $GITHUB_ENV
- name: Set SPC URL for ubuntu-24.04-arm
shell: bash
if: matrix.os == 'ubuntu-24.04-arm'
run: echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-linux-aarch64.tar.gz" >> $GITHUB_ENV
- name: Set SPC URL for windows-latest
shell: bash
if: matrix.os == 'windows-latest'
run: |
echo "SPC_URL=https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-windows-x64.exe" >> $GITHUB_ENV
echo "SPC_BINARY=spc.exe" >> $GITHUB_ENV
- name: Download SPC
shell: bash
run: |
cd ..
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
curl -fsSL -o ${{ env.SPC_BINARY }} ${{ env.SPC_URL }}
else
curl -fsSL -o ${{ env.SPC_BINARY }}.tar.gz ${{ env.SPC_URL }}
tar -xzf ${{ env.SPC_BINARY }}.tar.gz
fi
chmod +x ${{ env.SPC_BINARY }}
[ ! -d static-php-cli/bin ] && mkdir -p static-php-cli/bin
mv ${{ env.SPC_BINARY }} static-php-cli/bin/
- name: Create php-bin directory
shell: bash
run: |
cd ..
[ ! -d php-bin ] && mkdir -p php-bin
cd php-bin
- shell: bash
run: |
PHP_VERSION=$(echo "${{ matrix.version }}" | cut -d. -f1,2)
echo "PHP_VERSION=$PHP_VERSION" >> $GITHUB_ENV
- shell: bash
run: echo "SPC_BUILD_ARCH=x64" >> $GITHUB_ENV
- shell: bash
if: matrix.os == 'macos-latest' || matrix.os == 'ubuntu-24.04-arm'
run: echo "SPC_BUILD_ARCH=arm64" >> $GITHUB_ENV
- shell: bash
if: contains(matrix.os, 'macos')
run: |
brew install automake gzip
echo "SPC_BUILD_OS=mac" >> $GITHUB_ENV
- shell: bash
if: matrix.os == 'windows-latest'
run: echo "SPC_BUILD_OS=win" >> $GITHUB_ENV
- shell: bash
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-24.04-arm'
run: echo "SPC_BUILD_OS=linux" >> $GITHUB_ENV
- name: Setup system PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
tools: pecl, composer
extensions: curl, openssl, mbstring, sodium, tokenizer
ini-values: memory_limit=-1
- name: SPC doctor
run: |
cd ../static-php-cli
./bin/${{ env.SPC_BINARY }} doctor
cd ../php-bin
- name: Read PHP extensions from file
id: read-extensions
shell: bash
run: |
EXTENSIONS=$(php -r "echo trim(file_get_contents('php-extensions.txt'));")
# Windowsではintlを除外(ICU互換性問題)
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
EXTENSIONS=$(echo "$EXTENSIONS" | sed 's/,intl//g')
fi
EXT_HASH=$(php -r "echo md5(getenv('EXTENSIONS'));")
echo "PHP_EXTENSIONS=$EXTENSIONS" >> $GITHUB_ENV
echo "PHP_EXT_HASH=$EXT_HASH" >> $GITHUB_ENV
- name: Read PHP libraries from file
id: read-libs
shell: bash
run: |
LIBRARIES=$(php -r "echo trim(file_get_contents('php-libraries.txt'));")
# Windowsではzstd, brotli, nghttp2を除外(未サポート)
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
LIBRARIES=$(echo "$LIBRARIES" | sed 's/,zstd//g' | sed 's/,brotli//g' | sed 's/,nghttp2//g')
fi
LIBRARIES_HASH=$(php -r "echo md5(getenv('LIBRARIES'));")
echo "PHP_LIBS=$LIBRARIES" >> $GITHUB_ENV
# Cache downloaded source
- id: cache-spc-downloads
uses: actions/cache@v4
with:
path: ../static-php-cli/downloads
key: spc-downloads-${{ env.PHP_EXT_HASH }}
- name: Download PHP extension sources
if: steps.cache-spc-downloads.outputs.cache-hit != 'true'
run: |
cd ../static-php-cli
./bin/${{ env.SPC_BINARY }} download --with-php=${{ matrix.version }} --for-extensions "${{ env.PHP_EXTENSIONS }}" --prefer-pre-built
cd ../php-bin
- name: Build PHP
run: |
cd ../static-php-cli
./bin/${{ env.SPC_BINARY }} build --build-cli "${{ env.PHP_EXTENSIONS }}" --with-libs="${{ env.PHP_LIBS }}" --debug
cd ../php-bin
- name: Get built PHP version
shell: bash
run: |
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
PHP_VERSION_FULL=$(../static-php-cli/buildroot/bin/php.exe -r "echo PHP_VERSION;")
else
PHP_VERSION_FULL=$(../static-php-cli/buildroot/bin/php -r "echo PHP_VERSION;")
fi
echo "PHP_VERSION_FULL=$PHP_VERSION_FULL" >> $GITHUB_ENV
- name: Create bin directories
shell: bash
run: |
mkdir -p bin/${{ env.SPC_BUILD_OS }}/${{ env.SPC_BUILD_ARCH }}
mkdir -p license-files
mkdir -p build-meta
- name: Zip PHP binary, copy metadata
shell: bash
run: |
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
powershell Compress-Archive -Path "../static-php-cli/buildroot/bin/php.exe" -DestinationPath "bin/${{ env.SPC_BUILD_OS }}/${{ env.SPC_BUILD_ARCH }}/php-${{ env.PHP_VERSION }}.zip" -Force
else
rm -f bin/${{ env.SPC_BUILD_OS }}/${{ env.SPC_BUILD_ARCH }}/php-${{ env.PHP_VERSION }}.zip
mkdir -p tmp-bin
cp ../static-php-cli/buildroot/bin/php tmp-bin/
cd tmp-bin
zip ../bin/${{ env.SPC_BUILD_OS }}/${{ env.SPC_BUILD_ARCH }}/php-${{ env.PHP_VERSION }}.zip php
cd ..
rm -rf tmp-bin
fi
cp ../static-php-cli/buildroot/license/* license-files/
cp ../static-php-cli/buildroot/build-extensions.json build-meta/build-extensions-${{ env.SPC_BUILD_OS }}.json
cp ../static-php-cli/buildroot/build-libraries.json build-meta/build-libraries-${{ env.SPC_BUILD_OS }}.json
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
branch: update-php-${{ env.PHP_VERSION }}-${{ env.SPC_BUILD_OS }}-${{ env.SPC_BUILD_ARCH }}
title: "Update PHP ${{ env.PHP_VERSION }} build for ${{ env.SPC_BUILD_OS }} ${{ env.SPC_BUILD_ARCH }}"
commit-message: "build"
body: |
PHP: ${{ env.PHP_VERSION_FULL }}
Exts: ${{ env.PHP_EXTENSIONS }}
OS: ${{ env.SPC_BUILD_OS }}
Arch: ${{ env.SPC_BUILD_ARCH }}
base: main
cacert.pemの役割と取得方法
静的リンクされたPHPはOSのCA証明書ストアにアクセスできないため、HTTPS通信用の証明書をバンドルする必要があります。
用途
- PHPの
curl拡張機能でのHTTPS接続 -
file_get_contents('https://...')でのアクセス - NativePHPアプリでのAPI通信
取得方法
CA証明書はcurl公式サイトから取得できます。
# 最新のCA証明書をダウンロード
curl -O https://curl.se/ca/cacert.pem
自動更新ワークフロー
定期的に最新の証明書を取得するワークフローを設定します。
name: Fetch Latest CA File
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # 毎週日曜日に実行
jobs:
fetch-ca-file:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch the latest CA file
run: curl -O https://curl.se/ca/cacert.pem
- name: Check if the CA file has changed
id: cafile
run: |
CHANGED=$(git diff --name-only | grep cacert.pem || true)
if [[ ! -z "$CHANGED" ]]; then
echo "CHANGED=true" >> $GITHUB_ENV
fi
- name: Commit changes
if: env.CHANGED == 'true'
run: |
git config --local user.email "your-email@example.com"
git config --local user.name "Your Name"
git add cacert.pem
git commit -m "Update CA file"
git push
PHPでの使用例
NativePHPアプリ内でHTTPS通信を行う場合:
// curlでの使用
$ch = curl_init('https://api.example.com');
curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
// stream_contextでの使用
$context = stream_context_create([
'ssl' => [
'cafile' => '/path/to/cacert.pem',
'verify_peer' => true,
]
]);
$content = file_get_contents('https://api.example.com', false, $context);
NativePHPでカスタムバイナリを使用する
設定方法
.envファイルで環境変数を設定します。
NATIVEPHP_PHP_BINARY_PATH=/path/to/your-custom-php-bin/bin/
ディレクトリ構造
カスタムバイナリは以下の構造に従う必要があります:
bin/
├── linux/
│ ├── x64/
│ │ └── php-8.4.zip
│ └── arm64/
│ └── php-8.4.zip
├── mac/
│ ├── x64/
│ │ └── php-8.4.zip
│ └── arm64/
│ └── php-8.4.zip
└── win/
└── x64/
└── php-8.4.zip
まとめ
NativePHPでカスタムPHPバイナリをビルドする際の主なポイント:
- static-php-cliを使用して静的リンクされたPHPをビルド
-
拡張機能は
php-extensions.txt、ライブラリはphp-libraries.txtで管理 - プラットフォーム別の制約に注意(特にWindows)
-
GitHub Actionsのレート制限対策として
max-parallelを設定 - CA証明書はHTTPS通信のために必須(curl.seから取得)
Discussion