Codificando SQL_Latin1_General_CP1_CI_AS en UTF-8

Estoy generando un archivo XML con PHP usando DomDocument y necesito manejar caracteres asiáticos. Estoy extrayendo datos del servidor MSSQL2008 utilizando el controlador pdo_mssql y aplico utf8_encode () en los valores de los atributos XML. Todo funciona bien siempre que no haya caracteres especiales.

El servidor es MS SQL Server 2008 SP3

La recostackción de bases de datos, tablas y columnas son todas SQL_Latin1_General_CP1_CI_AS

Estoy usando PHP 5.2.17

Aquí está mi objeto PDO:

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

Mi consulta es un SELECCIONAMIENTO básico.

Sé que almacenar caracteres especiales en SQL_Latin1_General_CP1_CI_AS columnas no es genial, pero idealmente sería bueno hacerlo funcionar sin cambiarlo, porque otros progtwigs que no son PHP ya usan esa columna y funciona bien. En SQL Server Management Studio puedo ver los caracteres asiáticos correctamente.

Teniendo en cuenta todos los detalles anteriores, ¿cómo debo procesar los datos?

Encontré cómo resolverlo, así que espero que esto sea útil para alguien.

Primero, SQL_Latin1_General_CP1_CI_AS es una mezcla extraña de CP-1252 y UTF-8. Los caracteres básicos son CP-1252, así que esta es la razón por la que todo lo que tuve que hacer fue UTF-8 y todo funcionó. Los caracteres asiáticos y otros caracteres UTF-8 están codificados en 2 bytes y el controlador php pdo_mssql parece odiar caracteres de longitud variable, por lo que parece hacer un CAST para varchar (en lugar de nvarchar) y luego los caracteres de 2 bytes se convierten en signos de interrogación (‘ ? ‘).

Lo arreglé fundiéndolo en binario y luego reconstruí el texto con php:

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

En php:

 //Binary to hexadecimal $hex = bin2hex($bin); //And then from hex to string $str = ""; for ($i=0;$i 

Sé que esta publicación es antigua, pero lo único que funciona para mí fue iconv (“CP850”, “UTF-8 // TRANSLIT”, $ var); Tuve los mismos problemas con SQL_Latin1_General_CP1_CI_AI, tal vez también funcione para SQL_Latin1_General_CP1_CI_AS.

Puedes intentarlo así:

 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] 
"); }

De forma predeterminada, PDO utiliza PDO::SQLSRV_ENCODING_UTF8 para enviar / recibir datos.

Si su clasificación actual es LATIN1 , ¿ha intentado especificar PDO::SQLSRV_ENCODING_SYSTEM para informar a PDO que desea utilizar la encoding del sistema actual en lugar de UTF-8 ?

Incluso podría usar PDO::SQLSRV_ENCODING_BINARY que devuelve datos en forma binaria (no se realiza encoding o traducción al transferir datos). De esta forma, puedes manejar la encoding de caracteres de tu lado.

Más documentación aquí: http://ca3.php.net/manual/en/ref.pdo-sqlsrv.php

Gracias @SGr por la respuesta.
Descubrí una mejor manera de hacerlo:

SELECT CAST(CAST(MY_COLUMN AS VARBINARY(MAX)) AS VARCHAR(MAX)) as MY_COLUMN FROM MY_TABLE;
y también prueba con:
SELECT CAST(MY_COLUMN AS VARBINARY(MAX)) as MY_COLUMN FROM MY_TABLE;

Y en PHP debes convertirlo a UTF-8:

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

Para mí, ninguna de las soluciones anteriores fue la solución directa, aunque usé partes de las soluciones anteriores. Esto funcionó para mí con el alfabeto vietnamita. Si te encuentras con esta publicación y ninguno de los anteriores funciona para ti, intenta:

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

Y un pequeño bono: tuve que json_encode esta información y estaba (duh) obteniendo el código html en lugar de los caracteres especiales. para solucionar, solo use html_entity_decode () en las cadenas antes de enviar con json_encode.