Hôm nay thử cài đặt CakePHP 3.6 để kiểm tra các chức năng mới thì phát hiện từ phiên bản 3.6, CakePHP sử dụng setting 'encoding' => 'utf8mb4' mặc định cho database MySQL, thay cho 'encoding' => 'utf8' ở các phiên bản trước.

Chính vì setting mặc định này mà khi kết nối thử tới database MySQL thì bị lỗi sau:

2019, "Can't initialize character set utf8mb4 (path: /usr/share/mysql/charsets/)"

Khi tìm hiểu về lỗi này thì mình mới phát hiện ra trước giờ mình có 2 ngộ nhận về PHP và MySQL (có thể còn nhiều ngộ nhận khác nữa mà mình chưa biết). Vậy mới biết giữa bể học mênh mông này, kiến thức của mình chỉ là có hạn.

2 ngộ nhận:

  • Ngộ nhận 1:
    trong MySQL, khi muốn lưu các ký tự encode utf8, chỉ việc sử dụng encoding utf8 (cụ thể là utf8-general-ci)
  • Ngộ nhận 2:
    trong PHP, khi muốn kết nối với MySQL, chỉ việc cài đặt thư viện php-mysql

Về ngộ nhận 1

Nói một cách ngắn gọn, trên MySQL utf8mb4 mới thực sự là utf8, còn utf8 trên MySQL chỉ là bộ encoding gần đúng của utf8 mà thôi.

Như đã biết thì chuẩn utf8 sử dụng bộ mã khả biến (1~4 byte) để mã hoá cho các ký tự. Tuy nhiên trên MySQL, bộ encoding utf8 chỉ sử dụng tối đa 3 byte để mã hóa ký tự. Từ phiên bản MySQL5.5 (hình như) mới xuất hiện bộ encoding mới utf8mb4 sử dụng tối đa 4 byte, đúng với utf8 chuẩn.

Do chỉ dùng tối đa 3 byte nên khi sử dụng utf8 trên MySQL để lưu những ký tự đặc biệt (nằm ngoài bảng Basic Multilingual Plane, ví dụ như các emoji) thì sẽ xảy ra lỗi.

Muốn làm việc chính xác với utf8 trên MySQL thì cần sử dụng encoding utf8mb4. Và cũng có rất nhiều ý kiến khuyên nên sử dụng utf8mb4 thay cho utf8 trên MySQL (đây là 1 ví dụ).

Về ngộ nhận 2:

Theo như tài liệu của PHP cũng như nhiều nguồn khác, thì nên sử dụng library php-mysqlnd thay cho php-mysql. Lý do là thư viện này được hỗ trợ chính thức bởi PHP và có nhiều chức năng hơn so với thư việc cũ (cụ thể chức năng nào thì trong tài liệu trên đã có nói).

Và cũng chính vì sử dụng library cũ php-mysql mà xuất hiện lỗi liên quan đến encoding utf8mb4 như ở trên (mặc dù mình đã set encoding cho database là utf8mb4 cho khớp với setting mặc định của CakePHP 3.6). Sau khi chuyển sang cài library mới php-mysqlnd thì hết lỗi trên.