

<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>php &#8211; Max的程式語言筆記</title>
	<atom:link href="https://stackoverflow.max-everyday.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>https://stackoverflow.max-everyday.com</link>
	<description>我要當一個豬頭，快樂過每一天</description>
	<lastBuildDate>Fri, 29 May 2026 10:42:50 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://stackoverflow.max-everyday.com/wp-content/uploads/2017/02/max-stackoverflow-256.png</url>
	<title>php &#8211; Max的程式語言筆記</title>
	<link>https://stackoverflow.max-everyday.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>php get more detail error message</title>
		<link>https://stackoverflow.max-everyday.com/2026/05/php-get-more-detail-error-message/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/05/php-get-more-detail-error-message/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Fri, 29 May 2026 10:42:50 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8502</guid>

					<description><![CDATA[error_log = C:\Windows\T...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">error_log = C:\Windows\Temp\php_errors.log</p>



<p class="wp-block-paragraph">或直接搜尋：</p>



<p class="wp-block-paragraph">php -i | findstr error_log</p>



<p class="wp-block-paragraph">Config.php 裡的 error_log(&#8216;CloudRun Debug: …&#8217;) 就會寫到這裡，可以直接看 isCloudRun 回傳了什麼。</p>



<ol start="3" class="wp-block-list">
<li>IIS Log C:\inetpub\logs\LogFiles\W3SVC1\</li>



<li>臨時開啟 PHP 錯誤顯示（只在排查時用，用完關掉）</li>
</ol>



<p class="wp-block-paragraph">在 D:\your-project\api.php 最上方取消這行的注解：</p>



<p class="wp-block-paragraph">ini_set(&#8220;display_errors&#8221;,&#8221;On&#8221;); // 原本是被注解掉的</p>



<p class="wp-block-paragraph">這樣瀏覽器/API response 就會直接顯示 PHP fatal error 內容。</p>



<ol start="5" class="wp-block-list">
<li>直接打 health check endpoint GET https://your-server/portal/health.php</li>
</ol>



<p class="wp-block-paragraph">這不會載入 Config，可以確認 PHP 本身有沒有問題。</p>



<p class="wp-block-paragraph">最快的方法：看 php_errors.log，搜尋 CloudRun Debug，就能立刻看到 CONTAINER_APP_NAME 當前值是什麼，確認 isCloudRun 的判斷結果。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/05/php-get-more-detail-error-message/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>php vendor 不存在造成 500 Error</title>
		<link>https://stackoverflow.max-everyday.com/2026/05/php-vendor-500-error/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/05/php-vendor-500-error/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Fri, 29 May 2026 10:32:11 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8500</guid>

					<description><![CDATA[如果 vendor/ 目錄一直都不存在，那這支 ...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">如果 <code>vendor/</code> 目錄一直都不存在，那這支 API 應該從第一天起就直接炸 500 錯誤，而不是「最近才壞掉」。</p>



<p class="wp-block-paragraph">不過，在 IIS 這種 Windows 環境下，<strong>「原本好好的，突然變 500」</strong> 通常有兩種最大的可能性：</p>



<ol start="1" class="wp-block-list">
<li><strong>有人更新了代碼（例如新增了套件），但伺服器端沒有同步執行 <code>composer update</code> 或 <code>composer install</code></strong>，導致 autoload 找不到新類別。</li>



<li><strong>權限問題或 PHP 設定跑掉了</strong>（Windows 更新或 IIS 重啟有時會搞鬼）。</li>
</ol>



<p class="wp-block-paragraph">不論是哪種情況，我們都可以直接進 Windows Server 確認 <code>vendor</code> 的狀態並進行修復。以下是具體的檢查與安裝步驟：</p>



<h2 class="wp-block-heading">步驟一：檢查 <code>vendor</code> 目錄是否存在與權限</h2>



<ol start="1" class="wp-block-list">
<li><strong>遠端連線 (RDP)</strong> 登入你的 Windows Server。</li>



<li>開啟 <strong>檔案總管</strong>，導向到你 IIS 網站的實體路徑（例如 <code>C:\inetpub\wwwroot\your-project\</code>）。</li>



<li><strong>檢查是否存在 <code>vendor</code> 資料夾：</strong>
<ul class="wp-block-list">
<li><strong>如果不存在：</strong> 代表真的沒安裝，必須補跑安裝（見步驟二）。</li>



<li><strong>如果存在：</strong> 點進去看看有沒有 <code>autoload.php</code>。如果有，請右鍵點擊 <code>vendor</code> 資料夾 -> <strong>內容</strong> -> <strong>安全性</strong>，確認 IIS 的讀取權限（通常是 <code>IIS_IUSRS</code> 或 <code>IUSR</code>）沒有被搞丟。</li>
</ul>
</li>
</ol>



<h2 class="wp-block-heading">步驟二：在 Windows Server 上安裝/執行 Composer</h2>



<p class="wp-block-paragraph">如果確定需要執行 <code>composer install</code>，請依照以下步驟在伺服器上操作：</p>



<h3 class="wp-block-heading">1. 確認伺服器是否有安裝 Composer</h3>



<p class="wp-block-paragraph">開啟伺服器的 <strong>Command Prompt (CMD)</strong> 或 <strong>PowerShell</strong>，輸入：</p>



<p class="wp-block-paragraph">Bash</p>



<pre class="wp-block-code"><code>composer --version
</code></pre>



<ul class="wp-block-list">
<li><strong>有顯示版本：</strong> 太棒了，可以直接用。</li>



<li><strong>顯示找不到指令：</strong> 代表伺服器沒裝 Composer。請到 <a href="https://getcomposer.org/download/" target="_blank" rel="noreferrer noopener">Composer 官網</a> 下載 <code>Composer-Setup.exe</code> 並直接在伺服器上執行安裝。安裝過程中它會自動偵測你 IIS 目前使用的 <code>php.exe</code> 路徑。</li>
</ul>



<h3 class="wp-block-heading">2. 執行安裝或更新指令</h3>



<p class="wp-block-paragraph">在 CMD / PowerShell 中，切換到你的專案根目錄（<code>api.php</code> 所在目錄的上一層，也就是看得到 <code>composer.json</code> 的那層）：</p>



<p class="wp-block-paragraph">PowerShell</p>



<pre class="wp-block-code"><code># 切換到專案目錄 (路徑請根據實際狀況修改)
cd C:\inetpub\wwwroot\your-project

# 如果 vendor 完全不存在，或者你想嚴格還原當初測試成功的套件版本：
composer install --no-dev --optimize-autoloader

# 如果 vendor 存在，但懷疑是有人加了新套件沒同步：
composer update --no-dev --optimize-autoloader
</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>小提示：</strong> <code>--no-dev</code> 可以避免把開發用的測試套件（如 PHPUnit）裝到生產環境，<code>--optimize-autoloader</code> 則能提升 PHP 在 IIS 上的效能。</p>
</blockquote>



<h2 class="wp-block-heading">步驟三：如果 <code>vendor</code> 沒問題，如何抓出真正的 500 錯誤原因？</h2>



<p class="wp-block-paragraph">如果跑完 Composer 還是 500，或者發現 <code>vendor</code> 本來就是好的，那就必須叫 IIS 把隱藏的錯誤訊息吐出來，別再抓瞎了：</p>



<h3 class="wp-block-heading">1. 修改 <code>web.config</code> 顯示詳細錯誤</h3>



<p class="wp-block-paragraph">在專案根目錄下找到（或建立）<code>web.config</code> 檔案，確保 <code>&lt;system.webServer&gt;</code> 區段內有以下設定，這樣 IIS 才會把 PHP 的白畫面或詳細報錯傳回給瀏覽器：</p>



<p class="wp-block-paragraph">XML</p>



<pre class="wp-block-code"><code>&lt;configuration&gt;
  &lt;system.webServer&gt;
    &lt;httpErrors errorMode="Detailed" /&gt;
  &lt;/system.webServer&gt;
&lt;/configuration&gt;
</code></pre>



<h3 class="wp-block-heading">2. 檢查 PHP 錯誤日誌 (php_errors.log)</h3>



<p class="wp-block-paragraph">開啟你伺服器上的 <code>php.ini</code> 檔案，搜尋以下兩行，確認它們沒有被註解（拿掉前面的 <code>;</code>）：</p>



<p class="wp-block-paragraph">Ini, TOML</p>



<pre class="wp-block-code"><code>log_errors = On
error_log = "C:\inetpub\temp\PHP_errors.log" ; (或者是你指定的任何路徑)
</code></pre>



<p class="wp-block-paragraph">修改後記得去 <strong>IIS 管理員 (IIS Manager)</strong> 重新啟動網站，然後直接去該路徑打開 log 檔案。裡面絕對會清清楚楚寫著到底是哪一行程式碼（例如 <code>Fatal error: Class '...' not found in api.php on line 10</code>）導致 500 錯誤的！</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">破案了！你貼出的這段 <code>autoload.php</code> 原始碼，直接把最關鍵的線索攤在陽光下了。</p>



<p class="wp-block-paragraph">請注意這一段程式碼：</p>



<p class="wp-block-paragraph">PHP</p>



<pre class="wp-block-code"><code>if (PHP_VERSION_ID &lt; 50600) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    $err = 'Composer 2.3.0 dropped support for autoloading on PHP &lt;5.6 ... Aborting.';
    // ...
    throw new RuntimeException($err);
}
</code></pre>



<p class="wp-block-paragraph">這意味著：<strong>如果這台伺服器目前的 PHP 版本低於 5.6（例如 5.5, 5.4 甚至更舊），Composer 就會直接中斷執行，並主動噴出一個 <code>500 Internal Server Error</code>！</strong></p>



<p class="wp-block-paragraph">根據你提供的目錄列表，<code>vendor</code> 資料夾跟裡面的套件確實都存在（最後更新時間停在 2025 年 11 月左右）。這代表問題<strong>不是缺檔案</strong>，而是以下兩種可能性最高：</p>



<h3 class="wp-block-heading">可能性 1：這台 IIS 伺服器的 PHP 版本低於 5.6</h3>



<p class="wp-block-paragraph">如果最近有人動過 IIS 的 PHP 版本設定（例如降級、或者是處理了其他網站導致預設 PHP 版本跑掉），只要當前執行的 PHP 版本小於 5.6，就會完美觸發這個 500 錯誤。</p>



<ul class="wp-block-list">
<li><strong>如何驗證：</strong>在 <code>D:\</code>your-project<code>\</code> 下建立一個臨時的 <code>test.php</code>，內容寫：PHP<code>&lt;?php phpinfo(); </code>在瀏覽器打開這個網頁，確認最上方顯示的 <strong>PHP Version</strong> 是多少。如果是 5.5 以下，你就找到兇手了！請將 IIS 的 PHP 版本切換回 7.x 或 8.x。</li>
</ul>



<h3 class="wp-block-heading">可能性 2：代碼更新了，但 <code>vendor</code> 卻是舊的（2025年的遺物）</h3>



<p class="wp-block-paragraph">你看一下目錄列表，大部份套件的日期都停在 <strong>2025/09</strong> 或 <strong>2025/11</strong>。</p>



<p class="wp-block-paragraph">如果最近（2026年）有人更新了 <code>main</code> 分支的程式碼，並在 <code>composer.json</code> 裡面<strong>新增了套件</strong>、或者是<strong>升級了某些套件</strong>，但伺服器上的 <code>vendor</code> 資料夾卻一直停留在半年前的舊狀態。</p>



<p class="wp-block-paragraph">當 <code>api.php</code> 想要調用新版程式碼或新套件時，就會因為舊的 <code>vendor</code> 找不到類別而直接崩潰（500 錯誤）。</p>



<ul class="wp-block-list">
<li><strong>如何修正：</strong>直接在伺服器上同步更新 <code>vendor</code>。
<ol start="1" class="wp-block-list">
<li>開啟 CMD 或 PowerShell。</li>



<li>切換到專案根目錄：PowerShell<code>cd D:\your-project</code></li>



<li>執行更新指令（讓 <code>vendor</code> 同步成目前 <code>composer.json</code> 要求的最新狀態）：PowerShell<code>composer install --no-dev --optimize-autoloader </code><em>(如果沒有安裝 composer 指令，請參考前一次回覆下載安裝，或直接把開發環境整包最新、能跑的 <code>vendor</code> 資料夾打包，覆蓋到伺服器的 <code>D:\portal-backend\backend\vendor</code>)</em></li>
</ol>
</li>
</ul>



<h3 class="wp-block-heading">總結你的下一步</h3>



<ol start="1" class="wp-block-list">
<li>先檢查 <code>phpinfo()</code>，確定 PHP 版本大於 5.6。</li>



<li>只要版本沒問題，<strong>直接在 <code>D:\</code></strong>your-project<strong> 底下重新跑一次 <code>composer install</code></strong>。這有 90% 的機率能直接解決這個最近才出現的 500 錯誤！</li>
</ol>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/05/php-vendor-500-error/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>github CodeQL 支援 PHP 嗎?</title>
		<link>https://stackoverflow.max-everyday.com/2026/04/codeql-%e6%94%af%e6%8f%b4-php-%e5%97%8e/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/04/codeql-%e6%94%af%e6%8f%b4-php-%e5%97%8e/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 00:11:51 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8246</guid>

					<description><![CDATA[error message: Error: Di...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">error message:</p>



<pre class="wp-block-preformatted">Error: Did not recognize the following languages: php<br>Warning: This run of the CodeQL Action does not have permission to access the CodeQL Action API endpoints. This could be because the Action is running on a pull request from a fork. If not, please ensure the workflow has at least the 'security-events: read' permission. Details: Code scanning is not enabled for this repository. Please enable code scanning in the repository settings. - https://docs.github.com/rest</pre>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="976" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/04/chrome_2026-04-07-08-04-4n-1024x976.jpg?v=1775520285" alt="" class="wp-image-8247" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/04/chrome_2026-04-07-08-04-4n-1024x976.jpg?v=1775520285 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/04/chrome_2026-04-07-08-04-4n-600x572.jpg?v=1775520285 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/04/chrome_2026-04-07-08-04-4n-768x732.jpg?v=1775520285 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/04/chrome_2026-04-07-08-04-4n-1536x1463.jpg?v=1775520285 1536w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/04/chrome_2026-04-07-08-04-4n.jpg?v=1775520285 1797w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">這看起來像是 CodeQL 分析時遇到了兩個常見的障礙：一個是語言設定問題，另一個是 GitHub API 的權限或設定問題。</p>



<p class="wp-block-paragraph">以下是針對這兩項錯誤的解決方案：</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1. 語言錯誤：<code>Did not recognize the following languages: php</code></h2>



<p class="wp-block-paragraph"><strong>問題點：</strong> 雖然 CodeQL 支援 PHP，但系統提示無法辨認。</p>



<p class="wp-block-paragraph"><strong>解決方法：</strong></p>



<ul class="wp-block-list">
<li><strong>檢查大小寫：</strong> 在 <code>.github/workflows/codeql.yml</code> 檔案中，請確保語言名稱是<strong>全小寫</strong>。</li>



<li><strong>更新 Action 版本：</strong> 確保你使用的是較新的版本（建議使用 <code>@v3</code>）。</li>



<li><strong>縮排與語法：</strong> 如果有多種語言，請使用列表格式。</li>
</ul>



<p class="wp-block-paragraph">YAML</p>



<pre class="wp-block-code"><code># 範例設定
- name: Initialize CodeQL
  uses: github/codeql-action/init@v3
  with:
    languages: php  # 確保這裡是小寫
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">2. 權限與 API 錯誤：<code>does not have permission</code></h2>



<p class="wp-block-paragraph"><strong>問題點：</strong> 工作流（Workflow）沒有權限將掃描結果上傳到 GitHub 的安全後台。這通常發生在<strong>從 Fork（分叉）出來的 PR</strong>，或是權限設定過於嚴格時。</p>



<p class="wp-block-paragraph"><strong>解決方法：</strong></p>



<p class="wp-block-paragraph">你需要在 YAML 檔案中明確加入 <code>permissions</code> 區塊，賦予工作流寫入安全事件的權力：</p>



<p class="wp-block-paragraph">YAML</p>



<pre class="wp-block-code"><code>permissions:
  actions: read
  contents: read
  security-events: write  # 這是上傳結果最關鍵的權限
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">3. 警告：<code>Code scanning is not enabled</code></h2>



<p class="wp-block-paragraph"><strong>問題點：</strong> 你的儲存庫（Repository）尚未正式啟用 Code Scanning 功能。</p>



<p class="wp-block-paragraph"><strong>操作步驟：</strong></p>



<ol start="1" class="wp-block-list">
<li>進入 GitHub 儲存庫的 <strong>Settings（設定）</strong>。</li>



<li>點擊左側選單的 <strong>Code security and analysis</strong>。</li>



<li>找到 <strong>Code scanning</strong> 並點擊 <strong>Set up</strong> 或確保其為開啟狀態。</li>
</ol>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">[!IMPORTANT]</p>



<p class="wp-block-paragraph">如果這是<strong>私有儲存庫（Private Repo）</strong>，你必須擁有 <strong>GitHub Advanced Security</strong> 授權才能使用 CodeQL 的自動掃描功能。</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">快速檢查清單</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>問題類型</strong></td><td><strong>應對動作</strong></td></tr></thead><tbody><tr><td><strong>來自 Fork 的 PR</strong></td><td>到 <strong>Settings &gt; Actions &gt; General</strong> 確認是否允許 Fork 的 PR 執行工作流並存取秘密（Secrets）。</td></tr><tr><td><strong>多語言設定</strong></td><td>若有其他語言，請寫成：<code>languages: [ 'javascript', 'php' ]</code>。</td></tr><tr><td><strong>GitHub Enterprise</strong></td><td>如果你在企業版環境，請確認 Runner 是否可以連線到 GitHub 的 API 端點。</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">請問你這個專案是公開的還是組織內的私有專案呢？這會影響到權限設定的細節。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">討論串: Why doesn&#8217;t CodeQL support auditing PHP<br><a href="https://github.com/github/codeql/issues/12376">https://github.com/github/codeql/issues/12376</a></p>



<p class="wp-block-paragraph">這是一個很常見的誤解。簡單來說：<strong>CodeQL 絕對支援 PHP</strong>，但在 GitHub Action 的某些特定版本或環境下，可能會因為「配置方式」導致它找不到 PHP。</p>



<p class="wp-block-paragraph">關於你提到的 issue (#12376) 以及相關的討論，這裡有幾個核心重點幫助你理解：</p>



<h3 class="wp-block-heading">1. CodeQL 確實支援 PHP</h3>



<p class="wp-block-paragraph">PHP 是 CodeQL 官方支援的語言之一（包括分析 SQL 注入、跨站腳本 XSS 等漏洞）。你可以從官方文件中看到 PHP 始終在支援清單中。</p>



<h3 class="wp-block-heading">2. 為什麼會出現 &#8220;Did not recognize php&#8221; 的錯誤？</h3>



<p class="wp-block-paragraph">在該 issue 和類似案例中，通常是因為以下兩個原因：</p>



<ul class="wp-block-list">
<li><strong>版本相容性 (Action Version)：</strong> 如果你使用的 <code>github/codeql-action</code> 版本太舊，或者內含的 CodeQL CLI 版本不匹配，可能會導致語言包加載失敗。</li>



<li><strong>預設套件包 (Standard Bundles)：</strong>CodeQL 在執行時會下載一個包含所有語言規則的「套件包 (Bundle)」。如果下載過程中出錯，或是你指定的分析器路徑不對，就會報出找不到語言的錯誤。</li>



<li><strong>大小寫問題：</strong>CodeQL 對設定檔非常敏感，必須確保是全小寫的 <code>php</code>。</li>
</ul>



<h3 class="wp-block-heading">3. 如何解決這個問題？</h3>



<p class="wp-block-paragraph">根據目前的最佳實踐，請檢查並修正你的 <code>.github/workflows/codeql.yml</code>：</p>



<h4 class="wp-block-heading">A. 更新 Action 版本（最重要）</h4>



<p class="wp-block-paragraph">確保你使用的是 <code>v3</code>（目前的主流版本）：</p>



<p class="wp-block-paragraph">YAML</p>



<pre class="wp-block-code"><code>- name: Initialize CodeQL
  uses: github/codeql-action/init@v3
  with:
    languages: php
</code></pre>



<h4 class="wp-block-heading">B. 手動指定 CodeQL 套件來源（如果問題持續）</h4>



<p class="wp-block-paragraph">有時候 GitHub 的託管執行器（Runner）快取了壞掉的 CodeQL 版本。你可以嘗試強制它使用最新的版本：</p>



<p class="wp-block-paragraph">YAML</p>



<pre class="wp-block-code"><code>- name: Initialize CodeQL
  uses: github/codeql-action/init@v3
  with:
    languages: php
    tools: latest # 強制下載最新版工具
</code></pre>



<h3 class="wp-block-heading">4. 針對你提到的權限錯誤（補充）</h3>



<p class="wp-block-paragraph">你之前提到的第二個錯誤 <code>Warning: This run of the CodeQL Action does not have permission...</code> 其實才是主因。</p>



<p class="wp-block-paragraph">當 CodeQL 因為<strong>權限不足</strong>無法從 GitHub API 獲取配置或下載必要的語言組件時，它可能會退回到一個「空狀態」，然後報錯說它「不認識 php」。</p>



<p class="wp-block-paragraph"><strong>請務必檢查：</strong></p>



<ul class="wp-block-list">
<li>你的 Repository 設置中：<strong>Settings &gt; Code security and analysis &gt; Code scanning</strong> 是否已啟動？</li>



<li>如果這是 <strong>Fork</strong> 過來的專案，預設是不能執行 CodeQL 並回傳結果的（為了安全）。你必須在 PR 頁面手動核准執行，或者在該 Fork 倉庫的設定中開啟 Actions 權限。</li>
</ul>



<h3 class="wp-block-heading">總結</h3>



<p class="wp-block-paragraph"><strong>CodeQL 支援 PHP。</strong> 你看到的錯誤通常不是因為「不支援」，而是因為 <strong>權限被阻擋</strong> 或 <strong>Action 版本過舊</strong> 導致 CodeQL 無法正確加載 PHP 的分析模組。請嘗試將 Action 更新至 <code>v3</code> 並在 YAML 中加入 <code>permissions: security-events: write</code>。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<pre class="wp-block-code"><code>PHP is not supported by CodeQL. What should we do with <code>codeql-analysis.yml</code>?</code></pre>



<p class="wp-block-paragraph">雖然 CodeQL 目前不支援 PHP，但這並不代表 codeql-analysis.yml 就完全沒有用處。如果你的專案除了 PHP 之外，還包含 JavaScript、TypeScript、HTML 或 CSS 等前端程式碼，CodeQL 依然可以掃描這些語言中的安全漏洞。建議先確認專案的語言組成，如果確實只有純 PHP 程式碼，直接移除這個檔案是合理的選擇，這樣可以避免 CI 執行無意義的掃描，節省系統資源。</p>



<p class="wp-block-paragraph">如果專案包含前端程式碼，你可以修改設定檔，將語言限制在 CodeQL 支援的範圍內。如果你決定移除它，第一選項提到的 PHPStan 確實已經處理了大部分的靜態分析任務。不過要注意的是，PHPStan 主要專注於型別檢查和邏輯錯誤，而 CodeQL 類型的工具通常更偏向安全性漏洞掃描（如 SQL 注入）。如果你對安全性有高度要求，可以考慮第二選項，導入像 Snyk 或 Psalm 的安全分析外掛，來補足安全性掃描的空缺。</p>



<p class="wp-block-paragraph">若選擇移除，請直接刪除 .github/workflows/codeql-analysis.yml。若專案未來計畫引入其他語言，則可以考慮暫時停用而非刪除。總結來說，若專案結構單一且 PHPStan 已能滿足開發需求，採取第一選項移除檔案是最簡潔的做法。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">這兩款工具在 PHP 社群都非常知名，但定位和收費模式完全不同。簡單來說，Psalm 適合預算有限、追求深度程式碼檢查的專案；Snyk 則適合企業級開發，需要更完整的安全性掃描生態。</p>



<h3 class="wp-block-heading">Psalm 安全分析</h3>



<p class="wp-block-paragraph">Psalm 本身是<strong>完全免費且開源</strong>的靜態分析工具。它最強大的地方在於 Taint Analysis（汙點分析），可以追蹤不受信任的輸入（如 $_GET）是否流向了危險的函數（如 query()），從而檢測 SQL 注入或 XSS。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"><strong>安裝步驟</strong></p>



<p class="wp-block-paragraph">如果你已經有專案，可以使用 Composer 進行安裝：</p>



<ol start="1" class="wp-block-list">
<li><strong>安裝主程式：</strong><code>composer require --dev vimeo/psalm</code></li>



<li><strong>初始化設定：</strong><code>./vendor/bin/psalm --init</code>這會生成一個 psalm.xml 設定檔。</li>



<li><strong>啟用安全分析：</strong>在 psalm.xml 中確保啟用了 taintAnalysis，或是直接在執行時加入參數：<code>./vendor/bin/psalm --taint-analysis</code></li>



<li><strong>安裝框架外掛（選配）：</strong>如果你使用 Laravel 或 Symfony，建議安裝專屬外掛，分析會更準確：<code>composer require --dev psalm/plugin-laravel</code><code>./vendor/bin/psalm-plugin enable psalm/plugin-laravel</code></li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Snyk 安全掃描</h3>



<p class="wp-block-paragraph">Snyk 是一個商業產品。對於<strong>開源專案或個人小規模使用</strong>，它提供免費額度（Free Plan），但對於企業或需要大量掃描、進階合規報告的團隊，則需要付費。2026 年的 Team 版本起跳價大約在每位開發者每月 50 美元左右。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"><strong>安裝步驟</strong></p>



<p class="wp-block-paragraph">Snyk 通常是透過 CLI 或直接整合到 GitHub 工作流中。</p>



<ol start="1" class="wp-block-list">
<li><strong>安裝 Snyk CLI：</strong>在本地或 CI 環境執行：<code>npm install -g snyk</code></li>



<li><strong>驗證身份：</strong><code>snyk auth</code>這會跳轉到瀏覽器讓你登入帳號。</li>



<li><strong>進行掃描：</strong>在專案根目錄執行以下指令來檢查依賴套件與程式碼漏洞：<code>snyk test</code></li>



<li><strong>GitHub 工作流整合：</strong>你可以在 .github/workflows 中建立 snyk.yml，使用官方提供的 Action：YAML<code>steps: - uses: actions/checkout@v4 - uses: snyk/actions/php@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}</code></li>
</ol>



<h3 class="wp-block-heading">該選哪一個</h3>



<ul class="wp-block-list">
<li>如果你想要<strong>不花一毛錢</strong>就達到極致的程式碼安全檢查，選 <strong>Psalm</strong>。它對 PHP 的理解非常深，但設定上會比較囉嗦。</li>



<li>如果你希望有<strong>漂亮的儀表板</strong>、自動掃描開源套件（SCA）的漏洞，且不介意免費額度的限制，選 <strong>Snyk</strong>。它的強項在於全面性的漏洞資料庫。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">解決 Composer 找不到的問題</h3>



<p class="wp-block-paragraph">如果你是在 Windows 環境下，最簡單的解決方法是去 Composer 官網下載並執行 Composer-Setup.exe 安裝檔。</p>



<p class="wp-block-paragraph">傳送門: <a href="https://getcomposer.org/download/">https://getcomposer.org/download/</a></p>



<p class="wp-block-paragraph">安裝過程中它會自動尋找你的 php.exe 路徑，並幫你把執行命令設定好。安裝完成後，務必重新啟動你的終端機（如 CMD 或 PowerShell），這樣設定才會生效。</p>



<p class="wp-block-paragraph">如果你確定已經安裝過，請檢查 PHP 的安裝路徑是否已經加入到系統環境變數中。你可以在終端機輸入 php -v 來確認。如果連 php 都不被辨認，那代表你必須先搞定 PHP 的環境。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">關於在本機檢查</h3>



<p class="wp-block-paragraph">是的，當你執行 <code>composer require --dev vimeo/psalm</code> 時，這是在你的<strong>開發本機</strong>進行操作。</p>



<p class="wp-block-paragraph">這行指令的意思是將 Psalm 下載到你專案資料夾裡的 vendor 目錄中。<code>--dev</code> 參數表示這個工具只在開發環境使用，實際把程式碼上傳到正式伺服器時，不會包含這些測試工具。</p>



<p class="wp-block-paragraph">在本機檢查的好處是，你可以在程式碼還沒上傳到 GitHub 或伺服器之前，就先發現潛在的安全性問題。這通常被稱為「左移測試」（Shift-Left Testing），也就是在開發初期就介入檢查。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">執行本機檢查的流程</h3>



<p class="wp-block-paragraph">當你解決了 Composer 的問題後，在本機操作的完整流程如下：</p>



<p class="wp-block-paragraph"><strong>安裝：</strong> 執行 </p>



<pre class="wp-block-code"><code>composer require --dev vimeo/psalm</code></pre>



<p class="wp-block-paragraph"><strong>初始化：</strong> 執行 </p>



<pre class="wp-block-code"><code>./vendor/bin/psalm --init</code></pre>



<p class="wp-block-paragraph">這會在你的專案裡產生一個設定檔，讓 Psalm 知道要檢查哪些資料夾。</p>



<p class="wp-block-paragraph"><strong>執行掃描：</strong> 執行 </p>



<pre class="wp-block-code"><code>./vendor/bin/psalm</code></pre>



<p class="wp-block-paragraph">它會開始掃描你的程式碼並在終端機顯示錯誤報告。</p>



<p class="wp-block-paragraph">如果你覺得在本機手動執行很麻煩，通常我們會把這套流程整合進 VS Code 等編輯器的外掛中，讓你邊寫程式時，編輯器就直接畫紅線提醒你哪裡可能有安全性漏洞。</p>



<h3 class="wp-block-heading">為什麼這比在 GitHub 上檢查快</h3>



<p class="wp-block-paragraph">在本機執行檢查的反應速度最快。如果你只靠 GitHub Actions（也就是你原本提到的 <code>codeql-analysis.yml</code> 所在的環境）來檢查，你必須先 commit 並 push 程式碼，等待雲端主機啟動，然後才能看到結果。在本機跑 Psalm 通常只需要幾秒鐘，能節省大量的等待時間。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">● CodeQL 完全不支援 PHP，這也是我們移除 codeql-analysis.yml 的原因。</p>



<p class="wp-block-paragraph">支援的語言只有：C/C++、C#、Go、Java/Kotlin、JavaScript/TypeScript、Python、Ruby、Swift。</p>



<p class="wp-block-paragraph">針對 PHP 的替代方案：</p>



<pre class="wp-block-preformatted">┌────────────────────────────────┬───────────────────────────────────┐<br>│ 工具 │ 用途 │<br>├────────────────────────────────┼───────────────────────────────────┤<br>│ Psalm (--taint-analysis) │ 資安漏洞（SQL injection、XSS 等） │<br>├────────────────────────────────┼───────────────────────────────────┤<br>│ PHPStan │ 型別錯誤、靜態分析 │<br>├────────────────────────────────┼───────────────────────────────────┤<br>│ PHP CodeSniffer │ 程式碼風格（PSR-12） │<br>├────────────────────────────────┼───────────────────────────────────┤<br>│ composer audit │ 相依套件已知漏洞 │<br>└────────────────────────────────┴───────────────────────────────────┘</pre>



<p class="wp-block-paragraph">這些都能在本機直接執行，速度比 GitHub Actions 快很多。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/04/codeql-%e6%94%af%e6%8f%b4-php-%e5%97%8e/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>1CPU+1GB RAM 的 WordPress 主機效能瓶頸與優化</title>
		<link>https://stackoverflow.max-everyday.com/2026/02/1cpu-1gb-ram-wordpress-vps/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/02/1cpu-1gb-ram-wordpress-vps/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Wed, 11 Feb 2026 07:21:11 +0000</pubDate>
				<category><![CDATA[WordPress筆記]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wordpress]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7769</guid>

					<description><![CDATA[請求處理的瓶頸邏輯 當 Apache 面對大量連...]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">請求處理的瓶頸邏輯</h3>



<p class="wp-block-paragraph">當 Apache 面對大量連線時，即便 CPU 沒滿，使用者確實可能需要排隊。這通常是因為 Apache 的 mpm 設定限制了同時處理請求的數量（MaxRequestWorkers）。當請求超過這個值，後續的連線會被放在作業系統的 backlog 隊列中等待。如果這個隊列也滿了，使用者就會看到連線逾時或拒絕連線。</p>



<p class="wp-block-paragraph">在高併發場景下，Apache 每個連線通常會佔用一個進程或線程，這非常消耗記憶體與 CPU 資源。即便你調整了核心網路參數，如果 Apache 本身的工人數量設得太低，連線進不來；設得太高，記憶體會耗盡導致系統瘋狂交換資料（Swap），進而讓 CPU 飆升到 100%。</p>



<h3 class="wp-block-heading">記憶體與 Swap 的警訊</h3>



<p class="wp-block-paragraph">從你提供的資訊來看，這台 WordPress 主機只有約 1GB 的記憶體（961Mi），且目前已經使用了 196Mi 的 Swap。當系統開始頻繁讀寫 Swap 時，磁碟 I/O 會拖慢所有處理程序，CPU 會花費大量時間在等待 I/O 完成（iowait），這也是造成系統停擺與 CPU 滿載的常見原因。1GB 記憶體對於執行現代 WordPress 加上 Apache 來說非常吃力，建議至少提升至 2GB 以上，或嚴格限制 Apache 的進程數量。</p>



<h3 class="wp-block-heading">動態請求的資源消耗</h3>



<p class="wp-block-paragraph">WordPress 是基於 PHP 的動態網站，每一個連線都要啟動 PHP 解釋器去抓資料庫、執行外掛程式碼，這比處理靜態網頁耗費更多資源。如果你沒有使用快取機制（如 Redis 或是 WP Super Cache），每個訪客都會對 CPU 造成直接壓力。即便你把網路隊列加長（如 somaxconn），那也只是讓訪客在「門外排隊」排得久一點，並沒有真正解決「門內的消化速度」。</p>



<h3 class="wp-block-heading">改善建議</h3>



<p class="wp-block-paragraph">要解決排隊與 CPU 滿載問題，調整核心參數只是輔助，你需要針對軟體層優化：</p>



<ul class="wp-block-list">
<li>檢查 Apache 的 mpm_event 設定，確保 MaxRequestWorkers 與你的記憶體大小匹配，避免觸發 Swap。</li>



<li>安裝 PHP 的 OPcache，這能顯著降低 CPU 處理 PHP 代碼的負擔。</li>



<li>強烈建議在 WordPress 加入物件快取（Object Cache）並搭配 Redis，減少對 MySQL 的重複查詢。</li>



<li>如果硬體資源無法提升，考慮將前端換成 Nginx 或是在 Apache 前面擋一層 Cloudflare，過濾掉不必要的壓力。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">修改 prefork MPM 設定值:</p>



<pre class="wp-block-code"><code>nano /etc/apache2/mods-available/mpm_prefork.conf</code></pre>



<p class="wp-block-paragraph">prefork MPM 設定值:</p>



<pre class="wp-block-code"><code>StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 200
MaxConnectionsPerChild 2000</code></pre>



<h3 class="wp-block-heading">記憶體過載的風險</h3>



<p class="wp-block-paragraph">你目前的 MaxRequestWorkers 設定為 200，這對於一台只有 1GB 記憶體的主機來說非常危險。在 prefork 模式下，每個 Apache 進程都會消耗獨立的記憶體。以 WordPress 來說，一個 PHP 進程大約佔用 40MB 到 80MB 不等。</p>



<p class="wp-block-paragraph">如果同時有 200 個請求進來，記憶體需求會來到 200 x 40MB = 8000MB（約 8GB）。你的主機只有 1GB，這會導致系統強制使用硬碟當記憶體（Swap），讓 CPU 飆升到 100% 且網頁完全打不開。這就是為什麼你感覺到系統停擺的主因。</p>



<h3 class="wp-block-heading">針對 1GB 記憶體的設定建議</h3>



<p class="wp-block-paragraph">假設扣除作業系統與其他程序佔用的 300MB，剩下約 600MB 給 Apache 使用。以每個進程 40MB 計算，MaxRequestWorkers 設定在 15 到 20 之間比較安全。</p>



<p class="wp-block-paragraph">以下是建議的設定值：</p>



<pre class="wp-block-code"><code>StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 20
MaxConnectionsPerChild 1000</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">設定值的邏輯說明</h3>



<ul class="wp-block-list">
<li><strong>MaxRequestWorkers (20)</strong>：<br>這是最重要的防線。設定為 20 代表最多只允許 20 個連線同時進入 PHP 處理階段。雖然這會讓第 21 個人排隊，但至少能保證這 20 個人能快速拿到網頁，且不會搞垮整台主機。</li>



<li><strong>MaxConnectionsPerChild (1000)</strong>：<br>原先的 2000 稍微偏高。調低到 1000 可以更頻繁地釋放可能洩漏的記憶體，對於小記憶體主機比較友善。</li>



<li><strong>預留空間</strong>：<br>當你發現 CPU 依然很高，但記憶體還有剩時，再以每次加 5 的幅度調升 MaxRequestWorkers。</li>
</ul>



<h3 class="wp-block-heading">如何減少排隊感</h3>



<p class="wp-block-paragraph">雖然限制了進程數可以防止當機，但使用者可能會因為排隊感到緩慢。你可以嘗試以下方法緩解：</p>



<ol start="1" class="wp-block-list">
<li><strong>啟用 Page Cache</strong>：<br>使用外掛如 WP Rocket 或 WP Super Cache 將頁面轉為靜態 HTML。這樣 Apache 處理請求的速度會快上百倍，同樣 20 個進程能服務的總人數會大幅提升。</li>



<li><strong>更換 MPM 模式</strong>：<br>如果可能，建議將 Apache 從 prefork 換成 event 模式並搭配 PHP-FPM。event 模式處理連線的效率更高，且更省記憶體。</li>



<li><strong>檢查資料庫連線</strong>：<br>確保你的 WordPress 設定指向 MySQL 主機時使用的是私有 IP（例如 10.x.x.x），避免走公網造成額外的連線延遲。</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Q: 2GB swap 是否太多?</p>



<h3 class="wp-block-heading">Swap 的定位與影響</h3>



<p class="wp-block-paragraph">在 1GB 記憶體的主機上，設定 2GB 的 Swap 並不算是「太多」，但它是一把雙刃劍。當你的實體記憶體用完時，Swap 可以作為緩衝，防止系統因為記憶體不足（OOM Killer）直接強制關閉資料庫或 Apache 進程。然而，Swap 的存取速度遠慢於記憶體，一旦系統頻繁使用 Swap，整台主機的效能會劇烈下降。</p>



<p class="wp-block-paragraph">從你提供的數據看，目前已經使用了 196Mi 的 Swap，這代表 1GB 的記憶體已經不夠用了。系統正在把不常用的資料搬到硬碟，如果這個數值持續跳動或增加，就是 CPU 飆高的前兆，因為 CPU 會浪費大量時間在處理記憶體與硬碟之間的資料交換。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">為什麼不建議依賴大量 Swap</h3>



<ul class="wp-block-list">
<li><strong>效能瓶頸</strong>：<br>硬碟（即使是 SSD）的速度比記憶體慢上千倍。當 Apache 請求排隊且又需要讀取 Swap 時，反應時間會從毫秒變成秒，使用者會感覺網站掛掉了。</li>



<li><strong>CPU 負擔</strong>：<br>管理 Swap 需要 CPU 參與，當記憶體極度短缺導致系統瘋狂交換資料（Thrashing）時，CPU 使用率會直接衝上 100%，但實際上沒有處理任何網頁請求。</li>



<li><strong>硬碟壽命</strong>：<br>如果是雲端主機，頻繁的 Swap 讀寫會消耗大量的 IOPS，有些服務商會因此限制你的磁碟效能。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">調整建議與優化</h3>



<p class="wp-block-paragraph">與其擔心 Swap 太大，不如減少系統對它的依賴。</p>



<p class="wp-block-paragraph"><strong>1. 調整 Swappiness</strong></p>



<p class="wp-block-paragraph">你目前的 <code>vm.swappiness = 10</code> 已經是很合理的設定。這代表系統會盡可能使用實體記憶體，直到剩下約 10% 左右才會開始考慮使用 Swap。請保持這個設定。</p>



<p class="wp-block-paragraph"><strong>2. 核心問題在記憶體配置</strong></p>



<p class="wp-block-paragraph">2GB 的 Swap 空間本身沒問題，問題出在你的 Apache 配置（MaxRequestWorkers 200）會輕易吃光 1GB 記憶體，強制系統去填滿那 2GB 的 Swap。這就像是雖然路邊有很大的路肩可以停車，但如果你把高速公路主線都塞滿了，車流還是會動彈不得。</p>



<p class="wp-block-paragraph"><strong>3. 監控建議</strong></p>



<p class="wp-block-paragraph">你可以觀察 <code>vmstat 1</code> 指令中的 <code>si</code> (swap in) 與 <code>so</code> (swap out) 欄位。如果這兩個數字持續不是 0，代表系統正在發生頻繁交換，這才是真正的效能殺手。</p>



<p class="wp-block-paragraph">目前的狀況下，2GB Swap 是安全的備援，但你應該透過調整 Apache 的進程數，讓 Swap 使用量維持在幾百 MB 以內甚至不使用。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph" id="mpm_event">apache 的 mods mpm_event 沒被 enable, 只有 enable mpm_prefork</p>



<h3 class="wp-block-heading">為什麼你的主機只開啟了 mpm_prefork</h3>



<p class="wp-block-paragraph">在較舊的系統或預設安裝中，Apache 為了確保與 PHP 的相容性（特別是當 PHP 以 mod_php 模組運行時），會預設使用 mpm_prefork。這個模式的特色是每個請求由一個獨立的進程處理，雖然穩定，但非常耗費記憶體，這正是導致你 1GB 記憶體主機容易 CPU 100% 的根本原因。</p>



<p class="wp-block-paragraph">如果你想大幅提升連線處理能力，並讓 CPU 不再輕易滿載，切換到 mpm_event 是最有效的做法。mpm_event 使用線程（threads）處理連線，能用極少的記憶體處理數倍於 prefork 的併發量。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">切換到 mpm_event 的必要前提</h3>



<p class="wp-block-paragraph">在切換之前，你必須確認 PHP 的運行方式。mpm_event 不支援傳統的 mod_php。</p>



<p class="wp-block-paragraph"><strong>安裝 PHP-FPM</strong>：你必須先安裝並啟動 php-fpm 服務。</p>



<p class="wp-block-paragraph"><strong>停用 mod_php</strong>：切換 MPM 前需要先停用 PHP 模組。</p>



<p class="wp-block-paragraph"><strong>更換模組</strong>：</p>



<p class="wp-block-paragraph">停用 mpm_prefork：</p>



<pre class="wp-block-code"><code><code>sudo a2dismod mpm_prefork</code></code></pre>



<p class="wp-block-paragraph">啟用 mpm_event：</p>



<pre class="wp-block-code"><code><code>sudo a2enmod mpm_event</code></code></pre>



<p class="wp-block-paragraph">重啟 Apache：</p>



<pre class="wp-block-code"><code><code>sudo systemctl restart apache2</code></code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">如果決定留在 mpm_prefork 的優化</h3>



<p class="wp-block-paragraph">如果你因為某些舊外掛必須維持 mpm_prefork，那麼你必須嚴格執行我之前建議的 <strong>MaxRequestWorkers 20</strong>。</p>



<p class="wp-block-paragraph">在 prefork 模式下，當連線數超過 MaxRequestWorkers 時，多出來的連線會進入作業系統的等待隊列（backlog）。這就是你問的「排隊等待」：</p>



<ul class="wp-block-list">
<li><strong>CPU 沒滿載但要排隊</strong>：這是因為 MaxRequestWorkers 限制了同時作業的人數，門外的人在排隊，但門內的人處理很快。</li>



<li><strong>CPU 滿載且要排隊</strong>：這是因為 MaxRequestWorkers 設太大（如你原本的 200），門內擠滿了人，大家都在互搶記憶體跟磁碟 IO，導致系統接近崩潰。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">總結建議</h3>



<p class="wp-block-paragraph">以你目前的硬體資源（1GB RAM），維持 mpm_prefork 並設定 MaxRequestWorkers 200 絕對會當機。</p>



<ul class="wp-block-list">
<li><strong>短期方案</strong>：立即將 MaxRequestWorkers 調降至 20 左右，保證系統不崩潰。</li>



<li><strong>長期方案</strong>：改用 mpm_event 搭配 PHP-FPM。這樣同樣 1GB 的記憶體，你可能可以將 MaxRequestWorkers 開到 100 以上而不會觸發 Swap。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">如何知道目前是使用 mod_php or php-fpm?</p>



<h3 class="wp-block-heading">確認目前 PHP 運行方式</h3>



<p class="wp-block-paragraph">你可以透過以下兩種方式快速判斷：</p>



<p class="wp-block-paragraph"><strong>查看 Apache 模組清單</strong>：執行指令 </p>



<pre class="wp-block-code"><code><code>apache2ctl -M | grep php</code></code></pre>



<p class="wp-block-paragraph">如果你看到 <code>php_module</code> 或 <code>php7.x_module</code> / <code>php8.x_module</code>，代表你正在使用 <strong>mod_php</strong>。</p>



<p class="wp-block-paragraph"><strong>建立 info.php 網頁</strong>：在網頁根目錄建立一個檔案，內容寫 </p>



<pre class="wp-block-code"><code><code>&lt;?php phpinfo(); ?&gt;</code></code></pre>



<p class="wp-block-paragraph">用瀏覽器開啟後，搜尋 <strong>Server API</strong> 這一項：</p>



<p class="wp-block-paragraph">如果顯示 <code>Apache 2.0 Handler</code>，就是 <strong>mod_php</strong>。</p>



<p class="wp-block-paragraph">如果顯示 <code>FPM/FastCGI</code>，就是 <strong>php-fpm</strong>。</p>



<p class="wp-block-paragraph">修改前: Server API: Apache 2.0 Handler</p>



<figure class="wp-block-image size-full"><img decoding="async" width="744" height="300" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-02-11_14-47_m8.jpg?v=1770793963" alt="" class="wp-image-7770" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-02-11_14-47_m8.jpg?v=1770793963 744w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-02-11_14-47_m8-600x242.jpg?v=1770793963 600w" sizes="(max-width: 744px) 100vw, 744px" /></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">切換至 mpm_event 與 PHP-FPM 詳細步驟</h3>



<p class="wp-block-paragraph">假設你使用的是 PHP 8.3（請根據你的版本自行調整數字，例如 7.4 或 8.1）：</p>



<p class="wp-block-paragraph"><strong>1. 安裝 PHP-FPM 與相關模組</strong></p>



<pre class="wp-block-code"><code>sudo apt update
sudo apt install php8.3-fpm libapache2-mod-fcgid
</code></pre>



<p class="wp-block-paragraph">安裝完成後，確認 FPM 已經啟動：</p>



<pre class="wp-block-code"><code>sudo systemctl status php8.3-fpm
</code></pre>



<p class="wp-block-paragraph"><strong>2. 啟用必要模組並停用 mod_php</strong></p>



<p class="wp-block-paragraph">這是一連串的模組切換動作，請依序執行：</p>



<pre class="wp-block-code"><code># 啟用 proxy 相關模組，讓 Apache 能溝通 PHP-FPM
sudo a2enmod proxy_fcgi setenvif

# 啟用 FPM 的設定檔
sudo a2enconf php8.3-fpm

# 停用 PHP 模組 (注意版本號要對應)
sudo a2dismod php8.3

# 核心切換：停用 prefork 並啟用 event
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event</code></pre>



<p class="wp-block-paragraph"><strong>3. 檢查設定並重啟</strong></p>



<p class="wp-block-paragraph">在重啟前先測試設定檔是否正確：</p>



<pre class="wp-block-code"><code>sudo apache2ctl configtest</code></pre>



<p class="wp-block-paragraph">如果顯示 <code>Syntax OK</code>，就重啟服務：</p>



<pre class="wp-block-code"><code>sudo systemctl restart apache2</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">為什麼這能解決你的問題</h3>



<p class="wp-block-paragraph">切換到 mpm_event 後，Apache 不再為每個連線維持一個笨重的進程。這對你的 1GB 記憶體主機有以下好處：</p>



<ul class="wp-block-list">
<li><strong>記憶體佔用極低</strong>：Apache 進程只負責把連線傳遞給 PHP-FPM，閒置連線幾乎不佔記憶體。</li>



<li><strong>併發能力提升</strong>：你可以安全地將同時連線數設得更高。</li>



<li><strong>獨立管理</strong>：PHP-FPM 有自己的進程管理設定檔，你可以獨立限制 PHP 能用多少記憶體，而不會跟 Apache 搶資源。</li>
</ul>



<p class="wp-block-paragraph">切換完成後，原本在 <code>/etc/apache2/mods-enabled/mpm_prefork.conf</code> 的設定就失效了，你需要去修改 <code>/etc/apache2/mods-enabled/mpm_event.conf</code>。</p>



<p class="wp-block-paragraph">修改用指令:</p>



<pre class="wp-block-code"><code>nano /etc/apache2/mods-available/mpm_event.conf</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">針對 1GB 記憶體的 event 模式優化</h3>



<p class="wp-block-paragraph">切換到 mpm_event 後，你的主機體質已經大幅改善。在 event 模式下，Apache 的進程變得很輕量，主要的記憶體壓力轉移到了 PHP-FPM 手上。你提供的預設值對於 1GB 記憶體來說稍嫌激進，特別是 MaxRequestWorkers 150。如果這 150 個連線同時觸發 PHP 運算，主機依然會因為記憶體耗盡而崩潰。</p>



<p class="wp-block-paragraph">以下是針對 1GB 記憶體環境的建議設定值：</p>



<pre class="wp-block-code"><code>StartServers 2
MinSpareThreads 25
MaxSpareThreads 50
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 50
MaxConnectionsPerChild 1000</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">設定值調整邏輯</h3>



<ul class="wp-block-list">
<li><strong>MaxRequestWorkers (50)</strong>：雖然 event 模式很省資源，但後端的 PHP-FPM 依然很吃記憶體。將此值設為 50 是一個安全的基準，代表 Apache 最多同時送 50 個請求給 PHP 處理。這能確保在高負載時，系統仍有足夠的緩衝記憶體，不至於觸發大量的 Swap 讀寫。</li>



<li><strong>MaxSpareThreads (50)</strong>：將最大閒置線程調低，可以讓 Apache 在離峰時段釋放不必要的資源。</li>



<li><strong>MaxConnectionsPerChild (1000)</strong>：建議不要設定為 0（無限）。設定一個數值（如 1000）可以讓進程在處理一定量請求後重啟，有效防止長期運行可能產生的記憶體洩漏問題。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">同步檢查 PHP-FPM 的設定</h3>



<p class="wp-block-paragraph">切換到 event 模式後，你還需要檢查 PHP-FPM 的設定檔：</p>



<pre class="wp-block-code"><code>nano /etc/php/8.3/fpm/pool.d/www.conf</code></pre>



<p class="wp-block-paragraph">這才是決定 CPU 是否衝到 100% 的關鍵：</p>



<pre class="wp-block-code"><code>pm = dynamic
pm.max_children = 15
pm.process_idle_timeout = 10s
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
</code></pre>



<ul class="wp-block-list">
<li><strong>pm.max_children (20)</strong>：這限制了同時運行的 PHP 進程數。因為每個 PHP 進程大約 40-60MB，20 個大約佔用 1GB 左右的空間。這個數值應與 Apache 的 MaxRequestWorkers 搭配。如果你發現記憶體還有剩餘，可以慢慢往上加。 反之，如果設了 20 還是占用掉大量 swap 就要降低。</li>
</ul>



<h3 class="wp-block-heading">觀察成效</h3>



<p class="wp-block-paragraph">完成設定後，請重啟服務：</p>



<pre class="wp-block-code"><code><code>sudo systemctl restart php8.3-fpm apache2</code></code></pre>



<p class="wp-block-paragraph">你可以觀察 <code>top</code> 或 <code>htop</code>。如果 CPU 負載下降且 Swap 使用量不再增加，代表目前的平衡點是正確的。如果使用者仍反映要排隊，但 CPU 很閒，再逐步調高 <code>pm.max_children</code> 與 <code>MaxRequestWorkers</code>。</p>



<p class="wp-block-paragraph">修改之後: Server API: FPM/FastCGI</p>



<figure class="wp-block-image size-full"><img decoding="async" width="678" height="355" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-02-11_14-58_m9.jpg?v=1770794049" alt="" class="wp-image-7771" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-02-11_14-58_m9.jpg?v=1770794049 678w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-02-11_14-58_m9-600x314.jpg?v=1770794049 600w" sizes="(max-width: 678px) 100vw, 678px" /></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">計算單個 PHP 進程的記憶體平均值</h3>



<p class="wp-block-paragraph">要精確設定 <code>pm.max_children</code>，你需要知道每個 PHP 進程實際上吃了多少記憶體。請在終端機執行以下指令：</p>



<pre class="wp-block-code"><code>ps -ylC php-fpm8.3 --sort:rss | awk '{sum+=$8; ++n} END {if (n &gt; 0) print sum/n/1024 " MB"}'
</code></pre>



<p class="wp-block-paragraph">（請根據你的版本修改 <code>php-fpm8.3</code>）</p>



<p class="wp-block-paragraph">這條指令會抓取所有正在執行的 PHP-FPM 進程，並計算出平均每個進程佔用的實體記憶體（RSS）。</p>



<h3 class="wp-block-heading">如何根據結果調整 pm.max_children</h3>



<p class="wp-block-paragraph">得到平均值後，你可以使用以下公式來估算：</p>



<pre class="wp-block-preformatted">(可用記憶體 - 系統預留) / 單個 PHP 進程平均大小 = pm.max_children</pre>



<p class="wp-block-paragraph">舉例來說：</p>



<ul class="wp-block-list">
<li>可用記憶體：1024MB</li>



<li>系統預留（作業系統 + Apache + MySQL）：400MB</li>



<li>剩餘空間：624MB</li>



<li>如果你的 PHP 進程平均是 40MB，則 $624 / 40 = 15.6$。</li>



<li>建議設定：<strong>pm.max_children = 15</strong>。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">優化 PHP-FPM 與 Apache 的連動</h3>



<p class="wp-block-paragraph">當你設定好 <code>pm.max_children</code> 後，Apache 的 <code>MaxRequestWorkers</code> 應該設為與其相同或略大一點。如果 <code>pm.max_children</code> 設得太小，Apache 送過去的請求會因為沒有多餘的 PHP 工人處理而在後台排隊，這就是為什麼 CPU 沒滿但使用者要等待的原因之一。</p>



<h3 class="wp-block-heading">其他關鍵優化</h3>



<p class="wp-block-paragraph">為了讓這 1GB 記憶體發揮最大效益，請檢查以下設定：</p>



<ul class="wp-block-list">
<li><strong>pm.max_requests</strong>：在 <code>www.conf</code> 中將此值設為 <strong>500</strong> 或 <strong>1000</strong>。這會讓 PHP 進程在處理完固定次數請求後重啟，能有效清理記憶體殘留，對小主機非常重要。</li>



<li><strong>opcache</strong>：確保 <code>/etc/php/8.3/fpm/php.ini</code> 中的 <code>opcache.enable=1</code> 與 <code>opcache.memory_consumption=128</code> 是開啟的。這能大幅降低 CPU 負擔。</li>



<li><strong>MySQL 檢查</strong>：你的 WordPress 與 MySQL 分開兩台，這很好。但請確保 WordPress 那台主機的 <code>wp-config.php</code> 是使用私有 IP 連線，避免 DNS 解析或公網延遲拖慢 PHP 進程的存活時間。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">為什麼預設 /etc/php/8.3/fpm/php.ini&nbsp;中的&nbsp;opcache.enable 沒被啟用?</p>



<h3 class="wp-block-heading">PHP FPM 與 OPcache 的預設行為</h3>



<p class="wp-block-paragraph">在多數 Linux 發行版（如 Ubuntu 或 Debian）中，當你透過套件管理員安裝 PHP 8.3 時，你會發現 php.ini 檔案裡的 opcache.enable 前面標註了分號，這代表該行是被註釋掉的。雖然在 php.ini 檔案中看起來像是沒啟用，但實際上 OPcache 在 FPM 環境下通常是運行的。</p>



<p class="wp-block-paragraph">這是因為 PHP 的設定採用了模組化管理。在 /etc/php/8.3/fpm/conf.d/ 目錄下，會有一個類似 10-opcache.ini 的符號連結，它指向 /etc/php/8.3/mods-available/opcache.ini。在這個獨立的設定檔中，通常已經包含了 zend_extension=opcache.so 以及 opcache.enable=1。</p>



<p class="wp-block-paragraph">PHP 在啟動時會先讀取主 php.ini，接著讀取 conf.d 目錄下的所有額外設定。由於 conf.d 中的設定載入順序較晚，它會覆蓋掉 php.ini 裡的預設值。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">為什麼不直接在主設定檔啟用</h3>



<p class="wp-block-paragraph">這種設計主要是為了維護的便利性。透過將不同擴充功能的設定拆分到獨立檔案，系統管理員可以簡單地使用 phpenmod 或 phpdismod 指令來開啟或關閉特定功能，而不需要去更動核心的 php.ini 檔案。</p>



<p class="wp-block-paragraph">如果 opcache.enable 在 php.ini 中被硬編碼啟用，當你想暫時停用它來進行除錯時，操作會變得比較麻煩。模組化的做法讓升級 PHP 版本時，設定檔的遷移與管理變得更加直覺，也能避免主設定檔變得過於臃腫。</p>



<p class="wp-block-paragraph">如果你想確認目前 OPcache 是否真的有在運作，可以撰寫一個包含 phpinfo(); 內容的檔案並透過瀏覽器執行，或者在終端機輸入 php-fpm8.3 -i | grep opcache.enable 來查看最終生效的數值。</p>



<p class="wp-block-paragraph">指令實際執行畫面:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="682" height="184" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-03-02_16-13_mm.jpg?v=1772439227" alt="" class="wp-image-7811" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-03-02_16-13_mm.jpg?v=1772439227 682w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-03-02_16-13_mm-600x162.jpg?v=1772439227 600w" sizes="auto, (max-width: 682px) 100vw, 682px" /></figure>



<p class="wp-block-paragraph">opcache.enable 在 php.ini 裡, 是被註解沒啟用, 實際上是有被 enable</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">如何在負載測試期間（例如使用 ab 工具）監控記憶體與 Swap 的即時變化？</p>



<h3 class="wp-block-heading">即時監控與測試方法</h3>



<p class="wp-block-paragraph">要找出系統的極限，最有效的方法是在模擬負載時觀察資源變化。你可以使用 Apache 內建的 $ab$ (Apache Benchmark) 工具，從外部或另一台主機進行測試。</p>



<p class="wp-block-paragraph"><strong>1. 準備監控視窗</strong></p>



<p class="wp-block-paragraph">建議同時開啟兩個終端機視窗：</p>



<p class="wp-block-paragraph"><strong>視窗 A（觀察記憶體與 Swap）：</strong> 執行 </p>



<pre class="wp-block-code"><code><code>watch -n 1 free -m</code></code></pre>



<p class="wp-block-paragraph">這讓你每秒看到記憶體減少與 Swap 增加的速度。</p>



<p class="wp-block-paragraph"><strong>視窗 B（觀察 PHP 進程）：</strong> 執行 </p>



<pre class="wp-block-code"><code><code>watch -n 1 "ps aux | grep php-fpm | grep -v grep | wc -l"</code></code></pre>



<p class="wp-block-paragraph">這能讓你確認 <code>pm.max_children</code> 是否已經達到上限。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">使用 ab 進行壓力測試</h3>



<p class="wp-block-paragraph">在另一台電腦執行以下指令（不要在 WordPress 主機自己跑，會影響測試準確性）：</p>



<p class="wp-block-paragraph"><code>ab -n 500 -c 20 http://你的網站IP/</code></p>



<ul class="wp-block-list">
<li><code>-n 500</code>：總共發出 500 個請求。</li>



<li><code>-c 20</code>：同時有 20 個連線（併發）。</li>
</ul>



<p class="wp-block-paragraph"><strong>測試時的觀察重點：</strong></p>



<ul class="wp-block-list">
<li><strong>情境 1：</strong> 如果 Swap 數字開始快速跳動，代表 <code>pm.max_children</code> 設得太高，記憶體爆了。</li>



<li><strong>情境 2：</strong> 如果 <code>free</code> 顯示記憶體還有剩，但 <code>ab</code> 測試結果很慢，且 PHP 進程數卡在 20 不動，代表你的 <code>pm.max_children</code> 設太低，CPU 沒事做但大家在排隊。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">count children = 10, each thread 127MB  已大於該  VPS  的 1GB RAM.</p>



<h3 class="wp-block-heading">找出完美的平衡點</h3>



<p class="wp-block-paragraph">理想的狀態是：當併發連線進來時，CPU 使用率上升（代表有在做事），實體記憶體用到約 80%~90%，但 Swap 幾乎不動。</p>



<p class="wp-block-paragraph">如果你的測試結果顯示 CPU 還是很容易衝到 100%，即使記憶體夠用，那通常是因為 WordPress 處理每個請求的時間太長。這時你需要檢查：</p>



<ul class="wp-block-list">
<li><strong>MySQL 慢查詢：</strong> 檢查 MySQL 主機是否因為沒有索引導致查詢變慢，拖住 PHP 進程。</li>



<li><strong>Object Cache：</strong> 在 WordPress 安裝 Redis Object Cache 插件。這能讓原本需要 0.5 秒處理的頁面縮短到 0.1 秒，同樣的進程數就能服務 5 倍的使用者。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">記憶體共享機制與計算誤差</h3>



<p class="wp-block-paragraph">這是一個非常經典的誤區。雖然指令算出的平均值是 127MB，但這 10 個進程並不是真的佔用了 </p>



<pre class="wp-block-preformatted">10 x  127 = 1270MB</pre>



<p class="wp-block-paragraph"><strong>1. 共享記憶體 (Shared Memory)</strong></p>



<p class="wp-block-paragraph">PHP-FPM 的主進程啟動時，會載入 PHP 核心、擴充功能和常用代碼（特別是開啟 OPcache 後）。當它產生子進程（Workers）時，這些子進程會共享主進程已經載入的唯讀記憶體區塊。</p>



<p class="wp-block-paragraph"><code>ps</code> 指令算出的 RSS（Resident Set Size）包含了進程自己獨有的資料以及它跟別人共享的資料。如果你把每個進程的 RSS 全部加總，會重複計算那些「共享的部分」，導致總數看起來超過了實體記憶體。</p>



<p class="wp-block-paragraph"><strong>2. 為什麼系統沒崩潰</strong></p>



<p class="wp-block-paragraph">從你的 <code>free -m</code> 來看，<code>used</code> 是 678Mi，這才是系統目前真正消耗的實體記憶體。扣除掉快取後，你的 <code>available</code> 還有 282Mi。這代表這 10 個 PHP 進程實際上扣除掉彼此重複的部分，總共只佔用了大約 400 到 500MB 左右。</p>



<p class="wp-block-paragraph"><strong>3. 127MB 的警訊</strong></p>



<p class="wp-block-paragraph">雖然有共享機制，但平均每個進程 127MB 在 WordPress 裡算是偏肥大的。這通常代表：</p>



<ul class="wp-block-list">
<li>你安裝了較多或較大型的外掛。</li>



<li>你的主題（Theme）載入了大量函式庫。</li>



<li>這些進程在處理完請求後，還沒釋放某些動態生成的資料。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">如何更精準地觀察與調整</h3>



<p class="wp-block-paragraph"><strong>1. 使用 PSS 計算（更準確）</strong></p>



<p class="wp-block-paragraph">如果你想看扣除共享後「真正」佔用的記憶體，可以試試安裝 <code>smem</code> 工具，它計算的 PSS (Proportional Set Size) 會把共享記憶體平攤給每個進程，算出來的總和才等於系統實際消耗量。</p>



<p class="wp-block-paragraph"><strong>2. 調整 pm.max_requests</strong></p>



<p class="wp-block-paragraph">你的進程長到 127MB，有可能是因為處理過太多請求而累積了碎片。在 <code>www.conf</code> 裡設定：</p>



<pre class="wp-block-code"><code><code>pm.max_requests = 500</code></code></pre>



<p class="wp-block-paragraph">這能強迫進程在處理 500 次請求後重啟，把記憶體歸零，防止它無限制長大到真的塞爆 RAM。</p>



<p class="wp-block-paragraph"><strong>3. 修正 pm.max_children</strong></p>



<p class="wp-block-paragraph">根據你現在 127MB 的觀察值，即便有共享，我也建議你的 <code>pm.max_children</code> 最多設 <strong>10 到 12</strong> 就好。因為在高負載下，每個進程處理複雜查詢時，獨有的記憶體會迅速增加，那時共享部分的比例會下降，如果不限制數量，136Mi 的 Swap 很快就會變成 500Mi，到時 CPU 就會衝上 100%。</p>



<p class="wp-block-paragraph">你想確認目前 <code>www.conf</code> 裡的 <code>pm</code> 模式是 <code>static</code> 還是 <code>dynamic</code> 嗎？這會影響這 10 個進程是否會自動增減。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">雖然把數值調低, 在 CPU / RAM / Disk IO 都明顯下降，但實際上造成的平均反應時間是大大的上升，所以讓 CPU / RAM 微微滿載，可能可以再降低一點回應時間。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="809" height="665" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-03-01_23-27_ml.jpg?v=1772378866" alt="" class="wp-image-7808" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-03-01_23-27_ml.jpg?v=1772378866 809w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-03-01_23-27_ml-600x493.jpg?v=1772378866 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/02/2026-03-01_23-27_ml-768x631.jpg?v=1772378866 768w" sizes="auto, (max-width: 809px) 100vw, 809px" /></figure>



<p class="wp-block-paragraph">page views 下降，且page load time 還上升，也許不去調整，performance 才是更好的, 呵呵。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/02/1cpu-1gb-ram-wordpress-vps/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Windows 環境使用 XAMPP 時，遇到 SQLite3 找不到的錯誤</title>
		<link>https://stackoverflow.max-everyday.com/2026/01/windows-xampp-sqlite3/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/01/windows-xampp-sqlite3/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 05 Jan 2026 08:23:28 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[sqlite]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7624</guid>

					<description><![CDATA[在 Windows 環境使用 XAMPP 時，遇...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">在 Windows 環境使用 XAMPP 時，遇到 SQLite3 找不到的錯誤，通常是因為 PHP 的擴充功能沒有開啟。這個組件在 XAMPP 預設設定中可能是關閉的，需要手動編輯設定檔。</p>



<h3 class="wp-block-heading">修改 php.ini 設定檔</h3>



<p class="wp-block-paragraph">請先打開 XAMPP Control Panel 控制面板。點擊 Apache 該列的 Config 按鈕，選擇 php.ini 項目。</p>



<p class="wp-block-paragraph">檔案打開後，使用搜尋功能尋找 extension=sqlite3。你會看到前面有一個分號，這代表該行被註解掉了。請刪除該行最前面的分號，修改後應該長這樣：</p>



<p class="wp-block-paragraph">extension=sqlite3</p>



<p class="wp-block-paragraph">接著搜尋 extension=pdo_sqlite，同樣確認前面的分號已經移除。這能確保 PDO 模式的 SQLite 也能正常運作。</p>



<h3 class="wp-block-heading">重啟 Apache 服務</h3>



<p class="wp-block-paragraph">儲存 php.ini 檔案後回到 XAMPP 控制面板。點擊 Apache 的 Stop 按鈕停止服務。等待幾秒鐘後，再次點擊 Start 重新啟動。</p>



<p class="wp-block-paragraph">重啟是為了讓 PHP 載入剛才修改的設定。現在重新整理網頁，錯誤應該就會消失。</p>



<h3 class="wp-block-heading">確認環境變數</h3>



<p class="wp-block-paragraph">如果重啟後還是報錯，可能是缺少相關的 DLL 檔案。請確認 XAMPP 安裝目錄下的 php 資料夾中，是否存在 php_sqlite3.dll。</p>



<p class="wp-block-paragraph">通常 XAMPP 都會內建這個檔案。若檔案存在卻無法讀取，請檢查 php.ini 裡的 extension_dir 是否指向正確的 ext 路徑。</p>



<p class="wp-block-paragraph">你可以建立一個 info.php 檔案，內容寫入 phpinfo() 函式。在瀏覽器執行該檔案並搜尋 SQLite，就能確認模組是否成功掛載。</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/01/windows-xampp-sqlite3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>php 寫的 api 除錯</title>
		<link>https://stackoverflow.max-everyday.com/2026/01/php-api-debug/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/01/php-api-debug/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 05 Jan 2026 08:22:19 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7622</guid>

					<description><![CDATA[直接在命令列執行 PHP 檔案時，系統會把它當成...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">直接在命令列執行 PHP 檔案時，系統會把它當成一般的腳本路徑，所以沒辦法直接解析網址後面的參數字串。當你輸入問號時，終端機通常會誤認那是檔案名稱的一部分，或者把 &amp; 符號當成執行多個指令。</p>



<h3 class="wp-block-heading">使用內建開發伺服器測試</h3>



<p class="wp-block-paragraph">如果你只是想測試 API 的執行結果，最簡單的方法是啟動 PHP 內建的伺服器。在專案目錄下輸入：</p>



<pre class="wp-block-code"><code>php -S localhost:8000
</code></pre>



<p class="wp-block-paragraph">接著開啟瀏覽器或用 curl 存取 http://localhost:8000/api.php?action=decompose&amp;text=%E7%97%9B 就能看到結果。這最貼近真實網頁環境。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">在命令列模擬 GET 參數</h3>



<p class="wp-block-paragraph">如果一定要在純文字介面執行，可以使用 PHP 的 CGI 模式（如果環境有安裝的話），或是手動在執行前定義變數。你可以利用 php-cgi 指令並帶入參數字串：</p>



<pre class="wp-block-code"><code>php-cgi -f api.php action=decompose text=%E7%97%9B
</code></pre>



<p class="wp-block-paragraph">如果只有一般的 php 指令，你必須在 PHP 程式碼中稍微修改，讓它能接收命令列參數。或者用一種比較取巧的方法，在執行時透過環境變數傳入：</p>



<pre class="wp-block-code"><code>QUERY_STRING="action=decompose&amp;text=%E7%97%9B" php api.php
</code></pre>



<p class="wp-block-paragraph">不過這需要你的 api.php 是透過讀取 $_SERVER[&#8216;QUERY_STRING&#8217;] 來處理資料，而不是直接讀取 $_GET。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">使用 CURL 模擬請求</h3>



<p class="wp-block-paragraph">這是在伺服器端測試 API 最常用的方式。不需要改動任何程式碼，只要你的網頁伺服器（如 Apache 或 Nginx）正在運作，直接輸入：</p>



<pre class="wp-block-code"><code>curl "http://127.0.0.1/api.php?action=decompose&amp;text=%E7%97%9B"
</code></pre>



<p class="wp-block-paragraph">記得網址要加上引號，避免 &amp; 符號被終端機誤判。這樣就能直接在螢幕上看到 API 回傳的內容，也最符合你原本 log 紀錄的行為。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">直接顯示在網頁上</p>



<p class="wp-block-paragraph">最快的方法就是用 var_dump 或 print_r。這會把變數的內容直接吐到瀏覽器畫面。var_dump 會顯示變數的類型和長度，資訊最完整。print_r 則適合用來看陣列，版面比較乾淨。</p>



<p class="wp-block-paragraph">PHP</p>



<pre class="wp-block-code"><code>$data = &#91;'status' =&gt; 'ok', 'code' =&gt; 200];

// 顯示詳細資訊
var_dump($data);

// 顯示好讀的列表
print_r($data);
</code></pre>



<p class="wp-block-paragraph">這招很直覺。但在測試 API 時要注意。因為這些除錯文字會直接插在原本的 JSON 回傳內容前面。可能會導致前端解析錯誤。</p>



<p class="wp-block-paragraph">印在伺服器終端機</p>



<p class="wp-block-paragraph">如果你不想破壞網頁原本的回傳格式。建議把除錯訊息寫到伺服器的黑底白字視窗裡。也就是你執行 php -S 的那個地方。使用 error_log 函式就可以做到。</p>



<p class="wp-block-paragraph">PHP</p>



<pre class="wp-block-code"><code>// 印出純文字
error_log("這裡有問題");

// 印出陣列或是物件，要先轉成字串
// print_r 的第二個參數設為 true 會回傳字串而不是直接印出
error_log(print_r($data, true));
</code></pre>



<p class="wp-block-paragraph">這樣網頁運作一切正常。你轉頭看執行指令的視窗就能看到數值。這對 API 開發最友善。</p>



<p class="wp-block-paragraph">印出後直接暫停</p>



<p class="wp-block-paragraph">有時候程式碼很長。你只想確認某個地方的變數，不想看後面的結果。可以在印出後加上 die 或 exit。</p>



<p class="wp-block-paragraph">PHP</p>



<pre class="wp-block-code"><code>var_dump($test_variable);
die(); // 程式執行到這裡就會直接結束
</code></pre>



<p class="wp-block-paragraph">需要我幫你寫一個簡單的 Log 輔助函式，讓你在開發時不用每次都打 print_r 嗎？</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">SQL預處理參數寫法有誤</p>



<p class="wp-block-paragraph">這段程式碼最大的問題在 SQL 語句。你在字串引號裡面直接寫 :part。資料庫會把它當成純文字 %:part%。它不會把這當成要替換的變數。bindValue 綁定會失效。搜尋結果永遠是空的。</p>



<p class="wp-block-paragraph">正確做法是把百分比符號放在變數綁定時處理。或者在 SQL 裡用字串連接。</p>



<p class="wp-block-paragraph">修正方式參考</p>



<p class="wp-block-paragraph">把 SQL 改乾淨一點。只留參數佔位符。</p>



<pre class="wp-block-code"><code>// SQL 裡面不要寫 %，也不要引號包住變數
$stmt = $db-&gt;prepare("SELECT char FROM component WHERE paired1 LIKE :part");

// 在綁定時加上前後的 %
$stmt-&gt;bindValue(':part', '%' . $keyword . '%', SQLITE3_TEXT);</code></pre>



<p class="wp-block-paragraph">這樣 SQLite 才能正確吃到帶有通配符的查詢字串。</p>



<p class="wp-block-paragraph">只抓了一筆資料</p>



<p class="wp-block-paragraph">另一個邏輯盲點是 fetchArray 只跑了一次。如果資料庫裡符合條件的字有好幾個。這段程式碼只會抓第一筆。其他的都會被漏掉。通常搜尋功能會需要用 while 迴圈把所有結果都跑一遍。</p>



<pre class="wp-block-code"><code>// 改用迴圈抓取所有符合的結果
while ($row = $result-&gt;fetchArray(SQLITE3_ASSOC)) {
    if (!empty($row&#91;'char'])) {
        $matched_chars&#91;] = $row&#91;'char'];
    }
}</code></pre>



<p class="wp-block-paragraph">關鍵字命名風險</p>



<p class="wp-block-paragraph">char 是 SQL 的保留字。用來當欄位名稱很危險。雖然 SQLite 有時候比較寬容。但最好養成習慣用引號包起來。寫成 &#8220;char&#8221;。或者換個欄位名稱比較保險。避免語法解析錯誤。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">程式碼功能解說</h3>



<p class="wp-block-paragraph">這段程式碼的主要目的是從資料庫查詢結果中，把所有找到的字元一個一個抓出來，並存進一個陣列裡。它使用了 while 迴圈，這代表只要資料庫裡還有資料，它就會不斷執行大括號內的動作。</p>



<h3 class="wp-block-heading">逐行細節拆解</h3>



<p class="wp-block-paragraph">第一行 fetchArray(SQLITE3_ASSOC) 是關鍵。這是在告訴程式以關聯陣列的形式讀取每一筆資料。簡單來說，就是讓你可以直接用欄位名稱來存取資料。每次迴圈執行時，變數 row 就會代表目前讀到的那一列數據。</p>



<p class="wp-block-paragraph">接下來的 if (!empty($row[&#8216;char&#8217;])) 是一道檢查手續。程式會確認讀到的 char 欄位裡面到底有沒有東西。如果這個欄位是空的，或者根本沒內容，它就不會執行後面的動作。這樣可以確保最後拿到的清單是乾淨且有效的。</p>



<p class="wp-block-paragraph">最後的 $matched_chars[] = $row[&#8216;char&#8217;] 則是把資料塞進陣列的操作。中括號代表在 matched_chars 這個陣列的最後面新增一個位置，把剛才確認過有內容的字元放進去。等迴圈全部跑完，這個陣列就會收集好所有符合條件的字元。</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/01/php-api-debug/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>安裝 php 用的 SQLite 模組</title>
		<link>https://stackoverflow.max-everyday.com/2025/12/php-sqlite/</link>
					<comments>https://stackoverflow.max-everyday.com/2025/12/php-sqlite/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 01:46:09 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7521</guid>

					<description><![CDATA[在 /var/log/apache/error....]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">在 /var/log/apache/error.log 可以看到錯誤訊息:</p>



<pre class="wp-block-code"><code>&nbsp;PHP Fatal error:&nbsp; Uncaught Error: Class "SQLite3" not found in /var/www/dictionary/api.php:47\nStack trace:\n#0 /var/www/dictionary/api.php(97): get_db()\n#1 {main}\n&nbsp; thrown in /var/www/dictionary/api.php on line 47</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">這個錯誤是因為你的 PHP 環境沒有安裝或啟用 SQLite3 的擴充模組。雖然 PHP 核心支持 SQLite，但在 Ubuntu 上通常需要獨立安裝。</p>



<h2 class="wp-block-heading">安裝 SQLite 模組</h2>



<p class="wp-block-paragraph">你需要針對你的 PHP 版本安裝對應的擴充套件。最直接的方法是執行安裝指令。</p>



<p class="wp-block-paragraph">指令為 </p>



<pre class="wp-block-code"><code>sudo apt install php-sqlite3</code></pre>



<p class="wp-block-paragraph">這會安裝必要的函式庫，讓 PHP 能夠呼叫 SQLite3 類別。</p>



<h2 class="wp-block-heading">確認模組狀態</h2>



<p class="wp-block-paragraph">安裝完成後，模組通常會自動啟用。你可以透過指令 php -m | grep sqlite 來確認清單中是否有出現 sqlite3。</p>



<p class="wp-block-paragraph">如果有出現，代表模組已經就緒。如果沒有，可能需要手動執行 </p>



<pre class="wp-block-code"><code>sudo phpenmod sqlite3 </code></pre>



<p class="wp-block-paragraph">來開啟它。</p>



<h2 class="wp-block-heading">重啟 Apache</h2>



<p class="wp-block-paragraph">跟修改記憶體上限一樣，新增擴充模組後必須讓網頁伺服器重新載入設定。</p>



<p class="wp-block-paragraph">請執行 </p>



<pre class="wp-block-code"><code>sudo systemctl restart apache2</code></pre>



<p class="wp-block-paragraph">重啟後，api.php 第 47 行的 Class SQLite3 not found 錯誤應該就會消失。</p>



<h2 class="wp-block-heading">檢查資料庫檔案權限</h2>



<p class="wp-block-paragraph">模組裝好後，如果程式還是跑不動，通常是讀不到資料庫檔案。請確保 Apache 的使用者（通常是 www-data）有權限讀取你的 .db 檔案。</p>



<p class="wp-block-paragraph">同時，放資料庫的資料夾也需要寫入權限，否則 SQLite 無法產生暫存檔，會導致連線失敗。</p>



<p class="wp-block-paragraph">安裝完模組後，你的 API 還有出現其他錯誤訊息嗎？</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">錯誤訊息:</p>



<pre class="wp-block-code"><code>➜&nbsp; apache2 sudo phpenmod sqlite3
WARNING: Module sqlite3 ini file doesn't exist under /etc/php/8.3/mods-available</code></pre>



<p class="wp-block-paragraph">這個警告代表雖然你嘗試啟用模組，但系統目錄裡根本沒有 SQLite3 的設定檔，通常是因為套件沒有安裝成功。</p>



<h2 class="wp-block-heading">重新安裝正確套件</h2>



<p class="wp-block-paragraph">在 Ubuntu 中，你需要確保安裝的是 php8.3-sqlite3 這個特定版本的套件。</p>



<p class="wp-block-paragraph">請執行 sudo apt update，接著執行 sudo apt install php8.3-sqlite3。系統會自動在 mods-available 資料夾下建立所需的 ini 檔案。</p>



<h2 class="wp-block-heading">手動確認檔案</h2>



<p class="wp-block-paragraph">安裝完後，你可以檢查 /etc/php/8.3/mods-available/sqlite3.ini 是否已經存在。</p>



<p class="wp-block-paragraph">如果檔案出現了，再執行一次 sudo phpenmod sqlite3。這時候應該就不會跳出警告訊息。</p>



<h2 class="wp-block-heading">套用設定</h2>



<p class="wp-block-paragraph">最後一步依然是重啟網頁伺服器，讓 Apache 載入剛裝好的 SQLite 驅動。</p>



<p class="wp-block-paragraph">執行 sudo systemctl restart apache2。你可以寫一個簡單的 php 檔案，內容寫 var_dump(class_exists(&#8216;SQLite3&#8217;)); 來確認回傳是否為 true。</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2025/12/php-sqlite/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP 的記憶體不夠用</title>
		<link>https://stackoverflow.max-everyday.com/2025/12/php-exhausted/</link>
					<comments>https://stackoverflow.max-everyday.com/2025/12/php-exhausted/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 01:42:12 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7518</guid>

					<description><![CDATA[直接在 php 讀取 31MB 的 .json ...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">直接在 php 讀取 31MB 的 .json 檔案, 在 Windows 上執行沒問題, 改放到 RAM 超級小的虛擬主機上, 一執行 php script, 就 crash, 顯示 500 error:</p>



<pre class="wp-block-code"><code>&#91;Sun Dec 21 02:57:41.208976 2025] &#91;core:notice] &#91;pid 347231:tid 347231] AH00094: Command line: '/usr/sbin/apache2'
&#91;Sun Dec 21 03:02:54.255907 2025] &#91;php:error] &#91;pid 347475:tid 347475] &#91;client 172.71.124.192:9672] PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /var/www/dictionary/api.php on line 35</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">這個錯誤訊息代表 PHP 的記憶體不夠用了。系統預設通常只給 128MB，當程式處理大量資料時就會當掉。</p>



<h2 class="wp-block-heading">修改設定檔</h2>



<p class="wp-block-paragraph">你需要修改 php.ini 檔案來調高上限。在 Ubuntu 中，Apache 使用的路徑通常是 /etc/php/8.x/apache2/php.ini，請把 8.x 換成你的 PHP 版本。</p>



<p class="wp-block-paragraph">找到 memory_limit 這一行，把 128M 改成更大的數值，例如 256M 或 512M。如果確定程式需要極大空間，也可以視主機記憶體狀況調整。</p>



<h2 class="wp-block-heading">重新啟動服務</h2>



<p class="wp-block-paragraph">改完存檔後，設定不會立刻生效。你必須重啟 Apache 伺服器，讓它讀取新的設定值。</p>



<p class="wp-block-paragraph">執行指令 sudo systemctl restart apache2。重啟後，你可以再次執行原本報錯的 API，檢查是否還會出現記憶體不足的訊息。</p>



<h2 class="wp-block-heading">檢查程式碼</h2>



<p class="wp-block-paragraph">如果調高到 512M 還是報錯，可能就要回頭看程式碼了。報錯點在 api.php 的第 35 行，那裡可能正在讀取非常大的資料庫結果，或是陷入了無窮迴圈。</p>



<p class="wp-block-paragraph">長遠來看，優化程式碼減少記憶體佔用，會比單純調高記憶體上限更安全。</p>



<p class="wp-block-paragraph">需要我幫你看一下 api.php 第 35 行附近的程式碼邏輯嗎？</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2025/12/php-exhausted/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>XAMPP 修改 apache 的 web root 需要修改那些地方</title>
		<link>https://stackoverflow.max-everyday.com/2025/12/xampp-apache-web-root/</link>
					<comments>https://stackoverflow.max-everyday.com/2025/12/xampp-apache-web-root/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 01:30:59 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7513</guid>

					<description><![CDATA[在問AI 之前, 我自己亂改, 結果改錯地方, ...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">在問AI 之前, 我自己亂改, 結果改錯地方, 在 windows 上的 apache 完全掛掉, 使用安裝好的預設值是可以正常執行.</p>



<p class="wp-block-paragraph"><strong>正確</strong>的修改標的是 C:/xampp/htdocs , 而我修改<strong>錯誤</strong>的是 C:/xampp/apache</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">要修改 XAMPP 的網頁根目錄，主要需要動到 Apache 的設定檔。這個檔案路徑通常在 C:\xampp\apache\conf\httpd.conf。</p>



<h2 class="wp-block-heading">修改設定檔內容</h2>



<p class="wp-block-paragraph">打開 httpd.conf 檔案後，利用搜尋功能尋找 DocumentRoot 這個關鍵字。你會看到兩行需要修改的地方。</p>



<p class="wp-block-paragraph">第一行是 DocumentRoot &#8220;C:/xampp/htdocs&#8221;，請把它改成你的新路徑 &#8220;C:/Max/Documents/fonts/dictionary/dictionaryweb&#8221;。</p>



<p class="wp-block-paragraph">第二行緊接在下面，通常是 &lt;Directory &#8220;C:/xampp/htdocs&#8221;&gt;。請同步修改成 &lt;Directory &#8220;C:/Max/Documents/fonts/dictionary/dictionaryweb&#8221;&gt;。</p>



<h2 class="wp-block-heading">確認權限設定</h2>



<p class="wp-block-paragraph">在 &lt;Directory&gt; 區塊內，要確認權限是否有開放。確保裡面的設定包含 AllowOverride All 以及 Require all granted。這樣 Apache 才有權限讀取你放在文件資料夾裡的檔案。</p>



<p class="wp-block-paragraph">有些 Windows 資料夾會有權限限制，如果修改後出現 403 Forbidden 錯誤，可能需要手動去資料夾內容調整安全安全性設定，讓 Everyone 或 Everyone 組群有讀取權限。</p>



<h2 class="wp-block-heading">重啟服務生效</h2>



<p class="wp-block-paragraph">修改完儲存檔案後，設定並不會立刻生效。你必須回到 XAMPP Control Panel，先點擊 Apache 的 Stop 停止服務，等待幾秒後再點擊 Start 重新啟動。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">重新啟動後，你在瀏覽器輸入 localhost，它就會自動讀取你新路徑下的 index.php 或 index.html 了。</p>



<p class="wp-block-paragraph">需要幫你檢查如何設定虛擬主機（Virtual Host）來對應不同的專案路徑嗎？</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2025/12/xampp-apache-web-root/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>xampp 安裝好後, 如何執行php</title>
		<link>https://stackoverflow.max-everyday.com/2025/12/xampp-run-php/</link>
					<comments>https://stackoverflow.max-everyday.com/2025/12/xampp-run-php/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 01:26:10 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7511</guid>

					<description><![CDATA[要在 Windows 的一般命令提示字元（CMD...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">要在 Windows 的一般命令提示字元（CMD）或 PowerShell 執行 PHP，關鍵在於告訴系統 PHP 的程式放在哪裡。這就是設定環境變數。</p>



<h2 class="wp-block-heading">設定環境變數路徑</h2>



<p class="wp-block-paragraph">XAMPP 安裝完後，PHP 執行檔預設會放在 C:\xampp\php。你需要把這個路徑加到系統的 Path 變數中。</p>



<ol start="1" class="wp-block-list">
<li>在工作列搜尋「環境變數」，選擇編輯系統環境變數。</li>



<li>點擊右下角的環境變數按鈕。</li>



<li>在下方的系統變數清單中找到 Path，點兩下打開。</li>



<li>點擊右邊的新增，輸入 C:\xampp\php。</li>



<li>點擊確定儲存所有視窗。</li>
</ol>



<h2 class="wp-block-heading">重啟命令提示字元</h2>



<p class="wp-block-paragraph">設定好之後，必須關掉目前所有的 CMD 或 PowerShell 視窗再重新打開。這是因為舊的視窗還沒讀取到新的路徑設定。</p>



<ol start="1" class="wp-block-list">
<li>按下 Win + R，輸入 cmd 並按回車。</li>



<li>輸入 php -v 並按下 Enter。</li>



<li>如果看到 PHP 的版本資訊，就代表成功了。</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">檢查錯誤</h2>



<p class="wp-block-paragraph">如果輸入指令後出現找不到程式的錯誤，請確認 C:\xampp\php 這個資料夾內是否有 php.exe。如果你的 XAMPP 裝在 D 槽或其他位置，路徑也要跟著修改。</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2025/12/xampp-run-php/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
