はじめに
2026年10月はphp2shellが話題となり、「PHPに脆弱性!」という文言がお茶の間にも流れる衝撃的な月間となりました。
某SNSでは「言語に脆弱性ってどういうことなんだ」とか「PHPはソフトウェアなのか」という話題で盛り上がったりしていましたが、ご存知の通り、「PHP」という言葉は言語を指すこともあれば、その言語による命令を受け付けて動作する「処理系」を指すこともあります(後者ならソフトウェア)。言語によっては有力な処理系が複数存在するものもありますが、PHPの場合は公式の処理系である「PHP(Zend Engine)」以外を使う機会がほぼないため、両者を混同しやすくなっています。
では「Zend Engine以外にPHP言語を処理・実行できるソフトウェアは無いのか?」というと、そんなことはありません。今回は、C#製のPHP処理系である「PeachPie」を使って、実際にPHP(処理系)を使わずにPHP(言語)を使ったwebサーバーを立ててみましょう。
PeachPie
PeachPie は、PHPで書かれたプログラムをMicrosoft .NET上で実行できるようにする、PHPコンパイラ兼ランタイムです。PeachPieはPHPコードを.NET向けにコンパイルし、.NETの実行環境上で動作させます。
PHPのソースコードを.NETの中間言語にコンパイルするため、実行にZend Engineや通常のPHP実行環境を必要としません。また、PHPとC#のコードを同一の.NETプロジェクト内で連携させることもできます。
公式PHP処理系と互換であることを目指しており、この記事では扱いませんが、Wordpressをビルドしたものも公開されています。
PeachPie自身もC#で書かれています。最近話題になったPHPの脆弱性php2shellは、非局所ジャンプが通常のスタックアンワインドを伴わずに途中の後始末処理をスキップすることに起因していましたが、これは、公式のPHP処理系(Zend Engine)がC言語で実装されているために起こったミスとも言えます。一方、C#では通常の例外処理がスタックアンワインド時の後始末を保証するため、PeachPieでは同一の機序による脆弱性は原理上生じません(だからといってPeachPieがより安全であるという意味ではもちろんありません)。
オープンソースであり、GitHubでレポジトリが公開されています。
開発の活発さは......ぼちぼちといったところでしょうか。一応2016年から今に至るまで継続的に更新がされています。
この記事でのPeachPie Webサーバーの構築手順
公式PHPテンプレートをPeachPieでコンパイルし、Cloudflare Tunnel経由で公開します。
実施環境:
- Raspberry Pi 4 / Ubuntu 26.04 (arm64)、
- .NET SDK 10.0.403
- PeachPie 1.1.13
- Peachpie.Templates 1.0.33
1. 環境変数を設定する
以降のコマンドは、この環境変数を設定したシェルで実行するします。
cd ~/project_env
export DOTNET_ROOT=$PWD/.dotnet PATH=$PWD/.dotnet:$PATH DOTNET_CLI_HOME=$PWD/.dotnet-home \
NUGET_PACKAGES=$PWD/.nuget DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1 \
DOTNET_ROLL_FORWARD=Major
DOTNET_ROLL_FORWARD=Major は必須です。PeachPieのコンパイラは.NET 6向けなので、これがないと.NET 10だけの環境ではビルドに失敗します。
2. .NET SDKをインストールする
curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh
bash /tmp/dotnet-install.sh --channel 10.0 --install-dir ~/project_env/.dotnet --no-path
3. 公式テンプレートからプロジェクトを作る
dotnet new install Peachpie.Templates::1.0.33
mkdir web && cd web
dotnet new web -lang PHP -n web -o .
sed -i 's#<TargetFramework>net6.0#<TargetFramework>net10.0#' Server/Server.csproj Website/Website.msbuildproj
(Cloudflare tunnelを使う場合)Server/Program.cs を修正
今回はCloudflare tunnel + 自宅Raspberry piで試しているので、待ち受けをローカルのみに変更し、Cloudflare経由のヘッダーを処理するようにしました。直接公開する場合にはこの手順は不要。
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.HttpOverrides;
- .UseUrls("http://*:5004/")
+ .UseUrls("http://127.0.0.1:8790/")
+ // cloudflared connects from loopback, the default trusted proxy
+ services.Configure<ForwardedHeadersOptions>(options =>
+ options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto);
+
services.AddPhp(options =>
+ app.UseForwardedHeaders();
+
// enable session:
Cloudflare側では、Zero Trustのダッシュボードで、トンネルにPublic Hostname を追加しておきます。
例)
| 項目 | 値 |
|---|---|
| Subdomain | peachpie |
| Domain | example.com |
| Service |
HTTP / localhost:8790
|
5. PHPを書いてビルドする
Website/index.php を編集してからビルドします。
運用上は、*.phpを書き直すたびにビルド ➡ 公開という手順になります。
dotnet publish Server -c Release -o publish
6. systemdのユーザーサービスとして登録する
~/.config/systemd/user/peachpie-web.service を作成。
テスト用なのでリソース占有量は控えめにしてあります。
[Unit]
Description=PHP website compiled with PeachPie
[Service]
WorkingDirectory=%h/project_env/web/publish
ExecStart=%h/project_env/.dotnet/dotnet %h/project_env/web/publish/Server.dll
Environment=DOTNET_ROOT=%h/project_env/.dotnet
Environment=DOTNET_CLI_TELEMETRY_OPTOUT=1
Environment=ASPNETCORE_ENVIRONMENT=Production
Restart=on-failure
RestartSec=10s
MemoryMax=512M
CPUQuota=100%
Nice=10
NoNewPrivileges=true
[Install]
WantedBy=default.target
有効化
loginctl enable-linger $USER
systemctl --user daemon-reload
systemctl --user enable --now peachpie-web
curl -s http://127.0.0.1:8790/
8. 確認する
実際に構築・公開してみたもの: https://peachpie.haborite.com/?name=test
クエリに渡した文字列がHello, ****!の形で表示されればok
9. 実用性
PeachPieのwebページに、公式版PHP処理系との互換性の表があります。
見ての通りまだまだ非互換な部分も結構あるので、さすがに仕事用としては選択肢にはなりえないでしょうけど、個人で遊んでみる分には楽しいかもしれません。