Ich habe eine Anwendung, die sich mit Kunden aus der ganzen Welt befasst, und natürlich möchte ich, dass alles, was in meine Datenbanken gelangt, UTF-8-codiert wird.
Das Hauptproblem für mich ist, dass ich nicht weiß, wie die Quelle einer Zeichenfolge codiert werden soll - es könnte aus einem Textfeld stammen (die Verwendung <form accept-charset="utf-8">
ist nur nützlich, wenn der Benutzer das Formular tatsächlich gesendet hat) oder es könnte sein aus einer hochgeladenen Textdatei, so dass ich wirklich keine Kontrolle über die Eingabe habe.
Was ich brauche, ist eine Funktion oder Klasse, die sicherstellt, dass das Material, das in meine Datenbank gelangt, so weit wie möglich UTF-8-codiert ist. Ich habe es versucht, iconv(mb_detect_encoding($text), "UTF-8", $text);
aber das hat Probleme (wenn die Eingabe "Verlobte" ist, wird "Verlobte" zurückgegeben). Ich habe viele Dinge ausprobiert = /
Beim Hochladen von Dateien gefällt mir die Idee, den Endbenutzer zu bitten, die von ihm verwendete Codierung anzugeben und ihm eine Vorschau der Ausgabe anzuzeigen, aber dies hilft nicht gegen böse Hacker (tatsächlich könnte dies ihr Leben kosten etwas einfacher).
Ich habe die anderen SO-Fragen zu diesem Thema gelesen, aber sie scheinen alle subtile Unterschiede zu haben, wie "Ich muss RSS-Feeds analysieren" oder "Ich kratzte Daten von Websites" (oder "Sie können nicht").
Aber es muss etwas geben, das zumindest einen guten Versuch hat !
quelle
UTF-8//IGNORE
als 2. Parameter in zu verwendeniconv
?Antworten:
Was Sie verlangen, ist extrem schwer. Wenn möglich, ist es am besten, den Benutzer dazu zu bringen, die Codierung anzugeben. Das Verhindern eines Angriffs sollte auf diese Weise nicht viel einfacher oder schwieriger sein.
Sie können dies jedoch versuchen:
Wenn Sie es auf streng einstellen, erhalten Sie möglicherweise ein besseres Ergebnis.
quelle
mb_detect_encoding
Quellcode in Ihrer PHP-Distribution (irgendwo hier: ext / mbstring / libmbfl / mbfl / mbfl_ident.c). Diese Funktion funktioniert überhaupt nicht richtig. Für einige Codierungen hat es sogar "return true", lol. Andere befinden sich in Strg + C Strg + V-Funktionen. Das liegt daran, dass Sie die Codierung ohne ein Wörterbuch oder einen statistischen Ansatz (wie meinen) nicht erkennen können.mb_detect_encoding
gehe die Liste der bereitgestellten Codierungen durch und akzeptiere die erste, die keine ungültigen Byte-Sequenzen in der Zeichenfolge enthält ... Bei Codierungen, die keine ungültigen Byte-Sequenzen wie ISO-8859-1 enthalten, ist dies immer der Fall . Keine "intelligenten" Heuristiken, und die Ergebnisse variieren stark mit der Liste (und Reihenfolge) der von Ihnen übergebenen Codierungen.mb_detect_order()
, obwohl dies der Standardwert für diesen Parameter ist, da er die strikte Codierungserkennung auf true setzen wollte (der 3. Parameter) :)Im Mutterland Russland haben wir 4 beliebte Kodierungen, daher ist Ihre Frage hier sehr gefragt.
Nur durch Zeichencodes von Symbolen können Sie keine Codierung erkennen, da sich Codeseiten überschneiden. Einige Codepages in verschiedenen Sprachen haben sogar eine vollständige Überschneidung. Also brauchen wir einen anderen Ansatz .
Die einzige Möglichkeit, mit unbekannten Codierungen zu arbeiten, besteht darin, mit Wahrscheinlichkeiten zu arbeiten. Wir möchten also nicht die Frage "Was ist die Kodierung dieses Textes?" Beantworten, sondern versuchen zu verstehen, " Was ist die wahrscheinlichste Kodierung dieses Textes? ".
Ein Typ hier im beliebten russischen Tech-Blog hat diesen Ansatz erfunden:
Erstellen Sie den Wahrscheinlichkeitsbereich von Zeichencodes in jeder Codierung, die Sie unterstützen möchten. Sie können es mit einigen großen Texten in Ihrer Sprache erstellen (z. B. Fiktion, Shakespeare für Englisch und Tolstoi für Russisch, lol). Sie werden so etwas bekommen:
Nächster. Sie nehmen Text in unbekannter Codierung und suchen für jede Codierung in Ihrem "Wahrscheinlichkeitswörterbuch" nach der Häufigkeit jedes Symbols in unbekannt codiertem Text. Summenwahrscheinlichkeiten von Symbolen. Codierung mit höherer Bewertung ist wahrscheinlich der Gewinner. Bessere Ergebnisse für größere Texte.
Wenn Sie interessiert sind kann ich Ihnen bei dieser Aufgabe gerne weiterhelfen. Wir können die Genauigkeit erheblich erhöhen, indem wir eine Wahrscheinlichkeitsliste mit zwei Zeichen erstellen.
Übrigens. mb_detect_encoding funktioniert sicher nicht. Ja überhaupt. Bitte werfen Sie einen Blick auf den Quellcode von mb_detect_encoding in "ext / mbstring / libmbfl / mbfl / mbfl_ident.c".
quelle
Sie haben es wahrscheinlich versucht, aber warum nicht einfach die Funktion mb_convert_encoding verwenden? Es wird versucht, den Zeichensatz des bereitgestellten Textes automatisch zu erkennen, oder Sie können ihm eine Liste übergeben.
Außerdem habe ich versucht zu rennen:
und die Ergebnisse sind für beide gleich. Wie sehen Sie, dass Ihr Text auf "Verlobter" abgeschnitten ist? ist es in der DB oder in einem Browser?
quelle
iconv
. Ich habe versucht, einen fast reinen mb_ * Weg zu machen. Was denkst du?Es gibt keine Möglichkeit, den Zeichensatz einer Zeichenfolge zu identifizieren, der vollständig korrekt ist. Es gibt Möglichkeiten, den Zeichensatz zu erraten. Eine dieser Möglichkeiten und wahrscheinlich / derzeit die beste in PHP ist mb_detect_encoding (). Dadurch wird Ihre Zeichenfolge gescannt und nach Vorkommen von Dingen gesucht, die für bestimmte Zeichensätze einzigartig sind. Abhängig von Ihrer Zeichenfolge gibt es möglicherweise keine solchen unterscheidbaren Vorkommen.
Nehmen Sie den Zeichensatz ISO-8859-1 gegen ISO-8859-15 ( http://en.wikipedia.org/wiki/ISO/IEC_8859-15#Changes_from_ISO-8859-1 ).
Es gibt nur eine Handvoll verschiedener Zeichen, und um es noch schlimmer zu machen, werden sie durch dieselben Bytes dargestellt. Es gibt keine Möglichkeit zu erkennen, ob ein Byte 0xA4 ¤ oder € in Ihrer Zeichenfolge bedeuten soll, wenn eine Zeichenfolge angegeben wird, ohne zu wissen, dass sie codiert ist. Daher gibt es keine Möglichkeit, den genauen Zeichensatz zu ermitteln.
(Hinweis: Sie können einen menschlichen Faktor oder eine noch weiter fortgeschrittene Scan-Technik hinzufügen (z. B. was Oroboros102 vorschlägt), um anhand des umgebenden Kontexts herauszufinden, ob das Zeichen ¤ oder € sein sollte, obwohl dies wie eine Brücke erscheint zu weit)
Es gibt deutlichere Unterschiede zwischen z. B. UTF-8 und ISO-8859-1. Es lohnt sich also immer noch, dies herauszufinden, wenn Sie sich nicht sicher sind, obwohl Sie sich niemals darauf verlassen können und sollten, dass es korrekt ist.
Interessante Lektüre: http://kore-nordmann.de/blog/php_charset_encoding_FAQ.html#how-do-i-determine-the-charset-encoding-of-a-string
Es gibt jedoch auch andere Möglichkeiten, um den richtigen Zeichensatz sicherzustellen. Versuchen Sie in Bezug auf Formulare, UTF-8 so weit wie möglich durchzusetzen (überprüfen Sie den Schneemann, um sicherzustellen, dass Ihre Übermittlung in jedem Browser UTF-8 ist: http://intertwingly.net/blog/2010/07/29/Rails-and -Schneemänner ) Wenn Sie dies getan haben, können Sie zumindest sicher sein, dass jeder Text, der über Ihre Formulare gesendet wird, utf_8 ist. Versuchen Sie bei hochgeladenen Dateien, den Unix-Befehl 'file -i' über zB exec () (falls möglich auf Ihrem Server) auszuführen, um die Erkennung zu erleichtern (mithilfe der Stückliste des Dokuments). In Bezug auf Scraping-Daten können Sie die HTTP-Header lesen. das gibt normalerweise den Zeichensatz an. Überprüfen Sie beim Parsen von XML-Dateien, ob die XML-Metadaten eine Zeichensatzdefinition enthalten.
Anstatt zu versuchen, den Zeichensatz automatisch zu erraten, sollten Sie zunächst versuchen, einen bestimmten Zeichensatz selbst zu ermitteln, wo dies möglich ist, oder eine Definition aus der Quelle abrufen, von der Sie ihn erhalten (falls zutreffend), bevor Sie auf die Erkennung zurückgreifen.
quelle
Hier gibt es einige wirklich gute Antworten und Versuche, Ihre Frage zu beantworten. Ich bin kein Codierungsmaster, aber ich verstehe Ihren Wunsch nach einem reinen UTF-8-Stack bis hin zu Ihrer Datenbank. Ich habe die MySQL-
utf8mb4
Codierung für Tabellen, Felder und Verbindungen verwendet.Meine Situation beschränkte sich auf "Ich möchte nur, dass meine Desinfektionsmittel, Validatoren, Geschäftslogik und vorbereiteten Anweisungen mit UTF-8 umgehen, wenn Daten aus HTML-Formularen oder E-Mail-Registrierungslinks stammen." Auf meine einfache Art begann ich mit dieser Idee:
$encodings = ['UTF-8', 'ISO-8859-1', 'ASCII'];
throw new RuntimeException
UTF-8
, fahren Sie fort.Sonst, wenn es ist
ISO-8859-1
oderASCII
ein. Konvertierungsversuch auf UTF-8 versuchen (warten, nicht abgeschlossen)
b. Ermitteln Sie die Codierung des konvertierten Werts
c. Wenn die gemeldete Codierung und der konvertierte Wert beide
UTF-8
sind, fahren Sie fort.d. Sonst,
throw new RuntimeException
Aus meiner abstrakten Klasse
Sanitizer
Man könnte argumentieren, dass ich Codierungsprobleme von meiner abstrakten
Sanitizer
Klasse trennen und einfach einEncoder
Objekt in eine konkrete untergeordnete Instanz von einfügen sollteSanitizer
. Das Hauptproblem bei meinem Ansatz ist jedoch, dass ich ohne weitere Kenntnisse einfach Codierungstypen ablehne, die ich nicht möchte (und ich verlasse mich auf PHP mb_ * -Funktionen). Ohne weitere Studien kann ich nicht wissen, ob dies einigen Bevölkerungsgruppen schadet oder nicht (oder ob ich wichtige Informationen verliere). Also muss ich mehr lernen. Ich habe diesen Artikel gefunden.Was jeder Programmierer unbedingt über Codierungen und Zeichensätze wissen muss, um mit Text arbeiten zu können
Was passiert außerdem, wenn meinen E-Mail-Registrierungslinks verschlüsselte Daten hinzugefügt werden (mit
OpenSSL
odermcrypt
)? Könnte dies die Dekodierung stören? Was ist mit Windows-1252? Was ist mit den Auswirkungen auf die Sicherheit? Die Verwendung vonutf8_decode()
undutf8_encode()
inSanitizer::isUTF8
ist zweifelhaft.Die Leute haben auf Mängel in den PHP-Funktionen mb_ * hingewiesen. Ich habe mir nie Zeit genommen, um Nachforschungen
iconv
anzustellen, aber wenn es besser funktioniert als die Funktionen von mb_ *, lassen Sie es mich wissen.quelle
Ich denke nicht, dass es ein Problem ist. Eine Anwendung kennt die Quelle der Eingabe. Wenn es aus einem Formular stammt, verwenden Sie in Ihrem Fall die UTF-8-Codierung. Das funktioniert. Überprüfen Sie einfach, ob die angegebenen Daten korrekt codiert sind (Validierung). Beachten Sie, dass nicht alle Datenbanken UTF-8 in vollem Umfang unterstützen.
Wenn es sich um eine Datei handelt, wird UTF-8 nicht in der Datenbank, sondern in binärer Form gespeichert. Wenn Sie die Datei erneut ausgeben, verwenden Sie auch die Binärausgabe. Dies ist dann völlig transparent.
Ihre Idee ist schön, dass ein Benutzer die Codierung erkennen kann, sei es aber trotzdem nach dem Herunterladen der Datei, da sie binär ist.
Ich muss also zugeben, dass ich kein bestimmtes Problem sehe, das Sie mit Ihrer Frage ansprechen. Aber vielleicht können Sie weitere Details zu Ihrem Problem hinzufügen.
quelle
Sie können eine Reihe von Metriken einrichten, um zu erraten, welche Codierung verwendet wird. Wieder nicht perfekt, könnte aber einige der Fehler von mb_detect_encoding () abfangen.
quelle
mb_detect_encoding()
ich spreche von Fehlschlägen. Glaubst du, meine Antwort hat im Sommer in der Sahara die Chance eines Schneeballs?Wenn Sie bereit sind, "dies zur Konsole zu bringen", würde ich empfehlen
enca
. Im Gegensatz zu den eher simplenmb_detect_encoding
verwendet es "eine Mischung aus Analyse, statistischer Analyse, Vermutung und schwarzer Magie, um ihre Kodierungen zu bestimmen" (lol - siehe Manpage ). Normalerweise müssen Sie jedoch die Sprache der Eingabedatei übergeben, wenn Sie solche länderspezifischen Codierungen erkennen möchten. (Hat jedoch immb_detect_encoding
Wesentlichen die gleiche Anforderung, da die Codierung "an der richtigen Stelle" in der Liste der übergebenen Codierungen erscheinen müsste, damit sie überhaupt erkennbar ist.)enca
kam auch hier hoch: So finden Sie die Codierung einer Datei in Unix über Skriptequelle
Es scheint, dass Ihre Frage ziemlich beantwortet ist, aber ich habe einen Ansatz, der Ihren Fall vereinfachen kann:
Ich hatte ein ähnliches Problem beim Versuch, Zeichenfolgendaten von MySQL zurückzugeben, und konfigurierte sogar Datenbank und PHP so, dass Zeichenfolgen zurückgegeben wurden, die mit utf-8 formatiert waren. Der einzige Weg, wie ich den Fehler bekam, war, sie tatsächlich aus der Datenbank zurückzugeben.
Als ich schließlich durch das Web segelte, fand ich einen wirklich einfachen Weg, damit umzugehen:
Wenn Sie alle diese Arten von Zeichenfolgendaten in Ihrer MySQL in verschiedenen Formaten und Kollatierungen speichern können, müssen Sie die Kollatierung direkt in Ihrer PHP-Verbindungsdatei wie folgt auf utf-8 setzen:
Dies bedeutet, dass Sie zuerst die Daten in einem beliebigen Format oder einer beliebigen Sortierung speichern und sie erst bei der Rückkehr in Ihre PHP-Datei konvertieren.
Hoffe es war hilfreich!
quelle
Wenn der Text aus einer MySQL-Datenbank abgerufen wird, können Sie versuchen, ihn nach der BD-Verbindung hinzuzufügen.
mysqli_set_charset ($ con, "utf8");
https://www.php.net/manual/en/mysqli.set-charset.php
quelle
Standardoptionen von cURL:
Ich habe so etwas versucht. Es hat mir geholfen. Wenn in Meta-Zeichensatz-Informationen gefunden, konvertiere ich, sonst tue ich nichts.
quelle