UTF-8 ตลอดทาง


1191

ฉันกำลังตั้งค่าเซิร์ฟเวอร์ใหม่และต้องการรองรับ UTF-8 อย่างเต็มที่ในเว็บแอปพลิเคชันของฉัน ฉันเคยลองสิ่งนี้ในอดีตบนเซิร์ฟเวอร์ที่มีอยู่และดูเหมือนจะจบลงเสมอเมื่อต้องย้อนกลับไปใช้ ISO-8859-1

ฉันต้องตั้งค่าการเข้ารหัส / ชุดอักขระที่ไหน ฉันรู้ว่าฉันต้องกำหนดค่า Apache, MySQL และ PHP ให้ทำเช่นนี้ - มีรายการตรวจสอบมาตรฐานบางอย่างที่ฉันสามารถติดตามได้หรืออาจแก้ไขปัญหาที่เกิดความไม่ตรงกันหรือไม่

นี่เป็นเซิร์ฟเวอร์ Linux ตัวใหม่ที่รัน MySQL 5, PHP, 5 และ Apache 2


8
นี่คือภาพรวมเกี่ยวกับความผิดพลาดในการเข้ารหัสทั้งหมดที่คุณสามารถทำได้: sebastianviereck.de/en/…
Sebastian Viereck


การสนทนาล่าสุดเกี่ยวกับ PHP 7ระบุว่าไม่มีการเปลี่ยนแปลงในตำแหน่ง "ยกเลิกอย่างเป็นทางการ" ในปี 2010 ... มีอะไรเพิ่มเติมเกี่ยวกับ "PHP7 และ UTF-8" ใช่หรือไม่
Peter Krauss

ปัญหานี้เป็นเรื่องปกติ แต่ไม่มีวิธีแก้ปัญหาทางลัดคุณจะต้องตั้งค่าutf-8สำหรับแต่ละรายการแยกกัน - MySQL 5, PHP 5 หรือ Apache 2
Manish Shrivastava

คำตอบ:


1015

การจัดเก็บข้อมูล :

  • ระบุutf8mb4ชุดอักขระบนตารางและคอลัมน์ข้อความทั้งหมดในฐานข้อมูลของคุณ สิ่งนี้ทำให้ MySQL จัดเก็บและเรียกคืนค่าที่เข้ารหัสแบบดั้งเดิมใน UTF-8 โปรดทราบว่า MySQL จะใช้การutf8mb4เข้ารหัสโดยปริยายหากมีการutf8mb4_*ระบุการเรียง (ไม่มีชุดอักขระที่ชัดเจน)

  • ใน MySQL รุ่นเก่า (<5.5.3) คุณจะต้องถูกบังคับให้ใช้อย่างง่ายutf8ซึ่งรองรับเฉพาะชุดอักขระ Unicode ฉันหวังว่าฉันล้อเล่น

การเข้าถึงข้อมูล :

  • ในรหัสใบสมัครของคุณ (เช่น PHP) utf8mb4ในสิ่งที่วิธีการเข้าถึงฐานข้อมูลที่คุณใช้คุณจะต้องตั้งค่าการเชื่อมต่อกับ ด้วยวิธีนี้ MySQL จะไม่ทำการแปลงจาก UTF-8 ดั้งเดิมเมื่อส่งข้อมูลไปยังแอปพลิเคชันของคุณและในทางกลับกัน

  • ไดรเวอร์บางตัวมีกลไกของตัวเองสำหรับการกำหนดค่าชุดอักขระการเชื่อมต่อซึ่งทั้งสองปรับปรุงสถานะภายในของตัวเองและแจ้งให้ MySQL ของการเข้ารหัสที่จะใช้ในการเชื่อมต่อซึ่งมักเป็นวิธีที่ต้องการ ใน PHP:

    • หากคุณใช้เลเยอร์นามธรรมPDOกับ PHP ≥ 5.3.6 คุณสามารถระบุcharsetในDSN :

      $dbh = new PDO('mysql:charset=utf8mb4');
    • หากคุณใช้mysqliคุณสามารถโทรset_charset():

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • หากคุณติดอยู่กับmysqlธรรมดาแต่มีการเรียกใช้ PHP ≥ 5.2.3 คุณสามารถโทรmysql_set_charsetได้

  • ถ้าคนขับไม่ได้ให้กลไกของตัวเองสำหรับการตั้งค่าการเชื่อมต่อชุดตัวอักษรที่คุณอาจจะมีการออกแบบสอบถามเพื่อบอก MySQL SET NAMES 'utf8mb4'วิธีการใช้งานของคุณคาดว่าข้อมูลเกี่ยวกับการเชื่อมต่อที่จะเข้ารหัส:

  • ข้อพิจารณาเดียวกันเกี่ยวกับutf8mb4/ utf8นำไปใช้ข้างต้น

ผลผลิต :

  • หากแอปพลิเคชันของคุณส่งข้อความไปยังระบบอื่นพวกเขาจะต้องได้รับแจ้งเกี่ยวกับการเข้ารหัสอักขระด้วย ด้วยเว็บแอปพลิเคชันเบราว์เซอร์จะต้องได้รับการแจ้งให้ทราบถึงการเข้ารหัสที่ส่งข้อมูล (ผ่านส่วนหัวการตอบกลับ HTTP หรือเมตาดาต้า HTML )

  • ใน PHP คุณสามารถใช้default_charsetตัวเลือก php.ini หรือออกContent-Typeส่วนหัว MIME ด้วยตัวเองซึ่งทำงานได้มากกว่า แต่มีผลเหมือนกัน

  • เมื่อเข้ารหัสเอาต์พุตโดยใช้json_encode()ให้เพิ่มJSON_UNESCAPED_UNICODEเป็นพารามิเตอร์ตัวที่สอง

อินพุต :

  • น่าเสียดายที่คุณควรตรวจสอบสตริงที่ได้รับว่าเป็น UTF-8 ที่ถูกต้องก่อนที่จะลองเก็บหรือใช้ที่ใดก็ได้ PHP mb_check_encoding()นั้นหลอกลวง แต่คุณต้องใช้มันอย่างเคร่งครัด ไม่มีทางแก้ปัญหานี้เนื่องจากลูกค้าประสงค์ร้ายสามารถส่งข้อมูลในสิ่งที่ต้องการเข้ารหัสได้และฉันไม่พบเคล็ดลับในการทำให้ PHP ทำสิ่งนี้ให้คุณอย่างน่าเชื่อถือ

  • จากการอ่านข้อมูลจำเพาะ HTMLปัจจุบันของฉันกระสุนย่อยต่อไปนี้ไม่จำเป็นหรือแม้กระทั่งถูกต้องสำหรับ HTML ที่ทันสมัยอีกต่อไป ฉันเข้าใจว่าเบราว์เซอร์จะทำงานกับและส่งข้อมูลในชุดอักขระที่ระบุไว้สำหรับเอกสาร อย่างไรก็ตามหากคุณกำหนดเป้าหมายเป็น HTML รุ่นเก่า (XHTML, HTML4 เป็นต้น) ประเด็นเหล่านี้อาจยังมีประโยชน์:

    • สำหรับ HTML ก่อน HTML5 เท่านั้น : คุณต้องการให้เบราว์เซอร์ทั้งหมดส่งข้อมูลให้คุณเป็น UTF-8 แต่ถ้าคุณไปโดยวิธีเดียวที่จะทำเช่นนี้ได้อย่างน่าเชื่อถือคือเพิ่มaccept-charsetแอตทริบิวต์ของคุณทั้งหมดTags:<form><form ... accept-charset="UTF-8">
    • สำหรับ HTML ก่อน HTML5 เท่านั้น : โปรดทราบว่าข้อกำหนด W3C HTML บอกว่าลูกค้า "ควร" เป็นค่าเริ่มต้นในการส่งแบบฟอร์มกลับไปที่เซิร์ฟเวอร์ในชุดอักขระใดก็ตามที่เซิร์ฟเวอร์ให้บริการ แต่เห็นได้ชัดว่านี่เป็นเพียงคำแนะนำเท่านั้น<form>แท็ก

ข้อควรพิจารณาเกี่ยวกับรหัสอื่น ๆ :

  • เห็นได้ชัดว่าไฟล์ทั้งหมดที่คุณให้บริการ (PHP, HTML, JavaScript, ฯลฯ ) ควรเข้ารหัสใน UTF-8 ที่ถูกต้อง

  • คุณต้องตรวจสอบให้แน่ใจว่าทุกครั้งที่คุณประมวลผลสตริง UTF-8 คุณต้องทำอย่างปลอดภัย นี่คือส่วนที่ยาก คุณอาจต้องการใช้mbstringส่วนขยายของ PHP อย่างกว้างขวาง

  • การใช้งานสตริงในตัวของ PHP นั้นไม่ได้เป็นค่าเริ่มต้นที่ปลอดภัย UTF-8 มีบางสิ่งที่คุณสามารถทำได้อย่างปลอดภัยกับการทำงานของสตริง PHP ปกติ (เช่นการต่อข้อมูล) แต่สำหรับสิ่งส่วนใหญ่คุณควรใช้mbstringฟังก์ชั่นเทียบเท่า

  • หากต้องการทราบว่าคุณกำลังทำอะไร (อ่าน: อย่าทำให้ยุ่งเหยิง) คุณจำเป็นต้องรู้ UTF-8 และวิธีการทำงานในระดับที่ต่ำที่สุด ตรวจสอบลิงก์ใด ๆ จากutf8.comเพื่อหาแหล่งข้อมูลที่ดีเพื่อเรียนรู้ทุกสิ่งที่คุณจำเป็นต้องรู้


4
ฉันเข้าใจว่าถ้าคุณระบุ collation เป็น utf8_ * มันจะเข้ารหัสเป็น utf8 โดยอัตโนมัติเช่นกัน มันผิดหรือเปล่า?
chazomaticus

49
ฉันไม่ผิด: COLLATE หมายถึงชุดอักขระ ดูเช่นdev.mysql.com/doc/refman/5.0/en/charset-database.html
chazomaticus

7
พิจารณาเพิ่มตัวอย่าง PDO สำหรับการตั้งค่าชุดอักขระเช่นกัน
Ja͢ck

97
โปรดทราบว่า MySQL ไม่พูดภาษาเดียวกันกับทุกคน เมื่อ MySQL บอกว่า "utf8" มันหมายถึง "ตัวแปรบางตัวที่มีการหน่วงเวลาของ UTF-8 ที่ จำกัด อยู่ที่สามไบต์สำหรับพระเจ้าเท่านั้นที่รู้เหตุผลที่ไร้เหตุผล" หากคุณต้องการ UTF-8 จริงๆคุณควรจะบอก MySQL ที่คุณต้องการนี้สิ่งที่แปลก MySQL ชอบเรียกutf8mb4 ไม่ต้องกังวลกับการบันทึกใน "WTF!"
R. Martinho Fernandes

4
คำตอบนี้ช่วยฉันได้มาก แต่ฉันก็พบว่าในกรณีของฉันฉันต้องเพิ่ม JSON_UNESCAPED_UNICODE ใน json_encode PHP ของฉันเมื่อส่งผลลัพธ์แบบสอบถาม DB ผ่าน ajax
Petay87

150

ฉันต้องการเพิ่มสิ่งหนึ่งลงในคำตอบที่ยอดเยี่ยมของ chazomaticus :

อย่าลืมแท็ก META (เช่นนี้หรือเวอร์ชัน HTML4 หรือ XHTML ):

<meta charset="utf-8">

ดูเหมือนว่าจะเล็กน้อย แต่ IE7 ทำให้ฉันมีปัญหามาก่อน

ฉันทำทุกอย่างถูกต้อง ฐานข้อมูลการเชื่อมต่อฐานข้อมูลและส่วนหัว HTTP ของ Content-Type ถูกตั้งค่าเป็น UTF-8 และทำงานได้ดีในเบราว์เซอร์อื่น ๆ ทั้งหมด แต่ Internet Explorer ยังคงยืนยันในการใช้การเข้ารหัส "ยุโรปตะวันตก"

ปรากฏว่าหน้าเว็บไม่มีแท็ก META การเพิ่มที่แก้ปัญหาได้

แก้ไข:

ของ W3C จริงมีขนาดใหญ่มากกว่าส่วนที่ทุ่มเทให้กับ I18N มีหลายบทความที่เกี่ยวข้องกับปัญหานี้ - อธิบายถึงด้าน HTTP, (X) HTML และ CSS:

พวกเขาแนะนำให้ใช้ทั้งส่วนหัว HTTP และเมตาแท็ก HTML (หรือการประกาศ XML ในกรณีที่ XHTML ทำหน้าที่เป็น XML)


ไม่ควรระบุชุดอักขระในส่วนหัว HTTP ด้วยหรือไม่ อาจจะต้องการตัวเลือกการตั้งค่าบางอย่างสำหรับเว็บเซิร์ฟเวอร์ ...
โอลิเวอร์

2
@oliver: ใช่คุณสามารถส่งในส่วนหัว HTTP ได้ แต่จะดีกว่าถ้าส่งในเนื้อหาเพราะหากลูกค้าบันทึกไฟล์มันจะบันทึกเมตาแท็กเสมอ ส่วนหัว HTTP มีแนวโน้มที่จะหายไปนอกเสียจากว่าเบราว์เซอร์นั้นฉลาดพอที่จะคัดลอกลงในเมตาแท็กในไฟล์ที่บันทึกไว้

5
นอกจากนี้ตรวจสอบให้แน่ใจว่าบรรทัดนั้นเป็นลูกคนแรกขององค์ประกอบส่วนหัว (หน้าไฟล์ Unicode) เบราว์เซอร์อาจตีความหน้าเว็บอีกครั้งหลังจากกดปุ่มเมตาองค์ประกอบที่อธิบายไว้ข้างต้น
alex

64

นอกเหนือจากการตั้งค่าdefault_charsetใน php.ini คุณสามารถส่งชุดอักขระที่ถูกต้องโดยใช้header()จากภายในโค้ดของคุณก่อนหน้าเอาต์พุตใด ๆ :

header('Content-Type: text/html; charset=utf-8');

การทำงานกับ Unicode ใน PHP เป็นเรื่องง่ายตราบเท่าที่คุณทราบว่าส่วนใหญ่ของฟังก์ชั่นสตริงจะไม่ได้ทำงานกับ Unicode และบางสายอาจฉีกสมบูรณ์ PHP พิจารณาว่า "อักขระ" จะมีความยาว 1 ไบต์ บางครั้งสิ่งนี้ก็โอเค (ตัวอย่างเช่นexplode()จะค้นหาเฉพาะลำดับไบต์และใช้มันเป็นตัวแยก - ดังนั้นจึงไม่สำคัญว่าคุณจะมองหาตัวอักษรจริง ๆ ) แต่ในบางครั้งเมื่อฟังก์ชั่นนั้นถูกออกแบบมาเพื่อใช้กับตัวละคร PHP ก็ไม่ทราบว่าข้อความของคุณมีอักขระหลายไบต์ที่พบใน Unicode

ห้องสมุดที่ดีที่จะตรวจสอบในเป็นphputf8 นี่เป็นการเขียนฟังก์ชัน "ไม่ดี" ทั้งหมดเพื่อให้คุณสามารถทำงานกับสตริง UTF8 ได้อย่างปลอดภัย มีส่วนขยายเช่นส่วนขยาย mbstring ที่พยายามทำสิ่งนี้ให้คุณเช่นกัน แต่ฉันชอบที่จะใช้ห้องสมุดเพราะมันเป็นแบบพกพามากกว่า (แต่ฉันเขียนผลิตภัณฑ์ตลาดมวลดังนั้นมันสำคัญสำหรับฉัน) แต่ phputf8 สามารถใช้ mbstring เบื้องหลังเพื่อเพิ่มประสิทธิภาพ


ตั้งค่าโอเวอร์โหลดใน php.ini ช่วยเมื่อใช้สตริงที่มีหลายไบต์
Anthony Rutledge

32

ฉันพบปัญหากับคนที่ใช้ PDO และคำตอบคือใช้สำหรับสตริงการเชื่อมต่อ PDO:

$pdo = new PDO(
    'mysql:host=mysql.example.com;dbname=example_db',
    "username",
    "password",
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

เว็บไซต์ที่ฉันนำมาจากนี้หยุดทำงาน แต่ฉันสามารถใช้แคช Google ได้อย่างโชคดี


1
มองหาสิ่งนี้เพิ่มเติมอีกเล็กน้อยสิ่งนี้จำเป็นสำหรับ PHP เวอร์ชันก่อน 5.3.6 เท่านั้น ดูเพิ่มเติมที่: http://stackoverflow.com/a/4361485/2286722 (แม้ว่าพวกเขาจะใช้แยกกัน$dbh->exec("set names utf8");ฉันชอบวิธีที่นำเสนอที่นี่) Btw นอกจากนี้ยังทราบเหมือนกันเกี่ยวกับเรื่องนี้เป็นความคิดเห็นในคู่มือ PHP นี้: php.net/manual/en/pdo.construct.php#96325
Marten Koetsier


24

ในกรณีของฉันฉันใช้mb_splitซึ่งใช้ regex ดังนั้นฉันยังต้องตรวจสอบให้แน่ใจด้วยตนเองว่าการเข้ารหัส regex เป็น utf-8 โดยการทำmb_regex_encoding('UTF-8');

ตามบันทึกข้างผมยังค้นพบโดยการเรียกmb_internal_encoding()ว่าการเข้ารหัสภายในไม่ได้ UTF-8 mb_internal_encoding("UTF-8");และผมเปลี่ยนที่โดยการทำงาน


22

ก่อนอื่นถ้าคุณอยู่ใน <5.3PHP ดังนั้นไม่ คุณมีปัญหามากมายที่จะแก้ไขปัญหา

ฉันประหลาดใจที่ไม่มีใครพูดถึงintl ไลบรารี่ที่สนับสนุนยูนิโค้ด , กราฟิค , การทำงานของสตริง , การโลคัลไลเซชันและอื่น ๆ อีกมากมายดูด้านล่าง

ฉันจะอ้างอิงข้อมูลบางอย่างเกี่ยวกับการสนับสนุน Unicode ในสไลด์ของ Elizabeth Smith ที่PHPBenelux'14

INTL

ดี:

  • Wrapper รอบห้องสมุด ICU
  • โลแคลที่ได้มาตรฐานให้ตั้งค่าโลแคลต่อสคริปต์
  • การจัดรูปแบบตัวเลข
  • การจัดรูปแบบสกุลเงิน
  • การจัดรูปแบบข้อความ (แทนที่ gettext)
  • ปฏิทินวันที่เขตเวลาและเวลา
  • Transliterator
  • Spoofchecker
  • กลุ่มทรัพยากร
  • Convertors
  • รองรับ IDN
  • อักษร
  • การตรวจทาน
  • iterators

แย่:

  • ไม่รองรับ zend_multibite
  • ไม่รองรับการแปลงเอาต์พุต HTTP อินพุต
  • ไม่รองรับฟังก์ชั่นการโอเวอร์โหลด

mb_string

  • เปิดใช้งานการสนับสนุน zend_multibyte
  • รองรับการเข้ารหัส HTTP เข้า / ออกโปร่งใส
  • จัดเตรียม wrappers สำหรับ funtionallity เช่น strtoupper

iconv

  • หลักสำหรับการแปลงชุดอักขระ
  • ตัวจัดการบัฟเฟอร์ผลลัพธ์
  • ฟังก์ชั่นการเข้ารหัส mime
  • การแปลง
  • ตัวช่วยสตริงบางตัว (len, substr, strpos, strrpos)
  • ตัวกรองกระแส stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

ฐานข้อมูล

  • mysql: ชุดอักขระและการเรียงบนตารางและการเชื่อมต่อ (ไม่ใช่การเรียง) อย่าใช้ mysql - msqli หรือ PDO
  • postgresql: pg_set_client_encoding
  • sqlite (3): ตรวจสอบว่ามันถูกคอมไพล์ด้วยการสนับสนุน unicode และ intl

Gotchas อื่น ๆ

  • คุณไม่สามารถใช้ชื่อไฟล์ Unicode กับ PHP และ windows ได้เว้นแต่ว่าคุณจะใช้นามสกุลที่สาม
  • ส่งทุกอย่างใน ASCII ถ้าคุณใช้ exec, proc_open และการเรียกบรรทัดคำสั่งอื่น ๆ
  • ข้อความล้วนไม่ใช่ข้อความล้วนไฟล์มีการเข้ารหัส
  • คุณสามารถแปลงไฟล์ได้ทันทีด้วยตัวกรอง iconv

ฉันจะอัปเดตคำตอบนี้ในกรณีที่มีการเปลี่ยนแปลงคุณสมบัติที่เพิ่มขึ้นและ


2
ใช่ถูกต้อง. Mysqli และ PDO สามารถใช้ไดรเวอร์ดั้งเดิมได้ พวกเขายังสามารถใช้ไดรเวอร์ mysqlnd ถ้าคุณจะรวบรวม php ด้วย--with-mysqli=mysqlnd --with-pdo-mysql=mysqlndตัวเลือก
Alexander Yancharuk

14

สิ่งเดียวที่ฉันจะเพิ่มในคำตอบที่น่าทึ่งเหล่านี้คือการเน้นบันทึกไฟล์ของคุณในการเข้ารหัส utf8 ฉันสังเกตว่าเบราว์เซอร์ยอมรับคุณสมบัตินี้โดยตั้ง utf8 เป็นการเข้ารหัสรหัสของคุณ โปรแกรมแก้ไขข้อความที่เหมาะสมจะแสดงสิ่งนี้ให้คุณตัวอย่างเช่น Notepad ++ มีตัวเลือกเมนูสำหรับการเข้ารหัสไฟล์มันจะแสดงการเข้ารหัสปัจจุบันและให้คุณเปลี่ยนได้ สำหรับไฟล์ php ทั้งหมดของฉันฉันใช้ utf8 โดยไม่มี BOM

บางครั้งที่ผ่านมาฉันมีคนขอให้ฉันเพิ่มการสนับสนุน utf8 สำหรับแอปพลิเคชัน php / mysql ที่ออกแบบโดยคนอื่นฉันสังเกตว่าไฟล์ทั้งหมดถูกเข้ารหัสใน ANSI ดังนั้นฉันจึงต้องใช้ ICONV เพื่อแปลงไฟล์ทั้งหมดเปลี่ยนตารางฐานข้อมูลเพื่อใช้ utf8 charset และ utf8_general_ci collate, เพิ่ม 'SET NAMES utf8' ไปยังเลเยอร์นามธรรม abstraction layer หลังจากการเชื่อมต่อ (ถ้าใช้ 5.3.6 หรือเร็วกว่านั้นมิฉะนั้นคุณต้องใช้ charset = utf8 ในสตริงการเชื่อมต่อ) และเปลี่ยนฟังก์ชั่นสตริงเพื่อใช้ php multibyte ฟังก์ชั่นสตริงเทียบเท่า


13

ฉันเพิ่งค้นพบว่าการใช้strtolower()อาจทำให้เกิดปัญหาข้อมูลถูกตัดหลังจากอักขระพิเศษ

ทางออกคือการใช้

mb_strtolower($string, 'UTF-8');

mb_ ใช้ MultiByte รองรับตัวละครมากขึ้น แต่โดยทั่วไปจะช้ากว่าเล็กน้อย


9

ฉันเพิ่งผ่านปัญหาเดียวกันและพบทางออกที่ดีที่คู่มือ PHP

ฉันเปลี่ยนการเข้ารหัสไฟล์ของฉันทั้งหมดเป็น UTF8 จากนั้นเป็นการเข้ารหัสเริ่มต้นในการเชื่อมต่อของฉัน วิธีนี้ช่วยแก้ไขปัญหาทั้งหมด

if (!$mysqli->set_charset("utf8")) {
    printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
   printf("Current character set: %s\n", $mysqli->character_set_name());
}

ดูที่มา


2
ฉันใช้เวลาหนึ่งชั่วโมงเพื่อหาปัญหาการเข้ารหัสบนหน้าเว็บที่ฉันทำงานอยู่และโดยปกติฉันก็ค่อนข้างดีในการหาข้อมูล ฉันมักจะปรึกษาหน้านี้และคำตอบของคุณช่วยฉันได้มาก เตรียมพร้อมโหวตขึ้นของฉัน ในกรณีของฉันset_charset('utf8mb4')ไม่ทำงาน แต่>set_charset("utf8")ทำและไม่ได้แสดงจริงในคำตอบอื่น ๆ
Funk Forty Niner

@FunkFortyNiner ระวัง: set_charset("utf8")อาจทำงานได้ แต่จะทำงานแตกต่างกัน (ดูหมายเหตุเกี่ยวกับความแตกต่างระหว่างutf8และutf8mb4และประวัติรุ่น MySQL) ใช้utf8 ถ้าคุณต้องและเฉพาะถ้าคุณรู้ว่าคุณกำลังทำอะไร !
Martin Hennings

วิธีแก้ปัญหา 5 ดาวฉันอ่านไฟล์ข้อความทีละบรรทัดแล้วรับ สำหรับตัวละครแต่ละตัวจากนั้นฉันบันทึกเป็นแทน ansi ให้ใช้ utf8 ขอบคุณ
Atef Farouk

8

ใน PHP, คุณจะต้องทั้งใช้ฟังก์ชั่นสัญลักษณ์หรือเปิดmbstring.func_overload วิธีนี้จะทำให้ strlen ทำงานได้ถ้าคุณมีตัวละครที่มีมากกว่าหนึ่งไบต์

คุณจะต้องระบุชุดอักขระของคำตอบของคุณด้วย คุณสามารถใช้ AddDefaultCharset ตามด้านบนหรือเขียนโค้ด PHP ที่ส่งคืนส่วนหัว (หรือคุณสามารถเพิ่มแท็ก META ในเอกสาร HTML ของคุณ)


เคล็ดลับที่ยอดเยี่ยมเกี่ยวกับการตั้งค่า func_overload - อนุญาตให้ปรับเปลี่ยนเล็กน้อยกับรหัสที่มีอยู่
Simon East

4
โปรดระวัง - รหัสบางอย่างอาจจริงอาศัยลักษณะหนึ่งไบต์ต่ออักขระของฟังก์ชันสตริงมาตรฐาน
เจดับบลิว

สิ่งสำคัญที่ควรทราบคือฟีเจอร์ mbstring.func_overload กำลังถูกเลิกใช้ตั้งแต่ PHP 7.2 เนื่องจากปัญหาที่ระบุไว้ในความคิดเห็นของ @ JW ด้านบน ดังนั้นคำแนะนำที่ดีที่สุดคือ: ใช่คุณควรใช้ฟังก์ชั่น mbstring แต่อย่าใช้คุณสมบัติโอเวอร์โหลดเพื่อให้ฟังก์ชั่นมาตรฐานทำงานเป็นมัลติไบต์
สิงโต

6

การสนับสนุน Unicode ใน PHP ยังคงเป็นเรื่องใหญ่ แม้ว่ามันจะสามารถแปลงสตริง ISO8859 (ซึ่งใช้ภายใน) เป็น utf8 แต่มันก็ขาดความสามารถในการทำงานกับยูนิโค้ดสตริงโดยกำเนิดซึ่งหมายความว่าฟังก์ชันการประมวลผลสตริงทั้งหมดจะทำลายและทำลายสตริงของคุณ ดังนั้นคุณต้องใช้ไลบรารีแยกต่างหากสำหรับการสนับสนุน utf8 ที่เหมาะสมหรือเขียนฟังก์ชันการจัดการสตริงทั้งหมดด้วยตัวเอง

ส่วนที่ง่ายคือการระบุชุดอักขระในส่วนหัว HTTP และในฐานข้อมูลและเช่นนั้น แต่ก็ไม่มีสิ่งใดที่สำคัญหากรหัส PHP ของคุณไม่ส่งออก UTF8 ที่ถูกต้อง นั่นเป็นส่วนที่ยากและ PHP ไม่ได้ช่วยอะไรคุณ (ฉันคิดว่า PHP6 ควรจะแก้ไขสิ่งที่เลวร้ายที่สุด แต่ก็ยังห่างออกไป)


6

หากคุณต้องการเซิร์ฟเวอร์ MySQL ในการตัดสินใจชุดตัวอักษรและไม่ PHP เป็นลูกค้า (พฤติกรรมเก่าที่ต้องการในความคิดของฉัน) ลองเพิ่มskip-character-set-client-handshakeที่คุณmy.cnfภายใต้[mysqld], mysqlและเริ่มต้นใหม่

สิ่งนี้อาจทำให้เกิดปัญหาในกรณีที่คุณใช้สิ่งอื่นนอกเหนือจาก UTF8


5

คำตอบยอดเยี่ยม นี่คือสิ่งที่ฉันต้องทำในการตั้งค่า debian / php / mysql ปกติ:

// storage
// debian. apparently already utf-8

// retrieval
// the mysql database was stored in utf-8, 
// but apparently php was requesting iso. this worked: 
// ***notice "utf8", without dash, this is a mysql encoding***
mysql_set_charset('utf8');

// delivery
// php.ini did not have a default charset, 
// (it was commented out, shared host) and
// no http encoding was specified in the apache headers.
// this made apache send out a utf-8 header
// (and perhaps made php actually send out utf-8)
// ***notice "utf-8", with dash, this is a php encoding***
ini_set('default_charset','utf-8');

// submission
// this worked in all major browsers once apache
// was sending out the utf-8 header. i didnt add
// the accept-charset attribute.

// processing
// changed a few commands in php, like substr,
// to mb_substr

นั่นคือทั้งหมด!


1

หากคุณต้องการโซลูชัน mysql ฉันมีปัญหาที่คล้ายกันกับ 2 โครงการของฉันหลังจากการย้ายเซิร์ฟเวอร์ หลังจากค้นหาและลองใช้วิธีแก้ปัญหามากมายฉันเจอสิ่งนี้ / ไม่มีอะไรมาก่อนเลย)

mysqli_set_charset($con,"utf8");

หลังจากเพิ่มบรรทัดนี้ในไฟล์ปรับแต่งของฉันทุกอย่างทำงานได้ดี!

ฉันพบวิธีแก้ปัญหานี้https://www.w3schools.com/PHP/func_mysqli_set_charset.aspเมื่อฉันต้องการแก้ไขการแทรกจากแบบสอบถาม html

โชคดี!


1

เพียงแค่ทราบ:

คุณกำลังประสบปัญหาว่าตัวละครที่ไม่ใช่ภาษาละตินของคุณกำลังแสดงเป็น?????????คุณถามคำถามและมันถูกปิดโดยอ้างอิงถึงคำถามมาตรฐานนี้คุณลองทุกอย่างและไม่ว่าคุณจะยังได้รับ??????????จากMySQLอะไร

นั่นคือส่วนใหญ่เป็นเพราะคุณกำลังทดสอบเกี่ยวกับข้อมูลเก่าของคุณซึ่งได้รับการแทรกไปยังฐานข้อมูลโดยใช้ charset ?ผิดและได้รับการแปลงและจัดเก็บจริงตัวละครเครื่องหมายคำถาม ซึ่งหมายความว่าคุณสูญเสียข้อความต้นฉบับของคุณตลอดไปและไม่ว่าคุณจะลองทำอะไร???????ก็ตาม

กำลังใช้สิ่งที่คุณเรียนรู้จากคำตอบของคำถามนี้กับข้อมูลใหม่สามารถแก้ปัญหาของคุณได้


0

ฉันมีปัญหานี้เมื่อแสดงตาราง ฉันแค่ใส่สิ่งนี้ลงในตัวแปรเอาต์พุต echo แต่ละตัว:

<td><?php echo utf8_encode ($Local) ?></td>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.