toscho.design

UTF-8 mit PHP erzwingen

Wer schon einmal in eine UTF-8-kodierte Webseite fremde Texte – einen Trackback oder News – einbinden mußte, wird dies zu schätzen wissen: Eine Funktion, die solche Texte passend umkodiert und den Lesern die lästigen � erspart.

Dazu brauchen wir erstmal einen Helfer, der nachsieht, ob der Text vielleicht schon in UTF-8 vorliegt:

<?php
/**
 * Prüft einen String auf UTF-8-Kompatibilität.
 * RegEx von Martin Dürst
 * @source http://www.w3.org/International/questions/qa-forms-utf-8.html
 * @param string $str String to check
 * @return boolean
 */
function is_utf8($str)
{
    return preg_match("/^(
         [\x09\x0A\x0D\x20-\x7E]            # ASCII
       | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
       |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
       | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
       |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
       |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
       | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
       |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
      )*$/x",
      $str);
}
?>

Und jetzt das eigentliche Arbeitstier:

<?php
/**
 * Versucht, einen String nach UTF-8 zu konvertieren.
 *
 * @author Thomas Scholz <http://toscho.de>
 * @param string $str Zu kodierender String
 * @param string $inputEnc Vermutete Kodierung des Strings
 * @return string
 */
function force_utf8($str, $inputEnc='WINDOWS-1252')
{
    if ( is_utf8($str) )
    {
        // Nichts zu tun.
        return $str;
    }
    if ( strtoupper($inputEnc) == 'ISO-8859-1')
    {
        return utf8_encode($str);
    }
    if ( function_exists('mb_convert_encoding') )
    {
        return mb_convert_encoding($str, 'UTF-8', $inputEnc);
    }
    if ( function_exists('iconv') )
    {
        return iconv($inputEnc, 'UTF-8', $str);
    }
    else
    {
        // Alternativ kann man auch den Originalstring ausgeben.
        trigger_error(
        'Kann String nicht nach UTF-8 kodieren in Datei '
        . __FILE__ . ', Zeile ' . __LINE__ . '!', E_USER_ERROR);
    }
}
?>

Wenn dir all dies ein Rätsel ist, empfehle ich die Artikel Grundlagen der Zeichenkodierung und Zeichenkodierung angeben.

7 Kommentare

  1. Siegfried am 01.03.2009 · 18:08

    Das ist gut, das merke ich mir.

    Da ich im Allgemeinen mit xml und xsl arbeite, ist das Problem nicht ganz so schlimm. Der Ausgangstext liegt dann in einem iso-8859-1 kodierten xml vor, und das xsl macht daraus ein utf-8 kodiertes xml. Das Einzige, was mich noch stört, ist, dass man bei php die Validierung nicht abschalten kann. Das kostet Zeit. Könnte daher sein, dass mir Deine Funktion demnächst gelegen kommt. Sollte ich demnächst ein regelmäßiges Einkommen haben, wird Rorkvell umziehen auf einen Webspace mit php. Und dann werden auch Kommentare möglich sein. Dazu dürfte diese Funktion gerade recht kommen.

  2. tce am 05.04.2009 · 13:10

    Hallo wie bekomme ich hier dieses Zeichen am Anfang der Seite gelöscht oder umgeschrieben. ich verzweifelt da schon habe es mit verschiedenen Editoren schon probiert aber alles ohne erfolg.

    bitte mal um dringliche Hilfe.

  3. Thomas Scholz am 05.04.2009 · 13:23

    Du meinst vermutlich die Zeichen . Das ist ein UTF-8-BOM, welches in ISO-8859-1 ausgegeben wird.
    Entweder schickst du die entsprechende Seite mit der Zeichenkodierung UTF-8 ins Netz – dann werden die drei Zeichen zu einem zusammengefaßt und nicht mehr dargestellt – oder du speicherst die Datei im Editor als ISO-8859-1 (bzw. ANSI unter Windows) ab und löschst die Zeichen dann, falls sie dein Editor nicht automatisch entfernt.
    Siehe auch: BOM entfernen.

  4. Anonymous am 10.08.2010 · 21:05

    Hallo,
    vielen Dank erstmal für die Mühe.

    Ich scheitere leider gerade an einem Problem und hoffe auf Hilfe.

    Ich möchte mehrere Daten aus einer DB ausgeben und vorher umkodieren.

    Das Ganze sieht bei mir so aus:

    <?PHP
    $result=mysql_query("SELECT * FROM name WHERE datum >= Current_Date()  ORDER by datum LIMIT 5 ");
    while($str=mysql_fetch_array($result))
    ?>
    <?php
    /**
     * Prüft einen String auf UTF-8-Kompatibilität.
     * RegEx von Martin Dürst
     * @source http://www.w3.org/International/questions/qa-forms-utf-8.html
     * @param string $str String to check
     * @return boolean
     */
    function is_utf8($str)
    {
        return preg_match("/^(
             [\x09\x0A\x0D\x20-\x7E]            # ASCII
           | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
           |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
           | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
           |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
           |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
           | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
           |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
          )*$/x",
          $str);
    }
    ?>
    <?php
    /**
     * Versucht, einen String nach UTF-8 zu konvertieren.
     *
     * @author Thomas Scholz <http://toscho.de>
     * @param string $str Zu kodierender String
     * @param string $inputEnc Vermutete Kodierung des Strings
     * @return string
     */
    function force_utf8($str, $inputEnc='WINDOWS-1252')
    {
        if ( is_utf8($str) )
        {
            // Nichts zu tun.
            return $str;
        }
        if ( strtoupper($inputEnc) == 'ISO-8859-1')
        {
            return utf8_encode($str);
        }
        if ( function_exists('mb_convert_encoding') )
        {
            return mb_convert_encoding($str, 'UTF-8', $inputEnc);
        }
        if ( function_exists('iconv') )
        {
            return iconv($inputEnc, 'UTF-8', $str);
        }
        else
        {
            // Alternativ kann man auch den Originalstring ausgeben.
            trigger_error(
            'Kann String nicht nach UTF-8 kodieren in Datei '
            . __FILE__ . ', Zeile ' . __LINE__ . '!', E_USER_ERROR);
        }
    }
    ?>
    <?php echo $str[name]; ?>

    Bei der Ausgabe erscheint dann gar nichts...
    Ich find den Fehler nicht- hoffe ihr könnt mir helfen!

    Danke!

  5. Thomas Scholz am 10.08.2010 · 21:37

    @Anonymous: Sieh dir die Rückgabe komplett an, um den Fehler zu finden:

    print htmlspecialchars( var_export($str, TRUE) );

    Obendrein ist $str[name] sicher ein Versehen. Du meinst: $str['name'].

    Mehr Hilfe bekommst du in einem passenden Forum.

  6. Michael am 06.05.2011 · 10:41

    Hi,

    ich bekomme bei Aufruf der Funktion vereinzelt einen Speicherzugriffsfehler und habe leider keine Idee, woran das liegen mag.

    Ansonsten aber ein Klasse-Script!

  7. Thomas Scholz am 06.05.2011 · 11:57

    @Michael: Das kann passieren, wenn der eingelesene String sehr lang ist und das pcre.backtrack_limit zu niedrig. Setze es mal hoch, und probiere, ob es hilft.

    Ansonsten richte dir mal Xdebug ein. Im Logfile oder in der Ausgabe per Webgrind siehst du dann ganz genau, wer deinen Speicher wegfrißt.