<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Cgi on Tarragon</title><link>https://tarrragon.github.io/blog/tags/cgi/</link><description>Recent content in Cgi on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 05 Oct 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/cgi/index.xml" rel="self" type="application/rss+xml"/><item><title>CGI：每個請求啟動一個 PHP 程序的執行模型</title><link>https://tarrragon.github.io/blog/programming/php/01-server-runtime/cgi/</link><pubDate>Mon, 05 Oct 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/programming/php/01-server-runtime/cgi/</guid><description>&lt;p>這篇說明 CGI（Common Gateway Interface）這種執行模型，以及 PHP 用它執行時的行為與成本。它是 &lt;a href="https://tarrragon.github.io/blog/programming/php/01-server-runtime/request-lifecycle-and-sapi/" data-link-title="PHP 的請求生命週期與 SAPI：直譯器的位置、程序壽命與狀態壽命" data-link-desc="說明一個 HTTP 請求怎麼變成一次 PHP 執行：PHP 在程序啟動與每個請求開始、結束時各做什麼，SAPI 這一層介面怎麼讓同一個直譯器接上 CGI、Apache、FastCGI 與常駐伺服器，以及用直譯器住在哪裡、執行它的程序活多久、應用程式的狀態活多久這組問題比較各種執行模型">PHP 的請求生命週期與 SAPI&lt;/a> 那組問題的一組答案：PHP 直譯器住在每個請求新啟動的程序裡，程序與應用程式狀態都只活一個請求。&lt;/p>
&lt;h2 id="cgi-怎麼把請求交給外部程式">CGI 怎麼把請求交給外部程式&lt;/h2>
&lt;p>CGI 是 web 伺服器呼叫外部程式來產生回應的介面，規格寫成 RFC 3875（CGI/1.1），RFC 自己記載這個介面從 1993 年起就在 web 上使用。它跟語言無關：被呼叫的可以是 Perl、C、shell script 或 PHP，早期網站的 &lt;code>cgi-bin/&lt;/code> 目錄放的就是這類程式（見 &lt;a href="https://tarrragon.github.io/blog/devops/infra/knowledge-cards/cgi/" data-link-title="CGI（Common Gateway Interface）" data-link-desc="接手 cgi-bin 目錄或以 php-cgi 執行的舊站，或在 $_SERVER 看到 REQUEST_METHOD、QUERY_STRING 這類大寫鍵名，要知道它們從哪裡來時">CGI&lt;/a>）。&lt;/p>
&lt;p>一個請求經過 CGI 的過程：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>動作者&lt;/th>
 &lt;th>做的事&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>web 伺服器&lt;/td>
 &lt;td>收到請求，判斷這個路徑要交給哪一支程式&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>web 伺服器&lt;/td>
 &lt;td>啟動那支程式的一個新程序（fork 加 exec）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>web 伺服器&lt;/td>
 &lt;td>把請求的資訊放進這個程序的環境變數：&lt;code>REQUEST_METHOD&lt;/code>、&lt;code>QUERY_STRING&lt;/code>、&lt;code>CONTENT_TYPE&lt;/code>、&lt;code>CONTENT_LENGTH&lt;/code>、&lt;code>REMOTE_ADDR&lt;/code>，以及各個 HTTP 標頭&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>web 伺服器&lt;/td>
 &lt;td>把請求的內容（POST 的資料）寫進程序的標準輸入&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>外部程式&lt;/td>
 &lt;td>從環境變數與標準輸入讀到請求，把回應標頭、一個空行與回應內容寫到標準輸出&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>外部程式&lt;/td>
 &lt;td>結束程序&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>web 伺服器&lt;/td>
 &lt;td>把標準輸出的內容整理成 HTTP 回應送回客戶端&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>RFC 3875 把這些環境變數叫做 meta-variables。PHP 的 &lt;code>$_SERVER&lt;/code> 陣列裡那些大寫的鍵（&lt;code>REQUEST_METHOD&lt;/code>、&lt;code>QUERY_STRING&lt;/code>、&lt;code>SCRIPT_FILENAME&lt;/code>）就是從這裡來的，後來的 FastCGI 與 PHP-FPM 沿用了同一套名稱。&lt;/p>
&lt;h2 id="php-以-cgi-執行時的行為">PHP 以 CGI 執行時的行為&lt;/h2>
&lt;p>PHP 提供一支叫 &lt;code>php-cgi&lt;/code> 的程式給 CGI 使用，官方的 PHP Docker 映像檔（&lt;code>php:8.5-cli&lt;/code>）裡就有。下面用 lighttpd 當 web 伺服器，設定所有 &lt;code>.php&lt;/code> 結尾的請求都交給 &lt;code>php-cgi&lt;/code> 執行：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl"># lighttpd.conf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">server.document-root = &amp;#34;/var/www/html&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">server.modules = ( &amp;#34;mod_cgi&amp;#34; )
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"># 副檔名對應到要執行的程式：每個 .php 請求都啟動一個 php-cgi 程序
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">cgi.assign = ( &amp;#34;.php&amp;#34; =&amp;gt; &amp;#34;/usr/local/bin/php-cgi&amp;#34; )&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>server.document-root&lt;/code> 是網站檔案所在的目錄，&lt;code>cgi.assign&lt;/code> 的右邊是 &lt;code>php-cgi&lt;/code> 在這個環境裡的實際路徑，換到別的系統要用 &lt;code>which php-cgi&lt;/code> 查。對一支印出程序編號與計數器的腳本（腳本內容見 &lt;a href="https://tarrragon.github.io/blog/programming/php/01-server-runtime/request-lifecycle-and-sapi/#%e4%b8%80%e5%80%8b%e8%ab%8b%e6%b1%82%e5%9c%a8-php-%e8%a3%a1%e7%b6%93%e9%81%8e%e7%9a%84%e9%9a%8e%e6%ae%b5" data-link-title="PHP 的請求生命週期與 SAPI：直譯器的位置、程序壽命與狀態壽命" data-link-desc="說明一個 HTTP 請求怎麼變成一次 PHP 執行：PHP 在程序啟動與每個請求開始、結束時各做什麼，SAPI 這一層介面怎麼讓同一個直譯器接上 CGI、Apache、FastCGI 與常駐伺服器，以及用直譯器住在哪裡、執行它的程序活多久、應用程式的狀態活多久這組問題比較各種執行模型">PHP 的請求生命週期與 SAPI&lt;/a>）連續請求四次：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">pid=15 static=1 global=1 sapi=cgi-fcgi
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">pid=16 static=1 global=1 sapi=cgi-fcgi
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">pid=17 static=1 global=1 sapi=cgi-fcgi
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">pid=18 static=1 global=1 sapi=cgi-fcgi&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>每個請求都是一個新的程序。PHP 的兩層生命週期在這裡疊成一層：模組啟動（讀 &lt;code>php.ini&lt;/code>、初始化所有擴充）與請求啟動每個請求都各做一次，請求結束時程序也跟著結束。&lt;/p>
&lt;h3 id="每個請求付出的啟動成本">每個請求付出的啟動成本&lt;/h3>
&lt;p>在同一台電腦、同一支極小的腳本上，循序送 300 個請求，CGI 每個請求的平均時間大約是 PHP-FPM 的七倍（一次量測：8.7 ms 對 1.3 ms）。腳本本身幾乎不花時間，差距來自 CGI 每個請求都要做的事：作業系統建立一個新程序、載入 PHP 的執行檔與共用函式庫、讀設定、初始化每一個擴充。PHP-FPM 的 worker 是常駐的，這些工作在 worker 啟動時做過一次就不再重複。&lt;/p>
&lt;p>確切的倍數隨機器、載入的擴充數量與腳本大小變動，值得帶走的是成本的位置：CGI 的固定成本落在每一個請求上，常駐程序把它攤到很多個請求上。&lt;/p></description><content:encoded><![CDATA[<p>這篇說明 CGI（Common Gateway Interface）這種執行模型，以及 PHP 用它執行時的行為與成本。它是 <a href="/blog/programming/php/01-server-runtime/request-lifecycle-and-sapi/" data-link-title="PHP 的請求生命週期與 SAPI：直譯器的位置、程序壽命與狀態壽命" data-link-desc="說明一個 HTTP 請求怎麼變成一次 PHP 執行：PHP 在程序啟動與每個請求開始、結束時各做什麼，SAPI 這一層介面怎麼讓同一個直譯器接上 CGI、Apache、FastCGI 與常駐伺服器，以及用直譯器住在哪裡、執行它的程序活多久、應用程式的狀態活多久這組問題比較各種執行模型">PHP 的請求生命週期與 SAPI</a> 那組問題的一組答案：PHP 直譯器住在每個請求新啟動的程序裡，程序與應用程式狀態都只活一個請求。</p>
<h2 id="cgi-怎麼把請求交給外部程式">CGI 怎麼把請求交給外部程式</h2>
<p>CGI 是 web 伺服器呼叫外部程式來產生回應的介面，規格寫成 RFC 3875（CGI/1.1），RFC 自己記載這個介面從 1993 年起就在 web 上使用。它跟語言無關：被呼叫的可以是 Perl、C、shell script 或 PHP，早期網站的 <code>cgi-bin/</code> 目錄放的就是這類程式（見 <a href="/blog/devops/infra/knowledge-cards/cgi/" data-link-title="CGI（Common Gateway Interface）" data-link-desc="接手 cgi-bin 目錄或以 php-cgi 執行的舊站，或在 $_SERVER 看到 REQUEST_METHOD、QUERY_STRING 這類大寫鍵名，要知道它們從哪裡來時">CGI</a>）。</p>
<p>一個請求經過 CGI 的過程：</p>
<table>
  <thead>
      <tr>
          <th>動作者</th>
          <th>做的事</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>web 伺服器</td>
          <td>收到請求，判斷這個路徑要交給哪一支程式</td>
      </tr>
      <tr>
          <td>web 伺服器</td>
          <td>啟動那支程式的一個新程序（fork 加 exec）</td>
      </tr>
      <tr>
          <td>web 伺服器</td>
          <td>把請求的資訊放進這個程序的環境變數：<code>REQUEST_METHOD</code>、<code>QUERY_STRING</code>、<code>CONTENT_TYPE</code>、<code>CONTENT_LENGTH</code>、<code>REMOTE_ADDR</code>，以及各個 HTTP 標頭</td>
      </tr>
      <tr>
          <td>web 伺服器</td>
          <td>把請求的內容（POST 的資料）寫進程序的標準輸入</td>
      </tr>
      <tr>
          <td>外部程式</td>
          <td>從環境變數與標準輸入讀到請求，把回應標頭、一個空行與回應內容寫到標準輸出</td>
      </tr>
      <tr>
          <td>外部程式</td>
          <td>結束程序</td>
      </tr>
      <tr>
          <td>web 伺服器</td>
          <td>把標準輸出的內容整理成 HTTP 回應送回客戶端</td>
      </tr>
  </tbody>
</table>
<p>RFC 3875 把這些環境變數叫做 meta-variables。PHP 的 <code>$_SERVER</code> 陣列裡那些大寫的鍵（<code>REQUEST_METHOD</code>、<code>QUERY_STRING</code>、<code>SCRIPT_FILENAME</code>）就是從這裡來的，後來的 FastCGI 與 PHP-FPM 沿用了同一套名稱。</p>
<h2 id="php-以-cgi-執行時的行為">PHP 以 CGI 執行時的行為</h2>
<p>PHP 提供一支叫 <code>php-cgi</code> 的程式給 CGI 使用，官方的 PHP Docker 映像檔（<code>php:8.5-cli</code>）裡就有。下面用 lighttpd 當 web 伺服器，設定所有 <code>.php</code> 結尾的請求都交給 <code>php-cgi</code> 執行：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl"># lighttpd.conf
</span></span><span class="line"><span class="ln">2</span><span class="cl">server.document-root = &#34;/var/www/html&#34;
</span></span><span class="line"><span class="ln">3</span><span class="cl">server.modules = ( &#34;mod_cgi&#34; )
</span></span><span class="line"><span class="ln">4</span><span class="cl"># 副檔名對應到要執行的程式：每個 .php 請求都啟動一個 php-cgi 程序
</span></span><span class="line"><span class="ln">5</span><span class="cl">cgi.assign = ( &#34;.php&#34; =&gt; &#34;/usr/local/bin/php-cgi&#34; )</span></span></code></pre></div><p><code>server.document-root</code> 是網站檔案所在的目錄，<code>cgi.assign</code> 的右邊是 <code>php-cgi</code> 在這個環境裡的實際路徑，換到別的系統要用 <code>which php-cgi</code> 查。對一支印出程序編號與計數器的腳本（腳本內容見 <a href="/blog/programming/php/01-server-runtime/request-lifecycle-and-sapi/#%e4%b8%80%e5%80%8b%e8%ab%8b%e6%b1%82%e5%9c%a8-php-%e8%a3%a1%e7%b6%93%e9%81%8e%e7%9a%84%e9%9a%8e%e6%ae%b5" data-link-title="PHP 的請求生命週期與 SAPI：直譯器的位置、程序壽命與狀態壽命" data-link-desc="說明一個 HTTP 請求怎麼變成一次 PHP 執行：PHP 在程序啟動與每個請求開始、結束時各做什麼，SAPI 這一層介面怎麼讓同一個直譯器接上 CGI、Apache、FastCGI 與常駐伺服器，以及用直譯器住在哪裡、執行它的程序活多久、應用程式的狀態活多久這組問題比較各種執行模型">PHP 的請求生命週期與 SAPI</a>）連續請求四次：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pid=15 static=1 global=1 sapi=cgi-fcgi
</span></span><span class="line"><span class="ln">2</span><span class="cl">pid=16 static=1 global=1 sapi=cgi-fcgi
</span></span><span class="line"><span class="ln">3</span><span class="cl">pid=17 static=1 global=1 sapi=cgi-fcgi
</span></span><span class="line"><span class="ln">4</span><span class="cl">pid=18 static=1 global=1 sapi=cgi-fcgi</span></span></code></pre></div><p>每個請求都是一個新的程序。PHP 的兩層生命週期在這裡疊成一層：模組啟動（讀 <code>php.ini</code>、初始化所有擴充）與請求啟動每個請求都各做一次，請求結束時程序也跟著結束。</p>
<h3 id="每個請求付出的啟動成本">每個請求付出的啟動成本</h3>
<p>在同一台電腦、同一支極小的腳本上，循序送 300 個請求，CGI 每個請求的平均時間大約是 PHP-FPM 的七倍（一次量測：8.7 ms 對 1.3 ms）。腳本本身幾乎不花時間，差距來自 CGI 每個請求都要做的事：作業系統建立一個新程序、載入 PHP 的執行檔與共用函式庫、讀設定、初始化每一個擴充。PHP-FPM 的 worker 是常駐的，這些工作在 worker 啟動時做過一次就不再重複。</p>
<p>確切的倍數隨機器、載入的擴充數量與腳本大小變動，值得帶走的是成本的位置：CGI 的固定成本落在每一個請求上，常駐程序把它攤到很多個請求上。</p>
<h3 id="opcache-在-cgi-下沒有作用">OPcache 在 CGI 下沒有作用</h3>
<p>OPcache 把 PHP 檔案編譯好的 opcode 存在共享記憶體裡，讓之後的請求跳過編譯。它的共享記憶體屬於啟動它的那個程序，程序結束，快取就跟著消失。在 CGI 下印出 OPcache 的統計：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pid=19 opcache_enabled=true cached_scripts=1 hits=0
</span></span><span class="line"><span class="ln">2</span><span class="cl">pid=20 opcache_enabled=true cached_scripts=1 hits=0
</span></span><span class="line"><span class="ln">3</span><span class="cl">pid=21 opcache_enabled=true cached_scripts=1 hits=0</span></span></code></pre></div><p>OPcache 是開著的，每個程序也把腳本編譯進了快取（<code>cached_scripts=1</code>），可是命中次數永遠是 0：下一個請求是新程序，拿到的是一份全新、空白的快取。框架每個請求要載入數百個檔案，這些檔案在 CGI 下每次都要重新編譯。OPcache 與程序壽命的關係在 <a href="/blog/programming/php/01-server-runtime/opcache/" data-link-title="OPcache 與程序壽命：編譯結果的快取在各種執行模型下的效果" data-link-desc="說明 OPcache 快取的是什麼、它存在哪裡，以及為什麼它的效果取決於執行 PHP 的程序活多久：CGI 下命中次數永遠為零、PHP-FPM 的 worker 共用同一份快取；框架請求開與關 OPcache 的延遲差、memory_consumption 與 max_accelerated_files 的估算，以及部署新程式碼時 validate_timestamps 與 revalidate_freq 決定舊版還會執行多久">OPcache 與程序壽命</a> 展開。</p>
<h2 id="cgi-在共享主機上留下來的理由">CGI 在共享主機上留下來的理由</h2>
<p>CGI 的成本這麼高，它在共享主機上用了很久，理由是隔離。每個請求都是一個獨立的程序，所以 web 伺服器可以用不同的使用者身分啟動它。Apache 的 suEXEC 讓 CGI 程式以站台擁有者的帳號執行，而不是 Apache 自己的帳號：</p>
<ul>
<li><strong>站台之間互相看不到檔案</strong>：A 站的 PHP 以 A 的帳號執行，讀不到 B 站的設定檔與資料庫密碼。</li>
<li><strong>檔案權限對得上</strong>：PHP 上傳或產生的檔案屬於站台擁有者，透過 FTP 登入的同一個帳號能修改與刪除它們。</li>
<li><strong>一個請求出錯只影響那一個程序</strong>：記憶體洩漏或當掉都隨程序結束而消失。</li>
</ul>
<p>這組需求是 <a href="/blog/programming/php/01-server-runtime/mod-php/" data-link-title="mod_php：PHP 直譯器嵌進 Apache 程序的執行模型" data-link-desc="說明 mod_php 怎麼把 PHP 直譯器載入 Apache 的每個子程序：為什麼它要搭配 prefork MPM、每個子程序都帶著 PHP 對記憶體與並發的影響、所有站台共用 Apache 的執行帳號、php.ini 與 .htaccess 的設定方式，以及從 mod_php 搬到 PHP-FPM 時 .htaccess 的 php_value 與 .user.ini 的差異">mod_php</a> 在 Apache 官方的 MPM 下做不到的：mod_php 的 PHP 住在 Apache 的程序裡，所有站台都以同一個帳號執行。後來 <a href="/blog/programming/php/01-server-runtime/php-fpm/" data-link-title="PHP-FPM：常駐 PHP worker 的程序管理與主要的調校旋鈕" data-link-desc="說明 PHP-FPM 怎麼管理一群常駐的 PHP worker：pool 怎麼做到每個站台不同執行帳號、pm 的三種開程序策略、max_children 如何決定並發上限與請求排隊、max_requests 定期換掉 worker 控制記憶體、request_terminate_timeout 與 slowlog 怎麼處理跑太久的請求、status 頁怎麼讀，以及每一項對壓測數字的影響">PHP-FPM</a> 用 pool（每個站台一組 worker、各自指定執行帳號）在常駐程序上做到同樣的隔離，共享主機才有理由離開 CGI。</p>
<h2 id="請求資料與程式呼叫參數之間的邊界">請求資料與程式呼叫參數之間的邊界</h2>
<p>CGI 用啟動一支程式的方式處理請求，所以請求的內容有機會被當成「啟動程式的方式」解讀。PHP 在這個邊界上出過一個嚴重的漏洞：CVE-2012-1823。依 NVD 的公告，PHP 5.3.12 與 5.4.2 之前，<code>php-cgi</code> 以 CGI 方式執行時沒有正確處理不含 <code>=</code> 的查詢字串，使查詢字串的內容可能被當成 <code>php-cgi</code> 的命令列選項，進而導致遠端執行程式碼。修正方式是升級到修補過的版本，而這個類型的問題只出現在 PHP 以 CGI 程式被呼叫的部署上。</p>
<p>這類問題在 FastCGI 下不存在同樣的形式：FastCGI 的 PHP 程序早就啟動好了，請求資料走的是協定裡的參數，不會變成程序的啟動參數。PHP 端還有兩個跟 CGI 有關的設定一直保留到今天，<code>cgi.force_redirect</code> 與 <code>cgi.fix_pathinfo</code>，其中 <code>cgi.fix_pathinfo</code> 在 FastCGI 環境仍然影響安全，在 <a href="/blog/programming/php/01-server-runtime/fastcgi/#web-%e4%bc%ba%e6%9c%8d%e5%99%a8%e6%b1%ba%e5%ae%9a-php-%e5%9f%b7%e8%a1%8c%e5%93%aa%e5%80%8b%e6%aa%94%e6%a1%88" data-link-title="FastCGI：讓 web 伺服器與常駐的 PHP 程序溝通的協定" data-link-desc="說明 FastCGI 協定怎麼在 CGI 的基礎上去掉每個請求重啟程序這一點：常駐的應用程式程序、web 伺服器與它之間的連線、一個請求在協定裡的樣子，以及 SCRIPT_FILENAME 由 web 伺服器決定會帶來的安全邊界（cgi.fix_pathinfo 與 try_files）">FastCGI</a> 說明。</p>
<h2 id="cgi-在今天的位置">CGI 在今天的位置</h2>
<p>新部署很少用 CGI 執行 PHP，原因是前面量到的兩件事：每個請求的啟動成本，以及 OPcache 沒有作用。它仍然出現在兩種地方：一些舊的共享主機，以及只需要偶爾執行一支腳本、不值得常駐一個程序的場合。</p>
<p>CGI 的設計有兩項比它本身活得久：環境變數形式的請求資訊（<code>$_SERVER</code> 的鍵名）、「web 伺服器負責 HTTP、外部程式負責產生內容」的分工，都被 FastCGI 原樣繼承。FastCGI 改掉的只有一件事：程序不再每個請求結束，見 <a href="/blog/programming/php/01-server-runtime/fastcgi/" data-link-title="FastCGI：讓 web 伺服器與常駐的 PHP 程序溝通的協定" data-link-desc="說明 FastCGI 協定怎麼在 CGI 的基礎上去掉每個請求重啟程序這一點：常駐的應用程式程序、web 伺服器與它之間的連線、一個請求在協定裡的樣子，以及 SCRIPT_FILENAME 由 web 伺服器決定會帶來的安全邊界（cgi.fix_pathinfo 與 try_files）">FastCGI</a>。</p>
]]></content:encoded></item></channel></rss>