# phpenvmgr **Repository Path**: qruansoft_admin/phpenvmgr ## Basic Information - **Project Name**: phpenvmgr - **Description**: 一个单文件、免安装的 Windows PHP 本地开发环境,内置 Nginx + PHP +(可选)MariaDB,并附带 Web 控制面板与系统托盘。适合在本地跑 PHP 站点(ThinkPHP、WordPress、Discuz 等)。 - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-26 - **Last Updated**: 2026-08-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # envmgr · PHP 集成环境 一个**单文件、免安装**的 Windows PHP 本地开发环境,内置 Nginx + PHP +(可选)MariaDB,并附带 Web 控制面板与系统托盘。适合在本地跑 PHP 站点(ThinkPHP、WordPress、Discuz 等)。 ## 功能特性 - **单 exe,免安装**:一个 `envmgr.exe` 搞定全部,不写注册表、不留垃圾。 - **Web 控制面板**:在浏览器里启停服务、切换 PHP 版本、管理虚拟主机。 - **系统托盘常驻**:一键启动/停止全部、操作有气泡反馈、菜单项按状态自动置灰。 - **多 PHP 版本共存**:可装多个 PHP 版本,一键切换,**任意时刻只运行当前激活的那一个**(避免端口冲突与资源浪费)。 - **虚拟主机**:面板里填站点名+域名,自动建目录、生成 Nginx 配置、写入系统 hosts。 - **内置 SQLite**:`pdo_sqlite` 扩展默认开启,开箱即用。 - **可选 MariaDB / MySQL**:把官方便携版丢进 `bin\mariadb` 或 `bin\mysql\<版本>` 目录即被自动识别管理。 ## 快速开始 1. 把 `envmgr.exe` 放到一个**纯英文目录**,例如 `C:\envmgr`(`D:\php_env` 也行,但**不要**含中文或全角字符)。 2. 双击运行。首次启动会自动打开控制面板。 3. 在面板点「全部启动」,等状态变绿即可。 访问地址: | 用途 | 地址 | |------|------| | 控制面板 | http://127.0.0.1:9090/ | | 默认站点 | http://127.0.0.1/ | | phpinfo | http://127.0.0.1/phpinfo.php | > ⚠️ **强制要求:程序必须运行在纯英文路径下。** > 中文/全角路径会导致 Nginx 无法读取路径而启动失败,以及 PHP 在强 ASLR 环境下因 opcache 初始化致命退出。若放了中文路径,启动时会弹出提示并退出。 ## 目录结构 ``` C:\envmgr\ ├─ envmgr.exe # 主程序(单文件) ├─ bin\ │ ├─ nginx\ # Nginx 二进制与默认配置 │ ├─ php\ │ │ ├─ 8.5\ # 已安装的 PHP 版本(可存在多个,如 8.1、8.4…) │ │ │ ├─ php-cgi.exe │ │ │ └─ php.ini # 由程序自动生成,勿手改(见下) │ │ └─ ... │ ├─ mariadb\ # 可选:放 MariaDB 便携版到此目录即被识别 │ └─ mysql\ # 可选:放 MySQL 便携版(如 MySQL5.7.26)到此目录即被识别(端口 3307) ├─ conf\ │ ├─ nginx.conf # 由程序自动生成 │ ├─ active_php.txt # 当前激活的 PHP 版本号 │ ├─ vhosts.json # 虚拟主机清单(元数据) │ └─ vhosts\ # 各虚拟主机的 Nginx 配置 *.conf ├─ www\ │ ├─ default\ # 默认站点根目录(http://127.0.0.1/) │ └─ <站点名>\ # 每个虚拟主机一个目录 ├─ logs\ │ ├─ nginx\ # Nginx 日志 │ └─ php\ # 各 PHP 版本日志(如 8.5.log) └─ phpmyadmin\ # (可选)数据库管理工具 ``` ## 控制面板(Web) 打开 http://127.0.0.1:9090/ ,主要功能: ### 1. 工具栏 - **全部启动**:按依赖顺序拉起所有「应当运行」的服务(nginx + 当前激活 PHP + 已安装的 MariaDB/MySQL)。**只会启动激活的 PHP 版本,不拉起其它版本。** - **全部停止**:停止所有服务。 - **默认站点 / phpinfo**:新标签打开对应页面。 - **重载 Nginx**:修改配置后让 Nginx 重新加载(不重启进程)。 > 工具栏的「全部启动 / 全部停止」会跟随实际运行状态自动置灰:所有服务都跑起来了,「启动全部」变灰;全停了,「停止全部」变灰。 ### 2. 服务卡片 每个服务(nginx / php-8.5 / mariadb …)一张卡片,显示运行状态与端口,并提供: - **启动 / 停止 / 重启**:按钮按状态自动置灰(运行中的「启动」不可点,停止的「停止/重启」不可点;未安装则全部禁用)。 - **日志**:展开该服务的运行日志(取末尾 200 行)。 ### 3. PHP 版本切换 - 下拉框列出所有已安装版本,当前激活版本会标出。 - 点「切换版本」:写入 `conf/active_php.txt` → 重新生成配置 → **停止其它 PHP 版本、只启动目标版本** → 重载 Nginx。切换即时生效,不丢站点。 ### 4. 虚拟主机 - **站点名**:必填,如 `blog`(会建 `www/blog` 目录,且 `blog` 为保留名不可用)。 - **域名**:可空,默认 `<站点名>.test`,如 `blog.test`。 - 点「添加站点」后:自动建目录、生成 Nginx 配置、并把 `127.0.0.1 <域名>` 写入系统 hosts(**需以管理员身份运行 envmgr 才能写 hosts**;若失败会在面板提示,可手动加)。 - 站点列表里点「访问」打开 `http://<域名>/`,点「删除」移除(并尝试从 hosts 清理)。 ## 系统托盘菜单 右键任务栏托盘图标: | 菜单项 | 说明 | |--------|------| | 打开控制面板 | 在浏览器打开面板 | | 启动全部 | 编排启动全部应运行的服务(同面板「全部启动」) | | 停止全部 | 停止全部服务 | | 重启全部 | 停止后重新启动 | | 退出 | 停止服务并退出程序 | - 菜单项按实际状态自动置灰(所有服务已运行 →「启动全部」灰;全停 →「停止全部」灰)。 - 操作后会有**气泡通知**(如「全部服务已启动」),鼠标悬停图标可看运行概览。 - 单击托盘图标 = 打开控制面板。 ## 命令行参数 | 参数 | 默认值 | 说明 | |------|--------|------| | `-port` | `9090` | 控制面板监听端口 | | `-tray` | `true` | 是否启用系统托盘常驻;设 `false` 为控制台模式 | | `-download` | `false` | 启动时拉取缺失的二进制(nginx/php);MariaDB 因官方防盗链可能需手动放置 | 示例: ```bat envmgr.exe -port 9090 envmgr.exe -download ``` ## PHP 版本管理 - 把官方 PHP 的 `php-cgi` 构建解压到 `bin\php\<版本号>\`,例如 `bin\php\8.5\php-cgi.exe`。 - 多个版本可共存;`version.Scan` 会自动发现它们。 - **激活版本**记录在 `conf\active_php.txt`,缺失时回退到「最新安装的版本」。 - **FastCGI 端口**分配:`9000 + 版本在列表中的索引`(如第一个版本用 9000,第二个 9001)。Nginx 按此端口转发。 - 切换版本时,**只保留目标版本运行,其余 PHP 版本一律停止**(设计如此,避免多版本互相干扰)。 ## 数据库 ### MariaDB(可选) - 把 MariaDB 官方 Windows 便携版解压到 `bin\mariadb\`(含 `bin\mysqld.exe`)。 - 程序启动时会自动识别并纳入「全部启动」编排(端口 3306)。**注意:仅当 `bin\mariadb\bin\mysqld.exe` 存在时才注册该服务**,空目录不会拖垮「全部启动」。 - 一键下载(`-download`)因官方镜像防盗链通常拿不到,建议手动放置。 - 账号同 MySQL:`root`/`root` 与 `envmgr`/`envmgr`(首次启动自动初始化),连接示例 `new PDO("mysql:host=127.0.0.1;dbname=xxx", "envmgr", "envmgr")`。 - PHP 已开启 `mysqli` 与 `pdo_mysql` 扩展,可直接 `new PDO("mysql:host=127.0.0.1;dbname=xxx", ...)`。 ### MySQL(可选,与 MariaDB 并存) - 把 MySQL Windows 便携版解压到 `bin\mysql\<版本名>\`(如 `bin\mysql\MySQL5.7.26\`,需含 `bin\mysqld.exe`)。 - 程序启动时会自动识别并纳入「全部启动」编排;为避免与 MariaDB 抢 3306 端口,**MySQL 默认使用 3307 端口**。 - 配置文件 `conf\mysql.ini` 由程序按真实安装路径自动生成(自带 `my.ini` 里的写死路径不可用,会被覆盖)。 - **数据库账号(首次启动自动初始化,面板卡片也显示)**: - 管理员:`root` / `root` - 站点专用:`envmgr` / `envmgr`(建议网站连库用这个账号) - 连接示例:`new PDO("mysql:host=127.0.0.1;port=3307;dbname=xxx", "envmgr", "envmgr")` - 初始化逻辑:用 `--initialize-insecure` 建库,再用 `--init-file` 在启动时设好上述账号(含 127.0.0.1 TCP 账号),之后每次启动检测标记文件跳过。 - MariaDB 与 MySQL 可同时运行,按需在面板/托盘里单独启停某一个即可。 ### 修改密码 / 新建用户(控制面板) 数据库卡片上提供两个按钮,解决「多个网站不能共用同一密码」的问题: - **修改密码**:选择账号(`root` 或 `envmgr`)并输入新密码,后端用旧密码连库后执行 `ALTER USER` 改密,并把新密码记入 `conf\db_credentials.json`(面板卡片实时显示当前密码)。 - **新建用户**:输入用户名、密码、可选数据库名。后端以 `root` 连库新建专属账号(含 `127.0.0.1` TCP 账号);填了数据库名会自动建库并把该库授权给新用户,不填则授权全局。每个网站用一个独立账号+独立密码即可互不干扰。 > 当前密码保存在 `conf\db_credentials.json`(明文,仅本地开发用,已在 `.gitignore` 排除)。改密需数据库处于运行状态。 ### SQLite(已默认开启) - `pdo_sqlite` 扩展已默认启用,无需任何配置即可使用: ```php $db = new PDO('sqlite:C:/envmgr/www/default/data.db'); // 或内存库 $db = new PDO('sqlite::memory:'); $db->exec('CREATE TABLE IF NOT EXISTS t(id INTEGER)'); ``` ## 配置文件说明 多数配置文件由程序在启动时**自动生成**,**不要手动长期修改**——重启会被覆盖。需要持久化改动请改源码模板(`internal/config/config.go`)或对应生成逻辑。 | 文件 | 来源 | 能否手改 | |------|------|----------| | `conf/nginx.conf` | 自动生成 | 临时调试可改,重启覆盖 | | `conf/active_php.txt` | 版本切换写入 | 可改(即激活版本号) | | `conf/vhosts.json` | 虚拟主机元数据 | 建议在面板操作 | | `conf/vhosts/*.conf` | 自动生成 | 不建议手改 | | `bin/php/<版本>/php.ini` | 自动生成(模板见 `config.go`) | 临时可改;重启覆盖 | 当前 `php.ini` 默认已包含的关键设置: ```ini extension=pdo_sqlite ; 已开启 SQLite extension=pdo_mysql extension=mysqli opcache.enable=0 opcache.jit=disable ; 规避 Windows 强 ASLR 下 "Opcode handlers are unusable" 致命退出 opcache.jit_buffer_size=0 date.timezone = "Asia/Shanghai" ``` ## 日志与排错 - 服务日志:`logs\nginx\service.log`、`logs\php\8.5.log` 等,也可在面板点「日志」按钮直接看。 - Nginx 错误:`logs\nginx\error.log`。 常见问题: **Q1:双击没反应 / 启动失败?** 确认程序在**纯英文路径**下。中文路径会被直接拦截退出并提示。 **Q2:PHP 启动不了,日志报 `Opcode handlers are unusable due to ASLR`?** 这是 Windows 上 opcache 在强 ASLR 环境的已知问题。程序已默认 `opcache.jit=disable` 规避;若你手改过 php.ini 把它改回去了,请重新设为 disable。 **Q3:网站 502 Bad Gateway?** 通常是 PHP 没起来或 FastCGI 端口不对。点「全部启动」或「重启全部」,程序会在 Nginx 起来后做 502 自愈(自动重启激活 PHP 并 reload)。 **Q4:添加虚拟主机后浏览器打不开域名?** 多半是 hosts 没写成功——**用管理员身份运行 envmgr**。也可手动在 `C:\Windows\System32\drivers\etc\hosts` 加一行 `127.0.0.1 你的域名`。 **Q5:端口被占用(之前多次启动残留进程)?** 用任务管理器结束残留的 `nginx.exe` / `php-cgi.exe` / `envmgr.exe`,或在面板「全部停止」后重开。 ## 编译与二次开发 环境:Go 1.21+,Windows。 ```bat :: 直接编译(隐藏控制台黑框) go build -ldflags="-H=windowsgui -s -w" -o envmgr.exe . :: 一键编译并嵌入品牌图标 python build.py ``` 主要源码结构: ``` main.go 程序入口、参数解析、服务编排装配 internal/config 配置与 php.ini / nginx.conf 模板生成 internal/process 服务定义、启停、端口探测、编排(OrchestrateStart) internal/version PHP 版本扫描、激活版本、FastCGI 端口分配 internal/vhost 虚拟主机管理、Nginx 配置渲染、hosts 写入 internal/web 控制面板 HTTP 服务与 UI(ui.html 内嵌) internal/tray 系统托盘菜单、状态联动、气泡通知 internal/winutil Windows 原生调用(MessageBox / 托盘气泡 Toast) ``` > 编译产物 `envmgr.exe` 的图标通过 `embed_icon_api.py` 嵌入(调用 Windows `UpdateResourceW` API 注入 PE 资源,不依赖 windres),需先 `go build` 再嵌图标,避免复用破损 exe。