PHP, SQLite, MSAccess und chinesische Schriftzeichen

MSJones

Grünschnabel
Hallo zusammen.

Ich hab mal wieder ein größeres Problem.
Ich hab eine SQLite-Datenbank, in deren Tabellen mehrere Sprachen enthalten sind. Unter anderem auch chinesisch und koreanisch.
Diese Tabelle soll ich nun in eine Access-Datenbank schreiben, quasi als lokales Backup, in das der Benutzer auch mal reingucken kann.

Wenn ich jetzt einfach nur normalen Text da reinschreibe, also ANSI, funktioniert das ohne Probleme.
Aber sobald ich davon abweiche und eigentlich UTF-8 bräuchte, verhau ich mir die Zeichem.

Hier mal mein Code:
PHP:
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
</head>

<?php
// DB Verbindung 
$db_temp = null;
$db_temp_access = null;

function query_insert($SQL, $db)
{
    $result = $db->query($SQL);
    if ($result == null)
    {
        error_log($SQL);
    }
    return ($result);
}

function fetch_array($result)
{
  //return($result->fetchArray());
    if ($result == null)
    {
        return null;
    }
    return $result->fetch(PDO::FETCH_BOTH);
}

function connectDatabases()
{
    try
    {
        $db_access = new PDO("odbc:Driver={Microsoft Access-Treiber (*.mdb)};Dbq=".$_SERVER["DOCUMENT_ROOT"]."\\backup.mdb;Uid=Admin","","");
        $db = new PDO("sqlite:".$_SERVER["DOCUMENT_ROOT"]."sqlite3db");
    }
    catch (PDOException $e)
    {
        echo "Error: ".$e->getMessage()."<br>";
    }
    $GLOBALS["db_temp_access"] = $db_access;
    $GLOBALS["db_temp"] = $db;
}

function copyTables()
{
    copyTable("TEXTE");
}

function copyTable($tableName)
{
    // Spaltennamen ermitteln
    $SQL = " PRAGMA table_info(".$tableName.");";
    error_log($SQL);
    $result = query_insert($SQL, $GLOBALS["db_temp"]);
    while ($row = fetch_array($result))
    {
        $columnNames[] = $row[1];
        $columnType[] = $row[2];
    }
    
    // Tabelleninhalt selektieren
    $SQL = " SELECT ".implode(",",$columnNames)." FROM ".$tableName.";";
    $result = query_insert($SQL, $GLOBALS["db_temp"]);
    while ($row = fetch_array($result))
    {
        // Tabelleninhalt schreiben
        $SQL_insert = " INSERT INTO ".$tableName;
        $SQL_insert.= " (".implode(",",$columnNames).")";
        $SQL_insert.= " VALUES";
        $SQL_insert.= " (";
        for ($i=0; $i<count($columnNames); $i++)
        {
            if ($i > 0)
            {
                $SQL_insert.=", ";
            }
            
            // Vom Typ die Länge abschneiden
            $columnType[$i] = trim(preg_replace("/\(\d*\)/","",$columnType[$i]));
            
            // Einfache Anführungszeichen ersetzen
            $row[$columnNames[$i]] = str_replace("'", "''", $row[$columnNames[$i]]);
            
            switch (strtoupper($columnType[$i]))
            {
                case "LONG":
                case "INTEGER":
                case "BOOLEAN":
                case "SMALLINT":
                    if ($row[$columnNames[$i]] == "")
                    {
                        $SQL_insert.= "0";
                    }
                    else
                    {
                        $SQL_insert.=$row[$columnNames[$i]];
                    }
                    break;
                case "NVARCHAR":
                case "VARCHAR":
                    $SQL_insert.= "'".$row[$columnNames[$i]]."'";
                    break;
                default:
                    echo "Column: ".$columnType[$i]."<br>";
            }
        }
        $SQL_insert.= " );";
        $result2 = query_insert($SQL_insert, $GLOBALS["db_temp_access"]);
    }
    echo $tableName." copied.<br>";
}

connectDatabases();
copyTables();

?>
Ich würd mal sagen, am SQLite kanns erst mal nicht liegen, denn wenn ich die Werte auslese und auf der Webseite anzeigen lasse, werden die Strings richtig angezeigt, so wie es sein soll.

Hatte vielleicht jemand dieses Problem schon und ne Lösung oder nen Tip für mich?

Gruß,
MSJones
 
Hi,

ich habe mal gehört, dass Access Unicode Strings in UTF-16 Kodierung abspeichert, das bedeutet, du müsstest UTF-8, was aus SQLite kommt zunächst nach UTF-16 konvertieren, bevor du es in Access einfügst. Alternativ dazu müsstest du die "Unicode Compression" von Access nutzen können, um UTF-8 zu verwenden.
 
So, ich hab jetzt mal ein wenig rumprobiert.
Ich hab versucht, die Strings zu konvertieren mit "mb_convert_encoding".
Also sieht mein INSERT Befehl wie folgt aus:
PHP:
        // Tabelleninhalt schreiben
        $SQL_insert = " INSERT INTO ".$tableName;
        $SQL_insert.= " (".implode(",",$columnNames).")";
        $SQL_insert.= " VALUES";
        $SQL_insert.= " (";
        for ($i=0; $i<count($columnNames); $i++)
        {
            if ($i > 0)
            {
                $SQL_insert.=", ";
            }
           
            // Vom Typ die Länge abschneiden
            $columnType[$i] = trim(preg_replace("/\(\d*\)/","",$columnType[$i]));
           
            // Einfache Anführungszeichen ersetzen
            $row[$columnNames[$i]] = str_replace("'", "''", $row[$columnNames[$i]]);
           
            switch (strtoupper($columnType[$i]))
            {
                case "LONG":
                case "INTEGER":
                case "BOOLEAN":
                case "SMALLINT":
                    if ($row[$columnNames[$i]] == "")
                    {
                        $SQL_insert.= "0";
                    }
                    else
                    {
                        $SQL_insert.=$row[$columnNames[$i]];
                    }
                    break;
                case "NVARCHAR":
                case "VARCHAR":
                    $text = $row[$columnNames[$i]];
                    $SQL_insert.= "'".mb_convert_encoding($text,"UTF-16","UTF-8")."'";
                    break;
                default:
                    echo "Column: ".$columnType[$i]."<br>";
            }
        }
        $SQL_insert.= " );";
        $result2 = query_insert($SQL_insert, $GLOBALS["db_temp_access"]);
Statt diesem FROM-Encoding hab ich auch andere Encodings auprobiert und auch mal weggelassen.
Immer mit dem selben Ergebnis:
Nachdem der String umgewandelt ist, steht an erster Stelle ein \0 (was nach meinem Wissen das Ende eines Strings bedeutet) und dann erst der Buchstabe. Folglich wird der String noch vor dem ersten Zeichen beendet, was zwangläufig beim Einfügen in die Datenbank zu einem Fehler führt.

Die andere Methode, mit dem "Unicode Compression" hab ich auch probiert.
Hier hab ich mir eine Tabelle aus Access genommen und alle Textspalten auf Unicode-Kompression = Ja gesetzt.
Die Insert-Methode dann wie gehabt ohne ein Encoding.
Ergebnis:
Selbe wir ohne Unicode-Compression. Die Schriftzeichen (chinesisch...) werden nicht richtig dargestellt.

Wenn ich mir das Insert ausgeben lasse und von Hand bei Access als Abfrage reinkopiere, funktioniert das problemlos.
Kann es sein, das der ODBC-Treiber das nicht hinbekommt, den String richtig zu übermitteln?
 
Zuletzt bearbeitet:
Zurück