ĐẶT NAMES utf8 trong MySQL?


110

Tôi thường thấy một cái gì đó tương tự như thế này bên dưới trong các tập lệnh PHP sử dụng MySQL

query("SET NAMES utf8");   

Tôi chưa bao giờ phải làm điều này cho bất kỳ dự án nào nên tôi có một vài câu hỏi cơ bản về nó.

  1. Đây có phải là thứ chỉ được thực hiện với PDO?
  2. Nếu nó không phải là một thứ cụ thể của PDO, thì mục đích của việc làm đó là gì? Tôi nhận ra rằng nó đang đặt mã hóa cho mysql nhưng ý tôi là, tôi chưa bao giờ phải sử dụng nó, vậy tại sao tôi lại muốn sử dụng nó?

4
Nên tránh "SET NAMES utf8" vì có chèn SQL. Xem php.net/manual/en/mysqlinfo.concept.charset.php để biết chi tiết.
masakielastic

3
@masakielastic Tôi không thấy nơi đặt 'đặt tên utf8' là mối đe dọa cho việc tiêm sql? Sử dụng MySQL API thích hợp đâu là chủ đề?
băng thông rộng

3
Xin lỗi vì sự không ngoan của tôi. Xem câu trả lời của ircmaxell: stackoverflow.com/a/12118602/531320 Althogh "SET NAMES" không có vấn đề gì miễn là sử dụng UTF-8, khả năng bạn sẽ sử dụng GBK hoặc Big5 (Trung Quốc) hoặc Shift_JIS (Nhật Bản) trong tương lai là không thể phủ nhận .
masakielastic

Câu trả lời:


74

Nó là cần thiết bất cứ khi nào bạn muốn gửi dữ liệu đến máy chủ có các ký tự không thể được biểu diễn bằng ASCII thuần túy, như 'ñ' hoặc 'ö'.

Điều đó nếu phiên bản MySQL không được định cấu hình để mong đợi mã hóa UTF-8 theo mặc định từ các kết nối máy khách (nhiều tùy thuộc vào vị trí và nền tảng của bạn.)

Đọc http://www.joelonsoftware.com/articles/Unicode.html trong trường hợp bạn không biết Unicode hoạt động như thế nào.

Đọc Có sử dụng "ĐẶT TÊN" hay không để xem các lựa chọn thay thế ĐẶT NAM và nội dung chính xác của nó.


3
'ö' và 'ñ' là ASCII mở rộng. Bạn vẫn cần SET NAMES UTF8cho họ?
Tim

2
Tôi nhận thấy rằng tôi thường phải thêm utf8_decode ($ my_text); trong PHP để có được các ký tự UTF-8 đặc biệt để hiển thị trên các trang web đúng cách khi dữ liệu được truy vấn từ MySQL. Các bảng và cột của tôi được đặt thành UTF-8 trong MySQL — vì vậy điều này có cần thiết không?
NexusRex

1
@ Vinko Vrsalovic: Không nhất thiết ... tôi đã có tất cả các tệp của mình trong utf8 nhưng nhà cung cấp dịch vụ lưu trữ trước đây của tôi đã đặt bộ ký tự mysql thành latin1 và vì tôi đã nói với mysql rằng tôi đang gửi các ký tự trong utf8 (do đó đặt tên là utf8) nên nó đã lưu trữ chúng bằng bảng chữ cái latin và tất cả các ký tự đặc biệt của tôi (tiếng Slovenia čšž) trông giống như bị ô tô chạy qua - một điều nữa: khi bạn thực hiện tìm kiếm trong phpmyadmin, bạn sẽ không tìm thấy kết quả, vì một č giống Å, v.v.
Erik Čerpnjak

Lưu ý rằng nó cũng chỉ định bộ ký tự mà máy chủ nên sử dụng để gửi kết quả trở lại máy khách, do đó cũng cần thiết khi nhận dữ liệu này, ví dụ như sử dụng một SELECTcâu lệnh.
Leopoldo Sanczyk

@Tim. Không thực sự có bất kỳ thứ gì gọi là "ASCII mở rộng". Có một loạt các bảng mã khác nhau có thể được gọi là ASCII mở rộng (bất kỳ bộ ký tự byte đơn nào có nửa đầu giống với ASCII và có rất nhiều ký tự đó).
TRiG

43

Từ sách hướng dẫn :

SET NAMES cho biết bộ ký tự mà máy khách sẽ sử dụng để gửi các câu lệnh SQL đến máy chủ.

Công phu hơn, (và một lần nữa, được nâng lên một cách vô cớ từ sách hướng dẫn ):

SET NAMES cho biết bộ ký tự mà máy khách sẽ sử dụng để gửi các câu lệnh SQL đến máy chủ. Do đó, SET NAMES 'cp1251' cho máy chủ biết "các thư đến trong tương lai từ máy khách này nằm trong bộ ký tự cp1251." Nó cũng chỉ định bộ ký tự mà máy chủ nên sử dụng để gửi kết quả trở lại máy khách. (Ví dụ: nó cho biết bộ ký tự nào sẽ sử dụng cho các giá trị cột nếu bạn sử dụng câu lệnh SELECT.)


6
Tôi mến bạn. Chỉ làm buổi tối của tôi!
karim79

34

Bắt đúng mã hóa thực sự rất khó - có quá nhiều lớp:

  • Trình duyệt
  • Trang
  • PHP
  • MySQL

Lệnh SQL "SET CHARSET utf8" từ PHP sẽ đảm bảo rằng phía máy khách (PHP) sẽ nhận được dữ liệu trong utf8, bất kể chúng được lưu trữ trong cơ sở dữ liệu như thế nào. Tất nhiên, chúng cần được lưu trữ chính xác trước tiên.

Định nghĩa DDL so với dữ liệu thực

Mã hóa được xác định cho một bảng / cột không thực sự có nghĩa là dữ liệu nằm trong bảng mã đó. Nếu bạn tình cờ có một bảng được xác định là utf8nhưng được lưu trữ dưới dạng mã hóa khác nhau, thì MySQL sẽ coi chúng như vậy utf8và bạn đang gặp rắc rối. Có nghĩa là bạn phải sửa lỗi này trước.

Kiểm tra những gì

Bạn cần kiểm tra xem mã hóa luồng dữ liệu ở mỗi lớp.

  • Kiểm tra tiêu đề HTTP, tiêu đề.
  • Kiểm tra những gì thực sự được gửi trong nội dung của yêu cầu.
  • Đừng quên rằng MySQL có mã hóa hầu như ở khắp mọi nơi:
    • Cơ sở dữ liệu
    • Những cái bàn
    • Cột
    • Máy chủ nói chung
    • Khách hàng
      Đảm bảo rằng có một cái phù hợp ở mọi nơi.

Chuyển đổi

Nếu bạn nhận dữ liệu trong ví dụ windows-1250, và muốn lưu trữ trong utf-8, hãy sử dụng SQL này trước khi lưu trữ:

SET NAMES 'cp1250';

Nếu bạn có dữ liệu trong DB windows-1250và muốn truy xuất utf8, hãy sử dụng:

SET CHARSET 'utf8';

Thêm một số ghi chú:

  • Đừng dựa vào các công cụ quá “thông minh” để hiển thị dữ liệu. Ví dụ: phpMyAdmin không (đã làm khi tôi đang sử dụng nó) mã hóa thực sự tệ. Và nó đi qua tất cả các lớp nên rất khó để tìm ra.
  • Ngoài ra, Internet Explorer có hành vi thực sự ngu ngốc là "đoán" mã hóa dựa trên các quy tắc kỳ lạ.
  • Sử dụng các trình chỉnh sửa đơn giản để bạn có thể chuyển đổi mã hóa. Tôi khuyên bạn nên sử dụng MySQL Workbench.

19

Truy vấn này phải được viết trước truy vấn tạo hoặc cập nhật dữ liệu trong cơ sở dữ liệu, truy vấn này giống như sau:

mysql_query("set names 'utf8'");

Lưu ý rằng bạn nên viết mã mà bạn đang sử dụng trong tiêu đề, ví dụ: nếu bạn đang sử dụng utf-8, bạn thêm mã như thế này vào tiêu đề hoặc nó sẽ gây ra sự cố với Internet Explorer

vì vậy trang của bạn trông như thế này

<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
Bạn không nên sử dụng thư viện mysql PHP thay vào đó bạn nên sử dụng MySQLi hoặc PDO.
André Figueira

Câu trả lời tuyệt vời, cảm ơn vì ví dụ. Đây là một câu trả lời giúp tôi hình dung những gì tôi cần làm và nó giải quyết được vấn đề của tôi!
GTS Joe

1
Thẻ cuối cùng phải là </html> không phải <html>
GTS Joe

9

Giải pháp là

 $conn->set_charset("utf8");

5

Thay vì làm điều này thông qua truy vấn SQL, hãy sử dụng hàm 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.

Xem phần khái niệm bộ ký tự MySQL để biết thêm thông tin.

từ http://www.php.net/manual/en/mysqli.set-charset.php


1

Cảm ơn tất cả!

không sử dụng: query ("ĐẶT TÊN utf8"); đây là công cụ thiết lập và không phải là một truy vấn. đặt nó ngay sau khi bắt đầu kết nối bằng setCharset () (hoặc phương thức tương tự)

một số điều nhỏ trong mệnh:

trạng thái:

  • máy chủ mysql theo mặc định nói tiếng latin1
  • ứng dụng lỗ của bạn ở utf8
  • kết nối được thực hiện mà không có bất kỳ bổ sung nào (so: latin1) (không có SET NAMES utf8 ..., không có phương thức / hàm set_charset ())

Lưu trữ và đọc dữ liệu không có vấn đề gì miễn là mysql có thể xử lý các ký tự. Nếu bạn nhìn vào db, bạn sẽ thấy có một thứ tào lao trong đó (ví dụ: sử dụng phpmyadmin).

cho đến bây giờ đây không phải là một vấn đề! (sai nhưng hoạt động thường xuyên (ở châu Âu)) ..

..không có ứng dụng khách / chương trình khác hoặc thư viện đã thay đổi, hoạt động chính xác, sẽ đọc / lưu dữ liệu. thì bạn đang gặp rắc rối lớn!


0

Không chỉ PDO. Nếu câu trả lời sql như '????' biểu tượng, bộ ký tự đặt trước của bạn (hy vọng UTF-8) thực sự được khuyến nghị:

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

hoặc thông qua phong cách thủ tục mysqli_set_charset($db,"utf8")

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.