php - No se pueden recuperar caracteres acentuados UTF-8 de Access a través de PDO_ODBC
ms-access (2)
Estoy tratando de convertir una base de datos de acceso en MySQL. Todo funciona perfectamente, espere una llave inglesa grande ... Si el db de acceso tiene caracteres no estándar, no funcionará. Mi consulta me dirá:
Incorrect string value: ''/xE9d''
Si hago eco directamente del texto de las filas que tiene el carácter ''inválido'', obtengo un signo de interrogación en un cuadrado negro en mi navegador (por lo que é se convertiría en ese símbolo simbólico no válido en el eco).
NOTA: Eso mismo aceptará, guardará y mostrará la "é" muy bien en un cuadro de texto que se utiliza para titular esta carga db. Además, si ''guardo como'' la página y la vuelvo a abrir, la ''é'' se muestra correctamente ...
Así es como me conecto:
$conn = new PDO("odbc:Driver={Microsoft Access Driver (*.mdb)};Dbq=$fileLocation;SystemDB=$securefilePath;Uid=developer;Pwd=pass;charset=utf;");
He intentado numerosas cosas, que incluyen:
$conn -> exec("set names utf8");
Cuando pruebo un ''CurrentDb.CollatingOrder'' en el acceso, me dice 1033 aparentemente que es dbSortGeneral para "orden de clasificación en inglés, alemán, francés y portugués".
¿Qué está mal? Es casi como si el PDO me estuviera enviando una recopilación de mi navegador y PHP no comprende completamente.
El problema
Cuando se utilizan características ODBC PHP nativas (PDO_ODBC o las funciones
odbc_
más
odbc_
) y el controlador ODBC de Access, el texto no está codificado en UTF-8, aunque se almacena en la base de datos de Access como caracteres Unicode.
Entonces, para una tabla de ejemplo llamada "Equipos"
Team
-----------------------
Boston Bruins
Canadiens de Montréal
Федерация хоккея России
el código
<?php
header(''Content-Type: text/html; charset=utf-8'');
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Access character test</title>
</head>
<body>
<?php
$connStr =
''odbc:'' .
''Driver={Microsoft Access Driver (*.mdb)};'' .
''Dbq=C://Users//Public//__SO//28311687.mdb;'' .
''Uid=Admin;'';
$db = new PDO($connStr);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT Team FROM Teams";
foreach ($db->query($sql) as $row) {
$s = $row["Team"];
echo $s . "<br/>/n";
}
?>
</body>
</html>
muestra esto en el navegador
Boston Bruins
Canadiens de Montr�al
????????? ?????? ??????
Las soluciones fáciles pero incompletas
El texto devuelto por Access ODBC en realidad coincide con la codificación de caracteres de Windows-1252 para los caracteres en ese conjunto de caracteres, por lo que simplemente cambia la línea
$s = $row["Team"];
a
$s = utf8_encode($row["Team"]);
permitirá que la segunda entrada se muestre correctamente
Boston Bruins
Canadiens de Montréal
????????? ?????? ??????
pero la función utf8_encode() convierte de ISO-8859-1 , no de Windows-1252 , por lo que algunos caracteres (especialmente el símbolo del euro ''€'') desaparecerán. Una mejor solución sería usar
$s = mb_convert_encoding($row["Team"], "UTF-8", "Windows-1252");
pero eso aún no resolvería el problema con la tercera entrada en nuestra tabla de muestra.
La solución completa
Para obtener soporte completo para UTF-8, necesitamos usar COM con ADODB Connection y objetos Recordset como este
<?php
header(''Content-Type: text/html; charset=utf-8'');
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Access character test</title>
</head>
<body>
<?php
$connStr =
''Driver={Microsoft Access Driver (*.mdb)};'' .
''Dbq=C://Users//Public//__SO//28311687.mdb'';
$con = new COM("ADODB.Connection", NULL, CP_UTF8); // specify UTF-8 code page
$con->Open($connStr);
$rst = new COM("ADODB.Recordset");
$sql = "SELECT Team FROM Teams";
$rst->Open($sql, $con, 3, 3); // adOpenStatic, adLockOptimistic
while (!$rst->EOF) {
$s = $rst->Fields("Team");
echo $s . "<br/>/n";
$rst->MoveNext;
}
$rst->Close();
$con->Close();
?>
</body>
</html>
Un poco más fácil de manipular los datos. (Matriz de matriz).
function consulta($sql) {
$db_path = $_SERVER["DOCUMENT_ROOT"] . ''/database/Registros.accdb'';
$conn = new COM(''ADODB.Connection'', NULL, CP_UTF8) or exit(''Falha ao iniciar o ADO (objeto COM).'');
$conn->Open("Persist Security Info=False;Provider=Microsoft.ACE.OLEDB.12.0;Jet OLEDB:Database Password=ifpb@10510211298;Data Source=$db_path");
$rs = $conn->Execute($sql);
$numRegistos = $rs->Fields->Count;
$index = 0;
while (!$rs->EOF){
for ($n = 0; $n < $numRegistos; $n++) {
if(is_null($rs->Fields[$n]->Value)) continue;
$resultados[$index][$rs->Fields[$n]->Name] = $rs->Fields[$n]->Value;
echo ''.'';
}
echo ''<br>'';
$index = $index + 1;
$rs->MoveNext();
}
$conn->Close();
return $resultados;
}
$dados = consulta("select * from campus");
var_dump($dados);