我正在使用DomDocument使用PHP生成XML文件,我需要处理亚洲字符。我使用pdo_mssql驱动程序从MSSQL2008服务器提取数据,并在XML属性值上应用utf8_encode()。只要没有特殊字符,一切都很好。
服务器是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 :(得分:22)
我找到了如何解决它,所以希望这会对某人有所帮助。
首先,SQL_Latin1_General_CP1_CI_AS是CP-1252和UTF-8的奇怪组合。 基本字符是CP-1252,所以这就是为什么我所要做的就是UTF-8而且一切正常。亚洲和其他UTF-8字符编码为2个字节,php pdo_mssql驱动程序似乎讨厌不同长度的字符,因此它似乎对varchar(而不是nvarchar)执行CAST,然后所有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);
答案 1 :(得分:2)
我知道这篇文章很老,但对我来说唯一有用的是 iconv(“CP850”,“UTF-8 // TRANSLIT”,$ var); 我对SQL_Latin1_General_CP1_CI_AI也有同样的问题,也许它也适用于SQL_Latin1_General_CP1_CI_AS。
答案 2 :(得分: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>");
}
答案 3 :(得分:0)
默认情况下,PDO
使用PDO::SQLSRV_ENCODING_UTF8
发送/接收数据。
如果您当前的整理是LATIN1
,您是否尝试指定PDO::SQLSRV_ENCODING_SYSTEM
让PDO
知道您想要使用当前系统编码而不是UTF-8
?
您甚至可以使用PDO::SQLSRV_ENCODING_BINARY
以二进制形式返回数据(传输数据时不进行编码或转换)。这样,您可以处理您身边的字符编码。
答案 4 :(得分: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']);
答案 5 :(得分: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,并且(duh)获取html代码而不是特殊字符。修复在使用json_encode发送之前只对字符串使用html_entity_decode()。
答案 6 :(得分:0)
不需要疯狂的东西。排序规则SQL_Latin1_General_CP1_CI_AS
字符编码为:Windows-1252
这对我来说很完美:$str = mb_convert_encoding($str, 'UTF-8', 'Windows-1252');