Một chuỗi PHP chỉ là một chuỗi các byte, không có mã hóa nào được gắn thẻ cho nó. Các giá trị chuỗi có thể đến từ nhiều nguồn khác nhau: máy khách (qua HTTP), cơ sở dữ liệu, tệp hoặc từ chuỗi ký tự trong mã nguồn của bạn. PHP đọc tất cả những thứ này dưới dạng các chuỗi byte và nó không bao giờ trích xuất bất kỳ thông tin mã hóa nào.
Miễn là tất cả các nguồn dữ liệu và đích của bạn sử dụng cùng một mã hóa, điều tồi tệ nhất có thể xảy ra là vị trí chuỗi bị sai (nếu bạn sử dụng mã hóa nhiều byte), vì PHP sẽ đếm byte, không phải ký tự.
Nhưng nếu các mã hóa không khớp (ví dụ: bạn viết một chuỗi ký tự trong tệp nguồn được lưu dưới dạng UTF-8, sau đó gửi nó đến cơ sở dữ liệu mong đợi Latin-1), PHP sẽ không thực hiện bất kỳ chuyển đổi nào cho bạn: nó sẽ không thực hiện bất kỳ chuyển đổi nào cho bạn: nó sẽ vui vẻ sao chép các byte trên raw.
Giải pháp sạch nhất là đây:
- Đặt mã hóa nội bộ của PHP thành UTF-8.
- Lưu tất cả các tệp nguồn của bạn dưới dạng UTF-8.
- Sử dụng UTF-8 làm mã hóa đầu ra của bạn (đừng quên gửi
Content-type
các tiêu đề phù hợp ).
- Đặt kết nối cơ sở dữ liệu để sử dụng UTF-8 (
SET NAMES UTF8
trong MySQL).
- Định cấu hình mọi thứ khác thành UTF-8 nếu có thể.
- Đối với mọi thứ bạn không thể kiểm soát (ví dụ: dịch vụ web của bên thứ ba), hãy đảm bảo bạn biết mã hóa và chuyển đổi sang UTF-8 càng sớm càng tốt và quay lại mã hóa khác càng sớm càng tốt.
Tại sao UTF-8? Bởi vì nó có thể đại diện cho tất cả các ký tự Unicode và do đó thay thế tất cả các mã hóa 7 bit và 8 bit hiện có và bởi vì nó tương thích nhị phân với ASCII, nghĩa là, mọi chuỗi ASCII hợp lệ cũng là một chuỗi UTF-8 hợp lệ (nhưng không phải là vv .).
Trong ví dụ của bạn, những gì xảy ra là đây.
Đầu tiên, bạn lưu tệp nguồn của bạn; trình soạn thảo văn bản của bạn có thể được cấu hình để sử dụng UTF-8, do đó, chuỗi ký tự của bạn kết thúc được mã hóa UTF-8 trên đĩa. PHP đọc tệp này, diễn giải chuỗi dưới dạng một chuỗi byte; $original
hiện giữ một chuỗi được mã hóa UTF-8 gồm 7 ký tự, đây chỉ là một chuỗi byte (mặc dù nó chứa hơn 7 byte, vì mỗi ký tự được biểu thị bằng hai hoặc nhiều byte). Nếu sau đó bạn gọi echo $original
, chuỗi được mã hóa được gửi đến máy khách nguyên trạng; nếu bạn đã nói với khách hàng mong đợi UTF-8, mọi thứ đều ổn, nhưng nếu bạn không có, PHP không có cách nào để nói sự khác biệt và bạn sẽ kết thúc với rác trong trình duyệt. Để thử nghiệm, hãy thử điều này:
$original = "शक्नोम्यत्तुम्";
echo strlen($original);
strlen
là mã hóa không xác định và giả sử mã hóa 8 bit có độ rộng cố định, nghĩa là, một byte cho mỗi ký tự, vì vậy nó sẽ đếm byte, không phải ký tự.