文件版本:v1.0
適用專案:LAH-API(c:\Temp\DEV\LAH-Workspace\LAH-API\)
目標架構:Apache 2.4 (mod_php7+mod_proxy_fcgi) + PM2 託管 PHP 8.5 FastCGI (/v85/) + Oracle 9i / SQLite 3
因應近期 Windows 環境下之 PHP 安全事件(如 PHP2Shell / CVE-2024-4577 等舊版漏洞),本計畫採取風險最低、維運變動最小的**「絞殺者模式(Strangler Fig Pattern)」漸進式升級**:
- 新舊並存目錄(
www/與v85/):- 既有
LAH-API/www/維持 PHP 7.3 / 7.4 原狀運作,確保線上地政業務零中斷。 - 於
LAH-API/API/建立全新 PHP 8.5 專屬目錄,逐支檢視、修正並移植 API。
- 既有
- 伺服器雙軌分流(方案 B:保留 Apache 2.4 +
mod_proxy_fcgi):- 不替換現有 Apache 2.4 服務,因此各地所現有的防火牆規則、SSL 憑證與自動更新部署工具
LAH-Updater/updater.py均無需大幅改動。 - Apache 2.4 繼續以
mod_php7處理舊版/請求;同時啟用 Apache 內建的mod_proxy_fcgi模組,將/LAH-API/(或已移植之 API)透過本機迴路轉發至127.0.0.1:8085的 PHP 8.5 FastCGI 服務。
- 不替換現有 Apache 2.4 服務,因此各地所現有的防火牆規則、SSL 憑證與自動更新部署工具
- 進程高可用守護(PM2 託管
php-cgi.exe):- 由於 Windows 版 PHP 無原生
php-fpm,直接使用各所伺服器已安裝之 PM2 守護C:\AppServ\php85\php-cgi.exe,解決 Windows 下php-cgi.exe滿載自動退出造成的502 Bad Gateway問題。
- 由於 Windows 版 PHP 無原生
flowchart TD
subgraph Clients["前端與桌面客戶端"]
FE["LAH-FE (Nuxt 2 / Node v16)"]
MSG["lah-messenger (Electron)"]
end
subgraph Apache["Apache 2.4 伺服器 (Port 80)"]
ROUTER{"URL 路由判斷"}
MODPHP["mod_php7 (內嵌模組)<br/>PHP 7.3 / 7.4 TS"]
MODFCGI["mod_proxy_fcgi<br/>轉發 fcgi://127.0.0.1:8085"]
end
subgraph PM2Daemon["PM2 進程守護層 (同台伺服器)"]
PM2_FE["PM2: LAH-FE<br/>(Node.js v16)"]
PM2_WS["PM2: lah-messenger-server<br/>(Node.js v16)"]
PM2_PHP85["PM2: lah-api-v85<br/>(php-cgi.exe PHP 8.5 NTS :8085)"]
end
subgraph Codebase["LAH-API 程式碼與共用資料層"]
WWW["LAH-API/www/<br/>(舊版程式碼)"]
V85["LAH-API/API/<br/>(PHP 8.5 程式碼)"]
SHARED["共用資源 (www/.env & www/assets/db/*.db)<br/>SQLite 3 快取與設定庫"]
end
subgraph BackendDB["地所後端資料庫"]
ORA9I[("Oracle 9i<br/>核心地政資料庫")]
MSSQL[("MS SQL Server<br/>舊公文/差勤庫")]
end
FE & MSG -- "HTTP 請求" --> ROUTER
ROUTER -- "舊路徑 /api/*" --> MODPHP
ROUTER -- "新路徑 /LAH-API/v1/*<br/>(相容 /api/*)" --> MODFCGI
MODPHP --> WWW
MODFCGI --> PM2_PHP85
PM2_PHP85 --> V85
WWW & V85 --> SHARED
WWW & V85 --> ORA9I & MSSQL
您擔心:「伺服器上的 Node.js 因 LAH-FE (Nuxt 2) 限制鎖在 v16,若要用 PM2 管理 PHP 8.5 服務,是否需要用 nvm 克服?」
- 為什麼不需要為了 PHP 8.5 升級 Node.js?
- PM2 雖然本身是用 Node.js 寫的守護程式,但當它管理非 Node.js 程式(如
php-cgi.exe、Python、Go 執行檔)時,只需在設定檔指定interpreter: "none"。 - 此時 PM2 只負責透過 Windows OS API 啟動
C:\AppServ\php85\php-cgi.exe、監聽其 Process ID (PID),並在它崩潰或退出時於 100 毫秒內自動重啟。 - 因此,您現有跑在 Node.js v16 上的 PM2,可以直接把 PHP 8.5 (
php-cgi.exe) 納管進同一個pm2 list面板中,跟LAH-FE(Node 16) 完全相安無事!
- PM2 雖然本身是用 Node.js 寫的守護程式,但當它管理非 Node.js 程式(如
如果您未來因為其他專案或新版工具,想在同一台 Windows 伺服器安裝 nvm-windows,千萬不要在背景服務依賴 nvm use <version> 指令!
⚠️ nvm-windows的底層陷阱: 在 Windows 上,執行nvm use 22的原理是把系統全域捷徑C:\Program Files\nodejs指到 v22 目錄。如果此時LAH-FE被 PM2 自動重啟,它就會誤抓到 Node 22 而啟動失敗!- ✅ 正確的
nvm-windows+ PM2 多版本共存做法: 用nvm install 16.20.2與nvm install 22.14.0下載好各版本後,在 PM2 的ecosystem.config.js中,直接將interpreter指向該版本node.exe的實體絕對路徑,繞過全域捷徑:
// 檔案位置範例:c:\Temp\DEV\LAH-Workspace\LAH-API\API\ecosystem.config.js
module.exports = {
apps: [
// 1. 新增的 LAH-API v85 (PHP 8.5 FastCGI 服務)
{
name: "lah-api-v85",
script: "C:\\AppServ\\php85\\php-cgi.exe",
args: "-b 127.0.0.1:8085 -c C:\\AppServ\\php85\\php.ini",
cwd: __dirname, // 自動取得目錄(各所伺服器與開發筆電 Junction 皆為 C:\\AppServ\\LAH-API),
interpreter: "none", // 關鍵:告知 PM2 這是原生 .exe,不透過 node 執行
exec_mode: "fork", // 關鍵限制:PM2 cluster 僅支援 Node.js;原生 .exe 設 cluster 會因監聽同 Port 衝突 (EADDRINUSE) 崩潰,故必須使用 fork 模式
instances: 1, // PM2 僅需守護 1 個主父程序,內部多程序併發完全交由下方的 PHP_FCGI_CHILDREN 接管
autorestart: true, // 當達到記憶體上限或主程序異常退出時,PM2 立即於 100ms 內無縫重啟
watch: false,
max_memory_restart: "1G",
env: {
// 將 Oracle Instant Client 注入環境變數
PATH: "C:\\Tools\\instantclient_11_2;C:\\AppServ\\php85;" + process.env.PATH,
NLS_LANG: "American_America.US7ASCII",
// FastCGI 核心併發參數:
// 1. PHP_FCGI_CHILDREN: 父程序會在 Windows 底層衍生 16 個 worker 子程序共享 Port 8085(實測共 17 個 php-cgi.exe,約佔 400MB RAM)
// 2. PHP_FCGI_MAX_REQUESTS: 每個 worker 滿 10000 次請求自動平滑退出並由父程序重建,消除記憶體洩漏
PHP_FCGI_CHILDREN: "16",
PHP_FCGI_MAX_REQUESTS: "10000"
}
}
/*
// (補充範例) 若同台機器透過 nvm-windows 跑不同 Node 版本的服務,直接綁定實體路徑即可:
,{
name: "lah-fe-nuxt2",
script: "node_modules/nuxt/bin/nuxt.js",
args: "start",
cwd: "C:\\Temp\\DEV\\LAH-Workspace\\LAH-FE",
interpreter: "C:\\Users\\Administrator\\AppData\\Roaming\\nvm\\v16.20.2\\node.exe"
}
*/
]
};💡 核心結論:PM2 的
cluster模式「不適用」於原生 FastCGI 程式,必須使用fork模式!
但這絕不代表系統只有單執行緒處理能力。FastCGI 是透過環境變數PHP_FCGI_CHILDREN在 Windows 底層原生建立多程序處理池來達成高併發。
-
為什麼 PM2
cluster模式無法用於php-cgi.exe?- Node.js 專屬機制:PM2 的 Cluster Mode 是基於 Node.js 核心的
cluster模組(以 IPC channel 共享 Server Handle)。當指定interpreter: "none"執行原生 Windows 二進位檔時,PM2 無法注入 Node.js 的 Cluster 機制。 - Port 衝突崩潰 (EADDRINUSE):若在 PM2 強制設定
instances: 2以上,PM2 會啟動兩個獨立的php-cgi.exe同時嘗試bind()監聽127.0.0.1:8085,第二個程序會立即觸發 Windows 網路錯誤WSAEADDRINUSE (Error 10048: 通訊端位址已被佔用)而陷入不斷重啟崩潰迴圈。
- Node.js 專屬機制:PM2 的 Cluster Mode 是基於 Node.js 核心的
-
FastCGI 在 Windows 上的真正併發機制:
PHP_FCGI_CHILDREN- 由 PM2 守護 1 個
php-cgi.exe主父程序(負責 PID 監控與崩潰自動恢復)。 - 在啟動時注入環境變數
PHP_FCGI_CHILDREN: "16",父程序會在 Windows 核心底層安全共享 Socket 句柄,自動衍生 16 個 worker 子程序(實機以Get-Process php-cgi驗證共 17 個程序在線)。 - 記憶體與效能實測:每個
php-cgi.exe約佔 24MB,17 個程序合計僅耗用約 400MB 記憶體,可同時平行處理 16 條 HTTP 請求。 - 防記憶體洩漏機制:配合
PHP_FCGI_MAX_REQUESTS: "10000",任一子程序處理滿 10,000 次請求後會自動平滑退出,並由父程序無縫重啟,徹底消除 Windows 下 FastCGI 長期運行的記憶體洩漏風險。
- 由 PM2 守護 1 個
- Oracle 9i 伺服器的限制:
Oracle 官方自 Instant Client 12c 起,在底層
oci.dll移除了對 Oracle 9i (9.2) 的網路協定支援。只要用 12c / 19c Client 連 Oracle 9i,必定拋出:ORA-03134: Connections to this server version are no longer supported.因此,連線至 Oracle 9i 唯一合法的客戶端只有instantclient_11_2(11.2.0.4)。 - PHP 8.5 Windows 官方 DLL 的限制:
- PHP 8.4 / 8.5 官方預編譯套件僅提供
php_oci8_12c.dll與php_oci8_19.dll(不再提供預編譯的php_oci8_11g.dll)。 - 經二進位拆解驗證,
php_oci8_12c.dll在啟動時會強制向oci.dll尋找 Oracle 12c 才新增的 C 函式OCIStmtGetNextResult。 - 由於
instantclient_11_2\oci.dll沒有該函式,PHP 8.5 載入php_oci8_12c.dll配instantclient_11_2時會直接失敗。
- PHP 8.4 / 8.5 官方預編譯套件僅提供
由於 LAH-API 所有 Oracle 查詢 100% 封裝於 www/include/OraDB.class.php 單一類別中,我們在 v85/include/OraDB.class.php 設計**「智慧雙模連線」**,讓您完全不必被 DLL 卡住:
flowchart LR
API85["v85/api/*.php<br/>(運行於 PHP 8.5)"] --> ORADB["v85/include/OraDB.class.php<br/>(智慧雙模封裝)"]
ORADB -- "情況 1:若已放入自編譯<br/>php_oci8_11g.dll" --> NATIVE["PHP 8.5 原生 oci_connect()<br/>直連 instantclient_11_2"]
ORADB -- "情況 2:預設免編譯模式<br/>(透過本機 127.0.0.1 內部呼叫)" --> BRIDGE["本機 Apache PHP 7.4<br/>内部執行 SQL 並回傳 JSON"]
NATIVE & BRIDGE --> ORA9I[("Oracle 9i 資料庫")]
| 方案選項 | 運作方式 | 優缺點與適用時機 |
|---|---|---|
| 方案 1(推薦起步): 本機 127.0.0.1 內部橋接模式 |
在雙軌並行期間,Apache 本來就有載入 mod_php7 + instantclient_11_2。當 v85/ (PHP 8.5) 的 OraDB.class.php 發現環境未載入 oci8 時,自動將 SQL 與 Bind 參數透過本機迴路 http://127.0.0.1/internal_ora_bridge.php(僅限 127.0.0.1 存取)交由 PHP 7 查出結果並轉回陣列。 |
✅ 零編譯成本、5 分鐘搞定。 ✅ 對外 API、Session、檔案處理、SQLite 快取 100% 跑在 PHP 8.5。 ✅ 所有 30 支業務 API 程式碼與 SQL :bv_ 綁定一行都不用改! |
| 方案 2(純 PHP 8.5 免編譯): Windows ODBC 橋接 ( pdo_odbc) |
在 instantclient_11_2 安裝官方 instantclient-odbc-windows.x64-11.2.0.4.0.zip,PHP 8.5 開啟內建的 extension=odbc 與 extension=pdo_odbc,透過 Windows odbc32.dll 呼叫 11.2 Driver 連 Oracle 9i。 |
✅ 可完全移除 PHP 7,純 PHP 8.5 單一進程運作。v85/include/OraDB.class.php 內將 :bv_name 自動轉為 ? 位置參數。 |
| 方案 3(純 PHP 8.5 原生): VS2022 自編譯 php_oci8_11g.dll |
下載 PECL oci8-3.4.x C 原始碼(內部仍保留 #if OCI_MAJOR_VERSION >= 12 判斷),使用 Visual Studio 2022 + instantclient_11_2\sdk 編譯出 PHP 8.5 專用之 php_oci8_11g.dll。 |
✅ 效能最高、100% 原生 oci_* 函式。 |
在漸進移植期間,部分 API 跑在 www/ (PHP 7),部分 API 跑在 v85/ (PHP 8.5)。若兩邊各自擁有一份 SQLite 資料庫(dimension.db、cache.db、RKEYN.db),會造成使用者權限、系統設定與快取不同步。因此,v85/ 僅隔離 PHP 程式碼與 vendor/,底層資料一律指向 www/:
c:\Temp\DEV\LAH-Workspace\LAH-API\
├── www/ # [既有 PHP 7 目錄] 維持現狀
│ ├── .env # ★ 共用環境變數檔 (MOCK=true 等)
│ ├── assets/
│ │ ├── db/ # ★ 共用 SQLite 資料庫 (LAH.db, dimension.db, cache.db)
│ │ ├── files/ # ★ 共用 SQL 樣板 (.tpl)
│ │ └── xlsx/ # ★ 共用 Excel 匯出樣板
│ ├── log/ # ★ 共用日誌目錄
│ ├── include/ # 舊版 PHP 7 類別庫
│ └── api/ # 舊版 PHP 7 API 端點
│
└── v85/ # [新版 PHP 8.5 專屬目錄]
├── ecosystem.config.js # PM2 啟動 PHP 8.5 FastCGI 設定檔
├── composer.json # PHP 8.5 專用套件宣告 (PhpSpreadsheet ^2.0)
├── vendor/ # PHP 8.5 專用 Composer 依賴目錄
├── ver.php # PHP 8.5 雙軌健康檢查端點 (/LAH-API/ver.php)
├── include/ # 修正 PHP 8.5 相容性後之核心類別
│ ├── init.php
│ ├── Env.class.php
│ ├── GlobalConstants.inc.php # 定義 V85_ROOT_DIR 與共用 LEGACY_WWW_DIR
│ ├── GlobalFunctions.inc.php
│ ├── System.class.php
│ └── OraDB.class.php
└── v1/ # 逐支移植過來的 API 端點 (/LAH-API/v1/*.php,相容 /api/)
<?php
// v85 專屬程式碼根目錄:c:\Temp\DEV\LAH-Workspace\LAH-API\API
define('V85_ROOT_DIR', dirname(__DIR__));
// 指向既有 www 目錄以共用資料庫與資產:c:\Temp\DEV\LAH-Workspace\LAH-API\www
define('ROOT_DIR', dirname(V85_ROOT_DIR) . DIRECTORY_SEPARATOR . 'www');
// 類別引入走 v85/include,其餘資產與 SQLite 資料庫與 www 完全共用
define('INC_DIR', V85_ROOT_DIR . DIRECTORY_SEPARATOR . 'include');
define('ASSETS_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'assets');
define('EXPORT_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'export');
define('IMPORT_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'import');
define('LOG_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'log');
define('DB_DIR', ASSETS_DIR . DIRECTORY_SEPARATOR . 'db');
define('DEF_SQLITE_DB', DB_DIR . DIRECTORY_SEPARATOR . 'LAH.db');(同時在 v85/include/Env.class.php 中預設讀取 ROOT_DIR . '/.env',即可無縫讀取同一份 www/.env!)
將檔案從 www/ 複製到 v85/ 時,請依下表修正 PHP 8.0 ~ 8.5 的語法不相容與棄用項目:
- 原因:PHP 8.0 起
session_set_cookie_params()傳入陣列時,Key 必須全小寫(寫"SameSite"會報錯),且重複呼叫會互相覆蓋。 - 修改前(
www/include/init.php第 11~14 行):session_set_cookie_params(["SameSite" => "None"]); //none, lax, strict session_set_cookie_params(["Secure" => "false"]); //false, true session_set_cookie_params(["HttpOnly" => "true"]); //false, true session_start();
- 修改後(
v85/include/init.php):session_set_cookie_params([ 'samesite' => 'Lax', 'secure' => false, 'httponly' => true ]); session_start();
- 原因:PHP 8.2 起在雙引號字串中使用
"${var}"($在大括號外)會噴Deprecated: Using ${var} in strings is deprecated, use {$var} instead。 - 受影響檔案清單:
System.class.php(第 626, 633, 640, 646, 652, 658, 664 行): 將(HOST=${ip})(PORT=${port})))(CONNECT_DATA=(SERVICE_NAME=${site}WEB))改為(HOST={$ip})(PORT={$port})))(CONNECT_DATA=(SERVICE_NAME={$site}WEB))。MSDB.class.php(第 48 行):${key}改為{$key}。Logger.class.php(第 99, 101 行):log-${date}.zip改為log-{$date}.zip。GlobalFunctions.inc.php(第 181, 193, 212, 224 行):${zipcreated}改為{$zipcreated}。DocUserInfo.class.php、IPResolver.class.php、Message.class.php、MOIEXP.class.php:全數將${...}替換為{$...}。
| 檔案名稱 | 行號 | 舊寫法(PHP 7.3) | PHP 8.5 修正寫法 | 原因說明 |
|---|---|---|---|---|
OraDB.class.php |
L110, 141, 152 | trigger_error(..., E_USER_ERROR); |
throw new \RuntimeException($e['message']); |
PHP 8.4+ 正式棄用 trigger_error 搭配 E_USER_ERROR |
GlobalFunctions.inc.php |
L130 | imagedestroy($image); |
unset($image);(或直接移除) |
PHP 8.5 最新棄用:GdImage 物件會自動釋放記憶體 |
GlobalFunctions.inc.phpADService.class.phpDGXLandCaseParser.class.phpMOISMS.class.php |
各檔 cURL 結尾處 | curl_close($ch); |
unset($ch);(或直接移除) |
PHP 8.5 最新棄用:CurlHandle 物件自 PHP 8.0 起已改為自動回收,curl_close 在 PHP 8.5 觸發 Deprecated 警告 |
SQLSRV_DataBase.class.php |
L286, 321, 399, 438 | utf8_decode($value) |
mb_convert_encoding($value, 'ISO-8859-1', 'UTF-8') |
PHP 8.2+ 棄用 utf8_decode() |
在保留現有 Apache 2.4 (mod_php7) 的前提下,只需在 httpd.conf 進行以下 2 步微調,即可將 /v85 流量導向 PM2 管理的 PHP 8.5 FastCGI (127.0.0.1:8085):
打開 Apache 的 conf/httpd.conf(參考 LAH-API/httpd.conf-ref 第 148~166 行),確認以下三個模組前方的 # 已移除:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
LoadModule rewrite_module modules/mod_rewrite.so將以下設定區塊加在 httpd.conf 尾端(請依實際路徑調整 c:/Temp/DEV/LAH-Workspace/LAH-API):
# =====================================================================
# LAH-API v85 (PHP 8.5 FastCGI via PM2 on 127.0.0.1:8085) 雙軌設定
# =====================================================================
# 1. 將 /v85 虛擬路徑映射至實體 LAH-API/API 目錄
Alias /LAH-API/api "C:/AppServ/LAH-API/v1"
Alias /lah-api/api "C:/AppServ/LAH-API/v1"
Alias /LAH-API "C:/AppServ/LAH-API"
Alias /lah-api "C:/AppServ/LAH-API"
<Directory "C:/AppServ/LAH-API">
Header set Access-Control-Allow-Origin "*"
Options -Indexes +FollowSymLinks
AllowOverride None
Require all granted
# 關鍵:在 v85 目錄下,攔截所有 .php 請求,改由 PHP 8.5 FastCGI (8085) 處理,不走 mod_php7!
<FilesMatch "\.php$">
# 安全防護:確認實體 .php 檔案存在才轉發,徹底阻絕 CGI 路徑注入 (CVE-2024-4577 等)
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:fcgi://127.0.0.1:8085/"
ProxyFCGISetEnvIf "reqenv('SCRIPT_FILENAME') =~ m#^proxy:fcgi://127\.0\.0\.1:8085/(.*)$#" SCRIPT_FILENAME "$1"
</If>
</FilesMatch>
</Directory>
# 設定 FastCGI 逾時時間為 300 秒(避免跨所大筆地籍查詢 Timeout)
<Proxy "fcgi://127.0.0.1:8085/" enablereuse=on max=16>
ProxySet timeout=300
</Proxy>Tip
進階功能:想讓前端不用改網址就能自動吃到 v85 已移植的 API 嗎?
只要在原本 <Directory ".../LAH-API/www"> 區塊內加上以下 5 行 Rewrite 規則:當前端呼叫 /api/reg_json_api.php 時,Apache 會先偷看 v85/api/reg_json_api.php 存不存在;若存在就自動轉給 PHP 8.5 執行,若還沒搬過去就繼續給原本的 PHP 7 執行!
RewriteEngine On
RewriteCond "c:/Temp/DEV/LAH-Workspace/LAH-API/API%{REQUEST_URI}" -f
RewriteRule ^/(.*\.php)$ "fcgi://127.0.0.1:8085/c:/Temp/DEV/LAH-Workspace/LAH-API/API/$1" [P,L]以下步驟專為您的開發筆電量身打造,與您現有的 C:\AppServ\php7 及 start_dev.bat 完全相容:
- 前往 windows.php.net/download 下載 PHP 8.5 (8.5.x) VS17 x64 Non Thread Safe (NTS)
.zip壓縮包。 - 解壓縮至
C:\AppServ\php85\(確認C:\AppServ\php85\php-cgi.exe存在)。 - 複製
C:\AppServ\php85\php.ini-development為C:\AppServ\php85\php.ini,並修改以下關鍵設定:extension_dir = "ext" date.timezone = "Asia/Taipei" memory_limit = 512M max_execution_time = 300 display_errors = On error_reporting = E_ALL ; 開啟 LAH-API 所需擴充套件 extension=curl extension=fileinfo extension=gd extension=intl extension=mbstring extension=odbc extension=openssl extension=pdo_odbc extension=pdo_sqlite extension=sqlite3 extension=sockets extension=zip
- 在 PowerShell 驗證 PHP 8.5 是否正常運作:
C:\AppServ\php85\php.exe -v C:\AppServ\php85\php.exe -m
- 將先前建立的空目錄
v1重新命名為v85:Rename-Item -Path "c:\Temp\DEV\LAH-Workspace\LAH-API\v1" -NewName "v85"
- 在
c:\Temp\DEV\LAH-Workspace\LAH-API\API\ver.php建立第一支 PHP 8.5 驗證腳本:<?php header('Content-Type: application/json; charset=utf-8'); echo json_encode([ 'status' => 1, 'channel' => 'v85', 'php_version' => PHP_VERSION, 'sapi' => PHP_SAPI, 'extensions' => [ 'pdo_sqlite' => extension_loaded('pdo_sqlite'), 'sqlite3' => extension_loaded('sqlite3'), 'intl' => extension_loaded('intl'), 'curl' => extension_loaded('curl'), 'gd' => extension_loaded('gd'), 'oci8' => extension_loaded('oci8'), 'odbc' => extension_loaded('odbc'), ], 'timestamp' => date('Y-m-d H:i:s') ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
- 將第二章的
ecosystem.config.js存放在c:\Temp\DEV\LAH-Workspace\LAH-API\API\ecosystem.config.js。 - 在 PowerShell 啟動 PM2 服務(直接使用您現有的 Node v16 環境即可):
cd C:\AppServ\LAH-API pm2 start ecosystem.config.js pm2 status - 確認 Port
8085已開始監聽:Get-NetTCPConnection -LocalPort 8085 -State Listen
- 情境 A(筆電已安裝並啟動 Apache 2.4):
依第六章設定好
httpd.conf並重啟 Apache 後,開啟瀏覽器分別測試:http://127.0.0.1/ver.php👉 由舊版mod_php7回應(顯示 PHP 7.3 / 7.4)。http://127.0.0.1/LAH-API/ver.php👉 由 Apachemod_proxy_fcgi轉發給 PM2 的 PHP 8.5 回應(顯示"php_version": "8.5.x","sapi": "cgi-fcgi")!
- 情境 B(筆電平時沒開 Apache,而是用
start_dev.bat內建伺服器): 在筆電日常不開 Apache 時,也可隨時直接用 PHP 8.5 內建伺服器在 Port8085快速測試v85/:瀏覽器打開C:\AppServ\php85\php.exe -S 127.0.0.1:8085 -t c:\Temp\DEV\LAH-Workspace\LAH-API\API
http://127.0.0.1:8085/ver.php即可立即驗證。
- 第一批(系統基底):
v85/include/下的Env.class.php、GlobalConstants.inc.php、GlobalFunctions.inc.php、init.php、System.class.php、OraDB.class.php、Cache.class.php、SQLite*.class.php。 - 第二批(無外部複雜依賴之核心 API):
v85/api/auth_json_api.php(登入與權限驗證)v85/api/query_json_api.php(通用系統看板查詢)v85/api/system_json_api.php(系統設定與代碼同步)
- 第三批(地政核心業務 API):
v85/api/reg_json_api.php(登記案件)v85/api/sur_json_api.php(測量案件)v85/api/moicas_json_api.php(跨所與智慧控管查詢)v85/api/stats_json_api.php、v85/api/notification_json_api.php
- 第四批(含 Composer 外部套件與排程):
- 在
v85/執行C:\AppServ\php85\php.exe composer.phar install安裝新版phpoffice/phpspreadsheet。 - 移植
v85/api/export_xlsx_api.php、v85/api/export_txt_data.php與v85/task/排程腳本。
- 在