web-dev-qa-db-fra.com

Problèmes UTF-8 lors de la lecture du fichier CSV avec fgetcsv

J'essaie de lire un CSV et de faire écho au contenu. Mais le contenu affiche mal les caractères.

Mäx Müstermänn -> Mäx Müstermänn

L'encodage du fichier CSV est UTF-8 sans BOM (vérifié avec Notepad ++).

Voici le contenu du fichier CSV:

"Mäx";"Müstermänn"

Mon script PHP

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<?php
$handle = fopen ("specialchars.csv","r");
echo '<table border="1"><tr><td>First name</td><td>Last name</td></tr><tr>';
while ($data = fgetcsv ($handle, 1000, ";")) {
        $num = count ($data);
        for ($c=0; $c < $num; $c++) {
            // output data
            echo "<td>$data[$c]</td>";
        }
        echo "</tr><tr>";
}
?>
</body>
</html>

J'ai essayé d'utiliser setlocale(LC_ALL, 'de_DE.utf8'); comme suggéré ici sans succès. Le contenu est toujours mal affiché.

Qu'est-ce qui me manque?

Modifier:

Une echo mb_detect_encoding($data[$c],'UTF-8'); me donne UTF-8 UTF-8.

echo file_get_contents("specialchars.csv"); me donne "Mäx";"Müstermänn".

Et

print_r(str_getcsv(reset(explode("\n", file_get_contents("specialchars.csv"))), ';'))

donne moi

Array ( [0] => Mäx [1] => Müstermänn )

Qu'est-ce que ça veut dire?

31
testing

Maintenant, je l'ai fait fonctionner (après avoir supprimé la commande header). Je pense que le problème était que l'encodage du fichier php était en ISO-8859-1. Je l'ai réglé sur UTF-8 sans BOM. Je pensais l'avoir déjà fait, mais j'ai peut-être effectué une annulation supplémentaire.

De plus, j'ai utilisé SET NAMES 'utf8' pour la base de données. Maintenant, il est également correct dans la base de données.

2
testing

Essaye ça:

<?php
$handle = fopen ("specialchars.csv","r");
echo '<table border="1"><tr><td>First name</td><td>Last name</td></tr><tr>';
while ($data = fgetcsv ($handle, 1000, ";")) {
        $data = array_map("utf8_encode", $data); //added
        $num = count ($data);
        for ($c=0; $c < $num; $c++) {
            // output data
            echo "<td>$data[$c]</td>";
        }
        echo "</tr><tr>";
}
?>
50
robssanches

Problème similaire rencontré: analyse du fichier CSV avec des caractères spéciaux tels que é, è, ö etc ...

Les éléments suivants ont bien fonctionné pour moi:

Pour représenter correctement les caractères sur la page html, l'en-tête était nécessaire:

header('Content-Type: text/html; charset=UTF-8');

Afin d'analyser correctement chaque caractère, j'ai utilisé:

utf8_encode(fgets($file));

N'oubliez pas d'utiliser dans toutes les opérations de chaîne suivantes les "fonctions de chaîne multi-octets", comme:

mb_strtolower($value, 'UTF-8');
12
user2992220

Essayez de mettre cela en haut de votre fichier (avant toute autre sortie):

<?php

header('Content-Type: text/html; charset=UTF-8');

?>
6
Andreas Stokholm

Le problème est que la fonction renvoie UTF-8 (elle peut vérifier en utilisant mb_detect_encoding), mais ne convertit pas , et ces caractères prennent comme UTF-8. Par conséquent, il est nécessaire d'effectuer la conversion inverse en encodage initial (Windows-1251 ou CP1251) en utilisant iconv . Mais puisque par le fgetcsv retourne un tableau, je suggère d'écrire une fonction personnalisée: [ Désolé pour mon anglais]

function customfgetcsv(&$handle, $length, $separator = ';'){
    if (($buffer = fgets($handle, $length)) !== false) {
        return explode($separator, iconv("CP1251", "UTF-8", $buffer));
    }
    return false;
}
4
Manvel

Dans mon cas, le fichier source a un encodage Windows-1250 et iconv imprime des tonnes d'avis sur les caractères illégaux dans la chaîne d'entrée ...

Cette solution m'a donc beaucoup aidé:

/**
 * getting CSV array with UTF-8 encoding
 *
 * @param   resource    &$handle
 * @param   integer     $length
 * @param   string      $separator
 *
 * @return  array|false
 */
private function fgetcsvUTF8(&$handle, $length, $separator = ';')
{
    if (($buffer = fgets($handle, $length)) !== false)
    {
        $buffer = $this->autoUTF($buffer);
        return str_getcsv($buffer, $separator);
    }
    return false;
}

/**
 * automatic convertion windows-1250 and iso-8859-2 info utf-8 string
 *
 * @param   string  $s
 *
 * @return  string
 */
private function autoUTF($s)
{
    // detect UTF-8
    if (preg_match('#[\x80-\x{1FF}\x{2000}-\x{3FFF}]#u', $s))
        return $s;

    // detect WINDOWS-1250
    if (preg_match('#[\x7F-\x9F\xBC]#', $s))
        return iconv('WINDOWS-1250', 'UTF-8', $s);

    // assume ISO-8859-2
    return iconv('ISO-8859-2', 'UTF-8', $s);
}

Réponse à la réponse de @ manvel - utilisez str_getcsv au lieu d'exploser - à cause de cas comme celui-ci:

some;Nice;value;"and;here;comes;combinated;value";and;some;others

explode explose la chaîne en plusieurs parties:

some
Nice
value
"and
here
comes
combinated
value"
and
some
others

mais str_getcsv explose la chaîne en plusieurs parties:

some
Nice
value
and;here;comes;combinated;value
and
some
others
3
Petr Hladík