พบปัญหา PrestaShop 8.2 สร้าง SEF URL ภาษาไทยแล้วสระและวรรณยุกต์หาย หรือกด Generate URL ได้แต่บันทึกสินค้าไม่ได้ เพราะระบบแจ้งว่า Friendly URL is invalid บทความนี้จะพาแก้ไขปัญหาที่ต้นเหตุ โดยปรับการรองรับ Unicode ในขั้นตอนสร้างและตรวจสอบ URL พร้อมตั้งค่า Accented URL ให้ถูกต้อง เพื่อให้ลิงก์ภาษาไทยแสดงผลได้ครบถ้วนและบันทึกสินค้าได้ตามปกติ
สาเหตุที่แท้จริง
ปัญหามีสองส่วน ซึ่งอยู่คนละขั้นตอนของระบบ
1. สาเหตุที่ 1: ฟังก์ชันสร้าง URL ลบสระและวรรณยุกต์ภาษาไทย
ไฟล์:
src/Core/Util/String/StringModifier.php
เดิมอยู่ที่บรรทัด 84:
$return_str = preg_replace('/[^a-zA-Z0-9\s\'\:\/\[\]\-\p{L}]/u', '', $return_str);
Regex นี้อนุญาตอักขระ Unicode ประเภท Letter (\p{L}) แต่ไม่ได้อนุญาต Unicode Mark (\p{M})
อักษรภาษาไทยบางส่วน โดยเฉพาะสระและวรรณยุกต์ที่เข้ารหัสเป็น Combining Mark จึงถูกลบออกระหว่างการสร้าง URL
วิธีแก้: เพิ่ม \p{M} ในรายการอักขระที่อนุญาต
$return_str = preg_replace('/[^a-zA-Z0-9\s\'\:\/\[\]\-\p{L}\p{M}]/u', '', $return_str);
ผลที่ได้คือฟังก์ชันสร้าง URL สามารถเก็บอักขระประเภท Mark ที่จำเป็นสำหรับภาษาไทยไว้ได้
สาเหตุที่ 2: ตัวตรวจสอบ URL ปฏิเสธสระและวรรณยุกต์ตอนบันทึกสินค้า
ไฟล์:
src/Core/ConstraintValidator/TypedRegexValidator.php
หลังแก้ปัญหาในขั้นตอนสร้าง URL แล้ว ฟังก์ชัน Generate URL ทำงานได้ แต่เมื่อกด Save ระบบยังแสดงข้อผิดพลาด is invalid
จากการตรวจสอบพบว่า การตรวจสอบ URL ในฟอร์มมีอีกชั้นหนึ่ง ซึ่งใช้ Regex ของตัวเอง และยังไม่อนุญาต Unicode Mark (\p{M})
ดังนั้น แม้ขั้นตอนสร้าง URL จะสร้างข้อความภาษาไทยได้แล้ว ตัวตรวจสอบของฟอร์มก็ยังปฏิเสธข้อความเดียวกัน
วิธีแก้: เพิ่ม \pM ใน Regex ที่ใช้ตรวจสอบ URL ของตัวตรวจสอบนี้
แนวทาง Regex หลังแก้ไข:
return '/^[_a-zA-Z0-9\x{0600}-\x{06FF}\pL\pM\pS-]+$/u';
การเพิ่ม \pM ทำให้ Regex ยอมรับอักขระ Unicode ประเภท Mark ที่จำเป็นสำหรับสระและวรรณยุกต์ภาษาไทย
2. เหตุใดจึงไม่ต้องแก้ Validate.php
ไฟล์:
classes/Validate.php
โค้ดเดิมของเครื่องมี Regex ดังนี้:
return preg_match('/^[_a-zA-Z0-9\x{0E00}-\x{0E7F}\x{0600}-\x{06FF}\pL\pM\pS-]+$/u', $link);
ไฟล์นี้มี \pM อยู่แล้ว จึงรองรับอักขระประเภท Mark และไม่จำเป็นต้องแก้ไขเพิ่มเติม
นอกจากนี้ ผลทดสอบภายใน Container ยืนยันว่า:
PS_ALLOW_ACCENTED_CHARS_URL = 1 Validate::isLinkRewrite = 1 PHP regex status = No error
จึงยืนยันได้ว่า Validate::isLinkRewrite() ยอมรับ URL ตัวอย่างได้ และช่วยแยกปัญหาไปยังขั้นตอนตรวจสอบอีกชั้นหนึ่ง
3. ผลการแก้ไข
ไฟล์ที่แก้ไขมีทั้งหมดสองไฟล์:
- src/Core/Util/String/StringModifier.php
- src/Core/ConstraintValidator/TypedRegexValidator.php
สิ่งที่ดำเนินการ:
- เปิดให้ฟังก์ชันสร้าง URL เก็บ Unicode Mark
- เปิดให้ตัวตรวจสอบ URL ของฟอร์มยอมรับ Unicode Mark
- ตรวจสอบการตั้งค่า PS_ALLOW_ACCENTED_CHARS_URL
- ทดสอบการตรวจสอบ URL ด้วย PHP CLI ภายใน Container
- แก้ไขโค้ดโดยสำรองไฟล์เดิมก่อนเขียนทับ
- ทดสอบกับสินค้า ID 407 จนสามารถสร้าง URL และบันทึกได้สำเร็จ
ไม่จำเป็นต้องแก้ classes/Validate.php เพิ่ม และไม่จำเป็นต้องเปลี่ยนการตั้งค่าฐานข้อมูลเพื่อแก้ปัญหานี้
4. บทเรียนทางเทคนิค
การรองรับภาษาไทยใน SEF URL ไม่ได้ขึ้นอยู่กับการเปิด Accented URL เพียงอย่างเดียว แต่ต้องตรวจสอบให้ครบทั้งกระบวนการ:
- URL generation: ฟังก์ชันต้องไม่ลบสระและวรรณยุกต์ออกระหว่างสร้าง slug
- URL validation: ตัวตรวจสอบต้องยอมรับอักขระเดียวกับที่ขั้นตอนสร้าง URL สร้างขึ้น
- Configuration: ต้องเปิดใช้ Accented URL ให้ตรงกับบริบทของร้าน
- Testing: ต้องทดสอบทั้งการ Generate URL และการ Save สินค้า เพราะการผ่านขั้นตอนแรกไม่ได้รับประกันว่าจะผ่านขั้นตอนที่สอง
สาเหตุสำคัญคือระบบใช้ Regex มากกว่าหนึ่งตำแหน่ง และ Regex เหล่านั้นไม่ได้กำหนดชุดอักขระที่อนุญาตให้สอดคล้องกันทั้งหมด
5. ข้อควรระวังหลังแก้ไข
ไฟล์ทั้งสองเป็นไฟล์ Core ของ PrestaShop การอัปเดตเวอร์ชันในอนาคตอาจเขียนทับการแก้ไขนี้ได้
ควรดำเนินการดังนี้:
- เก็บไฟล์สำรอง .bak-* ที่สร้างไว้
- บันทึกแพตช์ที่เพิ่ม \p{M} ไว้สำหรับนำกลับมาใช้หลังอัปเดต
- หลังอัปเดต PrestaShop ให้ตรวจสอบ Regex ทั้งสองไฟล์อีกครั้ง
- ทดสอบการสร้างและบันทึก URL ภาษาไทยหลังอัปเดต
- สินค้าที่มี URL เดิมผิดอยู่แล้วอาจต้องสร้าง Friendly URL ใหม่เป็นรายสินค้า โดยไม่เปลี่ยนข้อมูลสินค้าทั้งหมดโดยอัตโนมัติ
ข้อสรุป: ปัญหาไม่ได้เกิดจากการตั้งค่า Accented URL หรือฐานข้อมูลโดยตรง แต่เกิดจาก Regex สองตำแหน่งที่จัดการ Unicode Mark ไม่สอดคล้องกัน การแก้ทั้งขั้นตอนสร้าง URL และขั้นตอนตรวจสอบทำให้ PrestaShop 8.2 สามารถสร้างและบันทึก SEF URL ภาษาไทยได้สำเร็จ
฿54.09


