2012-04-12 43 views
9

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.Codificando SQL_Latin1_General_CP1_CI_AS en UTF-8

El servidor es MS SQL Server 2008 SP3

La base de datos, tabla y la columna de colación están todos SQL_Latin1_General_CP1_CI_AS

estoy usando PHP 5.2.17

Aquí está mi DOP objeto:

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

Mi consulta es una SELECCIÓN básica.

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

Considerando todos los detalles anteriores, ¿cómo debo procesar los datos?

+0

¿Has probado ['utf8_encode()'] (http://ca3.php.net/manual/en/function.utf8-encode.php)? Según el manual: 'Codifica una cadena ISO-8859-1 a UTF-8'. –

+0

Por supuesto, eso es lo que estoy haciendo actualmente, pero los caracteres asiáticos aparecen como '?'. Incluso si solo ejecuto SELECT y luego pongo los datos en un archivo (utf8_encode o no), los caracteres asiáticos terminan como '?' en el archivo. – SGr

+0

Realmente me sorprende que en realidad pueda codificar caracteres asiáticos en 'LATIN1'. 'LATIN1' es solo para codificar caracteres europeos ... –

Respuesta

16

he encontrado la forma de resolverlo, así que espero que esto sea útil a alguien.

Primero, SQL_Latin1_General_CP1_CI_AS es una extraña mezcla de CP-1252 y UTF-8. Los caracteres básicos son CP-1252, por lo 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 (' ? ').

me fijo echándola a binario y luego reconstruir 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<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

¡para mí solo funcionó en binario! gracias –

+0

increíble !!! ¡¡¡Perfecto!!! y una respuesta de agradecimiento :) – SagarPPanchal

0

Por defecto, PDO usa PDO::SQLSRV_ENCODING_UTF8 para enviar/recibir datos.

Si su intercalación actual es LATIN1, ¿ha intentado especificando PDO::SQLSRV_ENCODING_SYSTEM dejar PDO saben que desea utilizar la codificación actual sistema en lugar de UTF-8?

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

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

+0

Ninguno de los parámetros' PDO :: SQLSRV_ * 'funcionan para mí en' SQL server 2008'. Me sale un error, que no está definido o algo así. –

2

Sé que este post es viejo, pero lo único que el trabajo para mí fue iconv ("CP850", "UTF-8 // TRANSLIT", $ var); Tuve los mismos problemas con SQL_Latin1_General_CP1_CI_AI, tal vez también funciona para SQL_Latin1_General_CP1_CI_AS.

2

Usted puede tratar 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] <br>"); 
} 
+1

¡Esto funcionó para mí! Gracias: 'print iconv (" CP1252 "," UTF-8 "," $ row [Nome]
"); – joelpittet

0

Gracias @SGr de respuesta.
descubrí una mejor manera de hacer eso:

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

Y en PHP que sólo debe convertirlo a UTF-8:

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

0

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 este post y ninguno de los trabajos arriba para usted, trate de:

$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 una pequeña prima - que tenía que json_encode estos datos y era (la) Cómo obtener 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.