Wie stellt PHP Strings intern dar?

18

UTF8?
UTF16?

Verfolgen Strings in PHP auch die verwendete Kodierung?

Schauen wir uns zum Beispiel dieses Skript an. Sagen wir ich laufe:

$original = "शक्नोम्यत्तुम्";

Was passiert eigentlich?

Offensichtlich denke ich, $originalwird nicht nur 7 Zeichen enthalten. Diese Glyphen müssen dort jeweils durch mehrere Bytes dargestellt werden.

Dann mach ich:

$converted = mb_convert_encoding ($original , "UTF-8");

Was wird passieren $converted? Wie wird $convertedanders sein als $original?

Wird es genau dieselbe Byte-Sequenz sein, $originalaber mit einer anderen Codierung?

user4951
quelle
1
Welche Version von PHP? PHP <6 kann natives UTF-8 nicht verarbeiten. Es gibt jedoch Pakete und Methoden, die dieses Problem lösen. Google spaß mit utf-8 und php. Wechseln Sie dann zu einer anderen Plattform anstelle von PHP. :)
Andrew T Finnell
4
PHP <6? Das würde jede Version von PHP
einschließen, die
1
Auch PHP kann UTF-8 umgehen, es funktioniert einfach nicht einen dedizierten Datentyp haben, so dass Sie achten haben , was du tust.
tdammers

Antworten:

22

Ein PHP-String ist nur eine Folge von Bytes, der keinerlei Kodierung zugeordnet ist. Zeichenfolgenwerte können aus verschiedenen Quellen stammen: dem Client (über HTTP), einer Datenbank, einer Datei oder aus Zeichenfolgenliteralen in Ihrem Quellcode. PHP liest all diese als Byte-Sequenzen und extrahiert niemals Kodierungsinformationen.

Solange alle Datenquellen und -ziele dieselbe Codierung verwenden, kann das Schlimmste sein, dass die Zeichenfolgenpositionen falsch sind (wenn Sie Mehrbyte-Codierungen verwenden), da PHP Bytes und keine Zeichen zählt.

Wenn die Codierungen jedoch nicht übereinstimmen (z. B. wenn Sie ein Zeichenfolgenliteral in eine als UTF-8 gespeicherte Quelldatei schreiben und es dann an eine Datenbank senden, die Latin-1 erwartet), führt PHP keine Konvertierung für Sie durch Kopieren Sie die Bytes glücklich über RAW.

Die vernünftigste Lösung lautet:

  • Setzen Sie die interne Kodierung von PHP auf UTF-8.
  • Speichern Sie alle Ihre Quelldateien als UTF-8.
  • Verwenden Sie UTF-8 als Ausgabecodierung (vergessen Sie nicht, geeignete Content-typeHeader zu senden ).
  • Stellen Sie die Datenbankverbindung so ein, dass UTF-8 ( SET NAMES UTF8in MySQL) verwendet wird.
  • Konfigurieren Sie alles andere nach Möglichkeit als UTF-8.
  • Stellen Sie für alles, was Sie nicht kontrollieren können (z. B. Webservices von Drittanbietern) sicher, dass Sie die Codierung kennen, und konvertieren Sie so früh wie möglich zu UTF-8 und so spät wie möglich zurück zur anderen Codierung.

Warum UTF-8? Da es alle Unicode-Zeichen darstellen kann und somit alle vorhandenen 7-Bit- und 8-Bit-Codierungen ersetzt, und weil es binär kompatibel mit ASCII ist, ist also jede gültige ASCII-Zeichenfolge auch eine gültige UTF-8-Zeichenfolge (aber nicht vv .).

In Ihrem Beispiel passiert Folgendes.

Zunächst speichern Sie Ihre Quelldatei. Ihr Texteditor ist wahrscheinlich für die Verwendung von UTF-8 konfiguriert, sodass Ihr Zeichenfolgenliteral UTF-8-codiert auf der Festplatte erhält. PHP liest diese Datei und interpretiert den String als eine Reihe von Bytes. $originalEnthält jetzt eine UTF-8-codierte Zeichenfolge mit 7 Zeichen, die nur eine Bytefolge ist (obwohl sie mehr als 7 Bytes enthält, da jedes Zeichen durch zwei oder mehr Bytes dargestellt wird). Wenn Sie dann anrufen echo $original, wird die codierte Zeichenfolge unverändert an den Client gesendet. Wenn Sie dem Client mitgeteilt haben, dass er mit UTF-8 rechnen soll, ist alles in Ordnung. Wenn Sie dies jedoch nicht tun, kann PHP den Unterschied nicht feststellen, und es kommt zu einem Müll im Browser. Versuchen Sie Folgendes als Experiment:

$original = "शक्नोम्यत्तुम्";
echo strlen($original);

strlen Es ist codierunabhängig und setzt eine 8-Bit-Codierung mit fester Breite voraus, dh ein Byte pro Zeichen, sodass es nur Bytes und keine Zeichen zählt.

tdammers
quelle
$ Convert repräsentiert also den gleichen String, jedoch in einer anderen Codierung. Die tatsächliche Rohkodierung, die in PhP gespeichert wird, ist unterschiedlich.
user4951
2
Ich wiederhole es für Sie: PHP speichert Bytes, keine Zeichen, und es weiß überhaupt nichts über Kodierungen (obwohl es einige Bibliotheksfunktionen tun).
tdammers
1
Oh, und es ist "PHP", nicht "PhP".
Tdammers
2
Wenn die rohen Bytes gleich sind, was ist dann der Unterschied zwischen $ original und $ converted? Das ist was ich frage.
user4951
2
Oh, OK, das meinst du. Ja, die unformatierten Bytes ändern sich entsprechend der Codierungskonvertierung. PHP kann sich jedoch nicht an die Codierung erinnern. Wenn Sie also einen String von beispielsweise utf-8 in latin-1 konvertieren und das Ergebnis dann als utf-8 behandeln, werden Sie merkwürdige Ergebnisse sehen.
Tdammers