Làm thế nào để PHP bên trong đại diện cho chuỗi?


18

UTF8?
UTF16?

Các chuỗi trong PHP cũng theo dõi mã hóa được sử dụng?

Hãy xem kịch bản này chẳng hạn. Nói rằng tôi chạy:

$original = "शक्नोम्यत्तुम्";

Điều gì thực sự xảy ra?

Rõ ràng tôi nghĩ $originalsẽ không chỉ có 7 ký tự. Mỗi glyph phải được đại diện bởi một vài byte ở đó.

Sau đó tôi làm:

$converted = mb_convert_encoding ($original , "UTF-8");

Điều gì sẽ xảy ra $converted? Làm thế nào sẽ $convertedkhác với $original?

Nó sẽ chỉ là chuỗi byte chính xác như $originalnhưng với một mã hóa khác nhau?


1
Phiên bản nào của PHP? PHP <6 không thể xử lý UTF-8 riêng. Có các gói và phương pháp mặc dù giúp / giải quyết vấn đề này. Google vui vẻ với utf-8 và php. Sau đó chuyển sang nền tảng khác thay vì PHP. :)
Andrew T Finnell

4
PHP <6? Điều đó sẽ bao gồm mọi phiên bản PHP từng được phát hành ...
tdammers

1
Ngoài ra, PHP có thể xử lý UTF-8, nó chỉ không có kiểu dữ liệu chuyên dụng, vì vậy bạn phải xem bạn đang làm gì.
tdammers

Câu trả lời:


22

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-typecác tiêu đề phù hợp ).
  • Đặt kết nối cơ sở dữ liệu để sử dụng UTF-8 ( SET NAMES UTF8trong 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; $originalhiệ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ự.


Vì vậy, $ convert sẽ đại diện cho cùng một chuỗi nhưng trong mã hóa khác. Mã hóa thô thực tế, là thứ mà PhP lưu trữ, sẽ khác.
dùng4951

2
Tôi sẽ lặp lại điều đó cho bạn: PHP lưu trữ byte, không phải ký tự và hoàn toàn không biết về mã hóa (mặc dù một số chức năng của thư viện thực hiện.
tdammers

1
Ồ, và đó là "PHP", không phải "PhP".
tdammers

2
nếu các byte thô giống nhau thì sự khác biệt giữa $ gốc và $ được chuyển đổi sau đó. Đó là những gì tôi đang hỏi.
dùng4951

2
Oh, OK, đó là những gì bạn có ý nghĩa. Có, các byte thô thay đổi theo chuyển đổi mã hóa. Mặc dù vậy, PHP không nhớ mã hóa, vì vậy nếu bạn chuyển đổi một chuỗi từ, giả sử, utf-8 sang latin-1, và sau đó coi kết quả là utf-8, bạn sẽ thấy kết quả lạ.
tdammers
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.