Hướng dẫn mysql convert latin1 to utf8 - mysql chuyển đổi latin1 thành utf8

Chỉ hôm nay tôi mới nhận ra rằng tôi đã bỏ lỡ điều này trong các tập lệnh PHP của mình:

mysql_set_charset('utf8');

Tất cả các bảng của tôi là Innodb, đối chiếu "UTF8_UNICODE_CI" và tất cả các cột Varchar của tôi cũng là "UTF8_UNICODE_CI". Tôi có

$m = mysql_real_escape_string('¿<?php echo "¬<b>\'PHP &aacute; (á)ţăriîş </b>"; ?> ă-ţi abcdd;//;ñç´พดแทฝใจคçăâξβψδπλξξςαยนñ ;');
mysql_set_charset('utf8');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('latin1');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('utf8');

$result = mysql_iquery('SELECT * FROM `table`');
while ($row = mysql_fetch_assoc($result)) {
    $message = $row['name'];
    $message = mb_convert_encoding($message, 'ISO-8859-15', 'UTF-8');
    //$message = iconv("UTF-8", "ISO-8859-1//IGNORE", $message);
    mysql_iquery('UPDATE `table` SET `name`="'.mysql_real_escape_string($message).'" WHERE `a1`="'.$row['a1'].'"');
}
3 trên các tập lệnh PHP của mình và tất cả các tệp PHP của tôi được mã hóa là UTF-8.

Vì vậy, cho đến bây giờ, mỗi khi tôi "chèn" một cái gì đó có dấu hiệu, ví dụ:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');

Nội dung 'Tên' sẽ là, trong trường hợp này:

$m = mysql_real_escape_string('¿<?php echo "¬<b>\'PHP &aacute; (á)ţăriîş </b>"; ?> ă-ţi abcdd;//;ñç´พดแทฝใจคçăâξβψδπλξξςαยนñ ;');
mysql_set_charset('utf8');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('latin1');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('utf8');

$result = mysql_iquery('SELECT * FROM `table`');
while ($row = mysql_fetch_assoc($result)) {
    $message = $row['name'];
    $message = mb_convert_encoding($message, 'ISO-8859-15', 'UTF-8');
    //$message = iconv("UTF-8", "ISO-8859-1//IGNORE", $message);
    mysql_iquery('UPDATE `table` SET `name`="'.mysql_real_escape_string($message).'" WHERE `a1`="'.$row['a1'].'"');
}
4.

Vì tôi đã sửa lỗi ký tự giữa PHP và MySQL, các phần chèn mới hiện đang lưu trữ chính xác. Tuy nhiên, tôi muốn sửa tất cả các hàng cũ hơn đang "lộn xộn" vào lúc này. Tôi đã thử nhiều thứ rồi, nhưng nó luôn phá vỡ các chuỗi trên nhân vật "bất hợp pháp" đầu tiên. Đây là mã hiện tại của tôi:

$m = mysql_real_escape_string('¿<?php echo "¬<b>\'PHP &aacute; (á)ţăriîş </b>"; ?> ă-ţi abcdd;//;ñç´พดแทฝใจคçăâξβψδπλξξςαยนñ ;');
mysql_set_charset('utf8');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('latin1');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('utf8');

$result = mysql_iquery('SELECT * FROM `table`');
while ($row = mysql_fetch_assoc($result)) {
    $message = $row['name'];
    $message = mb_convert_encoding($message, 'ISO-8859-15', 'UTF-8');
    //$message = iconv("UTF-8", "ISO-8859-1//IGNORE", $message);
    mysql_iquery('UPDATE `table` SET `name`="'.mysql_real_escape_string($message).'" WHERE `a1`="'.$row['a1'].'"');
}

Nó "cập nhật" s với các ký tự mong đợi, ngoại trừ chuỗi bị cắt sau khi ký tự "Ă". Ý tôi là, ký tự và ký tự sau không được bao gồm trên chuỗi.

Ngoài ra, kiểm tra với "ICONV ()" (được nhận xét trên mã) cũng vậy, ngay cả với // bỏ qua và // translit

Tôi cũng đã thử nghiệm một số ký tự, giữa ISO-8859-1 và ISO-8859-15.

Gần đây tôi đã tình cờ thấy một vấn đề mã hóa nhân vật chính trên một trong những trang web tôi chạy. & NBSP; Thông qua việc giải quyết vấn đề, tôi đã học được rất nhiều về sự phức tạp của việc hỗ trợ các bộ nhân vật quốc tế trong môi trường đèn (Linux, Apache, MySQL, PHP). & NBSP; Khắc phục vấn đề là một thách thức, vì vậy tôi muốn chia sẻ một số kiến ​​thức tôi có được trong trường hợp bất kỳ ai khác tìm thấy các vấn đề tương tự trên trang web của riêng họ.

Bài đăng dưới đây là một tài khoản dài nhưng chi tiết về kinh nghiệm của tôi. & NBSP; Hãy cho tôi biết nếu bạn đã có những trải nghiệm tương tự hoặc tìm thấy một giải pháp khác cho loại vấn đề này.

Ôi Münchhausen của tôi !!!

Một vài ngày trước, tôi đã được khách truy cập của một trong những trang web của tôi thông báo về việc tìm kiếm một thuật ngữ có ký tự không phải là ASCII trong đó (trong trường hợp này, Münchhausen) đã trả lại hơn 500 kết quả, mặc dù không có kết quả nào thực sự phù hợp với thuật ngữ tìm kiếm đã cho.ünchhausen”) was returning over 500 results, though none of the results actually matched the given search term.

Tôi bắt đầu xem xét vấn đề, và thấy điều tương tự anh ấy là. Nhật ký gỡ lỗi từ trang tìm kiếm cho thấy truy vấn SQL sau đây đang được sử dụng:

mysql> SELECT * FROM MyTable WHERE city = 'Münchhausen';
...
(7ms, 532 rows affected)

Tuy nhiên, không có kết quả nào thực sự có chứa Münchhausen, cho thành phố.

Tôi đã lấy cùng một truy vấn và chạy nó trong máy khách MySQL dòng lệnh. Thật kỳ lạ, điều này đã trả lại một kết quả khác:

mysql> SELECT * FROM MyTable WHERE city = 'Münchhausen';
(0ms, 0 rows affected)

Truy vấn chính xác, chạy thay vì từ dòng lệnh, trả về 0 hàng.

Giả sử điều này có liên quan đến nhân vật của người Hồi giáo, tôi bắt đầu một hành trình dài học tập lại tất cả các mã hóa nhân vật, bao gồm cả UTF-8, Latin1 và Unicode và cách chúng được sử dụng trong MySQL.

Chuyện gì đang xảy ra?

Latin1, AKA ISO 8859-1 là ký tự mặc định được đặt trong MySQL 5.0. Latin1 là mã hóa ký tự 8 bit-byte, trái ngược với UTF-8, là mã hóa ký tự 8 bit-byte. Latin1 có thể đại diện cho hầu hết các nhân vật trong bảng chữ cái tiếng Anh và châu Âu chỉ với một byte duy nhất (lên tới 256 ký tự cùng một lúc). UTF-8, mặt khác, có thể đại diện cho mọi nhân vật trong bộ ký tự Unicode (hơn 109.000 hiện tại) và là cách tốt nhất để giao tiếp trên internet nếu bạn cần lưu trữ hoặc hiển thị bất kỳ nhân vật khác nhau nào của thế giới.single-byte character encoding, as opposed to UTF-8 which is a 8-bit-multi-byte character encoding. latin1 can represent most of the characters in the English and European alphabets with just a single byte (up to 256 characters at a time). UTF-8, on the other hand, can represent every character in the Unicode character set (over 109,000 currently) and is the best way to communicate on the Internet if you need to store or display any of the world’s various characters.

Bạn có thể chỉ định một bộ ký tự mặc định trên mỗi máy chủ, cơ sở dữ liệu hoặc bảng của MySQL. Các mặc định cho cơ sở dữ liệu sẽ được áp dụng cho các bảng mới và mặc định cho bảng sẽ được áp dụng cho các cột mới. Bạn có thể thay đổi mặc định bất cứ lúc nào (bảng thay đổi, cơ sở dữ liệu thay đổi), nhưng chúng sẽ chỉ được áp dụng cho các bảng và cột mới.

Bạn cũng có thể chỉ định bộ ký tự mà bạn sử dụng cho các kết nối máy khách (thông qua dòng lệnh hoặc thông qua API như các chức năng PHP MYSQL).

Quay trở lại vấn đề Münchhausen, một trong những điều ban đầu tôi đã kiểm tra là những gì bộ nhân vật đã nói chuyện với MySQL với:

mysql>  SHOW VARIABLES LIKE 'character_set_client';
+----------------------+--------+
| Variable_name        | Value  |
+----------------------+--------+
| character_set_client | latin1 |
+----------------------+--------+
1 row in set (0.00 sec)

Biết được nhân vật, ü ü được thể hiện khác nhau trong Latin1 so với UTF-8 (xem bên dưới) và lấy một cú đâm hoang dã trong bóng tối, tôi đã cố gắng buộc ứng dụng PHP của mình sử dụng UTF-8 khi nói chuyện với cơ sở dữ liệu để xem điều này có sẽ khắc phục sự cố:

mysql_set_charset('utf8');

Voila! Vấn đề đã được khắc phục! Tìm kiếm về Münchhausen, trên trang web đã trả về 0 kết quả (số lượng trận đấu chính xác).

Vấn đề với người khác là nó không phải là một người khác

Hay là nó? Vài phút sau, tôi đang duyệt trang web và bắt đầu bắt gặp những nhân vật vui nhộn ở khắp mọi nơi. Ví dụ, một trang mà trước đây đã có văn bản Graffiti của Dolk và Pøbel, hiện đang đọc Graffiti của Dolk và Pøbel. Những chuỗi nhân vật kỳ lạ này cũng trông giống như một vấn đề mà tôi đã nhận thấy theo thời gian trong Phpmyadmin với các trường chỉnh sửa hiển thị các nhân vật lạ. Miễn là tôi đã không chỉnh sửa các nhân vật kỳ lạ, họ đã hiển thị chính xác khi PHP nhổ chúng trở lại là HTML, vì vậy tôi đã không mặc dù phần lớn cho đến bây giờ.øbel” was now reading “Graffiti by Dolk and Pøbel”. These strange character sequences also looked like an issue I had noticed from time to time in phpMyAdmin with edit fields showing strange characters. As long as I didn’t edit the strange characters, they displayed correctly when PHP spit them back out as HTML, so I hadn’t though much of it until now.

Nhìn thấy những chuỗi nhân vật kỳ lạ này ở khắp mọi nơi làm tôi sợ đủ để xem xét vấn đề hơn một chút. Tôi đã vô hiệu hóa cuộc gọi đến mysql_set_charset () và trang web được hoàn nguyên về hành vi chính xác trước đó là nói chuyện với máy chủ thông qua Latin1 và hiển thị Graffiti của Dolk và Pøbel.

Làm lại từ đầu.

Nó có tất cả các bit từ quan điểm của MySQL

Vì thuật ngữ này, Münchhausen, đã trả lại kết quả không phù hợp, tôi đã thử các thuật ngữ tìm kiếm khác có chứa các ký tự không phải ASCII. Ví dụ, tôi đã tìm kiếm thành phố São Paulo Paulo:

mysql> SELECT city FROM MyTable WHERE city = 'São Paulo';
+-----------+
| city      |
+-----------+
| Sao Paulo |
| Sao Paulo |
| Sao Paulo |
...
| Sao Paulo |
(2ms, 72 rows affected)

Như bạn có thể thấy, thuật ngữ tìm kiếm đã hoạt động. Nó tìm thấy những sự xuất hiện của Hồi Sao Paulo, nhưng không phải là São Paulo. Tôi biết có những hàng với São trong cơ sở dữ liệu, vì vậy truy vấn đã hoạt động chính xác 100%.ao Paulo” but not “São Paulo”. I know there are rows with São in the database, so the query wasn’t working 100% correctly.

Tôi đã thay đổi truy vấn một chút thành một trận đấu đại diện thay vì ký tự không phải ASCII:

mysql> SELECT city FROM MyTable WHERE city LIKE 'S%o Paulo';
+------------+
| city       |
+------------+
| Sao Paulo  |
| Sao Paulo  |
| Sao Paulo  |
...
| São Paulo |
| São Paulo |
(5ms, 348 rows affected)

Tìm kiếm này hoạt động tốt hơn một chút - nó tìm thấy các hàng với các thành phố của cả Sao Paulo và São Paulo. Tuy nhiên, nó đã trả lại chuỗi nhân vật, ta £ £ cho São Paulo vì một số lý do.ao Paulo and São Paulo. However, it returned the character sequence “ã” for São Paulo for some reason.

Lý do cho điều này là, từ quan điểm của MySQL, dữ liệu được lưu trữ trong các bảng của nó đều chỉ là bit. Loại cột và bộ ký tự của một cột Xác định cách các truy vấn hoạt động chống lại dữ liệu và cách dữ liệu được trả về do kết quả của truy vấn chọn.

Nó có lẽ khá rõ ràng khi cột City của tôi không phải là nhân vật phù hợp. Nó đã được đặt thành Latin1 khi cơ sở dữ liệu được tạo.

Điều thú vị là ứng dụng web của tôi, sử dụng PHP, dường như không quan tâm đến điều này. Lưu trữ và truy xuất từ ​​cột thành phố là an toàn cho nhị phân-nghĩa là MySQL không sửa đổi dữ liệu PHP gửi nó thông qua tiện ích mở rộng MySQL. & NBSP; & NBSP; Sau đó, MySQL sẽ cung cấp cho PHP cùng một dữ liệu (bit) chính xác. & Nbsp; Các vấn đề chỉ xảy ra khi bạn yêu cầu MySQL tự mình phân tích cột hoặc trình bày nó.

Vì vậy, tất cả thời gian này, ứng dụng web PHP của tôi đã lưu trữ dữ liệu được mã hóa UTF-8 trong cột Thành phố và sau đó truy xuất dữ liệu chính xác (nhị phân) chính xác mà nó hiển thị trên trang web. MySQL không sửa đổi dữ liệu cho các bản cập nhật và chọn đơn giản, vì vậy các ký tự UTF-8 vẫn được hiển thị đúng trên trang web.

Để khắc phục truy vấn SQL ở trên, chúng ta thực sự có thể buộc MYSQL phải diễn giải lại dữ liệu dưới dạng mã hóa ký tự cụ thể bằng cách chuyển đổi dữ liệu thành một loại nhị phân sau đó đúc đó là UTF-8. & NBSP; Nếu bạn cố gắng chuyển đổi đơn giản bằng UTF8, MySQL sẽ hữu ích chuyển đổi các ký tự rác của bạn thành các ký tự rác-UTF8. & NBSP; Quá trình hai bước tạm thời chuyển đổi sang nhị phân đảm bảo rằng MySQL không cố gắng giải thích lại cột trong mã hóa ký tự khác. & NBSP; Nếu chúng tôi không chuyển đổi thành nhị phân, MySQL cuối cùng sẽ hiển thị các ký tự Ã tương tự ngay cả trong đầu ra UTF-8.

Vì vậy, chúng tôi tạm thời chuyển sang nhị phân, sau đó chuyển đổi điều này bằng UTF-8:

mysql> SELECT city, CONVERT(CAST(city as BINARY) USING utf8) FROM MyTable WHERE city = 'São Paulo';
+------------+-------------+
| city       | CONVERT...  |
+------------+-------------+
| Sao Paulo  | Sao Paulo   |
| Sao Paulo  | Sao Paulo   |
...
| São Paulo | São Paulo   | ...

Thành công! & NBSP; Chúng tôi đã lừa MySQL cung cấp cho chúng tôi cách giải thích UTF-8 về cột Latin1 của chúng tôi một cách nhanh chóng và chúng tôi thấy rằng São Paulo được thể hiện đúng.

Tại sao họ khác nhau?

Một số nền tảng: Tại sao lại được đại diện cho Latin1 vs UTF-8?

Nhân vật trong Latin1 là mã ký tự 0xE3 trong Hex, hoặc 227 trong thập phân. Nó 8 bit sẽ được đại diện là:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
0

Latin1 là một mã hóa một byte, vì vậy mỗi trong số 256 ký tự chỉ là một byte duy nhất.

Mã hóa UTF-8 được thiết kế để tương thích ngược với các tài liệu ASCII, cho 128 ký tự đầu tiên. Đối với các ký tự trên #128, một chuỗi đa byte mô tả ký tự.

Nhân vật của chúng tôi, #227, bỏ lỡ khả năng tương thích một byte với 128 ký tự đầu tiên của ASCII và phải được đại diện thành hai byte như được mô tả trên trang Wikipedia UTF-8.

Ở đây, một đại diện của nhân vật trong cả hai mã hóa:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
1

Mã hóa UTF-8 biến chúng tôi, được biểu thị là 0xE3 trong Latin1, thành hai byte, 0xc3a3 trong UTF-8.0xC3A3 in UTF-8.

Lưu ý rằng hai byte 0xc3 và 0xa3 này trong UTF-8 tình cờ trông giống như thế này trong Latin1:0xC3 and 0xA3 in UTF-8 happen to look like this in latin1:

0xc3 = Ã in latin1

0xA3 = £ trong Latin1

Vì vậy, mã hóa UTF-8 của à giải thích chính xác lý do tại sao chúng ta thấy nó được giải thích lại là à ​​£ trong Latin1.

Phải làm gì, phải làm gì

Tại thời điểm này, nó rõ ràng là tôi đã gây rối ở đâu đó. Chính xác hơn, cột City nên là UTF-8, vì PHP luôn đặt dữ liệu UTF-8 vào đó. Lý do lớn mà tôi đã nhận thấy một vấn đề cho đến thời điểm này là trong khi cột MySQL là Latin1, ứng dụng PHP của tôi đã nhận được dữ liệu này và gọi HTMLEnties để chuyển đổi các ký tự UTF-8 thành mã HTML trước khi hiển thị chúng. Trang web của tôi, khách truy cập của tôi đã thấy các ký tự UTF-8 thích hợp trên trang web mặc dù cột MySQL là Latin1.

Như chúng tôi đã thấy, các vấn đề bắt đầu xảy ra khi bạn thực hiện các truy vấn đối với dữ liệu. Việc lựa chọn ở trên đã sử dụng một ký tự UTF-8, ü ü đối với Münchhausen, và khi so sánh điều này với dữ liệu của Lat Latin1 trong cột, MySQL bị nhầm lẫn (bạn có thể đổ lỗi không?). Các vấn đề bổ sung có thể xuất hiện với các ứng dụng hiển thị mã hóa tự nhiên của cột (như phpmyadmin): chúng hiển thị các chuỗi ký tự kỳ lạ như đã thấy ở trên, thay vì các ký tự được giải mã UTF-8.

Cốt lõi của vấn đề là cơ sở dữ liệu MySQL đã được tạo ra vài năm trước và đối chiếu mặc định tại thời điểm đó là latin1_swedish_ci. Trong những năm qua, tôi đã thay đổi mặc định thành UTF8_General_Ci cho các cột mới, nhưng các bảng và cột hiện có đã thay đổi. & NBSP; Tôi có hơn 100 bảng trong Latin1 nên được UTF-8 và cần được chuyển đổi.

Vì vậy, tôi đã bắt đầu điều tra những gì cần thiết để chuyển đổi các bảng Latin1 hiện tại của tôi thành UTF-8 khi thích hợp. Khi tôi đặt mã hóa ký tự đúng, các truy vấn đối với cơ sở dữ liệu sẽ hoạt động tốt hơn và tôi không nên lo lắng về các loại vấn đề này trong tương lai.

Có một vài cách để thực hiện chuyển đổi.

Một số người đã xuất thành công dữ liệu của họ sang Latin1, chuyển đổi tệp kết quả thành UTF-8 thông qua ICONV hoặc một tiện ích tương tự, cập nhật các định nghĩa cột của họ, sau đó nhập lại dữ liệu đó. Thật không may, điều này đòi hỏi phải giảm cơ sở dữ liệu khi các bảng bị bỏ và tạo lại, và điều này có thể hơi tốn thời gian.

Tôi đã hy vọng một quá trình mà tôi có thể áp dụng cho một cơ sở dữ liệu trực tuyến và may mắn là tôi đã tìm thấy một số ghi chú tốt của Paul Kortman và Fabio, vì vậy tôi đã kết hợp một số ý tưởng của họ và tự động hóa quá trình cho trang web của mình. Tôi đã gặp một vài vấn đề trên đường đi, vì vậy tôi muốn chia sẻ các bước làm việc cho tôi.

Quá trình

Sử dụng phương thức được mô tả trên blog Fabio, chúng ta có thể chuyển đổi các cột Latin1 có các ký tự UTF-8 thành các cột UTF-8 thích hợp bằng cách thực hiện các bước sau:

  1. Chuyển đổi cột thành loại nhị phân liên quan (thay đổi bảng mytable modify myColumn nhị phân)
  2. Chuyển đổi cột trở lại loại gốc và đặt ký tự được đặt thành UTF-8 cùng một lúc (thay đổi bảng mytable sửa đổi ký tự mycolumn set utf8 collate utf8_general_ci)

Đây là một cách tiếp cận tương tự với trò chơi chuyển đổi chọn lọc của chúng tôi (Cast (Thành phố là nhị phân) bằng UTF8) ở trên, trong đó về cơ bản chúng tôi ẩn dữ liệu thực tế của cột từ MySQL bằng cách che giấu nó như là nhị phân tạm thời.

Nếu bạn chỉ cần buộc cột đến UTF-8 mà không cần chuyển đổi nhị phân, MySQL thực hiện chuyển đổi thay đổi dữ liệu của các ký tự Lat Latin1 của bạn thành UTF-8 và bạn sẽ kết thúc với dữ liệu được chuyển đổi không đúng. Chuyển đổi cột thành nhị phân trước tiên buộc MYSQL không nhận ra dữ liệu ở UTF-8 ngay từ đầu.

Chúng ta cần chuyển đổi từng loại cột nguồn (char so với varchar so với văn bản, v.v.) thành loại nhị phân liên quan của nó (nhị phân so với varbinary so với blob).

Ngoài ra, các modifys cho nhị phân và trở lại cần giữ lại toàn bộ định nghĩa cột. Đối với các loại văn bản, một văn bản đơn giản để chuyển đổi blob là đủ. Nhưng đối với các định nghĩa cột có độ dài được chỉ định, mặc định hoặc không null:entire column definition. For TEXT types, a simple TEXT to BLOB conversion is sufficient. But for column definitions that have specified lengths, defaults or NOT NULL:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
2

Chúng ta cần sửa đổi giữ các thuộc tính tương tự hoặc định nghĩa cột sẽ được thay đổi cơ bản (xem ghi chú trong bảng thay đổi). Trong trường hợp này, chúng tôi sẽ chỉ định:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
3

Nếu chúng tôi không chỉ định độ dài, mặc định và không null, các cột không giống như trước khi chuyển đổi.

Kịch bản

Tập lệnh ở dưới cùng của bài đăng này tự động hóa việc chuyển đổi bất kỳ dữ liệu UTF-8 nào được lưu trữ trong các cột Latin1 sang các cột UTF-8 thích hợp.

Tôi đã sửa đổi tập lệnh Fabio, để tự động hóa việc chuyển đổi cho tất cả các cột Latin1 cho bất kỳ cơ sở dữ liệu nào bạn định cấu hình nó để xem xét. Nó chuyển đổi các cột trước tiên thành anh em họ nhị phân thích hợp, sau đó thành UTF8_General_Ci, trong khi vẫn giữ được các độ dài cột, mặc định và các thuộc tính null.all of the latin1 columns for whatever database you configure it to look at. It converts the columns first to the proper BINARY cousin, then to utf8_general_ci, while retaining the column lengths, defaults and NULL attributes.

CẢNH BÁO: Kịch bản này giả định rằng bạn biết bạn có các ký tự UTF-8 trong cột Latin1. Vui lòng kiểm tra các thay đổi của bạn trước khi chạy một cách mù quáng kịch bản!This script assumes you know you have UTF-8 characters in a latin1 column. Please test your changes before blindly running the script!

Dưới đây là các bước bạn nên thực hiện để sử dụng tập lệnh:

Bước 1. Xác định cột nào cần cập nhật

Nếu bạn giống như tôi, bạn có thể có một hỗn hợp các cột Latin1 và UTF-8 trong cơ sở dữ liệu của bạn. & NBSP; Không phải tất cả các cột trong cơ sở dữ liệu của tôi cần được cập nhật từ Latin1 đến UTF-8. & NBSP; Ví dụ: một số bảng thuộc về các ứng dụng PHP khác trên máy chủ và tôi chỉ muốn cập nhật các cột mà tôi biết phải được sửa. & NBSP; Tập lệnh hiện sẽ chuyển đổi tất cả các bảng cho cơ sở dữ liệu được chỉ định - bạn có thể sửa đổi tập lệnh để thay đổi các bảng hoặc cột cụ thể nếu bạn cần.

Ngoài ra, tập lệnh sẽ chỉ cập nhật các cột dựa trên văn bản phù hợp. & NBSP; Các bộ ký tự chỉ phù hợp với một số loại dữ liệu: char, varchar, tinytext, văn bản, phương tiện và longtext. Các loại cột khác như Numeric (Int) và Blobs không có một ký tự Set Set.

Bạn có thể thấy những gì ký tự đặt các cột của bạn đang sử dụng thông qua công cụ quản trị MySQL, phpmyadmin hoặc thậm chí sử dụng truy vấn SQL đối với thông tin_schema:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
4

Bước 2. Kiểm tra chuyển đổi các cột

Bạn nên kiểm tra tất cả các thay đổi trước khi cam kết chúng vào cơ sở dữ liệu của bạn.

Điều đầu tiên cần kiểm tra là SQL được tạo từ tập lệnh chuyển đổi là chính xác. & NBSP; Để làm điều này, bạn có thể đổ cấu trúc cơ sở dữ liệu của mình:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
5

Và nhập cấu trúc này vào một bài kiểm tra cơ sở dữ liệu MySQL khác:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
6

Tiếp theo, chạy tập lệnh chuyển đổi (bên dưới) so với cơ sở dữ liệu tạm thời của bạn:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
7

Kịch bản sẽ nhổ ra !!! Lỗi các câu lệnh nếu thay đổi thất bại. & NBSP; Nếu bạn gặp lỗi, có thể cần sửa đổi dựa trên các yêu cầu của bạn. & NBSP; Một số vấn đề phổ biến được liệt kê trong bước 3.

Sau khi bạn chạy tập lệnh chống lại cơ sở dữ liệu tạm thời của mình, hãy kiểm tra các bảng thông tin_schema để đảm bảo chuyển đổi thành công:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
8

Miễn là bạn thấy tất cả các cột của mình trong UTF8, bạn sẽ được thiết lập!

Bước 3. Các vấn đề bạn có thể gặp phải

Nếu nó chỉ đơn giản. Tôi đạt được một số vấn đề trên đường đi.

Bước 3.1. Chỉ số FULLTEXT

Tôi có một số cột với các chỉ mục FullText trên chúng. & NBSP; Lệnh thay đổi cho lệnh nhị phân cho một cột có chỉ mục FullText sẽ gây ra lỗi:

mysql_query('INSERT INTO `table` SET `name`="Jáuò Iñe"');
9

Giải pháp đơn giản mà tôi đưa ra là sửa đổi tập lệnh để bỏ chỉ mục trước khi chuyển đổi và khôi phục nó sau đó:

$m = mysql_real_escape_string('¿<?php echo "¬<b>\'PHP &aacute; (á)ţăriîş </b>"; ?> ă-ţi abcdd;//;ñç´พดแทฝใจคçăâξβψδπλξξςαยนñ ;');
mysql_set_charset('utf8');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('latin1');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('utf8');

$result = mysql_iquery('SELECT * FROM `table`');
while ($row = mysql_fetch_assoc($result)) {
    $message = $row['name'];
    $message = mb_convert_encoding($message, 'ISO-8859-15', 'UTF-8');
    //$message = iconv("UTF-8", "ISO-8859-1//IGNORE", $message);
    mysql_iquery('UPDATE `table` SET `name`="'.mysql_real_escape_string($message).'" WHERE `a1`="'.$row['a1'].'"');
}
0

Có các todos được liệt kê trong kịch bản nơi bạn nên thực hiện những thay đổi này.

Bước 3.2. Dữ liệu UTF-8 không hợp lệ

Vì cơ sở dữ liệu của tôi đã hơn 5 năm tuổi, nó đã có được một số cruft theo thời gian. Tôi không biết chính xác điều này đã xảy ra như thế nào, nhưng một số cột có dữ liệu không phải là mã hóa UTF-8 hợp lệ, mặc dù chúng là ký tự Latin1 hợp lệ. Tôi tin rằng điều này đã xảy ra trước khi tôi làm cứng ứng dụng PHP của mình để từ chối dữ liệu không UTF-8, nhưng tôi không chắc chắn. Tôi đã phát hiện ra điều này khi ban đầu cố gắng thực hiện chuyển đổi:

$m = mysql_real_escape_string('¿<?php echo "¬<b>\'PHP &aacute; (á)ţăriîş </b>"; ?> ă-ţi abcdd;//;ñç´พดแทฝใจคçăâξβψδπλξξςαยนñ ;');
mysql_set_charset('utf8');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('latin1');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('utf8');

$result = mysql_iquery('SELECT * FROM `table`');
while ($row = mysql_fetch_assoc($result)) {
    $message = $row['name'];
    $message = mb_convert_encoding($message, 'ISO-8859-15', 'UTF-8');
    //$message = iconv("UTF-8", "ISO-8859-1//IGNORE", $message);
    mysql_iquery('UPDATE `table` SET `name`="'.mysql_real_escape_string($message).'" WHERE `a1`="'.$row['a1'].'"');
}
1

Chuyện gì đang xảy ra?

Tại một số điểm, một chuỗi ký tự chứa các ký tự UTF-8 không hợp lệ đã được nhập vào cơ sở dữ liệu và bây giờ MySQL từ chối gọi varchar cột (là UTF-8) vì nó có các chuỗi ký tự không hợp lệ này.

Tôi đã kiểm tra biểu diễn HTML của cột này trong trang web PHP của mình và chắc chắn, rác cũng hiển thị ở đó:

… �? bay…

� là ký tự thực tế mà trình duyệt của bạn hiển thị. Không phải là trải nghiệm người dùng tốt nhất, và chắc chắn không phải là nhân vật chính xác.

Tôi đã sửa một hàng duy nhất đó (thông qua phpmyadmin) và chạy lại lệnh thay đổi bảng sửa đổi lại - cùng một vấn đề, một hàng khác. Có vẻ như có nhiều hơn một hàng tham nhũng duy nhất.

Tôi đã tìm thấy một cách tốt để root tất cả các cột sẽ khiến việc chuyển đổi bị lỗi. Nếu bạn chọn Chuyển đổi (MyColumn bằng UTF8) làm cột mới, bất kỳ cột null nào được trả về đều là các cột sẽ khiến bảng thay đổi bị lỗi.

Ví dụ:

$m = mysql_real_escape_string('¿<?php echo "¬<b>\'PHP &aacute; (á)ţăriîş </b>"; ?> ă-ţi abcdd;//;ñç´พดแทฝใจคçăâξβψδπλξξςαยนñ ;');
mysql_set_charset('utf8');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('latin1');
mysql_query('INSERT INTO `table` SET `name`="'.$m.'"');
mysql_set_charset('utf8');

$result = mysql_iquery('SELECT * FROM `table`');
while ($row = mysql_fetch_assoc($result)) {
    $message = $row['name'];
    $message = mb_convert_encoding($message, 'ISO-8859-15', 'UTF-8');
    //$message = iconv("UTF-8", "ISO-8859-1//IGNORE", $message);
    mysql_iquery('UPDATE `table` SET `name`="'.mysql_real_escape_string($message).'" WHERE `a1`="'.$row['a1'].'"');
}
2

Điều này cho tôi thấy các hàng cụ thể có chứa UTF-8 không hợp lệ, vì vậy tôi đã chỉnh sửa tay để sửa chúng. Bạn có thể tự lấy chúng ra bằng cách sử dụng bản cập nhật nếu bạn không sợ mất dữ liệu. Tôi đã phải làm điều này cho 6 cột trong số 115 cột đã được chuyển đổi. & NBSP; Chỉ có 30 hàng trong tổng cộng bị hỏng.

Bước 4. Lợi nhuận?

Tại thời điểm này, có thể mất một số can đảm để bạn nhấn nút GO trên cơ sở dữ liệu trực tiếp của bạn.

Cá nhân, tôi đã chạy tập lệnh đối với cơ sở dữ liệu kiểm tra (trống), sau đó là bản sao dữ liệu trực tiếp của tôi, sau đó là một máy chủ dàn trước khi cuối cùng thực hiện nó trên dữ liệu trực tiếp.

Cảnh báo: Hãy cẩn thận khi sử dụng tập lệnh và kiểm tra, kiểm tra, kiểm tra trước khi cam kết! Please be careful when using the script and test, test, test before committing to it!

Kịch bản

Kịch bản có thể được tìm thấy tại github: https://github.com/nicjansma/mysql-convert-latin1-t-tf8. Nếu bạn tìm thấy lỗi hoặc muốn đóng góp thay đổi, vui lòng đến đó.

Từ cuối cùng

Tôi hy vọng những gì tôi đã học được sẽ hữu ích cho người khác.

Nếu bạn đạt được bất kỳ vấn đề nào với tập lệnh chuyển đổi, xin vui lòng cho tôi biết.

Không UTF

Các ký tự và ký hiệu này là một phần của hệ thống mã hóa lớn hơn nhiều gọi là UTF8, bao gồm Latin1. Kể từ khi bắt đầu của WRD, tất cả dữ liệu của chúng tôi đã được lưu trữ trong mã hóa Latin1. Khi WRD trở nên toàn cầu hơn về phạm vi và nặng hơn nhiều, nhu cầu chuyển sang mã hóa UTF-8 là rõ ràng.UTF8, which also includes Latin1. Since WRDS' inception, all of our data has been stored in Latin1 encoding. As WRDS becomes much more global in scope and much more text-heavy, the need to move to UTF-8 encoding is apparent.

UTF8 latin1 là gì?

Chúng là các mã hóa khác nhau (với một số ký tự được ánh xạ tới các chuỗi byte phổ biến, ví dụ: các ký tự ASCII và nhiều chữ cái có dấu). UTF-8 là một mã hóa Unicode với tất cả các điểm codePoint của nó; Latin1 mã hóa ít hơn 256 ký tự. - Shreevatsar.UTF-8 is one encoding of Unicode with all its codepoints; Latin1 encodes less than 256 characters. – ShreevatsaR.

Mysql latin1 là gì?

Bộ ký tự Latin1 MySQL là một nhân vật một byte cho Tây Âu và đó là bộ ký tự mặc định của MySQL lên đến và bao gồm 5,7.Mặc dù có tên, bộ ký tự thực sự tuân thủ Windows-1252, đây là một siêu âm của ISO-8859-1, còn được gọi là Latin-1.a one-byte character set for Western Europe, and it is the default character set of MySQL up to and including 5.7. In spite of the name, the character set is actually Windows-1252 compliant, which is a superset of ISO-8859-1, also known as Latin-1.

Mã hóa Latin1 là gì?

Latin-1, còn được gọi là ISO-8859-1, là một nhân vật 8 bit được thiết lập bởi Tổ chức Tiêu chuẩn hóa Quốc tế (ISO) và đại diện cho bảng chữ cái của các ngôn ngữ Tây Âu.an 8-bit character set endorsed by the International Organization for Standardization (ISO) and represents the alphabets of Western European languages.