Mysql, tschechische/polnische Buchstaben

nebbiolo

Grünschnabel
Hallo
Ich habe eine SQL-Tabelle mit UTF8 und utf8_general_ci definiert.
Der Input ist aus einer ANSI-Datei die ich mit:
PHP:
$text=utf8_encode ($teile[6]);
einlese.
Die Umlaute wie öäüè etc. werden problemlos richtig abgelegt.
Nun habe ich aber festgestellt, dass z.B. von "DÉLKA ŠTOLY je cca 3 až" das "É" in der DB richtig dargestellt wird, das "Š" und "ž" jedoch als "�".
Der Header ist:
HTML:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">

Nun meine Frage:
kann ich etwas anders definieren, dass die Zeichen in der DB richtig angezeigt werden?
oder was muss/kann ich machen, dass die Zeichen richtig importiert werden?
Schönen Sonntag und viele Grüsse, nebbiolo
 
Zuletzt bearbeitet von einem Moderator:
Lösung
Grundsatz jeder Internationalization/Kodierungsgeschichte: kenne alle Kodierungen all deiner Eingabe- und Ausgabedaten.

Du sagst, deine Datei sei eine "ANSI-Datei". Laut What is ANSI format? ist das zu ungenau: es sagt nur aus, dass deine Datei mit 8-Bit pro Zeichen kodiert ist, wobei Bytes, deren MSB 0 ist, eben ASCII-kodiert sind, und deren MSB 1 ist anders kodiert sind.
Höchstwahrscheinlich ist deine Datei, wie in der StackOverflow-Antwort beschrieben wird, mit Windows-1252 kodiert.
Ergo musst du mal "php windows 1252 to utf8" auf Google suchen, um zu wissen, wie man das in UTF-8 konvertiert. Da kommt dann sowas wie $utf8String = iconv('Windows-1252', 'UTF-8', $win1252String); raus.

PHP: utf8_encode - Manual...
Grundsatz jeder Internationalization/Kodierungsgeschichte: kenne alle Kodierungen all deiner Eingabe- und Ausgabedaten.

Du sagst, deine Datei sei eine "ANSI-Datei". Laut What is ANSI format? ist das zu ungenau: es sagt nur aus, dass deine Datei mit 8-Bit pro Zeichen kodiert ist, wobei Bytes, deren MSB 0 ist, eben ASCII-kodiert sind, und deren MSB 1 ist anders kodiert sind.
Höchstwahrscheinlich ist deine Datei, wie in der StackOverflow-Antwort beschrieben wird, mit Windows-1252 kodiert.
Ergo musst du mal "php windows 1252 to utf8" auf Google suchen, um zu wissen, wie man das in UTF-8 konvertiert. Da kommt dann sowas wie $utf8String = iconv('Windows-1252', 'UTF-8', $win1252String); raus.

PHP: utf8_encode - Manual ist die falsche Funktion, siehe auch PHP: utf8_encode - Manual:
https://www.php.net/utf8_encode hat gesagt.:
Hinweis:

Viele Webseiten, die ausgewiesen sind die ISO-8859-1 Zeichenkodierung zu verwenden, nutzen in Wirklichkeit die ähnliche Windows-1252 Kodierung, und Webbrowser interpretieren ISO-8859-1 Webseiten als Windows-1252. Windows-1252 ermöglicht zusätzliche druckbare Zeichen, so wie das Euro-Zeichen (€) und geschweifte Anführungszeichen (“”) anstelle von bestimmten ISO-8859-1 Kontrollzeichen. Diese Funktion konvertiert solche Windows-1252 Zeichen nicht korrekt. Verwenden Sie eine andere Funktion, wenn Windows-1252 Konvertierung erforderlich ist.
(utf8_encode ist eine schreckliche Falschbezeichnung für die Fuktion.)

Der Header ist:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
Beachte, dass der HTTP-Header Content-Type Vorrang vor dieser Metadirektive hat, wenn der Content-Type-Header ein Charset spezifiziert. Ich würde also lieber den Server den Content-Type-Header mit UTF-8 ausgeben lassen als die Metadirektive zu nutzen. (Beides nutzen schadet natürlich nicht.)

Außerdem: ist deine SQL-Verbindung auch auf UTF-8 gestellt?

Du hast also drei Aufgaben :)
  • iconv wie oben beschrieben statt utf8_encode nutzen
  • Content-Type Header überprüfen/setzen lassen
  • Überprüfen, ob SQL-Verbindung auch auf UTF-8 gestellt ist

PS: Bitte Codetags in der Zukunft nutzen, siehe Link in meiner Signatur. Ich habe diese in deinen Beitrag mal reineditiert.
 
Lösung
Guten Morgen
Vielen Dank ComFreek für die ausführliche Hilfe - die ich sehr zu schätzen weiss!
Ich habe nun für die Konvertierung iconv (statt utf8_encode) verwendet und die Zeichen werden "richtig" dargestellt.
Schöne Woche und gute Gesundheit, Nebbiolo
 
Soll man utf8_encode nicht verwenden!
Genau. Wenn du sicher weißt, dass deine Quellkodierung ISO-8859-1 ist, dann kannst du utf8_encode (gemäß seiner API-Dokumentation) verwenden. Aber selbst wenn das der Fall ist, finde ich den Namen so irreführend und nichtssagend, dass ich lieber iconv verwenden würde.

Wie sieht es mit rawurlencode aus?
tl;dr: Die Funktion kannst du mit beliebigen Eingabedaten (als beliebige Bytes) verwenden. Zur Dekodierung bitte rawurldecode benutzen.

Längere Erklärung/Findungsweg:
Das ist eine gute Frage! rawurlencode sieht mir eigentlich nach einer Funktion aus, die eine Quellekodierung als Argument nehmen müsste -- oder eben implizit eins verwendet. Auf der PHP Dokuseite zu rawurlencode sehe ich allerdings keine Rede von irgendeiner Kodierung. Aber es steht geschrieben, dass die Funktion nach RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax (RFC3986) handelt.

Auszüge:
RFC 3986 hat gesagt.:
1.2.1. Transcription
[...]
In local or regional contexts and with improving technology, users
might benefit from being able to use a wider range of characters;
such use is not defined by this specification. Percent-encoded
octets (Section 2.1) may be used within a URI to represent characters
outside the range of the US-ASCII coded character set if this

2.5. Identifying Data
[...]
When a new URI scheme defines a component that represents textual
data consisting of characters from the Universal Character Set [UCS],
the data should first be encoded as octets according to the UTF-8
character encoding [STD63]; then only those octets that do not
correspond to characters in the unreserved set should be percent-
encoded. For example, the character A would be represented as "A",
the character LATIN CAPITAL LETTER A WITH GRAVE would be represented
as "%C3%80", and the character KATAKANA LETTER A would be represented
as "%E3%82%A2".

Ich könnte mir also vorstellen, dass rawurlencode einfach naiv den String byteweise durchgeht und -- soweit der Character von RFC 3986 abgdeckt ist -- prozentkodiert -- oder soweit von RFC 3986 unbehandelt -- als "percent-encoded octets" kodiert.

Dementsprechend müsste rawurlencode mit jeder Quellkodierung zurecht kommen, solange Daten in dieser Quellkodierung byteweise aufsplittbar sind. Dass Daten byteweise gespeichert sind, ist jedoch Standard auf normalen PCs und Server und sogar auf vielen Mikrocontrollern. Da musst du wahrscheinlich schon echt Geräte aus den 60er (?) ausgraben, um andere Speicherformen zu finden.

Theoretisch könntest du rawurlencode also auch rohe Bytes einer Binärdatei zukommen lassen, etwa von einer .exe-Datei.

Wichtig ist nur, dass wenn du die Daten wieder zurückmöchtest, dass du dann rawurldecode aufrufst, damit die Kodierung rückgängig gemacht wird.

Meine Vermutung, dass rawurlencode und rawurldecode beide byteweise arbeiten, deckt sich auch mit einem Kommentar von PHP: rawurldecode - Manual:
jakub 2014-01-24 07:59 hat gesagt.:
Be aware that rawurldecode does not warn you in any way if the output is nonvalid UTF-8.
For example if the input passed to the function is just "%C5", then since C is 1100 in binary, and UTF-8 characters starting with 110 should be followed by another character, the result of rawurldecode will be just a single byte (with value \xC5) which is not a correct UTF-8.

Theoretisch müsste man also nach Aufruf von rawurldecode noch prüfen, ob die Bytes in der erwarteten Kodierung überhaupt valide sind.

Fazit: rawurlencode nimmt rohe Bytes entgegen und gibt ASCII aus. rawurldecode nimmt ASCII entgegen und gibt rohe Bytes aus.
 
Zurück