ตั้งชื่อ utf8 ใน MySQL?


110

ฉันมักจะเห็นสิ่งที่คล้ายกับสิ่งนี้ด้านล่างในสคริปต์ PHP โดยใช้ MySQL

query("SET NAMES utf8");   

ฉันไม่เคยต้องทำสิ่งนี้สำหรับโครงการใด ๆ เลยดังนั้นฉันจึงมีคำถามพื้นฐานสองสามข้อเกี่ยวกับเรื่องนี้

  1. นี่เป็นสิ่งที่ทำกับ PDO เท่านั้นหรือไม่?
  2. ถ้าไม่ใช่เรื่องเฉพาะของ PDO แล้วจุดประสงค์ของการทำคืออะไร? ฉันรู้ว่ามันกำลังตั้งค่าการเข้ารหัสสำหรับ mysql แต่ฉันหมายความว่าฉันไม่เคยต้องใช้มันเลยทำไมฉันถึงต้องการใช้มัน?

4
ควรหลีกเลี่ยง "SET NAMES utf8" เนื่องจากการแทรก SQL ดู php.net/manual/en/mysqlinfo.concepts.charset.php สำหรับรายละเอียด
masakielastic

3
@masakielastic ฉันไม่เห็นว่าการตั้งค่า 'ชื่อชุด utf8' เป็นภัยคุกคามต่อการฉีด sql หรือไม่? การใช้ MySQL API ที่เหมาะสมเธรดอยู่ที่ไหน
บรอดแบนด์

3
ขอโทษสำหรับความไม่กรุณาของฉัน ดูคำตอบของ ircmaxell: stackoverflow.com/a/12118602/531320 Althogh "SET NAMES" ไม่มีปัญหาตราบใดที่ใช้ UTF-8 ความเป็นไปได้ที่คุณจะใช้ GBK หรือ Big5 (จีน) หรือ Shift_JIS (ภาษาญี่ปุ่น) ในอนาคตนั้นปฏิเสธไม่ได้ .
masakielastic

คำตอบ:


75

จำเป็นเมื่อใดก็ตามที่คุณต้องการส่งข้อมูลไปยังเซิร์ฟเวอร์ที่มีอักขระที่ไม่สามารถแสดงใน ASCII แท้ได้เช่น 'ñ' หรือ 'ö'

ว่าหากอินสแตนซ์ MySQL ไม่ได้รับการกำหนดค่าให้คาดหวังการเข้ารหัส UTF-8 โดยค่าเริ่มต้นจากการเชื่อมต่อไคลเอ็นต์ (ส่วนใหญ่ขึ้นอยู่กับตำแหน่งและแพลตฟอร์มของคุณ)

อ่านhttp://www.joelonsoftware.com/articles/Unicode.htmlในกรณีที่คุณไม่ทราบว่า Unicode ทำงานอย่างไร

อ่านว่าจะใช้ "SET NAMES"เพื่อดูทางเลือก SET NAMES หรือไม่และมันเกี่ยวกับอะไร


3
'ö' และ 'ñ' ถูกขยาย ASCII คุณยังต้องการSET NAMES UTF8สำหรับพวกเขาหรือไม่?
ทิม

2
ฉันพบว่าฉันมักจะต้องเพิ่ม utf8_decode ($ my_text); ใน PHP เพื่อรับอักขระ UTF-8 พิเศษเพื่อแสดงบนเว็บไซต์อย่างถูกต้องเมื่อมีการสืบค้นข้อมูลจาก MySQL ตารางและคอลัมน์ของฉันถูกตั้งค่าเป็น UTF-8 ใน MySQL สิ่งนี้จำเป็นหรือไม่
NexusRex

1
@ Vinko Vrsalovic: ไม่จำเป็น ... ฉันมีไฟล์ทั้งหมดใน utf8 แต่ผู้ให้บริการก่อนหน้าของฉันมีชุดอักขระ mysql ที่ตั้งค่าเป็น latin1 และเนื่องจากฉันไม่ได้บอก mysql ว่าฉันกำลังส่งตัวอักษรใน utf8 (ดังนั้นจึงตั้งชื่อ utf8) จึงเก็บไว้ ในชุดอักขระภาษาละตินและตัวอักษรพิเศษทั้งหมดของฉัน (ภาษาสโลวีเนียčš they) ดูเหมือนว่าพวกมันถูกรถทับ - อีกอย่างหนึ่ง: เมื่อคุณค้นหาใน phpmyadmin คุณจะไม่พบผลลัพธ์เพราะčเป็นเหมือนÅเป็นต้น
Erik Čerpnjak

โปรดทราบว่ายังระบุชุดอักขระที่เซิร์ฟเวอร์ควรใช้เพื่อส่งผลลัพธ์กลับไปยังไคลเอ็นต์ด้วยดังนั้นจึงจำเป็นเมื่อรับข้อมูลนี้โดยใช้ตัวอย่างเช่นSELECTคำสั่ง
Leopoldo Sanczyk

@ ทิม. ไม่มีสิ่งที่เรียกว่า "ASCII แบบขยาย" มีการเข้ารหัสที่แตกต่างกันมากมายที่สามารถเรียกได้ว่า ASCII แบบขยาย (ชุดอักขระไบต์เดี่ยวใด ๆ ที่ครึ่งแรกเหมือนกับ ASCII และมีจำนวนมาก)
TRiG

43

จากคู่มือ :

SET NAMES ระบุว่าชุดอักขระใดที่ไคลเอ็นต์จะใช้เพื่อส่งคำสั่ง SQL ไปยังเซิร์ฟเวอร์

อย่างละเอียดมากขึ้น (และอีกครั้งยกจากคู่มือโดยไม่จำเป็น):

SET NAMES ระบุว่าชุดอักขระใดที่ไคลเอ็นต์จะใช้เพื่อส่งคำสั่ง SQL ไปยังเซิร์ฟเวอร์ ดังนั้น SET NAMES 'cp1251' จะบอกเซิร์ฟเวอร์ว่า "ข้อความขาเข้าในอนาคตจากไคลเอนต์นี้อยู่ในชุดอักขระ cp1251" นอกจากนี้ยังระบุชุดอักขระที่เซิร์ฟเวอร์ควรใช้เพื่อส่งผลลัพธ์กลับไปยังไคลเอนต์ (ตัวอย่างเช่นระบุว่าชุดอักขระใดที่จะใช้สำหรับค่าคอลัมน์หากคุณใช้คำสั่ง SELECT)


6
ผมรักคุณ. เพิ่งทำตอนเย็นของฉัน!
karim79

34

การเข้ารหัสให้ถูกต้องเป็นเรื่องยุ่งยากมากมีหลายเลเยอร์เกินไป:

  • เบราว์เซอร์
  • หน้า
  • PHP
  • MySQL

คำสั่ง SQL "SET CHARSET utf8" จาก PHP จะช่วยให้มั่นใจได้ว่าฝั่งไคลเอ็นต์ (PHP) จะได้รับข้อมูลใน utf8 ไม่ว่าจะเก็บไว้ในฐานข้อมูลอย่างไร แน่นอนว่าต้องจัดเก็บให้ถูกต้องก่อน

คำจำกัดความ DDL เทียบกับข้อมูลจริง

การเข้ารหัสที่กำหนดไว้สำหรับตาราง / คอลัมน์ไม่ได้หมายความว่าข้อมูลนั้นอยู่ในการเข้ารหัสนั้นจริงๆ หากคุณบังเอิญมีตารางที่กำหนดutf8แต่จัดเก็บเป็นการเข้ารหัสที่แตกต่างกัน MySQL จะถือว่าเป็นutf8และคุณมีปัญหา ซึ่งหมายความว่าคุณต้องแก้ไขปัญหานี้ก่อน

สิ่งที่ต้องตรวจสอบ

คุณต้องตรวจสอบสิ่งที่เข้ารหัสการไหลของข้อมูลในแต่ละเลเยอร์

  • ตรวจสอบส่วนหัว HTTP ส่วนหัว
  • ตรวจสอบสิ่งที่ส่งมาจริงๆในเนื้อหาของคำขอ
  • อย่าลืมว่า MySQL มีการเข้ารหัสเกือบทุกที่:
    • ฐานข้อมูล
    • ตาราง
    • คอลัมน์
    • เซิร์ฟเวอร์โดยรวม
    • ลูกค้า
      ตรวจสอบให้แน่ใจว่ามีที่ถูกต้องทุกที่

การแปลง

หากคุณได้รับข้อมูลในเช่นwindows-1250และต้องการจัดเก็บutf-8ให้ใช้ SQL นี้ก่อนจัดเก็บ:

SET NAMES 'cp1250';

หากคุณมีข้อมูลใน DB เป็นwindows-1250และต้องการเรียกคืนให้utf8ใช้:

SET CHARSET 'utf8';

หมายเหตุเพิ่มเติม:

  • อย่าพึ่งพาเครื่องมือที่ "ฉลาด" เกินไปในการแสดงข้อมูล เช่น phpMyAdmin ทำ (กำลังทำเมื่อฉันใช้งาน) การเข้ารหัสไม่ดีจริงๆ และมันผ่านทุกชั้นจึงยากที่จะค้นพบ
  • นอกจากนี้ Internet Explorer ยังมีพฤติกรรมที่โง่เขลาในการ "คาดเดา" การเข้ารหัสตามกฎแปลก ๆ
  • ใช้เครื่องมือแก้ไขอย่างง่ายที่คุณสามารถเปลี่ยนการเข้ารหัสได้ ฉันแนะนำ MySQL Workbench

19

แบบสอบถามนี้ควรเขียนก่อนแบบสอบถามที่สร้างหรืออัปเดตข้อมูลในฐานข้อมูลแบบสอบถามนี้มีลักษณะดังนี้:

mysql_query("set names 'utf8'");

โปรดทราบว่าคุณควรเขียนการเข้ารหัสที่คุณใช้ในส่วนหัวเช่นหากคุณใช้ utf-8 คุณจะเพิ่มแบบนี้ในส่วนหัวมิฉะนั้นจะทำให้เกิดปัญหากับ Internet Explorer

หน้าของคุณจะเป็นแบบนี้

<html>
    <head>
        <title>page title</title>
        <meta charset="UTF-8" />   
    </head>
    <body>
    <?php
            mysql_query("set names 'utf8'");   
            $sql = "INSERT * FROM ..... ";  
            mysql_query($sql);
    ?>    

    </body>
</html>

8
คุณไม่ควรใช้ไลบรารี PHP mysql แทนคุณควรใช้ MySQLi หรือ PDO
André Figueira

คำตอบที่ดีขอบคุณสำหรับตัวอย่าง นี่คือคำตอบเดียวที่ช่วยให้ฉันเห็นภาพว่าฉันต้องทำอะไรและมันช่วยแก้ปัญหาของฉันได้!
GTS Joe

1
แท็กสุดท้ายควร </html> ไม่ใช่ <html>
GTS Joe


5

แทนที่จะทำสิ่งนี้ผ่านแบบสอบถาม SQL ให้ใช้ฟังก์ชัน php: mysqli :: set_charset mysqli_set_charset

Note:

This is the preferred way to change the charset. Using mysqli_query() to set it (such as SET NAMES utf8) is not recommended.

ดูส่วนแนวคิดชุดอักขระ MySQL สำหรับข้อมูลเพิ่มเติม

จากhttp://www.php.net/manual/en/mysqli.set-charset.php


1

ขอบคุณ @all!

อย่าใช้: query ("SET NAMES utf8"); นี่คือการตั้งค่าสิ่งต่างๆไม่ใช่การสืบค้น ทำให้ถูกต้องหลังจากการเชื่อมต่อเริ่มต้นด้วย setCharset () (หรือวิธีการที่คล้ายกัน)

บางสิ่งเล็กน้อยใน Parctice:

สถานะ:

  • เซิร์ฟเวอร์ mysql โดยค่าเริ่มต้นพูดถึง latin1
  • แอพหลุมของคุณอยู่ใน utf8
  • การเชื่อมต่อทำได้โดยไม่ต้องมีอะไรพิเศษ (ดังนั้น: latin1) (ไม่มี SET NAMES utf8 ... ไม่มี set_charset () วิธีการ / ฟังก์ชัน)

การจัดเก็บและอ่านข้อมูลไม่มีปัญหาตราบใดที่ mysql สามารถจัดการกับอักขระได้ หากคุณดูในฐานข้อมูลคุณจะเห็นว่ามีอึอยู่ (เช่นใช้ phpmyadmin)

จนถึงตอนนี้นี่ไม่ใช่ปัญหา! (ผิด แต่ใช้งานได้บ่อย (ในยุโรป)) ..

.. เว้นแต่ไคลเอนต์ / โปรแกรมอื่นหรือไลบรารีที่เปลี่ยนแปลงซึ่งทำงานได้ถูกต้องจะอ่าน / บันทึกข้อมูล แล้วคุณกำลังมีปัญหาใหญ่!


0

ไม่ใช่เฉพาะ PDO. ถ้า sql ตอบแบบ '????' สัญลักษณ์ที่ตั้งไว้ล่วงหน้าของคุณ charset (หวังว่า UTF-8) แนะนำจริงๆ:

if (!$mysqli->set_charset("utf8")) 
 { printf("Can't set utf8: %s\n", $mysqli->error); }

หรือผ่านรูปแบบขั้นตอน mysqli_set_charset($db,"utf8")

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