Détecter l'encodage et tout faire UTF-8

je suis en train de lire de nombreux textes de différents flux RSS et de les insérer dans ma base de données.

bien sûr, il y a plusieurs codages de caractères différents utilisés dans les alimentations, par exemple UTF-8 et ISO-8859-1.

malheureusement, il y a parfois des problèmes avec l'encodage des textes. Exemple:

  1. le "ß" dans "Fußball"devrait ressembler à ceci dans ma base de données: "Ÿ". Si c'est un "Ÿ", il est affiché correctement.

  2. parfois, le "ß" dans "Fußball"ressemble à ceci dans ma base de données: "Ãÿâÿ". Il est affiché à tort, bien sûr.

  3. dans les autres cas, le "ß" est enregistré comme un " ß " - donc sans aucun changement. Alors il est également affiché à tort.

Que puis-je faire pour éviter les cas 2 et 3?

Comment puis-je faire tout le même encodage, de préférence UTF-8? Quand doit-on utiliser utf8_encode() , quand doit-on utiliser utf8_decode() (il est clair que l'effet est mais quand dois-je utiliser les fonctions?) et quand dois-je ne rien faire avec l'entrée?

pouvez-vous m'aider et me dire comment faire tout le même encodage? Peut-être avec la fonction mb_detect_encoding() ? Je peux écrire une fonction pour ça? Donc mes problèmes sont:

  1. Comment savoir quel encodage utilise le texte?
  2. comment le convertir en UTF-8-quel que soit l'ancien encodage?

est-ce qu'une fonction comme celle-ci fonctionnerait?

function correct_encoding($text) {
    $current_encoding = mb_detect_encoding($text, 'auto');
    $text = iconv($current_encoding, 'UTF-8', $text);
    return $text;
}

Je l'ai testé mais ça ne marche pas. Quel est le problème avec elle?

272
demandé sur JakeGould 2009-05-26 17:50:34

24 réponses

si vous appliquez utf8_encode() à une chaîne déjà UTF8, il retournera une sortie UTF8 brouillée.

j'ai créé une fonction qui traite de toutes ces questions. Il s'appelle Encoding::toUTF8() .

Vous n'avez pas besoin de savoir ce que l'encodage de vos chaînes. Il peut être Latin1 (iso 8859-1), Windows-1252 ou UTF8, ou la chaîne peut avoir un mélange d'entre eux. Encoding::toUTF8() convertira tout en UTF8.

Je l'ai fait parce qu'un service il m'a donné un flux de données tout gâché, mélangeant UTF8 et Latin1 dans la même chaîne.

Utilisation:

require_once('Encoding.php'); 
use \ForceUTF8\Encoding;  // It's namespaced now.

$utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string);

$latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string);

télécharger:

https://github.com/neitanod/forceutf8

mise à jour:

j'ai inclus une autre fonction, Encoding::fixUFT8() , qui va corriger chaque chaîne UTF8 qui semble confus.

Utilisation:

require_once('Encoding.php'); 
use \ForceUTF8\Encoding;  // It's namespaced now.

$utf8_string = Encoding::fixUTF8($garbled_utf8_string);

exemples:

echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");

sortira:

Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football

mise à jour: j'ai transformé la fonction ( forceUTF8 ) en une famille de fonctions statiques sur une classe appelée Encoding . La nouvelle fonction est Encoding::toUTF8() .

321
répondu Sebastián Grignoli 2018-02-01 14:39:33

vous devez d'abord détecter quel encodage a été utilisé. Comme vous analysez les flux RSS (probablement via HTTP), vous devriez lire l'encodage du paramètre charset du champ Content-Type en-tête HTTP . S'il n'est pas présent, lire l'encodage de l'attribut encoding de l'instruction XML processing instruction . Si cela est manquant aussi, utiliser UTF-8 comme défini dans la spécification .


modifier voici ce que je ferais probablement:

je préfère utiliser cURL d'envoyer et de chercher la réponse. Cela vous permet de définir des champs d'en-tête spécifiques et de récupérer l'en-tête de réponse. Après avoir récupéré la réponse, vous devez analyser la réponse HTTP et la diviser en entête et corps. L'en-tête devrait alors contenir le champ d'en-tête Content-Type qui contient le type MIME et (avec un peu de chance) le paramètre charset avec l'encodage/charset aussi. Si ce n'est pas le cas, nous analyserons le PI XML pour la présence de l'attribut encoding et nous obtiendrons l'encodage à partir de là. Si cela est également manquant, les spécifications XML définissent pour utiliser UTF-8 comme encodage.

$url = 'http://www.lr-online.de/storage/rss/rss/sport.xml';

$accept = array(
    'type' => array('application/rss+xml', 'application/xml', 'application/rdf+xml', 'text/xml'),
    'charset' => array_diff(mb_list_encodings(), array('pass', 'auto', 'wchar', 'byte2be', 'byte2le', 'byte4be', 'byte4le', 'BASE64', 'UUENCODE', 'HTML-ENTITIES', 'Quoted-Printable', '7bit', '8bit'))
);
$header = array(
    'Accept: '.implode(', ', $accept['type']),
    'Accept-Charset: '.implode(', ', $accept['charset']),
);
$encoding = null;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
$response = curl_exec($curl);
if (!$response) {
    // error fetching the response
} else {
    $offset = strpos($response, "\r\n\r\n");
    $header = substr($response, 0, $offset);
    if (!$header || !preg_match('/^Content-Type:\s+([^;]+)(?:;\s*charset=(.*))?/im', $header, $match)) {
        // error parsing the response
    } else {
        if (!in_array(strtolower($match[1]), array_map('strtolower', $accept['type']))) {
            // type not accepted
        }
        $encoding = trim($match[2], '"\'');
    }
    if (!$encoding) {
        $body = substr($response, $offset + 4);
        if (preg_match('/^<\?xml\s+version=(?:"[^"]*"|\'[^\']*\')\s+encoding=("[^"]*"|\'[^\']*\')/s', $body, $match)) {
            $encoding = trim($match[1], '"\'');
        }
    }
    if (!$encoding) {
        $encoding = 'utf-8';
    } else {
        if (!in_array($encoding, array_map('strtolower', $accept['charset']))) {
            // encoding not accepted
        }
        if ($encoding != 'utf-8') {
            $body = mb_convert_encoding($body, 'utf-8', $encoding);
        }
    }
    $simpleXML = simplexml_load_string($body, null, LIBXML_NOERROR);
    if (!$simpleXML) {
        // parse error
    } else {
        echo $simpleXML->asXML();
    }
}
72
répondu Gumbo 2009-05-27 19:29:23

la détection de l'encodage est difficile.

mb_detect_encoding fonctionne en devinant, basé sur un certain nombre de candidats que vous réussissez. Dans certains codages, certaines séquences d'octets sont invalides, ce qui permet de distinguer différents candidats. Malheureusement, il y a beaucoup d'encodages, où les mêmes octets sont valides (mais différents). Dans ces cas, il n'y a aucun moyen de déterminer l'encodage; Vous pouvez implémenter votre propre logique de faire des suppositions dans ces cas. Pour exemple, les données provenant d'un site Japonais pourraient être plus susceptibles d'avoir un Japonais de codage.

aussi longtemps que vous ne vous occupez que des langues D'Europe occidentale, les trois principaux encodages à considérer sont utf-8 , iso-8859-1 et cp-1252 . Comme ce sont des valeurs par défaut pour de nombreuses plates-formes, elles sont aussi les plus susceptibles d'être signalées à tort. Par exemple. si les gens utilisent des encodages différents, ils sont susceptibles d'être francs à ce sujet, car autrement leur logiciel casserait très souvent. Par conséquent, une bonne stratégie consiste à faire confiance au fournisseur, à moins que l'encodage soit rapporté comme l'un de ces trois. Vous devez toujours vérifier qu'il est bien valide, en utilisant mb_check_encoding (notez que valide n'est pas la même chose que étant - la même entrée peut être valide pour de nombreux encodages). Si c'est l'un d'eux, vous pouvez alors utiliser mb_detect_encoding pour les distinguer. Heureusement que c'est assez déterministe; il Vous suffit d'utiliser le bon detect-sequence, qui est UTF-8,ISO-8859-1,WINDOWS-1252 .

une fois que vous avez détecté l'encodage, vous devez le convertir à votre représentation interne ( UTF-8 est le seul choix sain). La fonction utf8_encode transforme ISO-8859-1 en UTF-8 , de sorte qu'elle ne peut être utilisée que pour ce type d'entrée particulier. Pour les autres encodages, utilisez mb_convert_encoding .

35
répondu troelskn 2010-07-04 16:04:46

ce cheatsheet liste quelques mises en garde communes liées à la manipulation de L'UTF-8 en PHP: http://developer.loftdigital.com/blog/php-utf-8-cheatsheet

cette fonction de détection de caractères multi-octets dans une chaîne de caractères pourrait également s'avérer utile ( source ):


function detectUTF8($string)
{
    return preg_match('%(?:
        [\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
        )+%xs', 
    $string);
}
11
répondu miek 2009-06-09 15:05:52

Un vraiment belle façon de mettre en œuvre un isUTF8 -la fonction peut être trouvé sur php.net :

function isUTF8($string) {
    return (utf8_encode(utf8_decode($string)) == $string);
}
11
répondu harpax 2011-11-30 03:16:20

un petit avertissement, vous avez dit que le" ß "devrait être affiché comme" Ÿ " dans votre base de données.

c'est probablement parce que vous utilisez une base de données avec un codage de caractères latin1 ou peut-être votre connexion php-mysql est mal réglée, c'est, php croit que votre mysql est réglé pour utiliser utf-8, donc il envoie des données comme utf8, mais votre mysql croit que php envoie des données encodées comme iso-8859-1, donc il peut Une fois de plus essayer de coder vos données envoyées comme utf-8, causant ce genre de problème.

Regardez ceci, peut vous aider: http://php.net/manual/en/function.mysql-set-charset.php

9
répondu Krynble 2011-11-30 03:16:05

votre encodage ressemble à celui que vous avez encodé en UTF-8 deux fois ; c'est-à-dire, à partir d'un autre encodage, en UTF-8, et de nouveau en UTF-8. Comme si vous aviez iso-8859-1, converti de iso-8859-1 en utf-8, et traité la nouvelle chaîne comme iso-8859-1 pour une autre conversion en UTF-8.

voici un pseudo de ce que vous avez fait:

$inputstring = getFromUser();
$utf8string = iconv($current_encoding, 'utf-8', $inputstring);
$flawedstring = iconv($current_encoding, 'utf-8', $utf8string);

, Vous devriez essayer:

  1. détecter l'encodage en utilisant mb_detect_encoding() ou ce que vous voulez utiliser
  2. si C'est UTF-8, convertissez en iso-8859-1, et répétez l'étape 1
  3. enfin, convertir de nouveau en UTF-8

qui suppose que dans la conversion "moyenne" vous avez utilisé iso-8859-1. Si vous utilisez windows-1252, convertissez-le en windows-1252 (latin1). L'encodage source original n'est pas important; celui que vous avez utilisé dans la deuxième conversion défectueuse l'est.

c'est à mon avis, à ce qui s'est passé, il y a très peu d'autres choses que vous auriez pu faire pour obtenir quatre octets au lieu d'un octet ASCII étendu.

allemand langue utilise également iso-8859-2 et windows-1250 (latin2).

3
répondu Ivan Vučica 2009-06-04 10:07:44

vous devez tester le jeu de caractères sur l'entrée car les réponses peuvent être codées avec différents encodages.

je me force à tous les contenus été envoyé en UTF-8 par faire de la détection et de la traduction à l'aide de la fonction suivante:

function fixRequestCharset()
{
  $ref = array( &$_GET, &$_POST, &$_REQUEST );
  foreach ( $ref as &$var )
  {
    foreach ( $var as $key => $val )
    {
      $encoding = mb_detect_encoding( $var[ $key ], mb_detect_order(), true );
      if ( !$encoding ) continue;
      if ( strcasecmp( $encoding, 'UTF-8' ) != 0 )
      {
        $encoding = iconv( $encoding, 'UTF-8', $var[ $key ] );
        if ( $encoding === false ) continue;
        $var[ $key ] = $encoding;
      }
    }
  }
}

cette routine transformera toutes les variables PHP provenant de l'hôte distant en UTF-8.

ou ignorez la valeur si le codage n'a pas pu être détecté ou converti.

vous pouvez l'adapter à vos besoins.

il suffit de l'invoquer avant d'utiliser les variables.

3
répondu cavila 2011-12-16 16:46:49

la chose intéressante à propos de mb_detect_encoding et mb_convert_encoding est que l'ordre des encodages que vous suggérez importe:

// $input is actually UTF-8

mb_detect_encoding($input, "UTF-8", "ISO-8859-9, UTF-8");
// ISO-8859-9 (WRONG!)

mb_detect_encoding($input, "UTF-8", "UTF-8, ISO-8859-9");
// UTF-8 (OK)

donc vous pourriez vouloir utiliser un ordre spécifique lorsque vous spécifiez des encodages attendus. Enfin, gardez à l'esprit que ce n'est pas infaillible.

3
répondu Halil Özgür 2012-03-11 17:58:32

c'est simple: quand vous obtenez quelque chose qui n'est pas UTF8, vous devez L'encoder en utf8.

donc, quand vous allez chercher un certain flux qui est ISO-8859-1 Analyse par utf8_encode.

cependant, si vous allez chercher un aliment UTF8, vous n'avez pas besoin de faire quoi que ce soit.

2
répondu Seb 2009-05-26 13:55:14

travailler sur le codage de caractères des flux RSS semble être compliqué . Même les pages Web normales omettent souvent, ou mentent sur leur encodage.

Alors vous pouvez essayer d'utiliser le bon moyen de détecter l'encodage et ensuite revenir à une certaine forme d'auto-détection (deviner).

2
répondu Kevin ORourke 2009-05-26 14:02:41

je sais que c'est une question plus ancienne, mais je pense qu'une réponse utile ne fait jamais de mal. J'avais des problèmes avec mon encodage entre une application de bureau, SQLite, et les variables GET/POST. Certains seraient en UTF-8, d'autres en ASCII, et en gros tout serait foutu en l'air quand des personnages étrangers seraient impliqués.

voici ma solution. Il scrute votre GET/POST / REQUEST (j'ai omis les cookies, mais vous pouvez les ajouter si vous le souhaitez) sur chaque page chargée avant le traitement. Il fonctionne bien dans un en-tête. PHP lancera des avertissements s'il ne peut pas détecter le codage source automatiquement, donc ces avertissements sont supprimés avec @'S.

//Convert everything in our vars to UTF-8 for playing nice with the database...
//Use some auto detection here to help us not double-encode...
//Suppress possible warnings with @'s for when encoding cannot be detected
try
{
    $process = array(&$_GET, &$_POST, &$_REQUEST);
    while (list($key, $val) = each($process)) {
        foreach ($val as $k => $v) {
            unset($process[$key][$k]);
            if (is_array($v)) {
                $process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = $v;
                $process[] = &$process[$key][@mb_convert_encoding($k,'UTF-8','auto')];
            } else {
                $process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = @mb_convert_encoding($v,'UTF-8','auto');
            }
        }
    }
    unset($process);
}
catch(Exception $ex){}
2
répondu jocull 2010-05-23 05:52:59

je vérifiais des solutions pour encoder depuis des âges, et cette page est probablement la conclusion d'années de recherche! J'ai testé certaines des suggestions que vous avez mentionnées et voici mes notes:

C'est ma chaîne de test:

c'est un" wròng wrìtten " string bùt inèed to pù 'sòme' special chàrs à voir thèm, convertèd par fùnctìon!! et c'est tout!

je fais un INSERT pour enregistrer cette chaîne sur un DB dans un champ qui est défini comme utf8_general_ci

Charset de ma page est UTF-8

si je fais un INSERT comme ça, dans mon DB j'ai des caractères venant probablement de Mars... donc j'ai besoin de les transformer en un UTF-8 sain d'esprit. J'ai essayé utf8_encode() mais des extraterrestres ont envahi ma base de données...

donc j'ai essayé d'utiliser la fonction forceUTF8 postée sur le numéro 8 mais sur DB la chaîne de caractères sauvée ressemble à cela:

c'est un "wrÃ2ng wrÃtten" chaîne bÃ1t je nÃed à pÃ1 'sÃ2me spécial mouans rs pour voir thÃm, convertÃd par fÃ1nctÃon!! et c'est tout!

donc en recueillant plus d'infos sur cette page et en les fusionnant avec d'autres infos sur d'autres pages j'ai résolu mon problème avec cette solution:

$finallyIDidIt = mb_convert_encoding(
  $string,
  mysql_client_encoding($resourceID),
  mb_detect_encoding($string)
);

maintenant dans ma base de données j'ai ma chaîne avec le codage correct.

NOTE: La seule note à prendre en charge est sur la fonction mysql_client_encoding ! Vous devez être connecté à DB parce que cette fonction veut un ID de ressource comme paramètre.

mais bon, je fais juste ce ré-encodage avant mon INSERT donc pour moi ce n'est pas un problème.

j'espère que cela aidera quelqu'un comme cette page m'a aidé!

merci à tous!

Mauro

2
répondu Mauro 2014-04-29 11:06:24

php.net/ mb_detect_encoding

echo mb_detect_encoding($str, "auto");

ou

echo mb_detect_encoding($str, "UTF-8, ASCII, ISO-8859-1");

Je ne sais vraiment pas quels sont les résultats, mais je vous suggérerais de prendre quelques-uns de vos flux avec des encodages différents et d'essayer si mb_detect_encoding fonctionne ou non.

mise à jour

auto est le diminutif de "ASCII,JIS,UTF-8,EUC-JP, SJIS". il renvoie le jeu de caractères détecté, que vous pouvez utiliser pour convertissez la chaîne en utf-8 avec iconv .

<?php
function convertToUTF8($str) {
    $enc = mb_detect_encoding($str);

    if ($enc && $enc != 'UTF-8') {
        return iconv($enc, 'UTF-8', $str);
    } else {
        return $str;
    }
}
?>

je n'ai pas testé, donc pas de garantie. et peut-être il ya un moyen plus simple.

1
répondu stefs 2009-05-26 15:18:05

@harpax qui a fonctionné pour moi. Dans mon cas, c'est suffisant:

if (isUTF8($str)) { 
    echo $str; 
}
else
{
    echo iconv("ISO-8859-1", "UTF-8//TRANSLIT", $str);
}
1
répondu PJ Brunet 2011-07-27 00:48:03

après avoir trié vos scripts php, n'oubliez pas de dire à mysql quel charset vous passez et que vous aimeriez recevoir.

exemple: jeu de caractères utf8

passer des données utf8 à une table latin1 dans une session I/O latin1 donne ces vilains birdfeets. Je le vois tous les deux jours dans les magasins oscommerce. Retour en arrière et quatrième il pourrait sembler juste. Mais phpmyadmin montrera la vérité. En disant à mysql quel charset vous passez, il gérera le conversion de données mysql pour vous.

comment récupérer des données MySQL brouillées existantes est un autre sujet à discuter. :)

0
répondu tim 2012-01-18 19:40:18

cette version est pour la langue allemande mais vous pouvez modifier les $ CHARSETS et les $TESTCHARS

class CharsetDetector
{
private static $CHARSETS = array(
"ISO_8859-1",
"ISO_8859-15",
"CP850"
);
private static $TESTCHARS = array(
"€",
"ä",
"Ä",
"ö",
"Ö",
"ü",
"Ü",
"ß"
);
public static function convert($string)
{
    return self::__iconv($string, self::getCharset($string));
}
public static function getCharset($string)
{
    $normalized = self::__normalize($string);
    if(!strlen($normalized))return "UTF-8";
    $best = "UTF-8";
    $charcountbest = 0;
    foreach (self::$CHARSETS as $charset) {
        $str = self::__iconv($normalized, $charset);
        $charcount = 0;
        $stop   = mb_strlen( $str, "UTF-8");

        for( $idx = 0; $idx < $stop; $idx++)
        {
            $char = mb_substr( $str, $idx, 1, "UTF-8");
            foreach (self::$TESTCHARS as $testchar) {

                if($char == $testchar)
                {

                    $charcount++;
                    break;
                }
            }
        }
        if($charcount>$charcountbest)
        {
            $charcountbest=$charcount;
            $best=$charset;
        }
        //echo $text."<br />";
    }
    return $best;
}
private static function __normalize($str)
{

$len = strlen($str);
$ret = "";
for($i = 0; $i < $len; $i++){
    $c = ord($str[$i]);
    if ($c > 128) {
        if (($c > 247)) $ret .=$str[$i];
        elseif ($c > 239) $bytes = 4;
        elseif ($c > 223) $bytes = 3;
        elseif ($c > 191) $bytes = 2;
        else $ret .=$str[$i];
        if (($i + $bytes) > $len) $ret .=$str[$i];
        $ret2=$str[$i];
        while ($bytes > 1) {
            $i++;
            $b = ord($str[$i]);
            if ($b < 128 || $b > 191) {$ret .=$ret2; $ret2=""; $i+=$bytes-1;$bytes=1; break;}
            else $ret2.=$str[$i];
            $bytes--;
        }
    }
}
return $ret; 
}
private static function __iconv($string, $charset)
{
    return iconv ( $charset, "UTF-8" , $string );
}
}

0
répondu Lukas Gottschall 2012-02-22 18:53:49

récupérez l'encodage des en-têtes et convertissez-le en utf-8.

$post_url='http://website.domain';

/// Get headers ////////////////////////////////////////////////////////////
function get_headers_curl($url) 
{ 
    $ch = curl_init(); 

    curl_setopt($ch, CURLOPT_URL,            $url); 
    curl_setopt($ch, CURLOPT_HEADER,         true); 
    curl_setopt($ch, CURLOPT_NOBODY,         true); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_TIMEOUT,        15); 

    $r = curl_exec($ch); 
    return $r; 
}
$the_header = get_headers_curl($post_url);
/// check for redirect /////////////////////////////////////////////////
if (preg_match("/Location:/i", $the_header)) {
    $arr = explode('Location:', $the_header);
    $location = $arr[1];

    $location=explode(chr(10), $location);
    $location = $location[0];

$the_header = get_headers_curl(trim($location));
}
/// Get charset /////////////////////////////////////////////////////////////////////
if (preg_match("/charset=/i", $the_header)) {
    $arr = explode('charset=', $the_header);
    $charset = $arr[1];

    $charset=explode(chr(10), $charset);
    $charset = $charset[0];
    }
///////////////////////////////////////////////////////////////////////////////
// echo $charset;

if($charset && $charset!='UTF-8') { $html = iconv($charset, "UTF-8", $html); }
0
répondu Arsen 2014-02-01 09:20:41

Ÿ est Mojibake pour ß . Dans votre base de données, vous pouvez avoir hex

DF if the column is "latin1",
C39F if the column is utf8 -- OR -- it is latin1, but "double-encoded"
C383C5B8 if double-encoded into a utf8 column

Vous devriez pas utiliser n'importe quel codage/décodage des fonctions en PHP; au lieu de cela, vous devez configurer la base de données et la connexion correctement.

si MySQL est impliqué, voir: problème avec les caractères utf8; ce que je vois n'est pas ce que j'ai stocké

0
répondu Rick James 2017-05-23 12:10:41

je trouve la solution ici http://deer.org.ua/2009/10/06/1 /

class Encoding
{
    /**
     * http://deer.org.ua/2009/10/06/1/
     * @param $string
     * @return null
     */
    public static function detect_encoding($string)
    {
        static $list = ['utf-8', 'windows-1251'];

        foreach ($list as $item) {
            try {
                $sample = iconv($item, $item, $string);
            } catch (\Exception $e) {
                continue;
            }
            if (md5($sample) == md5($string)) {
                return $item;
            }
        }
        return null;
    }
}

$content = file_get_contents($file['tmp_name']);
$encoding = Encoding::detect_encoding($content);
if ($encoding != 'utf-8') {
    $result = iconv($encoding, 'utf-8', $content);
} else {
    $result = $content;
}

je pense que @ est une mauvaise décision, et de faire quelques changements à la solution de deer.org.ua;

0
répondu Paul 2016-12-13 15:05:09

la réponse la plus votée ne fonctionne pas. Voici le mien et j'espère que ça vous aidera.

function toUTF8($raw) {
    try{
        return mb_convert_encoding($raw, "UTF-8", "auto"); 
    }catch(\Exception $e){
        return mb_convert_encoding($raw, "UTF-8", "GBK"); 
    }
}
0
répondu fzyzcjy 2017-06-29 03:51:00

quand vous essayez de gérer plusieurs langues comme le japonais et le coréen, vous pourriez avoir des problèmes. mb_convert_encoding avec le paramètre 'auto' ne fonctionne pas bien. Définir mb_detect_order ('ASCII,UTF-8,JIS,EUC-JP,SJIS,EUC-KR,UHC') n'aide pas car il détectera EUC-* à tort.

j'ai conclu que tant que les chaînes d'entrée proviennent de HTML, il devrait utiliser 'charset' dans un méta-élément. J'utilise simple HTML DOM Parser parce qu'il supporte HTML invalide.

l'extrait ci-dessous extrait l'élément titre d'une page web. Si vous souhaitez convertir la page entière, alors vous pouvez supprimer quelques lignes.

<?php
require_once 'simple_html_dom.php';

echo convert_title_to_utf8(file_get_contents($argv[1])), PHP_EOL;

function convert_title_to_utf8($contents)
{
    $dom = str_get_html($contents);
    $title = $dom->find('title', 0);
    if (empty($title)) {
        return null;
    }
    $title = $title->plaintext;
    $metas = $dom->find('meta');
    $charset = 'auto';
    foreach ($metas as $meta) {
        if (!empty($meta->charset)) { // html5
            $charset = $meta->charset;
        } else if (preg_match('@charset=(.+)@', $meta->content, $match)) {
            $charset = $match[1];
        }
    }
    if (!in_array(strtolower($charset), array_map('strtolower', mb_list_encodings()))) {
        $charset = 'auto';
    }
    return mb_convert_encoding($title, 'UTF-8', $charset);
}
-1
répondu Nobu 2011-09-14 23:29:02

j'ai eu le même problème avec phpQuery ( ISO-8859-1 au lieu de UTF-8 ) et ce hack qui m'a aidé:

$html = '<?xml version="1.0" encoding="UTF-8" ?>' . $html;

mb_internal_encoding('UTF-8') , phpQuery::newDocumentHTML($html, 'utf-8') , mbstring.internal_encoding et d'autres manipulations n'ont eu aucun effet.

-1
répondu user2448995 2013-07-15 20:35:51

Essayer sans "auto",

C'est-à-dire:

mb_detect_encoding($text)

au lieu de:

mb_detect_encoding($text, 'auto')

plus d'informations peuvent être trouvées ici: mb_detect_encoding

-1
répondu tkartas 2017-07-22 21:03:40