Ankündigung

Einklappen
Keine Ankündigung bisher.

PHP, MySQL und der Charset

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • PHP, MySQL und der Charset

    Ich ärger mich jetzt schon seit gestern mit einem Problem rum und komme nicht weiter, ich hoffe hier kann mir jemand helfen.

    In meiner Testumgebung läuft das so:
    MySQL 4.1.. d.h. der Server kann mit UTF-8 umgehen.
    Ich lese über PHP aus einer MySQL Datenbank Inhalte für Webseiten aus (den Title und die Überschrift der Webseite). Die Seiten sind UTF-8 codiert.

    Bisher dachte ich das von meiner Testatenbank auch, gerade ist mir aber aufgefallen, dass die Datenbank zwar als default charset utf8 hat, die Tabellen aber latin1 (da ich sie wohl vom richtigen Server importiert habe, auf dem noch MySQL 4.0.. läuft). Mit meinen Webseitenscript werden nun alle Umlaute und andere deutschen Zeichen (äüöß) als Fragezeichen-Symbol dargestellt.
    Wenn ich mir aber die Tabellen mit PHPMyAdmin anschaue und dort UTF-8 einstelle, sieht alles gut aus. Auf meinem richtigen Webserver sieht auch mein Skript gut aus (allerdings auch nur wenn ich als Seitenkodierung UTF-8 angebe), wie kann das sein, der Inhalt ist doch in Latin1 gespeichert und die Seiten in UTF-8 kodiert?

    Kann mir das jemand erklären bzw. sagen wie ich PHP konfigurieren muss, damit es auch auf meinem Testserver alles richtig angezeigt wird?

    Danke für Eure Hilfe.

    PS: Ich vermute, dass es ein PHP Problem ist, falls das nicht so sein sollte, bitte ins MySQL-Forum verschieben...


  • #2
    Hallo.

    Fragezeichen siehst du, wenn du dir z.B. Latin-1-Zeichen (außerhalb des ASCII-Satzes) durch die UTF-8-Brille anschaust. Ich würde mir in dem Fall ein Skript schreiben, dass alle Daten in der Datenbank via utf8_encode() bzw. iconv() in UTF-8 konvertiert (gibts bestimmt auch einige im Netz).

    Dass die Ausgabe via phpMyAdmin und Live-Server doch geklappt hat, kann ich nicht nachvollziehen. Ich vermute, dass die explizite Angabe der Kodierung (UTF- nicht gegriffen hat und die Zeichen als Latin-1 erkannt und dementsprechend angezeigt wurden. Vielleicht ist das auch irgendein Default-Wert und es wurde garnichts erkannt.

    Basti

    Kommentar


    • #3
      Zitat von Basti
      Ich würde mir in dem Fall ein Skript schreiben, dass alle Daten in der Datenbank via utf8_encode() bzw. iconv() in UTF-8 konvertiert (gibts bestimmt auch einige im Netz).
      Basti
      Vielen Dank jetzt sieht es auch auf meinem Testserver gut aus. Alle Daten, die auch aus der Datenbank auslese bearbeite ich erstmal mit utf8_encode, dann siehts gut aus.

      Irgendwie blick ich das nicht so ganz, was macht den utf8_encode jetzt genau? Der Bitwert des Zeichen müsste doch gleich sein, da ich den String als UTF8 in die Datenbank eingetragen hab oder nicht? Da muss doch dann eigentlich gar nicht encodet werden oder nicht?

      Kommentar


      • #4
        Hi.

        Offensichtlich liegen die Inhalte in der DB nicht als UTF-8 vor. Ich weiß auch nicht genau, wie es läuft, aber ich vermute Folgendes:

        Wenn du Daten in die Datenabank schreibst, dann werden da einfach die Byte für Byte reingeschrieben. In dem Fall würde es, falls die Daten UTF-8-kodiert und die Tabelle auf Latin-1 eingestellt ist, Probleme mit den Sting-Längen geben. Also, wenn dein Feld vom Typ varchar(10) ist und der Wert neben 9 ASCII-Zeichen auch z.B. ein Umlaut enthält, dann sind das ja mind. ein Byte zuviel. Auch steht was im Manual von einer Relevanz auf die Namen. Damit sind dann wohl Bezeichnungen von Tabellen, Feldern etc. gemeint, wobei ich bisher dachte, dass hier ohnehin nur [a-zA-Z0-9\-_] oder so in Frage kämen. Ansonsten ist es aber, wenn ich da richtig liege, der Datenbank Wurscht, wie die Daten kodiert sind. Wenn da 11 Bytes UTF-8 ankommen und soviel Platz vorgesehen ist, dann kommen die ein, ganz gleich, ob sie eigentlich 11 Latin-1-Zeichen repräsentieren. Nur eben für die Sortierung ist es dann natürlich wieder relevant.

        Mach doch einfach mal eine Ausgabe eines DB-Feldes und schau dir die Seite dann einmal in Latin-1 und einmal in UTF-8 an. Das müssten bei dir jetzt Latin-1-Zeichen sein, die in einer UTF-8-Tabelle liegen ... und dann, jetzt wieder in deinem System, via utf8_encode nach UTF-8 konvertiert werden, um sie dann auf einer mit charset=utf-8 markierten Seite korrekt angezeigt zu werden. Mit dem Konvertieren meinte ich jedoch ein umwandeln der Daten in der Datenbank. Wenn deine Datenbank UTF-8 unterstützt, dann lies alle Daten aus, konvertiere sie nach UTF-8 und schreib sie wieder rein. Dann hast du (soweit möglich) dein ganzes System auf UTF-8 umgestellt. Daten, die über Formulare an dich gehen, sollten UTF-8 kodiert sein, wenn das Formular (bzw. eben de entsprechende HTML-Seite) diese Kodierung aufweist.

        Problematisch ist jetzt natürlich noch, dass PHP immernoch kein UTF-8 unterstützt (...warten auf PHP 6 ...). Hier musst du dann die iconf_*-Funktionen benutzen, denen du vorher erzählst, welche Kodierung du verwendest. Natürlich kannst du die Funktionen auch nachbuen. Hier mal ein Schnipsel von mir zum Experimentieren und Ausbauen:

        PHP-Code:
        <?php

        class String
        {
            private 
        $aCharArray NULL;
            private 
        $iLenght    NULL;

            public function 
        __construct($sValue '')
            {
                
        $this->set($sValue);
            }

            public function 
        set($sValue)
            {
                
        preg_match_all("/./su", (string)$sValue$a);
                
        $this->aCharArray $a[0];
                
        $this->iLenght sizeof($this->aCharArray);
            }

            public function 
        lenght()
            {
                return 
        $this->iLenght;
            }

            public function 
        substr($iStart$iEnd=false)
            {
                if (
        false === $iEnd$iEnd $this->iLenght;
                return 
        join(''array_slice($this->aCharArray$iStart$iEnd));
            }
        }
        header("Content-type: text/html; charset=utf-8");
        print 
        '<html><head>';
        print 
        '<meta http-equiv = "Content-Type" content="text/html; charset=utf-8" >';
        print 
        '</head><body>';

        $sString 'Tätärätätäää!';
        // Falls die Datein nicht als UTF-8 abgespeichert wurde auskommenieren:
        // $sString = utf8_encode('Tätärätätäää!');
        $String = new String($sString);
        iconv_set_encoding("internal_encoding""UTF-8");

        printf('utf-8: %s
        Latin-1: %s
        '
        ,
            
        $sString,
            
        iconv('UTF-8''ISO-8859-1'$sString));

        printf('strlen(): %s
        iconv_strlen(): %s
        String::lenght(): %s
        '
        ,
            
        strlen($sString),
            
        iconv_strlen($sString),
            
        $String->lenght());

        printf('substr($sString, 1,5): %s
        iconv_substr($sString, 1,5): %s
        String::substr(1,5): %s
        '
        ,
            
        substr($sString15),
            
        iconv_substr($sString15),
            
        $String->substr(1,5));

        iconv_set_encoding('internal_encoding''ISO-8859-1');
        printf('iconv_strlen() with Latin-1 set as internal encoding type: %s',
            
        iconv_strlen($sString));

        print 
        '</body></html>';
        ?>
        Basti

        Kommentar


        • #5
          Vielen Dank für Deine ausführliche Hilfe.

          Das Problem ist aber die MySQl-Datenbank auf dem Live-Server, da liegt ja noch Version 4.0... vor, die kein UTF8 unterstützt. Deswegen ist die Lösung schon OK so. Ich muss jetzt nur mal testen, ob das auf dem Live-Server genauso aussieht wie auf meinem Test-Server.

          Kommentar


          • #6
            Wenn ich den Default-Charset des Webservers auf ISO-8859-1 umstelle, sehen die ausgelesen Daten aus der Datenbank richtig aus, aber die äöüs aus den UTF8 HTML-Dateien werden falsch dargestellt (ist ja auch logisch). Mich wunder nur, dass die äöüs im Quelltext auch wirklich als äöü stehen und nicht als &auml; usw. und trotzdem richtig angezeigt werden. Ich vermute, dass das an den Webbrowsern liegt, ich habe mal gelsen, dass die größtenteil gar nicht auf den gesendet charset-Wert achten, sondern selber versuchen, den richtigen Charset herauszufinen und anzuwenden...

            Kommentar


            • #7
              Hi.

              Ich schicke immer einen Header raus und schreibs dann nochmal als Meta-Tag in den HTML-Code.

              Wichtig ist, dass du bei dieser Lösung dann aufpasst, dass du dir keine UTF-8-Zeichen in die Datenbank packst. Wie bereits erwähnt: Wenn du ein Formular auf einer UTF-8-Seite ausgibst, der Benutzer schreibt ein "ä" rein und schickt das an den Server zurück, dann kommt dort ein UTF-8-"ä" an. Wenn du dir das jetzt in die Datenbank packst, dann hast du hinterher ein riesiges Ducheinander.

              Ich hab hier ein kleines Skript, das dieses Verhalten verdeutlicht:

              http://coyserve.de/charsetform.php

              PHP-Code:
              <?php
              error_reporting
              (E_ALL);

              $aCharsets = array(
                  
              'UTF-8',
                  
              'ISO-8859-1');

              $bSent      false;
              $sCharset   $aCharsets[0];
              $sFormValue '';
              $sErrMsg    '';

              if (isset(
              $_POST['sent'])) {

                  try {

                      
              $sText '';

                      if (!isset(
              $_POST['charset']))
                          throw new 
              Exception('No charset set');
                      if (!
              in_array($_POST['charset'], $aCharsets))
                          throw new 
              Exception('Unknown charset');
                      if (!isset(
              $_POST['form_charset']) or !in_array($_POST['form_charset'], $aCharsets))
                          throw new 
              Exception('Bad request');
                      if (!isset(
              $_POST['text']))
                          throw new 
              Exception('No text submitted');

                      
              $bSent true;

                      
              $sCharset     $_POST['charset'];
                      
              $sFormCharset $_POST['form_charset'];

                      
              $sText get_magic_quotes_gpc() ? stripslashes($_POST['text']) : $_POST['text'];

                      
              $sFormValue $sText;
                      if (
              $sFormCharset === 'UTF-8'$sFormValue iconv('UTF-8''ISO-8859-1'$sFormValue);
                      
              $sFormValue htmlentities($sFormValue);

                      
              $sText htmlspecialchars($sText);

                  } catch (
              Exception $e) {
                      
              $sErrMsg '<div class="errmsg">[b]Invalid data:[/b] ' $e->getMessage() . '</div>';
                  }
              }

              header("Content-type: text/html; charset=$sCharset");
              print 
              '<?xml version="1.0" encoding="' $sCharset '"?>';
              ?>
              <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
              <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
              <head>
                  <meta http-equiv="content-type" content="text/html; charset=<?php print $sCharset?>" />
                  <title>Zeichensatz-per-Formular-Test</title>
                  <style type="text/css">

                      .errmsg {
                          color: #f00;
                          margin-bottom: 3em;
                      }

                      fieldset {
                          padding-top: 1.4em;
                      }

                      input[type=submit] {
                          margin-top: 1em;
                      }

                  </style>
              </head>

              <body>

              <?php
              print $sErrMsg;
              if (
              $bSent) {
              ?>

                  

              Folgender Text wurde &uuml;ber ein Formular auf einer
                  <?php print $sFormCharset?>-Seite eingegeben und hier auf einer
                  <?php print $sCharset?>-Seite ausgegeben:</p>
                  

              <?php print $sText?></p>

              <?php
              }
              ?>

                  <form action="<?php print getenv('SCRIPT_NAME');?>" method="post">
                      <fieldset>

                          <input type="hidden" name="form_charset" value="<?php print $sCharset?>" />

                          <legend><?php print $sCharset?>-Formular:</legend>

                          <label>Zeichensatz:</label>

              <?php
              foreach ($aCharsets as $sValue) {

                  
              $sChecked = ($sValue === $sCharset) ? ' checked="checked"' '';
              ?>

                          <input type="radio" name="charset" value="<?php print $sValue?><?php print $sChecked?> />
                          <label><?php print $sValue?></label>


              <?php
              }
              ?>
                          


                          <label>Text:</label>

                          <input type="text" name="text" size="30" value="<?php print $sFormValue?>" />

                          


                          <input type="submit" name="sent" value="abschicken" />

                      </fieldset>
                  </form>
              </body>
              </html>
              Basti

              Kommentar

              Lädt...
              X