2012-04-12 36 views
9

我使用DomDocument生成一個PHP文件,我需要處理亞洲字符。我使用pdo_mssql驅動程序從MSSQL2008服務器提取數據,並對XML屬性值應用utf8_encode()。只要沒有特殊字符,一切都可以正常工作。將SQL_Latin1_General_CP1_CI_AS編碼爲UTF-8

該服務器的MS SQL Server 2008 SP3

數據庫,表和列排序規則都SQL_Latin1_General_CP1_CI_AS

我使用PHP 5.2.17

這裏是我的PDO對象:

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

我的查詢是一個基本的SELECT。

我知道在SQL_Latin1_General_CP1_CI_AS列中存儲特殊字符並不是很好,但理想情況下,它可以很好地工作而不改變它,因爲其他非PHP程序已經在使用該列並且工作正常。在SQL Server Management Studio中,我可以正確地看到亞洲字符。

考慮到上述所有細節,我應該如何處理數據?

+0

你試過['utf8_encode()'](http://ca3.php.net/manual/en/function.utf8-encode.php)嗎?根據手冊:'將ISO-8859-1字符串編碼爲UTF-8'。 – 2012-04-12 14:00:37

+0

當然,這就是我目前正在做的,但是它的亞洲字符顯示爲'?'。即使我只是運行SELECT,然後將數據放入文件(utf8_encode或不),亞洲字符最終爲'?'在文件中。 – SGr 2012-04-12 14:01:24

+0

真的讓我感到驚訝,你實際上能夠在'LATIN1'中編碼亞洲字符。 'LATIN1'僅用於編碼歐洲字符...... – 2012-04-12 14:10:32

回答

16

我發現怎麼解決呢,所以希望這會有所幫助的人。

首先,SQL_Latin1_General_CP1_CI_AS是CP-1252和UTF-8的奇怪組合。 基本的角色是CP-1252,所以這就是爲什麼我所要做的只是UTF-8並且一切正常。亞洲和其他UTF-8字符編碼在2個字節和PHP pdo_mssql驅動程序似乎討厭變長的字符,所以它似乎做一個CAST varchar(而不是nvarchar),然後所有的2字節字符成爲問號(' ?')。

我固定它通過強制轉換爲二進制,然後我重新用PHP文本:

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

在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

對我來說只有將它鑄造成二元工作!謝謝 – 2017-02-01 14:02:25

+0

真棒!完善!!!並讚賞回答:) – SagarPPanchal 2017-03-15 05:26:39

0

默認情況下,PDO使用PDO::SQLSRV_ENCODING_UTF8發送/接收數據。

如果您目前的整理是LATIN1,你嘗試specifiying PDO::SQLSRV_ENCODING_SYSTEMPDO知道你想使用當前的系統編碼,而不是UTF-8

您甚至可以使用PDO::SQLSRV_ENCODING_BINARY以二進制形式返回數據(傳輸數據時不會進行編碼或轉換)。這樣,你就可以在你身邊處理字符編碼。

更多的文檔在這裏:http://ca3.php.net/manual/en/ref.pdo-sqlsrv.php

+0

'SQL Server 2008'上沒有任何'PDO :: SQLSRV_ *'參數適用於我。我得到一些錯誤,它是未定義的或類似的東西。 – 2016-10-05 09:51:08

2

,但唯一的事情,爲我工作是 iconv(「CP850」,「UTF-8 // TRANSLIT」,$ var); 我有與SQL_Latin1_General_CP1_CI_AI相同的問題,也許它也適用於SQL_Latin1_General_CP1_CI_AS。

2

你可以試試這樣:

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

這一個爲我工作!謝謝:'print iconv(「CP1252」,「UTF-8」,「$ row [Nome]
」);'' – joelpittet 2015-02-18 18:23:51

0

感謝@SGr的答案。
我發現了一個更好的方式做這件事:

SELECT CAST(CAST(MY_COLUMN AS VARBINARY(MAX)) AS VARCHAR(MAX)) as MY_COLUMN FROM MY_TABLE;
也嘗試:
SELECT CAST(MY_COLUMN AS VARBINARY(MAX)) as MY_COLUMN FROM MY_TABLE;

而在PHP你應該只將其轉換爲UTF-8:

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

0

對我而言,以上都不是直接解決方案 - 儘管我確實使用了上述解決方案的一部分。這對越南字母表適合我。如果你遇到這個帖子並沒有爲你上面的工作,嘗試:

$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); 
    } 

還有一點獎金 - 我不得不json_encode這些數據,併爲(杜)獲得HTML代碼,而不是特殊字符。在使用json_encode發送消息之前,修復在字符串上使用html_entity_decode()。