

<?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>Thu, 09 Apr 2026 07:31:19 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</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>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>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>這看起來像是 CodeQL 分析時遇到了兩個常見的障礙：一個是語言設定問題，另一個是 GitHub API 的權限或設定問題。</p>



<p>以下是針對這兩項錯誤的解決方案：</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><strong>問題點：</strong> 雖然 CodeQL 支援 PHP，但系統提示無法辨認。</p>



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



<p><strong>解決方法：</strong></p>



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



<p>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><strong>問題點：</strong> 你的儲存庫（Repository）尚未正式啟用 Code Scanning 功能。</p>



<p><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>[!IMPORTANT]</p>



<p>如果這是<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>請問你這個專案是公開的還是組織內的私有專案呢？這會影響到權限設定的細節。</p>



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



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



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



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



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



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



<p>在該 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>根據目前的最佳實踐，請檢查並修正你的 <code>.github/workflows/codeql.yml</code>：</p>



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



<p>確保你使用的是 <code>v3</code>（目前的主流版本）：</p>



<p>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>有時候 GitHub 的託管執行器（Runner）快取了壞掉的 CodeQL 版本。你可以嘗試強制它使用最新的版本：</p>



<p>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>你之前提到的第二個錯誤 <code>Warning: This run of the CodeQL Action does not have permission...</code> 其實才是主因。</p>



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



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



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



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



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



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



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



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



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



<p><strong>安裝步驟</strong></p>



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



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



<p><strong>安裝步驟</strong></p>



<p>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>如果你是在 Windows 環境下，最簡單的解決方法是去 Composer 官網下載並執行 Composer-Setup.exe 安裝檔。</p>



<p>傳送門: <a href="https://getcomposer.org/download/">https://getcomposer.org/download/</a></p>



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



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



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



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



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



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



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



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



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



<p>當你解決了 Composer 的問題後，在本機操作的完整流程如下：</p>



<p><strong>安裝：</strong> 執行 </p>



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



<p><strong>初始化：</strong> 執行 </p>



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



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



<p><strong>執行掃描：</strong> 執行 </p>



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



<p>它會開始掃描你的程式碼並在終端機顯示錯誤報告。</p>



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



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



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



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



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



<p>支援的語言只有：C/C++、C#、Go、Java/Kotlin、JavaScript/TypeScript、Python、Ruby、Swift。</p>



<p>針對 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>這些都能在本機直接執行，速度比 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>當 Apache 面對大量連線時，即便 CPU 沒滿，使用者確實可能需要排隊。這通常是因為 Apache 的 mpm 設定限制了同時處理請求的數量（MaxRequestWorkers）。當請求超過這個值，後續的連線會被放在作業系統的 backlog 隊列中等待。如果這個隊列也滿了，使用者就會看到連線逾時或拒絕連線。</p>



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



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



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



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



<p>要解決排隊與 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>修改 prefork MPM 設定值:</p>



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



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



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



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



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



<p>以下是建議的設定值：</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>雖然限制了進程數可以防止當機，但使用者可能會因為排隊感到緩慢。你可以嘗試以下方法緩解：</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>Q: 2GB swap 是否太多?</p>



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



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



<p>從你提供的數據看，目前已經使用了 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>與其擔心 Swap 太大，不如減少系統對它的依賴。</p>



<p><strong>1. 調整 Swappiness</strong></p>



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



<p><strong>2. 核心問題在記憶體配置</strong></p>



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



<p><strong>3. 監控建議</strong></p>



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



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



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



<p id="mpm_event">apache 的 mods mpm_event 沒被 enable, 只有 enable mpm_prefork</p>



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



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



<p>如果你想大幅提升連線處理能力，並讓 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>在切換之前，你必須確認 PHP 的運行方式。mpm_event 不支援傳統的 mod_php。</p>



<p><strong>安裝 PHP-FPM</strong>：你必須先安裝並啟動 php-fpm 服務。</p>



<p><strong>停用 mod_php</strong>：切換 MPM 前需要先停用 PHP 模組。</p>



<p><strong>更換模組</strong>：</p>



<p>停用 mpm_prefork：</p>



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



<p>啟用 mpm_event：</p>



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



<p>重啟 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>如果你因為某些舊外掛必須維持 mpm_prefork，那麼你必須嚴格執行我之前建議的 <strong>MaxRequestWorkers 20</strong>。</p>



<p>在 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>以你目前的硬體資源（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>如何知道目前是使用 mod_php or php-fpm?</p>



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



<p>你可以透過以下兩種方式快速判斷：</p>



<p><strong>查看 Apache 模組清單</strong>：執行指令 </p>



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



<p>如果你看到 <code>php_module</code> 或 <code>php7.x_module</code> / <code>php8.x_module</code>，代表你正在使用 <strong>mod_php</strong>。</p>



<p><strong>建立 info.php 網頁</strong>：在網頁根目錄建立一個檔案，內容寫 </p>



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



<p>用瀏覽器開啟後，搜尋 <strong>Server API</strong> 這一項：</p>



<p>如果顯示 <code>Apache 2.0 Handler</code>，就是 <strong>mod_php</strong>。</p>



<p>如果顯示 <code>FPM/FastCGI</code>，就是 <strong>php-fpm</strong>。</p>



<p>修改前: 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>假設你使用的是 PHP 8.3（請根據你的版本自行調整數字，例如 7.4 或 8.1）：</p>



<p><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>安裝完成後，確認 FPM 已經啟動：</p>



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



<p><strong>2. 啟用必要模組並停用 mod_php</strong></p>



<p>這是一連串的模組切換動作，請依序執行：</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><strong>3. 檢查設定並重啟</strong></p>



<p>在重啟前先測試設定檔是否正確：</p>



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



<p>如果顯示 <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>切換到 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>切換完成後，原本在 <code>/etc/apache2/mods-enabled/mpm_prefork.conf</code> 的設定就失效了，你需要去修改 <code>/etc/apache2/mods-enabled/mpm_event.conf</code>。</p>



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



<p>以下是針對 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>切換到 event 模式後，你還需要檢查 PHP-FPM 的設定檔：</p>



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



<p>這才是決定 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>完成設定後，請重啟服務：</p>



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



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



<p>修改之後: 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>要精確設定 <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>（請根據你的版本修改 <code>php-fpm8.3</code>）</p>



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



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



<p>得到平均值後，你可以使用以下公式來估算：</p>



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



<p>舉例來說：</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>當你設定好 <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>為了讓這 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>為什麼預設 /etc/php/8.3/fpm/php.ini&nbsp;中的&nbsp;opcache.enable 沒被啟用?</p>



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



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



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



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



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



<p>指令實際執行畫面:</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>opcache.enable 在 php.ini 裡, 是被註解沒啟用, 實際上是有被 enable</p>



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



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



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



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



<p><strong>1. 準備監控視窗</strong></p>



<p>建議同時開啟兩個終端機視窗：</p>



<p><strong>視窗 A（觀察記憶體與 Swap）：</strong> 執行 </p>



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



<p>這讓你每秒看到記憶體減少與 Swap 增加的速度。</p>



<p><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>這能讓你確認 <code>pm.max_children</code> 是否已經達到上限。</p>



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



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



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



<p><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><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>count children = 10, each thread 127MB  已大於該  VPS  的 1GB RAM.</p>



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



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



<p>如果你的測試結果顯示 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>這是一個非常經典的誤區。雖然指令算出的平均值是 127MB，但這 10 個進程並不是真的佔用了 </p>



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



<p><strong>1. 共享記憶體 (Shared Memory)</strong></p>



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



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



<p><strong>2. 為什麼系統沒崩潰</strong></p>



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



<p><strong>3. 127MB 的警訊</strong></p>



<p>雖然有共享機制，但平均每個進程 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><strong>1. 使用 PSS 計算（更準確）</strong></p>



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



<p><strong>2. 調整 pm.max_requests</strong></p>



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



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



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



<p><strong>3. 修正 pm.max_children</strong></p>



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



<p>你想確認目前 <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>雖然把數值調低, 在 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>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>在 Windows 環境使用 XAMPP 時，遇到 SQLite3 找不到的錯誤，通常是因為 PHP 的擴充功能沒有開啟。這個組件在 XAMPP 預設設定中可能是關閉的，需要手動編輯設定檔。</p>



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



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



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



<p>extension=sqlite3</p>



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



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



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



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



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



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



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



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



<p></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>直接在命令列執行 PHP 檔案時，系統會把它當成一般的腳本路徑，所以沒辦法直接解析網址後面的參數字串。當你輸入問號時，終端機通常會誤認那是檔案名稱的一部分，或者把 &amp; 符號當成執行多個指令。</p>



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



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



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



<p>接著開啟瀏覽器或用 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>如果一定要在純文字介面執行，可以使用 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>如果只有一般的 php 指令，你必須在 PHP 程式碼中稍微修改，讓它能接收命令列參數。或者用一種比較取巧的方法，在執行時透過環境變數傳入：</p>



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



<p>不過這需要你的 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>這是在伺服器端測試 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>記得網址要加上引號，避免 &amp; 符號被終端機誤判。這樣就能直接在螢幕上看到 API 回傳的內容，也最符合你原本 log 紀錄的行為。</p>



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



<p>直接顯示在網頁上</p>



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



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



<p>印在伺服器終端機</p>



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



<p>PHP</p>



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

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



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



<p>印出後直接暫停</p>



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



<p>PHP</p>



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



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



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



<p>SQL預處理參數寫法有誤</p>



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



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



<p>修正方式參考</p>



<p>把 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>這樣 SQLite 才能正確吃到帶有通配符的查詢字串。</p>



<p>只抓了一筆資料</p>



<p>另一個邏輯盲點是 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>關鍵字命名風險</p>



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



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



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



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



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



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



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



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



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



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



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



<p>指令為 </p>



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



<p>這會安裝必要的函式庫，讓 PHP 能夠呼叫 SQLite3 類別。</p>



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



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



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



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



<p>來開啟它。</p>



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



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



<p>請執行 </p>



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



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



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



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



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



<p>安裝完模組後，你的 API 還有出現其他錯誤訊息嗎？</p>



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



<p>錯誤訊息:</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>這個警告代表雖然你嘗試啟用模組，但系統目錄裡根本沒有 SQLite3 的設定檔，通常是因為套件沒有安裝成功。</p>



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



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



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



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



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



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



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



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



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



<p></p>



<p></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>直接在 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>這個錯誤訊息代表 PHP 的記憶體不夠用了。系統預設通常只給 128MB，當程式處理大量資料時就會當掉。</p>



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



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



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



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



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



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



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



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



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



<p>需要我幫你看一下 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>在問AI 之前, 我自己亂改, 結果改錯地方, 在 windows 上的 apache 完全掛掉, 使用安裝好的預設值是可以正常執行.</p>



<p><strong>正確</strong>的修改標的是 C:/xampp/htdocs , 而我修改<strong>錯誤</strong>的是 C:/xampp/apache</p>



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



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



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



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



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



<p>第二行緊接在下面，通常是 &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>在 &lt;Directory&gt; 區塊內，要確認權限是否有開放。確保裡面的設定包含 AllowOverride All 以及 Require all granted。這樣 Apache 才有權限讀取你放在文件資料夾裡的檔案。</p>



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



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



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



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



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



<p>需要幫你檢查如何設定虛擬主機（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>要在 Windows 的一般命令提示字元（CMD）或 PowerShell 執行 PHP，關鍵在於告訴系統 PHP 的程式放在哪裡。這就是設定環境變數。</p>



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



<p>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>設定好之後，必須關掉目前所有的 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>如果輸入指令後出現找不到程式的錯誤，請確認 C:\xampp\php 這個資料夾內是否有 php.exe。如果你的 XAMPP 裝在 D 槽或其他位置，路徑也要跟著修改。</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2025/12/xampp-run-php/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>在 VS Code 裡面跑 PHP</title>
		<link>https://stackoverflow.max-everyday.com/2025/12/vs-code-php/</link>
					<comments>https://stackoverflow.max-everyday.com/2025/12/vs-code-php/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 01:24:09 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7507</guid>

					<description><![CDATA[在 VS Code 裡面跑 PHP 其實很方便，...]]></description>
										<content:encoded><![CDATA[
<p>在 VS Code 裡面跑 PHP 其實很方便，只要裝好外掛並設定好路徑就可以了。</p>



<h2 class="wp-block-heading">安裝必要的擴充功能</h2>



<p>首先打開 VS Code 的擴充功能商店。搜尋 PHP Debug 和 PHP Intelephense 這兩個外掛並安裝。PHP Debug 是用來除錯的，而 Intelephense 可以提供程式碼自動補完和語法檢查，讓寫程式變輕鬆很多。</p>



<h2 class="wp-block-heading">設定 PHP 執行路徑</h2>



<p>VS Code 需要知道你的 PHP 裝在哪裡。點擊左下角的齒輪圖示打開設定，搜尋 php.validate.executablePath。點擊編輯 settings.json，在裡面加入你的 PHP 路徑。例如 &#8220;php.validate.executablePath&#8221;: &#8220;C:/php/php.exe&#8221;。記得路徑要指向那個執行檔。</p>



<h2 class="wp-block-heading">使用內建終端機執行</h2>



<p>最簡單的執行方式是直接用終端機。在 VS Code 下方打開 Terminal。輸入 php 加上你的檔名，例如 php index.php。畫面上就會直接跑出執行結果，這對測試小段程式碼非常方便。</p>



<h2 class="wp-block-heading">使用 Live Server 預覽</h2>



<p>如果你想在瀏覽器即時看到網頁效果，可以安裝 PHP Server 這個擴充功能。安裝後，在你的 PHP 檔案上按右鍵，選擇 PHP Server: Serve project。它會自動幫你開啟瀏覽器並執行該頁面，省去手動重整的麻煩。</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2025/12/vs-code-php/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>在 Windows 上安裝 PHP</title>
		<link>https://stackoverflow.max-everyday.com/2025/12/windows-install-php/</link>
					<comments>https://stackoverflow.max-everyday.com/2025/12/windows-install-php/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 01:17:48 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=7502</guid>

					<description><![CDATA[我以為安裝 php 和安裝 python 一樣簡...]]></description>
										<content:encoded><![CDATA[
<p>我以為安裝 php 和安裝 python 一樣簡單, 到 php 網站點2下就解決, 結果到了 php 網站, 完全看不懂要下載那一個才是 windows 的安裝檔, 結果一問 AI, 原來要用第三方的工具才是正解, 太神奇了。</p>



<p>xampp windows 下載點:<br><a href="https://sourceforge.net/projects/xampp/files/XAMPP%20Windows/">https://sourceforge.net/projects/xampp/files/XAMPP%20Windows/</a></p>



<p>實際使用之後, 發現在 Win11 上使用 xampp 很容易 crash, 請改用 xampp-lite 64bit<br><a href="https://sourceforge.net/projects/xampplite/">https://sourceforge.net/projects/xampplite/</a></p>



<p>如果你想讓整個  windows 任意路徑都可以執行 php, 請增加 path 變數:</p>



<pre class="wp-block-code"><code>C:\xampp_lite\apps\php;C:\xampp_lite\apps\mysql\bin;</code></pre>



<p>如果安裝 xampp-lite, 請在系統變數增加這個項目:</p>



<pre class="wp-block-code"><code>XAMPP_LITE_ROOT=c:/xampp_lite</code></pre>



<p>不知道為什麼 xampp_lite 的 apache 一直遇到問題, 請改用下列的 httpd.conf 設定檔:</p>



<pre class="wp-block-code"><code>Define SRVROOT "C:/xampp_lite/apps/apache"
ServerRoot "C:/xampp_lite/apps/apache"
Listen 80
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule actions_module modules/mod_actions.so
LoadModule alias_module modules/mod_alias.so
LoadModule allowmethods_module modules/mod_allowmethods.so
LoadModule asis_module modules/mod_asis.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule cgi_module modules/mod_cgi.so
LoadModule dav_lock_module modules/mod_dav_lock.so
LoadModule dir_module modules/mod_dir.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule include_module modules/mod_include.so
LoadModule info_module modules/mod_info.so
LoadModule isapi_module modules/mod_isapi.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule cache_disk_module modules/mod_cache_disk.so
LoadModule mime_module modules/mod_mime.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule status_module modules/mod_status.so
LoadModule version_module modules/mod_version.so
&lt;IfModule unixd_module>
User daemon
Group daemon
&lt;/IfModule>
ServerAdmin postmaster@localhost
ServerName localhost:80
&lt;Directory />
    AllowOverride none
    Require all denied
&lt;/Directory>
DocumentRoot "C:/your-path/web"
&lt;Directory "C:/your-path/web">
    Options Indexes FollowSymLinks Includes ExecCGI
    AllowOverride All
    Require all granted
&lt;/Directory>
&lt;IfModule dir_module>
    DirectoryIndex index.php index.pl index.cgi index.asp index.shtml index.html index.htm \
                   default.php default.pl default.cgi default.asp default.shtml default.html default.htm \
                   home.php home.pl home.cgi home.asp home.shtml home.html home.htm
&lt;/IfModule>
&lt;Files ".ht*">
    Require all denied
&lt;/Files>
ErrorLog "logs/error.log"
LogLevel warn
&lt;IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    &lt;IfModule logio_module>
      # You need to enable mod_logio.c to use %I and %O
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    &lt;/IfModule>
    CustomLog "logs/access.log" combined
&lt;/IfModule>
&lt;IfModule alias_module>
    ScriptAlias /cgi-bin/ "C:/xampp_lite/cgi-bin/"
&lt;/IfModule>
&lt;IfModule cgid_module>
&lt;/IfModule>
&lt;Directory "C:/xampp_lite/cgi-bin">
    AllowOverride All
    Options None
    Require all granted
&lt;/Directory>
&lt;IfModule headers_module>
    RequestHeader unset Proxy early
&lt;/IfModule>
&lt;IfModule mime_module>
    TypesConfig conf/mime.types
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
    AddHandler cgi-script .cgi .pl .asp
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml
&lt;/IfModule>
&lt;IfModule mime_magic_module>
    MIMEMagicFile "conf/magic"
&lt;/IfModule>
Include conf/extra/httpd-mpm.conf
Include conf/extra/httpd-autoindex.conf
Include conf/extra/httpd-languages.conf
Include conf/extra/httpd-userdir.conf
Include conf/extra/httpd-info.conf
Include conf/extra/httpd-vhosts.conf
Include "conf/extra/httpd-default.conf"
Include "conf/extra/httpd-xampp-lite.conf"
&lt;IfModule proxy_html_module>
Include conf/extra/proxy-html.conf
&lt;/IfModule>
Include conf/extra/httpd-ssl.conf
&lt;IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
&lt;/IfModule>
AcceptFilter http none
AcceptFilter https none
&lt;IfModule mod_proxy.c>
&lt;IfModule mod_proxy_ajp.c>
&lt;/IfModule>
&lt;/IfModule></code></pre>



<p>請手動修改上面的 C:/your-path/web 為你實際的 web root path.</p>



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



<p>在 Windows 上安裝 PHP 其實不難，主要有手動安裝和使用整合軟體兩種方式。如果你是初學者，建議用整合軟體會省掉很多設定麻煩。</p>



<h2 class="wp-block-heading">使用整合軟體（推薦初學者）</h2>



<p>這類軟體通常叫做 XAMPP 或 WAMP。它們把 PHP、資料庫 MySQL 和網頁伺服器 Apache 打包在一起，點幾下滑鼠就裝好了。</p>



<ol start="1" class="wp-block-list">
<li>到 XAMPP 官網下載安裝檔。</li>



<li>執行安裝程式，基本上一直點下一步就好。</li>



<li>預設會裝在 C 槽的 xampp 資料夾。</li>



<li>安裝完打開 XAMPP Control Panel，點擊 Apache 後面的 Start。</li>



<li>把你的 PHP 檔案丟到 C:\xampp\htdocs，用瀏覽器打開 localhost 就能看到結果。</li>
</ol>



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



<h2 class="wp-block-heading">手動安裝步驟</h2>



<p>如果你想要自己掌控版本，可以選擇手動安裝。這會需要一點點電腦路徑的操作。</p>



<ol start="1" class="wp-block-list">
<li>到 PHP for Windows 官網下載 Zip 壓縮檔，記得選 Thread Safe 版本。</li>



<li>在 C 槽建立一個資料夾叫 php，把壓縮檔裡的所有東西解壓縮進去。</li>



<li>進入該資料夾，把 php.ini-development 改名成 php.ini。</li>



<li>設定環境變數。打開電腦的進階系統設定，找到環境變數裡的 Path。</li>



<li>新增一條路徑，填入 C:\php。這讓你能在任何地方用終端機執行 PHP 指令。</li>



<li>打開 CMD 輸入 php -v，如果有顯示版本號碼就代表成功了。</li>
</ol>



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



<p>手動安裝雖然比較乾淨，但如果你還要架資料庫，建議還是用整合包比較快。</p>



<p>想了解怎麼在 VS Code 裡面跑 PHP 嗎？</p>



<p>如果你在安裝過程中遇到困難，這段影片示範了如何在 Windows 10 或 11 上手動下載並安裝 PHP 的完整流程：<a target="_blank" rel="noreferrer noopener" href="https://www.youtube.com/watch?v=gG5h4zskTeE">Windows PHP 手動安裝教學</a></p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2025/12/windows-install-php/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
