2019年10月28日 星期一

PHP 與伺服器之間的應用程式介面 (Server Application Programming Interface, SAPI)

PHP 和伺服器之間的應用程式介面 (Application Programming Interface, API) 可分為四種,分別為:共用閘道介面 (Common Gateway Interface, CGI)、伺服器應用程式介面 (Server Application Programming Interface, SAPI)、快速共用閘道介面 (Fast Common Gateway Interface, FastCGI)、以及命令列介面 (Command Line Interface, CLI) 等。透過這四種 API,可以在伺服器上執行 PHP 程式。

CGI

共用閘道介面 (Common Gateway Interface, CGI) 是一個用來在網頁伺服器上執行外部應用程式的標準協定 (Protocol)。早期要經由網頁伺服器執行其它的應用程式都需要透過 CGI。例如,當網頁服務收到具有 php 副檔名的頁面請求時,會啟動一個執行 php-cgi 的程序來處理 .php 網頁,並在網頁內容執行完畢後關閉該程序。


CGI 模式的執行流程為:
網頁伺服器收到請求 -> 啟動 php-cgi 程序 -> php-cgi 處理請求 -> 關閉 php-cgi


使用 CGI 的好處是穩定,當 PHP 網頁發生執行錯誤時只會影響 php-cgi,其它的程序不會受到影響。CGI 的主要缺點是執行效能,在每一次收到一個新的請求時,都要啟動一個執行 php-cgi 的程序,這個程序需要載入 PHP 的相關設定檔案以及所有的擴充。這樣的過程需要花費較多的時間以及伺服器資源。因此 Fork-and-Execute 模式成為 CGI 最為人所詬病的一個缺點。

SAPI

根據維基百科,伺服器應用程式介面 (Server Application Programming Interface, SAPI) 是網頁伺服器的直接模組介面,是一種由網頁伺服器所提供的應用程式介面,用來擴展網頁伺服器的功能1

不同的網頁伺服器所提供的介面並不相容,因此應用程式需要針對不同的網頁伺服器開發專用的 SAPI 模組 (因此 SAPI 模式也被稱為模組模式)。例如,PHP 針對 IIS2 以及 httpd3 等都有相對應的 SAPI 模組。SAPI 模組使用直接模組介面,所以只要將模組資訊寫入網頁伺服器的設定檔中,在網頁伺服器啟動時就會被載入。例如,將下列 PHP SAPI 模組資訊寫入 Apache HTTP Server (httpd) 的設定檔 httpd.conf 中,當重新啟動 httpd 時,PHP 的 SAPI 模組就會被載入:
LoadModule php7_module /usr/local/opt/php/lib/httpd/modules/libphp7.so


模組模式的執行流程為:
網頁伺服器收到請求 -> php 模組


使用 SAPI 模組執行 PHP 意謂著 PHP 會在網頁伺服器的程序中執行,而不再需要針對每個請求啟動一個新的程序。例如,當 httpd 採用 Prefork 模式4時,在啟動時就會預先 fork 一些子程序來等待請求,當有新的請求出現時,httpd 會調用閒罝的子程序來回應請求。這樣的過程可以減少啟動新程序所花費的時間以及降低伺服器的負載。

穩定性是使用 SAPI 模組會遭遇到的最大問題。因為 PHP 在網頁伺服器的程序中執行,當 PHP 應用程式出問題時,可能會使得網頁伺服器發生當機的情況。當 PHP 在執行時具有網頁伺服器程序的所有權限,這也會造成資訊安全問題。最後,目前除了 httpd 之外,主流的網頁伺服器皆不支援 SAPI 模組。


註1. SAPI 有時也泛指伺服器與應用程式之間的 API,因此除了 SAPI 外,CGI、FastCGI、以及 CLI 等也都可以視為是不同類型的 SAPI。
註2. IIS 上的 SAPI 被稱為 ISAPI,ISAPI 的擴充都是實作成為 DLLs,會被載入由 IIS 控制的程序中。從 IIS 7.0 開始,已經統一改用 FastCGI,而不建議使用 ISAPI。
註3. httpd 2.x 上的 SAPI 稱為 Apache 2.0 Handler。
註4. Prefork 是 httpd 的一種 MPM,相關介紹介請參考


FastCGI


和 CGI 相同,快速共用閘道介面 (Fast Common Gateway Interface, FastCGI) 也是一個協定;它是 CGI 的加強版,不僅保留了 CGI 的好處,而且還提升了 CGI 的性能。FastCGI 將 CGI 應用程式包裝起來,並且使用 FastCGI 伺服器來建立程序並且管理從網頁伺服器送來的請求。

FastCGI 的運作機制為,當系統啟動 FastCGI 伺服器時,會建立一個主要程序 (Master Process),Master Process 會建立多個稱為工作者 (Worker) 的子程序;當收到請求時,網頁伺服器可以透過插座 (Socket) 或是 TCP 連線跟 FastCGI 模組進行通信;Master Process 會選擇一個閒置的 Worker Process 處理並回應請求,處理完畢後 Worker Process 會回到閒置狀態,而不是結束行程。當 Worker Process 不夠時,Master Process 可以動態配罝新的 Worker Process;當有過多的 Worker Process 閒置時,則可以適度的終止 Worker Process。這樣的機制可以解決 CGI 需要反覆的建立程序的缺點。


FastCGI 模式的執行流程為:
網頁伺服器收到請求 -> 主要程序 -> 工作者子程序


PHP-FPM(FastCGI Process Manager)是 PHP 實作 FastCGI 的管理套件。通常 PHP 在搭配 httpd 使用時,預設會使用 Prefork 加上 SAPI 的方式。但是如果基於效能考量,httpd 可以使用 Event 模組,再搭配使用 PHP-FPM。


CLI

PHP 的命令列介面 (Command Line Interface, CLI) 主要的用途是開發 Shell 應用程式。通常我們在終端機執行的 PHP Script 就是透過 CLI。例如,我們可透過下列的指令查詢 PHP 的版本以及所使用的 SAPI 為何:
php -v


PHP 7.3.10 (cli) (built: Sep 30 2019 19:59:54) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.10, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.10, Copyright (c) 1999-2018, by Zend Technologies


在版本號碼 7.3.10 後面的 (cli),表示在終端機執行的 PHP 是使用 CLI SAPI。


CLI 模式的執行流程為:
終端機輸入請求 -> CLI SAPI


大部份的腳本語言 (Script Language) 都有提供交互模式,進行簡易的程式執行與測試。從 PHP 5.1.0 開始,藉由 php -a 指令,CLI SAPI 提供了交互模式:
php -a
Interactive shell


我們可以在互動模式下執行程式或內建的函數:
php > phpinfo();


要結束交互模式可以使用 control+z 或是 control+c 組合鍵。


從 PHP 5.4.0 開始,CLI SAPI 還提供一個簡單的內建網頁伺服器,供使用者進行簡單的 PHP 網頁程式開發測試。不過,這個伺服器在執行時僅使用單一執行緒程序,如果有請求受阻時,應用程式將會停滯。使用下列的指令可以執行內建網頁伺服器:
php -S localhost:8000



終端機會有下列的訊息:
PHP 7.3.11 Development Server started at Wed Oct 30 16:36:39 2019
Listening on http://localhost:8000
Document root is /usr/local/Cellar/httpd/2.4.41_1
Press Ctrl-C to quit.



結論


要使用 PHP 開發 Shell 應用程式或是進行簡易的程式測試與除錯,可以選擇 CLI;如果是要用來做為網頁應用程式開發使用,則可以使用 SAPI 或是 FastCGI。CGI 因為效能較差,再加上目前主流的網頁伺服器都支援具有增強功能的 FastCGI,因此已經較少人使用。


在使用 httpd + PHP + MySQL 開發網頁應用時,目前多數的套件預設為使用 SAPI,在設定上也較為簡單,所以初學者適合使用 SAPI。但是如果是使用 nginx 或是 IIS 做為網頁伺服器,或是重視應用程式的效能,則需要使用 FastCGI。

沒有留言: