WordPress 上傳檔案大小限制改了沒用?拆解 4 層

PHP 官方手冊寫得很清楚,upload_max_filesize 的預設值只有 2MB。但同一份規格,落到各家主機商手上實際調整的幅度落差極大,有的主機一開機就給到 64MB 甚至更高,有的卻死守在 8MB 附近動也不動。更麻煩的是,就算主機端已經調到夠大,只要網站前面多掛一層 CDN 或防火牆,Cloudflare 官方文件顯示免費與 Pro 方案的上傳上限也只有 100MB,上限又會被重新收窄一次。

這就是「WordPress 上傳檔案大小限制」最容易讓人卡關的地方。明明後台已經改過設定,影片或高解析度圖片還是傳不上去,還是會跳出「已超過這個網站的檔案上傳限制」這行錯誤訊息。原因不在於改錯了哪個數字,而是這個上限從來就不是單一設定值,而是好幾層各自獨立的天花板疊在一起,只要有一層沒對齊,改了其他層也是白改。

先從這行錯誤訊息實際上是怎麼跳出來的講起,再一層一層拆開它是哪幾個設定疊出來的。

「超過這個網站的檔案上傳限制」是怎麼跳出來的?

這行錯誤訊息不是 WordPress 自己發明的規則,而是它把 PHP 設定值原封不動顯示給使用者看。翻開 WordPress 官方開發文件裡 upload_size_limit 這個 filter,可以直接看到底層邏輯是這一行:

return apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );Code language: PHP (php)

這段程式碼由核心函式 wp_max_upload_size() 呼叫。它做的事很單純,讀取 PHP 的 upload_max_filesizepost_max_size 兩個值,取其中較小的那一個,當作媒體庫顯示與實際生效的上限。也就是說,無論後台看到的數字是多少,它永遠是這兩個 PHP 設定裡比較小的那個,不是 WordPress 另外訂出來的門檻。

後台有兩個地方都能親眼看到目前的上限。「媒體庫 > 新增媒體」的上傳頁面下方,會直接寫出目前允許的檔案大小;「工具 > 網站健康 > 資訊」裡的「媒體處理」區塊,也會列出同一個數字。這兩處看到的都不是 WordPress 自訂的規則,而是它動態讀出 PHP 層當下數值後算出來的結果。

這只是第一層。後面還有其他幾層各自設了自己的門檻,疊在一起才是實際能上傳的檔案大小,這也是為什麼「改了上傳限制」常常還是沒有用的原因。

為什麼「改了上傳限制」卻常常沒有效?

多數人調這個設定時,只改了後台看得到的 upload_max_filesize,以為這樣就夠了。實際上,能不能順利傳上一個大檔案,要看四層各自獨立的門檻是不是都放大到位。只要其中一層比其他層低,最終生效的永遠是四層裡最小的那個數字,改了其他層等於沒改。

層級涉及設定誰在管使用者能不能自己改
① PHP 本身upload_max_filesizepost_max_sizememory_limitPHP 直譯器能,但方法依設定而異(見下一節)
② WordPress 內部upload_size_limit filter,取①的最小值WordPress 核心能透過程式碼過濾器調整,但無法超過①的實際值
③ 網頁伺服器層Apache 執行模式、Nginx 的 client_max_body_size伺服器軟體需要主機控制台或設定檔存取權才能改
④ CDN/反向代理/防火牆層例如 Cloudflare 的方案上限CDN/WAF 服務商免費與大多數付費方案不能自訂,只能換方案
WordPress 上傳檔案大小限制其實分成 PHP、WordPress 核心、網頁伺服器、CDN 四層,最終能傳多大由設定值最小的那一層決定
檔案要一路通過 PHP、WordPress、Nginx、CDN 四層限制,實際能傳的大小等於設定最小的那一層,一層沒對齊、其他層改再大也沒用。

這四層裡最容易踩雷的是第一層。PHP 官方手冊替每個設定都標了一個「Changeable」欄位,決定它可以在哪裡被改動。memory_limit 屬於 INI_ALL,是這三個裡最寬鬆的一個,可以直接用 ini_set()functions.phpwp-config.php 裡動態修改:

// 這行可以生效,因為 memory_limit 屬於 INI_ALL
ini_set( 'memory_limit', '256M' );Code language: PHP (php)

upload_max_filesizepost_max_size 這兩個設定都屬於 INI_PERDIR,這個層級不允許用 ini_set() 動態設定,只能透過 .htaccessphp.ini 或主機控制台去改。也就是說,下面這種寫法不管貼多少次進 functions.php,都完全不會生效:

// 這兩行寫在 functions.php 或 wp-config.php 都不會生效
ini_set( 'upload_max_filesize', '64M' );
ini_set( 'post_max_size', '64M' );Code language: PHP (php)

這也解釋了為什麼不少教學教人在 functions.phpini_set() 想放大上傳限制,實際套用後卻完全沒有變化。不是設定值錯,是方法從一開始就用錯了層級。

知道問題分散在哪四層之後,與其把 .htaccessphp.ininginx.conf、CDN 設定全部改一輪碰運氣,不如照順序一層一層排查、一層一層放大。

分層排查,一步步找出問題出在哪一層

排查的順序建議照著上面四層的次序走,先看目前卡在哪個數字,再決定要動哪一層,而不是把每個地方的設定都改一遍碰運氣。

WordPress 上傳限制分層排查流程:先到網站健康看生效數字,再依序放大 PHP 三個值與 Nginx client_max_body_size,最後檢查 CDN 是否偷設更低上限
照 PHP、伺服器、CDN 四層順序逐一排查,每放大一層就重測一次,才能對症找出把上傳卡住的那一層。

第一步:到「網站健康」看目前是哪個數字在擋你

打開 WordPress 後台的「工具 > 網站健康 > 資訊」,展開「伺服器」這個區塊,可以直接看到目前 upload_max_filesizepost_max_sizememory_limit 三個實際生效的數值;往上翻到「媒體處理」區塊,則會看到系統算出來的「單一檔案最大上傳大小」,也就是前面提到取最小值後的結果。

WordPress 工具、網站健康的除錯資訊頁,媒體處理區塊顯示有效檔案大小上限為 40 MB,也就是目前實際生效的單檔上傳上限
網站健康 › 資訊 › 媒體處理裡的『有效檔案大小上限』就是目前真正生效的單檔上傳上限,排查前先來這裡確認卡在哪個數字。

先看這個頁面再動手有個好處,如果這裡顯示的數字已經夠大(比如已經是 128MB),但上傳還是失敗、還跳出錯誤,問題多半不在 PHP 層,而是卡在後面的伺服器層或 CDN 層。這種情況再回頭一直調 PHP 設定不會有幫助,該往第三步、第四步去查。

第二步:PHP 三個數值要一起調,不能只改一個

確認問題出在 PHP 層之後,接下來要放大的是 upload_max_filesizepost_max_sizememory_limit 三個數值,而且順序有講究,memory_limit 要大於等於 post_max_sizepost_max_size 又要大於等於 upload_max_filesize。只放大第一個、後兩個沒跟著調,上傳照樣會被卡在中間那一層。

如果是共享主機,最常見的做法是在網站根目錄的 .htaccess 檔案裡加上三行:

php_value upload_max_filesize 64M
php_value post_max_size 64M
php_value memory_limit 256MCode language: plaintext (plaintext)

不過這個寫法有個前提,主機的 PHP 要是用 Apache 的 mod_php 模式在跑,才認得 php_value 這個指令。如果主機是用 CGI 或 FastCGI 模式執行 PHP(不少較新的共享主機、雲端主機都是這個模式),.htaccess 裡加 php_value 反而會直接讓整個網站跳出 500 錯誤,這時候要改用下一種方法,或直接聯絡主機商。

如果主機允許存取 php.ini(通常是 VPS 或有主機控制權限的環境),可以直接找到對應的檔案,把這三行數值改成想要的大小:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256MCode language: plaintext (plaintext)

改完要記得讓 PHP 重新讀取設定才會生效,這點會在後面「四層只要有一層沒對齊」那一節詳細說。

不少使用 cPanel 控制台的主機,不需要碰任何檔案,後台裡就有「MultiPHP INI Editor」這個工具。選擇要修改的網域,切到「Editor Mode」,就能直接在介面上找到 upload_max_filesizepost_max_sizememory_limit 三個欄位,輸入數字存檔即可,不用手動寫語法,也不用擔心打錯字元。

PHP 層調完只是完成一半,如果主機跑的是 Nginx,還有一層預設更嚴格的門檻在前面等著。

第三步:網頁伺服器層也要放大,Nginx 預設更小

不少雲端主機、容器化架設、部分較新的代管方案,實際上是用 Nginx 而不是 Apache 在處理請求。Nginx 官方文件裡,client_max_body_size 這個指令的預設值只有 1MB,而且它可以放在 httpserverlocation 三種區塊裡設定。也就是說,就算 PHP 層的三個數值都已經放大到位,請求進到 PHP 之前,只要超過這個 1MB 的預設上限,Nginx 就會直接擋下來,回傳 413 錯誤,PHP 根本沒有機會處理這次請求。

調整方式是找到 nginx.conf 或對應網站的設定檔,在合適的區塊加上這一行,再重新載入(不是重啟)Nginx 服務:

client_max_body_size 100m;Code language: plaintext (plaintext)

判斷卡在哪一層有個簡單方法,如果瀏覽器跳出來的錯誤是數字「413」,而不是 WordPress 常見的「已超過這個網站的檔案上傳限制」這行文字提示,通常就代表卡在這一層,而不是 PHP 層,該往 nginx.conf 去查,不用再回頭改 php.ini

第四步:檢查 CDN、防火牆有沒有偷偷設更低的上限

這是最常被漏掉的一層,也是「主機端明明都調好了、上傳卻還是卡在同一個數字」最常見的真正原因。如果網站前面有掛 Cloudflare 之類的 CDN、反向代理或 WAF,它會在請求送到主機之前就先檢查一次檔案大小,跟主機端、PHP 端的設定完全無關,調得再大也沒用。

Cloudflare 官方文件公布的各方案上傳上限如下:免費與 Pro 方案都是 100MB,Business 方案提高到 200MB,企業版則要另外與 Cloudflare 洽談才能再往上調。如果網站掛在免費或 Pro 方案下,單一檔案想傳超過 100MB,不管主機端和 PHP 端再怎麼放大,都會在這一層被擋下來。

判斷方法很簡單,先把該網域在 Cloudflare 的 DNS 設定裡,暫時切成「僅 DNS」模式(那個橘色雲朵圖示會變成灰色,代表暫時關閉代理,流量直接打到主機),再測試一次上傳。如果切成灰色雲朵後就能順利傳上去,就能確定問題出在 CDN 這一層,而不是主機或 PHP 設定;測試完記得把代理切回原本的橘色雲朵狀態。

排查到這裡,四層各自要放大的地方都講完了,接下來看幾個「明明照著改了、還是沒生效」的常見誤區。

四層只要有一層沒對齊,上傳限制照樣改了沒用

即使把上面四層的設定都改過一遍,還是有幾個常見誤區會讓改動看起來「沒生效」。

  1. 改完 php.ini.htaccess 後,沒有讓 Apache 或 PHP-FPM 重新讀取設定。設定檔本身有快取,大多數共享主機需要主機商協助重新載入服務,VPS 或有主機控制權限的環境則要自己重啟 PHP-FPM 或 Apache 服務,不重啟,改了的數值就不會套用。
  2. 只顧著調 upload_max_filesize,卻忘記 post_max_sizememory_limit 也要跟著放大。三個數值要維持大小關係,漏調其中一個,上傳依舊會被卡在中間那一層,看起來就像「改了沒用」。
  3. 在 CGI 或 FastCGI 模式下的 Apache 主機,用 .htaccessphp_value 反而會直接造成 500 錯誤。這種情況容易被誤以為是「設定寫錯」,回頭反覆檢查語法,其實是方法從一開始就用錯了層級,該換成 php.ini 或聯絡主機商代為調整。

另外,如果網站是用 WordPress 多站網路(Multisite)在跑,「網路設定」裡還另外藏著一個「Max upload file size」欄位,這是 WordPress 內部又疊加的一層限制,只能設定得比伺服器實際上限更低,就算把這個欄位設得比伺服器上限還高,也不會真的生效,上限還是回到伺服器實際能給的那個數字。

上傳限制還是放大不了,怎麼辦?兩個能應急的替代方案

如果四層都排查過一遍,問題卡在主機端的硬性上限(常見於部分共享主機,主機商直接把數值鎖死,後台跟設定檔都改不了),還有兩個能應急的路可以走。

第一個是直接聯絡主機商客服,請求調高帳號的上傳上限。這其實是最快,也是多數共享主機使用者唯一能真正突破硬性上限的做法。主機商內部通常有辦法在伺服器端直接調整,不需要自己碰任何設定檔。

第二個是改用 FTP 或 SFTP,把檔案直接傳到伺服器上的媒體目錄,再從媒體庫的匯入功能把檔案讀進 WordPress,藉此繞過瀏覽器上傳這條路徑會經過的 PHP 限制。要注意的是,這個方法只繞過 PHP 與 WordPress 這兩層,如果 Nginx 或 CDN 那兩層還設有更低的請求大小限制,即使用 FTP 傳上伺服器,後續媒體庫要讀取或處理這個檔案時,還是可能碰到同樣的門檻。

補充一點,如果常態性都在處理大型影音檔案,更根本的做法是改放到外部的影音託管平台,再把連結或嵌入碼放進頁面裡,而不是每次都想著要把上傳上限再往上調。檔案越放越大,四層門檻遲早又會追上來。

下次 WordPress 網站又跳出「已超過這個網站的檔案上傳限制」,與其把 .htaccessphp.ininginx.conf、CDN 設定全部改一輪碰運氣,不如先照順序想清楚,目前的數字卡在哪一層,再對症把那一層放大。四層都對齊了,同一個檔案才能真正一次傳上去。

資料來源
  1. Description of core php.ini directives — PHP 官方手冊
  2. wp_max_upload_size() – Function — WordPress 官方開發文件
  3. Module ngx_http_core_module(client_max_body_size) — Nginx 官方文件
  4. Error 413 — Cloudflare 官方文件