2012-04-12 19 views
9

Tôi đang tạo một tệp XML với PHP bằng cách sử dụng DomDocument và tôi cần xử lý các ký tự Châu Á. Tôi đang kéo dữ liệu từ máy chủ MSSQL2008 bằng trình điều khiển pdo_mssql và tôi áp dụng utf8_encode() trên các giá trị thuộc tính XML. Tất cả mọi thứ hoạt động tốt miễn là không có ký tự đặc biệt.Mã hóa SQL_Latin1_General_CP1_CI_AS thành UTF-8

Máy chủ là MS SQL Server 2008 SP3

Cơ sở dữ liệu, bảng và cột chiếu đều SQL_Latin1_General_CP1_CI_AS

Tôi đang sử dụng PHP 5.2.17

Dưới đây là đối tượng PDO của tôi:

$pdo = new PDO("mssql:host=MyServer,1433;dbname=MyDatabase", user123, password123); 

Truy vấn của tôi là SELECT cơ bản.

Tôi biết việc lưu trữ các ký tự đặc biệt vào các cột SQL_Latin1_General_CP1_CI_AS không phải là tuyệt vời, nhưng tốt nhất là làm cho nó hoạt động mà không thay đổi nó, bởi vì các chương trình không phải PHP đã sử dụng cột đó và nó hoạt động tốt. Trong SQL Server Management Studio tôi có thể thấy các ký tự Châu Á một cách chính xác.

Xem xét tất cả các chi tiết ở trên, tôi nên xử lý dữ liệu như thế nào?

+0

Bạn đã thử ['utf8_encode()'] (http://ca3.php.net/manual/en/function.utf8-encode.php) chưa? Theo hướng dẫn: 'Mã hóa chuỗi ISO-8859-1 thành UTF-8'. –

+0

Tất nhiên, đó là những gì tôi hiện đang làm, nhưng các ký tự Châu Á xuất hiện dưới dạng '?'. Ngay cả khi tôi chỉ chạy SELECT và sau đó đưa dữ liệu vào một tệp (utf8_encode hay không), các ký tự Châu Á kết thúc bằng '?' Trong tập tin. – SGr

+0

Nó thực sự làm tôi ngạc nhiên rằng bạn thực sự có thể mã hóa các ký tự Châu Á trong 'LATIN1'. 'LATIN1' chỉ để mã hóa các ký tự châu Âu ... –

Trả lời

16

tôi thấy làm thế nào để giải quyết nó, vì vậy hy vọng điều này sẽ rất hữu ích cho một ai đó.

Đầu tiên, SQL_Latin1_General_CP1_CI_AS là sự kết hợp kỳ lạ giữa CP-1252 và UTF-8. Các ký tự cơ bản là CP-1252, vì vậy đây là lý do tại sao tất cả những gì tôi phải làm là UTF-8 và mọi thứ hoạt động. Các ký tự UTF-8 và Châu Á được mã hóa trên 2 byte và trình điều khiển pdo_mssql php dường như ghét các ký tự có độ dài khác nhau, vì vậy nó có vẻ như làm một CAST thành varchar (thay vì nvarchar) và sau đó tất cả ký tự 2 byte trở thành dấu hỏi (' ? ').

tôi cố định nó bằng cách đúc nó để nhị phân và sau đó tôi xây dựng lại các văn bản với php:

SELECT CAST(MY_COLUMN AS VARBINARY(MAX)) FROM MY_TABLE; 

Trong php:

//Binary to hexadecimal 
$hex = bin2hex($bin); 

//And then from hex to string 
$str = ""; 
for ($i=0;$i<strlen($hex) -1;$i+=2) 
{ 
    $str .= chr(hexdec($hex[$i].$hex[$i+1])); 
} 
//And then from UCS-2LE/SQL_Latin1_General_CP1_CI_AS (that's the column format in the DB) to UTF-8 
$str = iconv('UCS-2LE', 'UTF-8', $str); 
+0

cho tôi chỉ đúc nó để làm việc nhị phân! cảm ơn –

+0

tuyệt vời !!! hoàn hảo!!! và câu trả lời đánh giá cao :) – SagarPPanchal

0

Theo mặc định, PDO sử dụng PDO::SQLSRV_ENCODING_UTF8 để gửi/nhận dữ liệu.

Nếu đối chiếu hiện tại của bạn là LATIN1, bạn đã cố gắng specifiying PDO::SQLSRV_ENCODING_SYSTEM để cho PDO biết rằng bạn muốn sử dụng mã hóa hệ thống hiện tại thay vì UTF-8?

Bạn thậm chí có thể sử dụng PDO::SQLSRV_ENCODING_BINARY để trả về dữ liệu dưới dạng nhị phân (không mã hóa hoặc dịch được thực hiện khi chuyển dữ liệu). Bằng cách này, bạn có thể xử lý mã hóa ký tự ở bên cạnh bạn.

Nhiều tài liệu ở đây: http://ca3.php.net/manual/en/ref.pdo-sqlsrv.php

+0

Không có tham số' PDO :: SQLSRV_ * 'nào hoạt động với tôi trên' SQL server 2008'. Tôi nhận được một số lỗi, rằng nó không xác định hoặc một cái gì đó như thế. –

2

Tôi biết bài này là cũ, nhưng điều duy nhất mà làm việc cho tôi là biểu tượngv ("CP850", "UTF-8 // TRANSLIT", $ var); Tôi có cùng vấn đề với SQL_Latin1_General_CP1_CI_AI, có thể nó cũng hoạt động với SQL_Latin1_General_CP1_CI_AS.

2

Bạn có thể thử như vậy:

header("Content-Type: text/html; charset=utf-8"); 
$dbhost = "hostname"; 
$db  = "database"; 
$query = "SELECT * 
    FROM Estado 
    ORDER BY Nome"; 
$conn = new PDO("sqlsrv:server=$dbhost ; Database = $db", "", ""); 
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED, PDO::SQLSRV_ENCODING_SYSTEM)); 
$stmt->execute(); 
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) 
{ 
// CP1252 == code page Latin1 
print iconv("CP1252", "ISO-8859-1", "$row[Nome] <br>"); 
} 
+1

Điều này làm việc cho tôi! Cảm ơn bạn: 'print iconv (" CP1252 "," UTF-8 "," $ row [Nome]
");' – joelpittet

0

Cảm ơn @SGr cho câu trả lời.
tôi phát hiện ra một cách tốt hơn để làm điều đó:

SELECT CAST(CAST(MY_COLUMN AS VARBINARY(MAX)) AS VARCHAR(MAX)) as MY_COLUMN FROM MY_TABLE;
và cũng thử với:
SELECT CAST(MY_COLUMN AS VARBINARY(MAX)) as MY_COLUMN FROM MY_TABLE;

Và trong PHP bạn chỉ nên chuyển nó sang UTF-8:

$string = iconv('UCS-2LE', 'UTF-8', $row['MY_COLUMN']);

0

Đối với tôi, không có giải pháp nào ở trên là giải pháp trực tiếp - mặc dù tôi đã sử dụng các phần của giải pháp trên. Điều này làm việc cho tôi với bảng chữ cái tiếng Việt. Nếu bạn gặp bài đăng này và không ai trong số các công việc trên cho bạn, hãy thử:

$req = "SELECT CAST(MY_COLUMN as VARBINARY(MAX)) as MY_COLUMN FROM MY_TABLE"; 
    $stmt = $conn->prepare($req); 
    $stmt->execute(); 
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
     $str = pack("H*",$row['MY_COLUMN']); 
     $str = mb_convert_encoding($z, 'HTML-ENTITIES','UCS-2LE'); 
     print_r($str); 
    } 

Và một phần thưởng nhỏ - Tôi phải json_encode dữ liệu này và đã (duh) nhận được mã html thay vì ký tự đặc biệt. để sửa chữa chỉ cần sử dụng html_entity_decode() trên các chuỗi trước khi gửi với json_encode.

Các vấn đề liên quan