WordPress ขึ้น "HTTP error" ตอนอัพโหลดรูป: ผังตัดสินใจที่หาต้นเหตุเจอจริง
หาสาเหตุที่แท้จริงของ HTTP error ตอนอัพโหลดรูปใน WordPress ด้วยการตรวจครั้งเดียว แล้วแก้ให้ตรงกิ่ง ไม่ว่าจะเป็นไฟร์วอลล์ หน่วยความจำ PHP post_max_size หรือ Imagick
เผยแพร่แล้ว
“HTTP error” ไม่ใช่สาเหตุ มันคือการที่ตัวอัพโหลดสื่อยอมรับว่าส่งไฟล์ไปที่เซิร์ฟเวอร์แล้ว แต่ได้คำตอบกลับมาแบบที่ตีความเป็นความสำเร็จไม่ได้ และมีความล้มเหลวอย่างน้อยหกแบบที่ไม่เกี่ยวกันเลย ซึ่งให้ข้อความสามคำเดียวกันนี้ การเดาสุ่มระหว่างหกแบบนั้นคือเหตุผลที่หลายคนเสียเวลาทั้งบ่ายไปกับการเพิ่ม upload_max_filesize บนเว็บที่ปัญหาจริงคือกฎไฟร์วอลล์
ทางออกที่เร็วที่สุดคือการสังเกตเพียงจุดเดียว ที่แยกหกสาเหตุออกเป็นสองกลุ่ม แล้วตรวจเพิ่มอีกกิ่งละหนึ่งอย่าง
ก่อนอื่น: อ่านคำตอบตัวจริง
เปิดเครื่องมือนักพัฒนาในเบราว์เซอร์ ไปที่แท็บ Network แล้วอัพโหลดไฟล์อีกครั้ง จับตาดูคำขอที่ยิงไปยัง async-upload.php สิ่งที่ตอบกลับมาคือผลวินิจฉัยของคุณ
| สิ่งที่คุณเห็น | ความหมาย | ไปที่ |
|---|---|---|
| 403 หรือ 406 เนื้อหาเป็น HTML | ไฟร์วอลล์หรือ mod_security ปฏิเสธคำขอ | กิ่ง A |
| 500 หรือคำตอบเปล่า หรือเนื้อหาขาดกลางคัน | PHP พังหรือหน่วยความจำหมดกลางทาง | กิ่ง B |
| 413 | เนื้อหาคำขอเกินลิมิตของเซิร์ฟเวอร์ | กิ่ง C |
| 200 แต่เนื้อหาไม่ใช่ JSON ที่สะอาด | ปลั๊กอินหรือธีมพิมพ์อะไรออกมาก่อนคำตอบ | กิ่ง D |
| คำขอไม่จบสักที หรือหมดเวลา | ลิมิตเวลาประมวลผล มักเกิดกับไฟล์ใหญ่ | กิ่ง B |
การมองครั้งเดียวนั้นตัดคำแนะนำส่วนใหญ่บนอินเทอร์เน็ตออกไปให้คุณเลย ถ้าเข้าเครื่องมือในเบราว์เซอร์ไม่ได้ ให้เปิดการบันทึก log ใน wp-config.php ก่อน:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
ทำให้เกิดปัญหาซ้ำ แล้วเปิดอ่าน wp-content/debug.log บรรทัด fatal error จะระบุกิ่งให้ตรง ๆ ถ้าบรรทัดนั้นอ่านยาก ลองวางลงใน ตัวถอดรหัส error log ซึ่งจับคู่ลายเซ็นของ fatal error ที่พบบ่อยเข้ากับสิ่งที่พังจริง
กิ่ง A — กฎของไฟร์วอลล์หรือ mod_security
403 ที่มีหน้า HTML อยู่ในเนื้อหา แปลว่าคำขอนั้นไปไม่ถึง WordPress เลย มีบางอย่างที่ยืนอยู่ข้างหน้า ไม่ว่าจะเป็น mod_security, Cloudflare, Wordfence, Sucuri หรือชุดกฎของโฮสต์เอง ตัดสินว่าคำขอ POST นั้นดูอันตราย
วิธีตรวจ: ปิดปลั๊กอินความปลอดภัยชั่วคราว แล้วอัพโหลดใหม่ ถ้าไม่มีอะไรเปลี่ยน แปลว่ากฎอยู่ที่ระดับเซิร์ฟเวอร์ และคุณต้องให้โฮสต์เข้าไปดู mod_security audit log ที่เวลาซึ่งการอัพโหลดล้มเหลว เขาจะปลดล็อกกฎเฉพาะรหัสนั้นให้ได้
พูดกันตรง ๆ เรื่องคำแนะนำที่คุณจะเจอในหัวข้อนี้ สคริปต์ที่บอกให้คุณวางบรรทัดนี้ลงใน .htaccess:
SecFilterEngine Off
SecFilterScanPOST Off
ใช้กับ mod_security 1.x ซึ่งแทบสูญพันธุ์ไปแล้ว บนเซิร์ฟเวอร์สมัยใหม่ คำสั่งพวกนี้ไม่ทำอะไรเลย หรือไม่ก็โยน 500 ออกมาทำให้เว็บแย่ลงกว่าเดิม mod_security รุ่นใหม่ใช้ SecRuleEngine และโฮสต์แบบ managed ส่วนใหญ่ก็บล็อกการเขียนทับค่านี้รายไดเรกทอรีอยู่แล้ว ถามโฮสต์เถอะ อย่าก๊อบวาง
กิ่ง B — ลิมิตหน่วยความจำหรือเวลาประมวลผลของ PHP
นี่คือกิ่งที่พบบ่อยที่สุด และมีสัญญาณชัดที่สุด คือ มันเกิดบ้างไม่เกิดบ้าง ไฟล์เดิมอัพโหลดผ่านในครั้งที่สาม หรือรูป 2MB ล้มเหลวขณะที่ PDF 6MB ผ่านฉลุย ลิมิตในการตั้งค่าแบบตายตัวจะล้มเหลวเหมือนเดิมทุกครั้ง แต่ปัญหาหน่วยความจำไม่เป็นแบบนั้น เพราะปริมาณที่ว่างขึ้นอยู่กับว่าเซิร์ฟเวอร์กำลังทำอะไรอยู่
ทำไมต้องเป็นรูปภาพโดยเฉพาะ เพราะ WordPress ไม่ได้แค่เก็บไฟล์ แต่คลายมันออกเป็นพิกเซลดิบเพื่อสร้างขนาดกลางทางทุกขนาด ทั้ง medium_large ทุกขนาดที่ลงทะเบียนไว้ด้วย add_image_size รวมถึง woocommerce_thumbnail ถ้าคุณเปิดร้านค้า บวกสำเนา -scaled อีกหนึ่งชุดถ้าภาพใหญ่เกิน big_image_size_threshold ไฟล์ JPEG 12 ล้านพิกเซลมีขนาดไม่กี่ MB บนดิสก์ แต่กินราว 48MB ในหน่วยความจำ ก่อนจะนับบัฟเฟอร์สำหรับย่อภาพด้วยซ้ำ ลิมิต 128MB จึงหมดไปอย่างรวดเร็ว
เพิ่มค่าใน wp-config.php เหนือบรรทัด “stop editing”:
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );
ต้นทุนจริงคือ WP_MEMORY_LIMIT ไม่สามารถเกินค่าที่ PHP อนุญาตได้ ถ้าโฮสต์ล็อก memory_limit ไว้ที่ 128M ค่าคงที่นี้ก็เป็นแค่ของประดับ ตรวจค่าจริงได้ที่ Tools → Site Health → Info → Server ไม่ใช่จากสิ่งที่คุณพิมพ์ลงไป ถ้าลิมิตของ PHP เองคือเพดาน มีแต่โฮสต์เท่านั้นที่ขยับได้
กิ่ง C — ลิมิตขนาดไฟล์และขนาดคำขอ
ดูตัวเลขจริงได้ที่ Tools → Site Health → Info → Media Handling มีสองค่าที่สำคัญ แต่คนมักเปลี่ยนแค่ค่าเดียว
upload_max_filesize— เพดานของไฟล์เดี่ยวpost_max_size— เพดานของเนื้อหาคำขอ ทั้งก้อน
ถ้าคำขอ POST ทั้งก้อนเกิน post_max_size PHP จะทิ้งคำขอนั้นก่อนที่ WordPress จะได้รันโค้ดสักบรรทัด จึงไม่มีอะไรให้ตอบกลับ ตัวอัพโหลดได้คำตอบที่ตีความไม่ได้และขึ้นว่า “HTTP error” ค่า post_max_size ควรใหญ่กว่า upload_max_filesize อย่างสบาย ๆ เสมอ
มีข้อสังเกตที่ควรรู้ เมื่อไฟล์เกินแค่ upload_max_filesize ตัวอัพโหลดมักดักได้ตั้งแต่ในเบราว์เซอร์และบอกว่าไฟล์เกินขนาดสูงสุดที่อัพโหลดได้ ซึ่งเป็นข้อความที่ชัดเจนกว่า ดังนั้น “HTTP error” เปล่า ๆ จึงชี้ไปที่ post_max_size หรือกิ่ง B บ่อยกว่าค่าที่ทุกคนรีบเพิ่มเป็นอย่างแรก
จะแก้ที่ไหนขึ้นอยู่กับสแตกของคุณ บน Apache ที่ใช้ mod_php ใช้ .htaccess ได้:
php_value upload_max_filesize 64M
php_value post_max_size 128M
บน PHP-FPM, LiteSpeed หรือ NGINX ซึ่งคือโฮสติ้งสมัยใหม่ส่วนใหญ่ บรรทัดพวกนี้ไม่ทำอะไรเลย และอาจโยน 500 ออกมา ให้ใช้แผงตั้งค่า PHP ของโฮสต์ หรือไฟล์ .user.ini แทน NGINX ยังบังคับใช้ client_max_body_size ของตัวเองด้วย ซึ่งมีแต่โฮสต์เท่านั้นที่เพิ่มให้ได้
กิ่ง D — ไลบรารีจัดการภาพ (Imagick กับ GD)
WordPress เลือกใช้ ImageMagick ก่อนถ้ามีส่วนขยาย PHP ตัวนั้นอยู่ ไม่อย่างนั้นก็ถอยไปใช้ GD บนโฮสต์แบบแชร์ ImageMagick มักเป็นตัวปัญหา เพราะไฟล์กำหนดนโยบายของมันจำกัดหน่วยความจำ พื้นที่ดิสก์ และพื้นที่ภาพต่อหนึ่งการทำงาน และเมื่อการย่อภาพชนลิมิตใดลิมิตหนึ่ง โปรเซสก็ตายโดยไม่มีข้อความที่เป็นประโยชน์ คุณมักเจออาการนี้กับภาพใหญ่ ขณะที่ภาพเล็กทำงานได้ปกติ ซึ่งดูเหมือนกิ่ง B แต่ไม่ใช่
บังคับใช้ GD เพื่อทดสอบสมมติฐาน:
add_filter( 'wp_image_editors', function ( $editors ) {
return array( 'WP_Image_Editor_GD' );
} );
วางไว้ใน functions.php หรือทำเป็น mu-plugin เล็ก ๆ ลองอัพโหลดใหม่ แล้วเอาออกถ้าไม่มีอะไรเปลี่ยน
ข้อแลกเปลี่ยนตามจริง: GD ไม่ได้ดีกว่าเสมอไป มันเก็บบิตแมปที่คลายแล้วทั้งหมดไว้ในหน่วยความจำของ PHP ดังนั้นกับไฟล์ขนาดใหญ่มาก มันอาจชน memory_limit ในจุดที่ ImageMagick ซึ่งทำงานบางส่วนนอกการจองหน่วยความจำของ PHP ทำสำเร็จได้ การสลับจึงอาจเป็นการแลกความล้มเหลวแบบหนึ่งกับอีกแบบหนึ่ง ให้ถือว่ามันเป็นเครื่องมือวินิจฉัยก่อน แล้วค่อยเป็นทางแก้
กิ่ง E — สิทธิ์ของไดเรกทอรี uploads
พบน้อยบนโฮสต์แบบ managed แต่พบบ่อยหลังการย้ายเว็บหรือย้ายเซิร์ฟเวอร์ด้วยมือ ถ้า wp-content/uploads ไม่เปิดให้ผู้ใช้ของเว็บเซิร์ฟเวอร์เขียนได้ หรือโฟลเดอร์ย่อยปี/เดือนที่เพิ่งสร้างได้เจ้าของผิดคนมา การเขียนก็ล้มเหลว
ls -ld wp-content/uploads
ls -ld wp-content/uploads/2026/07
โดยทั่วไปไดเรกทอรีควรเป็น 755 และเป็นของผู้ใช้ที่ PHP รันอยู่ อย่าตั้ง 777 เพียงเพราะมีคนในเว็บบอร์ดบอกให้ทำ เพราะมันแก้อาการด้วยการเปิดให้ทุกบัญชีบนเซิร์ฟเวอร์เขียนโฟลเดอร์นั้นได้ ซึ่งบนโฮสต์แบบแชร์ถือเป็นช่องโหว่ของจริง
กิ่ง F — ชื่อไฟล์
เป็นการตรวจที่ถูกที่สุดในรายการนี้ ทำตั้งแต่แรกได้เลยแม้จะมีโอกาสน้อยที่สุด เปลี่ยนชื่อไฟล์เป็นตัวพิมพ์เล็ก ตัวเลข และขีดกลางล้วน ๆ ไม่มีเครื่องหมายเสริมสัทอักษร อะพอสทรอฟี แอมเปอร์แซนด์ # หรืออักขระที่ไม่ใช่ละติน แล้วอัพโหลดใหม่ อักขระพิเศษบางครั้งไปสะดุดกฎความปลอดภัย หรือพังบนระบบไฟล์ที่ตั้งค่าการเข้ารหัสไม่ตรงกัน ใช้เวลาสิบวินาทีเพื่อตัดออกจากรายการ
สิ่งที่ไม่ควรทำ
อย่าเริ่มด้วยการปิดปลั๊กอินทั้งหมด มันกระทบการใช้งาน และทดสอบได้แค่กิ่ง A กับกิ่ง D เท่านั้น คำตอบจากแท็บ network บอกคุณได้มากกว่าภายในห้าวินาที
อย่าใส่บรรทัด handler มั่ว ๆ ลงใน .htaccess สคริปต์ที่แชร์กันซึ่งเพิ่มคำสั่ง SetHandler หรือ AddHandler ตั้งอยู่บนสมมติฐานว่าโฮสต์ตั้งค่า PHP แบบหนึ่งเท่านั้น บนสแตกที่ไม่ตรงกัน มันทำให้เว็บทั้งเว็บล่มด้วย 500
อย่ารับว่า “ลองใหม่แล้วผ่าน” คือแก้แล้ว การสำเร็จแบบสุ่มคือลายเซ็นของกิ่ง B และมันจะกลับมาทันทีที่เซิร์ฟเวอร์งานหนัก หรือมีคนอัพโหลดไฟล์ที่ใหญ่กว่าเดิม
ยังติดอยู่ใช่ไหม
ถ้าคำตอบเป็น 200 สะอาด ๆ พร้อม JSON ที่ถูกต้อง แต่การอัพโหลดยังล้มเหลว แสดงว่าจุดที่พังอยู่หลังจากไฟล์ลงพื้นที่แล้ว ซึ่งมักเป็นปลั๊กอินที่เกี่ยวเข้ากับขั้นตอนประมวลผลไฟล์แนบแล้วโยน fatal error ออกมา หรือปลั๊กอินบีบอัดภาพที่ยิงคำขอของตัวเองไปยังบริการภายนอกแล้วหมดเวลา เปิด WP_DEBUG_LOG ทำให้เกิดปัญหาซ้ำ แล้วเอา fatal error ที่ได้ไปรันผ่าน ตัวถอดรหัส error log เพื่อดูว่าไฟล์ไหนและ hook ไหนที่รับผิดชอบจริง ๆ
FAQ
คำถาม
HTTP error ตอนอัพโหลดรูปเข้า WordPress หมายความว่าอะไร
แปลว่าตัวอัพโหลดในเบราว์เซอร์ส่งไฟล์ไปที่เซิร์ฟเวอร์แล้ว แต่ได้คำตอบกลับมาเป็นสิ่งที่มันตีความเป็นผลสำเร็จไม่ได้ ข้อความนี้บอกอาการ ไม่ได้บอกสาเหตุ ทั้งโปรเซส PHP ที่พัง ไฟร์วอลล์ที่บล็อก สถานะ 403 และการตอบกลับที่ว่างเปล่า ล้วนทำให้ขึ้นข้อความสามคำเดียวกันนี้
ทำไมรูปเดียวกันบางครั้งอัพโหลดผ่าน บางครั้งไม่ผ่าน
อาการที่เกิดบ้างไม่เกิดบ้างเกือบทั้งหมดชี้ไปที่หน่วยความจำหรือ CPU ไม่พอ มากกว่าจะเป็นลิมิตในการตั้งค่า การย่อภาพขนาดใหญ่ต้องใช้หน่วยความจำก้อนโตชั่วขณะ และบนโฮสต์แบบแชร์ ปริมาณที่ว่างจะเปลี่ยนไปตามภาระของเซิร์ฟเวอร์ ส่วนลิมิตตายตัวอย่าง post_max_size จะพังเหมือนเดิมทุกครั้งไม่มีพลาด
การสลับ WordPress จาก Imagick ไปใช้ GD แก้ HTTP error ได้ไหม
บางครั้งได้ และได้เฉพาะกิ่งเดียวเท่านั้น ImageMagick บนโฮสต์แบบแชร์มักถูกจำกัดด้วยไฟล์นโยบายหรือลิมิตทรัพยากรที่ต่ำ จึงพังในจุดที่ GD ทำงานได้ แต่ GD ใช้หน่วยความจำมากกว่ากับไฟล์ขนาดใหญ่มาก การสลับจึงอาจทำให้ปัญหาที่เกิดจากหน่วยความจำแย่ลงแทนที่จะดีขึ้น
จะรู้ได้อย่างไรว่าไฟร์วอลล์ของโฮสต์กำลังบล็อกการอัพโหลด
เปิดเครื่องมือ network ในเบราว์เซอร์ อัพโหลดไฟล์ แล้วดูรหัสสถานะที่ได้กลับมาจาก async-upload.php ถ้าเป็น 403 หรือ 406 พร้อมเนื้อหาเป็น HTML แปลว่า web application firewall หรือกฎ mod_security ปฏิเสธคำขอนั้น แต่ถ้าเป็น 500 หรือได้คำตอบเปล่า ๆ ชี้ไปที่ PHP พังมากกว่า
เพิ่ม upload_max_filesize แล้วจะแก้ HTTP error ได้ไหม
ได้เฉพาะกรณีที่ไฟล์เกินลิมิตจริง ๆ และโดยมาก post_max_size สำคัญกว่า ถ้าเนื้อหาคำขอทั้งก้อนใหญ่กว่า post_max_size PHP จะทิ้งมันก่อนที่ WordPress จะได้ทำงาน ตัวอัพโหลดจึงไม่ได้อะไรกลับมาเลย การเพิ่มค่าหนึ่งโดยไม่เพิ่มอีกค่าจึงทิ้งปัญหาไว้ที่เดิม
ชื่อไฟล์ทำให้เกิด HTTP error ใน WordPress ได้ไหม
ได้ แม้จะเป็นกิ่งที่พบน้อยที่สุด อักขระที่มีเครื่องหมายเสริมสัทอักษร อะพอสทรอฟี แอมเปอร์แซนด์ และตัวอักษรที่ไม่ใช่ละติน อาจไปสะดุดกฎความปลอดภัยหรือทำให้พาธเพี้ยนบนระบบไฟล์ที่ตั้งค่าการเข้ารหัสไม่ตรงกัน การเปลี่ยนชื่อเป็นตัวพิมพ์เล็ก ตัวเลข และขีดกลาง ไม่มีต้นทุนอะไรเลย และตัดกิ่งนี้ทิ้งได้ในสิบวินาที