2012-02-02 12 views
8

Tôi có một đối tượng php lớn mà tôi muốn tuần tự hóa và lưu trữ trong cơ sở dữ liệu MySql. Bảng mã hóa là UTF-8 và cột để giữ mã hóa đối tượng được tuần tự hóa cũng là UTF-8.Lưu trữ một đối tượng được tuần tự hóa trong cơ sở dữ liệu MySql

Vấn đề là đối tượng chứa chuỗi văn bản chứa ký tự tiếng Pháp.

Ví dụ:

Merci d'avoir passé commande avec Lovre. Voici le récapitulatif de votre commande 

Khi tôi serialize các đối tượng sau đó unserialize nó một lần nữa trực tiếp chuỗi được duy trì và là định dạng chính xác.

Tuy nhiên, khi tôi lưu trữ các đối tượng serialized vào một cơ sở dữ liệu MySql sau đó lấy nó một lần nữa sau đó unserialize nó chuỗi trở nên như thế này:

Merci d'avoir passé commande avec Lovre. Voici le récapitulatif de votre commande 

họ gặp khó khăn khi tôi lưu trữ các đối tượng trong cơ sở dữ liệu.

Ghi chú:

  • Các đối tượng được lưu trữ sử dụng đẩy ORM.
  • Loại cột là text.
  • Chuỗi được lưu trữ và đọc từ tệp html.
+0

Mã hóa tệp của bạn là gì? – alexn

+0

Bạn có thể thử base_64 mã hóa nó nhưng bạn không cần phải làm điều đó. Loại cột cơ sở dữ liệu là gì? Bạn đã kiểm tra cài đặt kết nối cơ sở dữ liệu trong php chưa? –

+0

@TheSilencer loại cột cơ sở dữ liệu là văn bản. Kết nối cơ sở dữ liệu được thực hiện bằng PROPEL. – Songo

Trả lời

10

Các chuỗi được tạo bởi serialize là chuỗi nhị phân, chúng không có bộ mã ký tự cụ thể nhưng chỉ là một "mảng" byte (trong đó một byte là 8 bit, một octet).

Nếu bây giờ bạn lấy một chuỗi như vậy và nói với cơ sở dữ liệu của bạn rằng nó được mã hóa LATIN-1 và cơ sở dữ liệu của bạn lưu nó vào trường văn bản với mã hóa UTF-8, cơ sở dữ liệu sẽ thay đổi mã hóa từ LATIN-1 thành UTF-8. UTF-8 là một bộ mã hóa bảng mã sử dụng nhiều hơn một byte cho mỗi ký tự cho một số ký tự, ví dụ như các ký tự bạn đưa ra trong câu hỏi của mình như é.

Ký tự é sau đó được lưu trữ dưới dạng é bên trong cơ sở dữ liệu, là chuỗi byte UTF-8 cho é.

Nếu bây giờ bạn tìm nạp dữ liệu từ cơ sở dữ liệu mà không chỉ định mã hóa nào bạn cần, cơ sở dữ liệu sẽ trả về dưới dạng UTF-8.

Hiện tại unserialize có vấn đề vì chuỗi nhị phân đã được sửa đổi theo cách khiến cho nó không hợp lệ.

Thay vào đó, bạn cần phải thông báo cho cơ sở dữ liệu của mình rằng cơ sở dữ liệu không nên sửa đổi mã hóa khi lưu trữ chuỗi được tuần tự hóa, ví dụ: bằng cách chọn đúng loại cột và mã hóa (trường nhị phân, BLOB - Binary Large Object­MySQL Docs, xem thêm Binary Types­Propel Docs) - hay - khi bạn tìm nạp dữ liệu từ cơ sở dữ liệu, bạn hoàn nguyên mã hóa ký tự trở lại định dạng gốc. Cách tiếp cận đầu tiên (trường nhị phân) là tốt hơn bởi vì nó chính xác là những gì bạn đang tìm kiếm.

Đối với dữ liệu đã được lưu trữ trong cơ sở dữ liệu ở định dạng sai, bạn cần sửa dữ liệu. Để thực hiện điều đó, trước tiên bạn cần tìm hiểu xem mã hóa lại nào đã được áp dụng, ví dụ: từ bộ ký tự nào đến bộ ký tự nào. Tôi cho rằng đó là LATIN-1 nhưng không có bảo đảm. Bạn cần xem lại mã hóa dữ liệu ứng dụng hiện tại của mình và các quy trình để tìm hiểu.

Sau khi bạn đã phát hiện ra, hãy mã hóa các giá trị từ UTF-8 thành mã hóa ban đầu.

+0

Tôi đã thử những gì bạn đã nói và chuyển đổi loại cột thành BLOB, nhưng vấn đề vẫn tồn tại.Tuy nhiên, tôi đã quyết định 'utf_decode' chính thư đó sau khi truy xuất đối tượng từ cơ sở dữ liệu và giải quyết vấn đề. – Songo

+0

Google có duy trì dữ liệu hiện tại và/hoặc cho dữ liệu mới không? Ngoài ra tôi không có chuyên gia propel, nhưng tôi khá chắc chắn rằng phải có một giải pháp chuyển tiếp thẳng với lớp cơ sở dữ liệu, do đó bạn không cần phải quan tâm đến việc mã hóa trong mã logic ứng dụng của bạn. Nếu bạn không thể giải quyết nó trên tầng cơ sở dữ liệu, cũng có giao diện ['Serializable'] (http://php.net/Serializable) trong PHP, điều này có thể hữu ích để giữ cho mã của bạn luôn sạch sẽ. – hakre

+0

Tôi không có dữ liệu hiện tại vì tôi vẫn đang trong giai đoạn phát triển. Tôi đã kiểm tra cấu hình PROPEL và nó sử dụng UTF-8 trong kết nối của nó. Có lẽ có cái gì đó mà tôi bỏ lỡ ở đó, nhưng tôi sẽ xem xét giao diện Serializable bạn đã đề cập. Cảm ơn bạn đã giúp đỡ. – Songo

4

đảm bảo sử dụng utf-8 ở mọi nơi - có vẻ như bạn đã bỏ lỡ điều gì đó.

trong trường hợp của bạn, tôi nghĩ bạn đã quên đặt bộ ký tự chính xác cho kết nối cơ sở dữ liệu của mình (sử dụng câu lệnh SET NAMES hoặc mysql_set_charset()) - nhưng khó nói mà không nhìn thấy mã của bạn (và tôi không biết propel).

sau đây là một trích dẫn từ chazomaticus, người đã đưa ra một câu trả lời hoàn hảo trong UTF-8 all the way through, liệt kê tất cả các điểm bạn cần phải chăm sóc:

Bảo quản:

  • Chỉ định utf8_unicode_ci (hoặc tương đương) đối chiếu trên tất cả các bảng và các cột văn bản trong cơ sở dữ liệu của bạn. Điều này làm cho MySQL lưu trữ vật lý và truy xuất các giá trị nguyên bản trong UTF-8.

Retrieval:

  • Trong PHP, trong bất cứ wrapper DB bạn sử dụng, bạn sẽ cần phải thiết lập các kết nối charset để utf8. Bằng cách này, MySQL thực hiện không có chuyển đổi từ mã UTF-8 gốc khi nó chuyển dữ liệu sang PHP. * Lưu ý rằng nếu bạn không sử dụng một DB wrapper, có thể bạn sẽ phải phát hành một truy vấn để nói với MySQL cung cấp cho bạn kết quả dưới dạng UTF-8: SET NAMES 'utf8' (ngay sau khi bạn kết nối).

Delivery:

  • Bạn đã có nói với PHP để cung cấp tiêu đề thích hợp cho khách hàng, vì vậy văn bản sẽ được hiểu là UTF-8. Trong PHP, bạn có thể sử dụng tùy chọn default_charset php.ini hoặc tự phát hành tiêu đề Content-Type, trong đó chỉ hoạt động nhiều hơn nhưng có cùng hiệu lực .

nộp:

  • Bạn muốn tất cả các dữ liệu được gửi đến cho bạn bởi trình duyệt được trong UTF-8. Thật không may, cách duy nhất để đáng tin cậy làm điều này là thêm thuộc tính accept-charset vào tất cả các thẻ <form>: <form ... accept-charset="UTF-8"> của bạn.
  • Note rằng spec W3C HTML nói rằng khách hàng "nên" mặc định để gửi dạng lại cho máy chủ trong bất cứ charset máy chủ phục vụ, nhưng đây là dường như chỉ một đề nghị, vì vậy cần phải được rõ ràng trên mỗi thẻ <form>.
  • Mặc dù, ở mặt trước đó, bạn vẫn sẽ muốn xác minh mọi chuỗi được gửi làm UTF-8 hợp lệ trước khi bạn cố gắng lưu trữ hoặc sử dụng nó ở bất kỳ đâu. PHP mb_check_encoding() thực hiện thủ thuật, nhưng bạn phải sử dụng nó một cách tôn giáo.

chế biến:

  • Đây là, không may, những khó khăn phần. Bạn cần phải đảm bảo rằng mỗi khi bạn xử lý một chuỗi UTF-8, bạn làm như vậy một cách an toàn. Cách dễ nhất để thực hiện điều này là bằng cách sử dụng rộng rãi tiện ích mở rộng của PHP mbstring.
  • PHP hoạt động chuỗi KHÔNG theo mặc định an toàn UTF-8. Có một số điều bạn có thể làm một cách an toàn với chuỗi PHP bình thường hoạt động (như ghép), nhưng đối với hầu hết mọi thứ bạn nên sử dụng chức năng tương đương mbstring.
  • Để biết bạn đang làm gì (đọc: không lộn xộn ), bạn thực sự cần biết UTF-8 và cách hoạt động ở mức thấp nhất có thể là . Kiểm tra bất kỳ liên kết nào trong số từ utf8.com để có một số tài nguyên tốt để tìm hiểu mọi thứ bạn cần để biết.
  • Ngoài ra, tôi cảm thấy như thế này nên được nói ở đâu đó, mặc dù có vẻ hiển nhiên: mọi tệp PHP hoặc HTML bạn sẽ phân phát phải là được mã hóa bằng UTF-8 hợp lệ.

lưu ý rằng bạn không cần phải sử dụng utf-8 - một phần quan trọng là sử dụng cùng charset ở khắp mọi nơi, không phụ thuộc vào những gì charset rằng có thể. nhưng nếu bạn cần thay đổi mọi thứ, hãy sử dụng utf-8.

1

Tôi luôn lưu trữ dữ liệu đã được xử lý bằng cách sử dụng base64_encode(). Dữ liệu tuần tự đôi khi gây ra vấn đề, nhưng sau khi sử dụng giá trị base64 của nó, chỉ còn lại các ký tự đơn giản.

1

Tôi thực sự khuyên bạn nên sử dụng json_encode thay vì sắp xếp từng hàng. Một ngày nào đó bạn sẽ thấy mình đang cố gắng sử dụng dữ liệu đó từ một nơi khác không phải là PHP và việc lưu trữ nó trong JSON làm cho nó có thể đọc được ở mọi nơi; hầu như mọi ngôn ngữ đều hỗ trợ giải mã JSON và là một tiêu chuẩn được thiết lập tốt.

Câu trả lời về việc sử dụng utf8 ở mọi nơi lưu giữ! :-D

+0

Không phải là một ý tưởng hay: 1. nó biến mảng thành các đối tượng, 2. loại lớp và phương thức bị mất –

+0

Các phương thức bị mất anyway .... bạn không lưu chúng với lệnh gọi 'serialize' Tin tôi đi, là một ý tưởng tồi tệ hơn để lưu trữ các nội dung tuần tự hóa .. cuối cùng bạn sẽ cần phải đọc những thứ đó từ một nơi khác. nếu bạn cần de-serialize trở lại một lớp chỉ lưu trữ kiểu như chuỗi và chuyển đổi sau đó để khởi tạo lớp bên phải với dữ liệu json như trường vs trả về json đơn giản, giống như bất kỳ ORM nào về cơ bản cho bản ghi DB. –