tox: und (Software) Zeichenkodierung mit Zend Studio und Apache

Guten Morgen,

im Moment beschäftige ich mich mit der richtigen Zeichenkodierung für meine Webseiten. Dabei habe ich mich für UTF-8 entschieden und dafür folgende notwendigen Schritte zusammengesammelt:

1. Die Quelldateien der Webseiten müssen bereits in einem Editor geschrieben sein der in UTF-8 kodiert.

2. In diesen Dateien muss als Content-Typ UTF-8 angegeben werden.

3. In diesen Dateien muss bei Benutzereingaben sichergestellt werden, dass sie als UTF-8 übernommen werden.

4. Die benutzte Server-Skriptsprache (in meinem Fall PHP) muss als CharSet UTF-8 benutzen.

5. Die benutzte Datenbank (in meinem Fall MySQL) muss als Zeichensatz Unicode (UTF-8) und als Kollationen UTF-8 verwenden.

6. Der Webserver (in meinem Fall Apache) muss als HTTP-Header UTF-8 senden.

Stimmt das so? Fehlt noch was?

Zu 1.: Ich editiere mit Zend Studio 5 Enterprise Edition (Build 183). Weder in der Software, noch auf der Zend Homepage oder in Google habe ich ein Wort über die Zeichenkodierung gefunden.

Wie kann ich sicherstellen, dass ich in UTF-8 programmiere?

Zu 6.: Wenn ich z.B. mit dem Web-Sniffer meine HTTP Header ausgeben lasse, dann habe ich als Transfer-Encoding die Angabe "chunked". Das damit eine Auslieferung in Teilen gemeint ist, ist klar.

Wie kann ich aber an die Infomation kommen mit welcher Zeichenkodierung im HTTP Header mein gemieteter Webspace die Seiten ausliefert?

Danke und Gruss

  1. echo $begrüßung;

    1. Die Quelldateien der Webseiten müssen bereits in einem Editor geschrieben sein der in UTF-8 kodiert.

    Besser ist das. Nötig ist es aber nur, wenn im Quelltext Zeichen vorkommen, die jenseits von ASCII liegen.

    1. In diesen Dateien muss als Content-Typ UTF-8 angegeben werden.

    Wichtiger als die charset-Angabe im Meta-Element Content-Type ist die Angabe des gleichnamigen HTTP-Headers, den der hat Vorrang wenn beide vorhanden sind. Oder anders gesagt: Das Meta-Element ist nur ein Ersatz für eine fehlende HTTP-Header-Angabe.

    1. In diesen Dateien muss bei Benutzereingaben sichergestellt werden, dass sie als UTF-8 übernommen werden.
    2. Die benutzte Server-Skriptsprache (in meinem Fall PHP) muss als CharSet UTF-8 benutzen.

    PHP bietet momentan nur rudimentäre/kaum Unterstützung beim Thema Zeichensatz/-kodierung. Erst PHP 6 wird vollständig mit Multibyte-Zeichenkodierungen umgehen können. Solange liefert strlen() beispielsweise bei einem UTF-8-kodierten Täst eine Länge von 5.
    Es gibt zwar die Multibyte String Functions-Extension, doch die ist nicht bei jedem Hoster freigegeben (und wohl auch nicht besonders schnell). Zur bisherigen UTF-8-Unterstützung gibt es eine Übersicht: http://wiki.silverorange.com/UTF-8_Notes

    1. Die benutzte Datenbank (in meinem Fall MySQL) muss als Zeichensatz Unicode (UTF-8) und als Kollationen UTF-8 verwenden.

    Es gibt viele verschiedene Stellen, an denen in MySQL eine Angabe zum Zeichensatz/-kodierung wirkt. Das MySQL-Handbuch spendiert diesem Thema ein eigenes Haupt-Kapitel. Wichtig für die Kommunikation mit Clients (z.B. PHP) sind die "Connection Character Set"-Einstellungen. (Zusammenfassung: SET NAMES utf8)

    1. Der Webserver (in meinem Fall Apache) muss als HTTP-Header UTF-8 senden.
      Zu 6.: Wenn ich z.B. mit dem Web-Sniffer meine HTTP Header ausgeben lasse, dann habe ich als Transfer-Encoding die Angabe "chunked". Das damit eine Auslieferung in Teilen gemeint ist, ist klar.

    Diese Transfer-Encoding-Angabe ist in dem Zusammenhang unwichtig. Am Content-Type-Header hängt eine charset-Angabe dran, oder auch nicht. Ändern kannst du das durch eine Konfiguration des Apachen. Schau dir die Direktiven an, die was mit "Charset" im Namen haben. Oder du kannst mit PHP selbst einen passenden Content-Type-Header inklusive charset-Angabe senden. (header())

    Wie kann ich aber an die Infomation kommen mit welcher Zeichenkodierung im HTTP Header mein gemieteter Webspace die Seiten ausliefert?

    Neben dem Websniffer gibt es Erweiterungen für die Browser, z.B. die livehttpheaders-Extension für den Firefox.

    Zu 1.: Ich editiere mit Zend Studio 5 Enterprise Edition (Build 183). Weder in der Software, noch auf der Zend Homepage oder in Google habe ich ein Wort über die Zeichenkodierung gefunden.

    Im Zend Studio 5.2.0 Professional Edition Build 233 lässt sich das Encoding einstellen.

    Wie kann ich sicherstellen, dass ich in UTF-8 programmiere?

    Wenn die 183er Ausgabe das nicht kann ... Pech gehabt. Updaten, anderen Editor verwenden, hinterher iconv oder recode auf die Dateien anwenden, ...

    echo "$verabschiedung $name";

    1. Hallo dedlfix,

      danke für Deine Zeit.

      »» Besser ist das. Nötig ist es aber nur, wenn im Quelltext Zeichen vorkommen, die jenseits von ASCII liegen.

      Verstehe, dann bevorzuge ich aber den Editor der das kann.

      »» Im Zend Studio 5.2.0 Professional Edition Build 233 lässt sich das Encoding einstellen.

      Aha, ist die Software also schon wieder veraltet.

      »» Wenn die 183er Ausgabe das nicht kann ... Pech gehabt. Updaten, anderen Editor verwenden, hinterher iconv oder recode auf die Dateien anwenden, ...

      Update ist schon unterwegs.

      »» Wichtiger als die charset-Angabe im Meta-Element Content-Type ist die Angabe des gleichnamigen HTTP-Headers, den der hat Vorrang wenn beide vorhanden sind. Oder anders gesagt: Das Meta-Element ist nur ein Ersatz für eine fehlende HTTP-Header-Angabe.

      Also klar, muss rein, wichtiger ist aber der HTTP-Header.

      »» PHP bietet momentan nur rudimentäre/kaum Unterstützung beim Thema Zeichensatz/-kodierung. Erst PHP 6 wird vollständig mit Multibyte-Zeichenkodierungen umgehen können. Solange liefert strlen() beispielsweise bei einem UTF-8-kodierten Täst eine Länge von 5.
      »» Es gibt zwar die Multibyte String Functions-Extension, doch die ist nicht bei jedem Hoster freigegeben (und wohl auch nicht besonders schnell). Zur bisherigen UTF-8-Unterstützung gibt es eine Übersicht: http://wiki.silverorange.com/UTF-8_Notes

      Hab mir beides angeschaut, ehrlich gesagt kann ich das so gar nicht brauchen, seufz. Was passiert denn wenn ich in meiner UTF-8 Kette bei PHP ISO-8859-1 nutze? Was genau geht da schief? Ich muss dazu sagen, dass ich bisher eine Mischung aus beiden habe und bisher habe ich noch keinen Nachteil bemerkt. Weder lokal noch online.

      Ich muss aber sicherstellen, dass Clients die kein ISO-8859-1 erwarten sondern u.a. UTF-8 keinen Buchstabensalat am Bildschirm haben.

      »» Es gibt viele verschiedene Stellen, an denen in MySQL eine Angabe zum Zeichensatz/-kodierung wirkt. Das MySQL-Handbuch spendiert diesem Thema ein eigenes Haupt-Kapitel. Wichtig für die Kommunikation mit Clients (z.B. PHP) sind die "Connection Character Set"-Einstellungen. (Zusammenfassung: SET NAMES utf8)

      Alles klar, ist im Griff.

      »» Diese Transfer-Encoding-Angabe ist in dem Zusammenhang unwichtig. Am Content-Type-Header hängt eine charset-Angabe dran, oder auch nicht. Ändern kannst du das durch eine Konfiguration des Apachen. Schau dir die Direktiven an, die was mit "Charset" im Namen haben. Oder du kannst mit PHP selbst einen passenden Content-Type-Header inklusive charset-Angabe senden. (header())

      Bei meinem Provider war das bisher unproblematisch. Das sind supernette Leute, die haben bis jetzt alle Änderungen an der Konfiguration vorgenommen um die sie gebeten habe.

      Mit PHP header() ist es eher umständlich. Gefällt mir nicht so gut, behalte ich aber im Hinterkopf, ist zumindest eine Möglichkeit.

      »» Neben dem Websniffer gibt es Erweiterungen für die Browser, z.B. die livehttpheaders-Extension für den Firefox.

      Das ist ja sensationell! Diese 87 kB bereiten mir mehr Freude als so manche Megabyte grossen Anwendungen. Allerdings habe ich jetzt gleich zuviel Informationen, allen Ernstes:

      GET / HTTP/1.1
      Host: domain.com
      User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1) Gecko/20061010 Firefox/2.0
      Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
      Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
      Accept-Encoding: gzip,deflate
      Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
      Keep-Alive: 300
      Connection: keep-alive

      HTTP/1.x 200 OK
      Date: Fri, 22 Dec 2006 10:04:18 GMT
      Server: Apache/1.3.36 (Unix) mod_auth_passthrough/1.8 mod_log_bytes/1.2 mod_bwlimited/1.4 PHP/4.4.2 FrontPage/5.0.2.2635.SR1.2 mod_ssl/2.8.27 OpenSSL/0.9.7a mod_mono/1.0.2
      X-Powered-By: PHP/4.4.2
      Connection: close
      Transfer-Encoding: chunked
      Content-Type: text/html

      Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 -> Heisst das, dass das Dokument mit zwei Kodierungen gesendet wird, oder wie?

      Danke und Gruss

      1. echo $begrüßung;

        Was passiert denn wenn ich in meiner UTF-8 Kette bei PHP ISO-8859-1 nutze? Was genau geht da schief? Ich muss dazu sagen, dass ich bisher eine Mischung aus beiden habe und bisher habe ich noch keinen Nachteil bemerkt. Weder lokal noch online.

        Die Stringverarbeitung geht bisher davon aus, dass ein Zeichen aus einem Byte besteht. Ein in UTF-8 kodiertes ä besteht aber aus zwei Bytes. strlen() liefert 2 statt 1. Wenn du von "Täst" den Teilstring drei Zeichen von hinten haben möchtest (äst), dann schneidet substr('Täst', -3) das ä in zwei Teile. Usw. usf. Das einfache Durchreichen von der Datenbank zum HTML-Code bereitet aber keine Probleme.

        Ich muss aber sicherstellen, dass Clients die kein ISO-8859-1 erwarten sondern u.a. UTF-8 keinen Buchstabensalat am Bildschirm haben.

        Wichtig ist, dass das von dir Ausgelieferte mit der von dir angegebenen Kodierungsangabe übereinstimmt. Der Browser muss natürlich diese Kodierung verstehen, doch das ist heutzutage bei UTF-8 mit den gängigen aktuellen Browser-Versionen kein Problem. Ein Problem, das du nicht beinflussen kannst, sind nicht vorhandene Glyphen in den Fonts des Clients zum Darstellen der Zeichen.

        »» Neben dem Websniffer gibt es Erweiterungen für die Browser, z.B. die livehttpheaders-Extension für den Firefox.

        Das ist ja sensationell! Diese 87 kB bereiten mir mehr Freude als so manche Megabyte grossen Anwendungen. Allerdings habe ich jetzt gleich zuviel Informationen, allen Ernstes:

        GET / HTTP/1.1
        Host: domain.com
        User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1) Gecko/20061010 Firefox/2.0
        Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
        Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
        Accept-Encoding: gzip,deflate
        Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
        Keep-Alive: 300
        Connection: keep-alive

        HTTP/1.x 200 OK
        Date: Fri, 22 Dec 2006 10:04:18 GMT
        Server: Apache/1.3.36 (Unix) mod_auth_passthrough/1.8 mod_log_bytes/1.2 mod_bwlimited/1.4 PHP/4.4.2 FrontPage/5.0.2.2635.SR1.2 mod_ssl/2.8.27 OpenSSL/0.9.7a mod_mono/1.0.2
        X-Powered-By: PHP/4.4.2
        Connection: close
        Transfer-Encoding: chunked
        Content-Type: text/html

        Der obere Teil ist der Request, also das was der Browser zum Server sendet, um eine Ressource anzufordern. Der untere Teil sind die Kopfzeilen der Antwort, Response genannt.

        Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 -> Heisst das, dass das Dokument mit zwei Kodierungen gesendet wird, oder wie?

        Das ist ein Wunsch des Clients, der besagt, mit welcher Wertigkeit welche Kodierung (der Antwort) bevorzugt wird. Praktisch kann man den im Fall von ISO 8859-1 und UTF-8 einfach ignorieren, da die Browser beides beherrschen. Meist hat sich auch der Anwender keinen Kopf bei der Einstellung seiner Browserkonfiguration gemacht, womit dieser Wunsch ebenfalls wertlos wird.

        P.S. Bitte die Zitat-Zeichen nicht verändern, sonst wird es unübersichtlich.

        echo "$verabschiedung $name";

        1. Hallo dedlfix.

          P.S. Bitte die Zitat-Zeichen nicht verändern, sonst wird es unübersichtlich.

          Wobei ich mich gerade frage, warum die an sich korrekten Zitatzeichen („»» “) in seinem Posting nicht als Zitat ausgezeichnet wurden …

          Einen schönen Freitag noch.

          Gruß, Mathias

          --
          ie:% fl:| br:< va:) ls:& fo:) rl:( n4:~ ss:) de:] js:| mo:| zu:)
          debian/rules
          1. echo $begrüßung;

            P.S. Bitte die Zitat-Zeichen nicht verändern, sonst wird es unübersichtlich.

            Wobei ich mich gerade frage, warum die an sich korrekten Zitatzeichen („»» “) in seinem Posting nicht als Zitat ausgezeichnet wurden …

            Welche Zitatzeichen korrekt sind und welche nicht, bestimmt der angemeldete Benutzer in seiner Konfiguration. Die Forensoftware wandelt da im Bedarfsfall selbständig hin und her.

            Wenn ich poste ist nur "» " richtig. Nehme ich "»» " geht das schief.

            Zitat

            »» kein Zitat

            echo "$verabschiedung $name";

            1. Hallo dedlfix.

              P.S. Bitte die Zitat-Zeichen nicht verändern, sonst wird es unübersichtlich.

              Wobei ich mich gerade frage, warum die an sich korrekten Zitatzeichen („»» “) in seinem Posting nicht als Zitat ausgezeichnet wurden …

              Welche Zitatzeichen korrekt sind und welche nicht, bestimmt der angemeldete Benutzer in seiner Konfiguration.

              War mir bewusst.

              Die Forensoftware wandelt da im Bedarfsfall selbständig hin und her.

              Das auch.

              Wenn ich poste ist nur "» " richtig. Nehme ich "»» " geht das schief.

              Nur das nicht. Danke.

              Einen schönen Freitag noch.

              Gruß, Mathias

              --
              ie:% fl:| br:< va:) ls:& fo:) rl:( n4:~ ss:) de:] js:| mo:| zu:)
              debian/rules
        2. Hallo dedlfix,

          jetzt habe ich auch die Build 233 laufen. Da habe ich sofort den Encoding Select-Button gefunden und auf UTF-8 stellen können. Und siehe da, bei meiner alten Version ist er an der gleichen Stelle. Eigenartig nicht? Dass man manchmal den Wald vor lauter Bäumen nicht sieht.

          Wie kann ich denn nun ausgeben lassen wie mein Provider die Seiten kodiert? Klar, kann ich denen schreiben "Hallo, wie kodiert mein Webspace-Server? Ich hätte gern UTF-8", aber soviel Ehrgeiz hab ich dann schon, sagen zu können "Hallo Ihr kodiert in ISO-8859, ich hätte aber gern UTF-8". Ich habe im Moment keine Möglichkeit das zu prüfen. Nicht mal zu Testzwecken.

          Dann hat auf meiner Seite der Benutzer die Möglichkeit Text einzugeben. Dieser Text wird dann mit PHP (ISO-8859-1) geprüft, ergänzt, in MySQL (UTF-8) gespeichert und später wieder ausgelesen und ausgegeben. Tu ich dann überhaupt noch vollständig UTF-8 ausliefern?

          Danke und Gruss

          1. echo $begrüßung;

            Wie kann ich denn nun ausgeben lassen wie mein Provider die Seiten kodiert?

            Das hast du schon gemacht, als du mit der livehttpheaders-Extension die Headers ausgegeben hast. Vorausgesetzt, das war eine Ausgabe von einer vom Provider ausgelieferten Seite. Die meisten Provider werden zwar einen passenden Content-Type für HTML-Dokumente mitsenden, aber keinerlei Default-Kodierungsangabe. Denn dann hat die vom Kunden gemachte charset-Angabe im Meta-Element des HTML-Textes die Möglichkeit, zur Geltung zu kommen.

            Wenn du eine Per-Verzeichnis-Konfigurationsdatei - meist .htaccess genannt - nutzen kannst, kannst du dort selbst bestimmen, welche Default-Kodierungsangabe im Content-Type-Header mitgesendet werden soll. Außerdem kannst auch den passenden Content-Type-Header inklusive charset-Angabe mittels PHP selbst setzen - Stichwort: header(). Beide Themen hatte ich bereits verlinkt.

            Dann hat auf meiner Seite der Benutzer die Möglichkeit Text einzugeben. Dieser Text wird dann mit PHP (ISO-8859-1) geprüft, ergänzt, in MySQL (UTF-8) gespeichert und später wieder ausgelesen und ausgegeben. Tu ich dann überhaupt noch vollständig UTF-8 ausliefern?

            Wenn du die Seite UTF-8-kodiert lieferst, und auch dem Browser nicht bittest, für das auszufüllende Formular eine andere Kodierung zu verwenden (Attribut accept-charset), dann wird er dir ebenfalls UTF-8-kodiert antworten. Wenn du das zum Zwecke der Prüfung mittels PHP-Stringfunktionen in ISO 8859-1 umwandelst, kannst du auch gleich auf UTF-8 verzeichten, denn bei dieser Umwandlung gehen alle Zeichen verloren, die sich nicht mit ISO 8859-1 kodieren lassen. Du musst schon vollständig bei UTF-8 bleiben (oder eine andere der Unicode-Kodierungen verwenden, die allerdings noch weniger von PHP unterstützt werden). Die Regular Expression Functions (Perl-Compatible) kennen einen Modifier u. Das scheint mir dann die einzige sinnvolle, provider-relevante Prüfungsmöglichkeit zu sein, doch da kann ich dir nicht mit Erfahrung dienen.

            echo "$verabschiedung $name";

            1. Hallo dedlfix,

              korrigiere mich bitte, wenn ich Mist schreibe. Der Provider kann den Server so konfigurieren, dass er in den HTTP-Headern gar keine Angabe zur Zeichenkodierung sendet. Eine solche mögliche Ausgabe der Header könnte dann so wie die meine aussehen:

              GET / HTTP/1.1
              Host: domain.com
              User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1) Gecko/20061010 Firefox/2.0
              Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
              Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
              Accept-Encoding: gzip,deflate
              Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
              Keep-Alive: 300
              Connection: keep-alive

              HTTP/1.x 200 OK
              Date: Tue, 26 Dec 2006 05:19:31 GMT
              Server: Apache/1.3.36 (Unix) mod_auth_passthrough/1.8 mod_log_bytes/1.2 mod_bwlimited/1.4 PHP/4.4.2 FrontPage/5.0.2.2635.SR1.2 mod_ssl/2.8.27 OpenSSL/0.9.7a mod_mono/1.0.2
              X-Powered-By: PHP/4.4.2
              Connection: close
              Transfer-Encoding: chunked
              Content-Type: text/html

              Jetzt könnte ich entweder meinen Provider bitten HTTP-Header mit UTF-8 zu senden oder ich bau in die .htaccess-Datei ensprechende Kodierungsanweisung. Angenommen es passiert beides, welche Angabe hat höhere Priorität? HTTP-Header oder .htaccess-Datei?

              Wenn du die Seite UTF-8-kodiert lieferst, und auch dem Browser nicht bittest, für das auszufüllende Formular eine andere Kodierung zu verwenden (Attribut accept-charset), dann wird er dir ebenfalls UTF-8-kodiert antworten.

              Aha, sehr gut.

              Du musst schon vollständig bei UTF-8 bleiben. Die Regular Expression Functions (Perl-Compatible) kennen einen Modifier u. Das scheint mir dann die einzige sinnvolle, provider-relevante Prüfungsmöglichkeit zu sein, doch da kann ich dir nicht mit Erfahrung dienen.

              Das werde ich mir jetzt mal ansehen. Irgendwie muss das doch zu packen sein.

              Danke nochmals für Deine Zeit. Wünsche noch einen schönen Weihnachtsausklang

              Und Gruss

              1. echo $begrüßung;

                Content-Type: text/html

                Jetzt könnte ich entweder meinen Provider bitten HTTP-Header mit UTF-8 zu senden oder ich bau in die .htaccess-Datei ensprechende Kodierungsanweisung. Angenommen es passiert beides, welche Angabe hat höhere Priorität? HTTP-Header oder .htaccess-Datei?

                Die .htaccess veranlasst nur den Apachen, zusätzlich zu den Konfigurationen des Providers weitere Konfigurationen speziell für dieses Verzeichnis und seinen Inhalt (inklusive Unterverzeichnisse) vorzunehmen. Eine der Anweisungen fügt dem zitierten Content-Type-Header eine charset-Angabe hinzu. Ob du das in der .htaccess konfigurierst oder dein Provider das irgendwo zentraler einstellt, ist dabei egal. Und den gleichen Effekt erzielst du auch mit der PHP-gesendeten header()-Zeile. Alle drei Möglichkeiten ergeben eine HTTP-Header-Zeile à la: Content-Type: text/html;charset=utf-8

                echo "$verabschiedung $name";