Page 1 sur 1

Problème d'encodage / caractères ésotériques

Posté : 08 déc. 2010, 13:01
par chodaboy
Bonjour à tous :)

Je viens vous voir aujourd'hui parce que je rencontre un souci très irritant avec un script PHP que j'ai mis en place. Il s'alimente dans deux bases (Deux SQL server, un datawarehouse et une base "de prod") pour récupérer un certain nombre d'informations sur des articles, dont une description, et vient écrire dans une table articles dans une base mysql que j'ai créé.

Seulement voilà, dans ma base "finale", j'ai certaines description qui s'affichent correctement, et d'autres non! Pour celles ci, les guillemets ou les oe sont remplacés par des caractères ésotériques. EN gros sur 18 000 enregistrements, 2000 sont défectueux.

Exemple: "qui apporteront l’énergie nécessaire à l’ organisme pour retrouver l’ harmonie"
"ces jeunettes avaient appris par cœur"

EDIT: (Heu là c'est un truc de dingue ^^ Le deuxième "extrait" que vous voyez affiché correctement "ces jeunettes avaient appris par coeur", est en fait un copier coller et quand j'édite mon message, il affiche "appris par c& #1546;eur") :shock:

Je me dis donc que j'ai un problème de jeu de caractères, mais est ce possible d'avoir 2 charsets différents au sein d'une même table source? Et si oui, quels mesures je peux prendre pour uniformiser tout ça? Ou alors je fais complètement fausse route?

Merci d'avance pour tout coup de pouce :)

Clement

Re: Problème de CHARSET / caractères ésotériques

Posté : 08 déc. 2010, 17:16
par jojolapine
A première vue, je ne dirait pas que le problème vient d'un jeu de caractères, mais plutôt d'un encodage du style htmlentities(), htmlspecialchars(), etc...
Qui doit être fait avant ou après l'enregistrement...
Peux-tu synthétiser les différentes étapes d'enregistrement, de récupération et d'affichage? (avec les vrais codes à chaque fois...)

Re: Problème de CHARSET / caractères ésotériques

Posté : 09 déc. 2010, 10:59
par chodaboy
Bonjour Jojolapine :)

Merci de t'intéresser à mon cas.

Voilà ce que je fais:
<?php/*RECUPERATION DES INFOS ARTICLE DANS CEGID GA_ARTICLE ET ECRITURE DANS LA TABLE MYSQL temp_cegid_article*/

$input_query_result_4 = sqlsrv_query($sqlsrv_connexion_CG, "SELECT A.GA_CODEARTICLE, A.GA_CODEBARRE, A.GA_DESIGNATION1, A.GA_DESIGNATION2, A.GA_POIDSBRUT, A.GA_PVTTC, A.GA_PVHT, A.GA_VOLUME, I.RD4_RD4LIBDATE1, A.GA_LINEAIRE, I.RD4_BLOCNOTE, A.GA_BLOCNOTE, A.GA_SURFACE, A.GA_FAMILLENIV2, I.RD4_RD4LIBTEXTE0, I.RD4_RD4LIBTEXTE3, I.RD4_RD4LIBTABLE3, T.YTC_TABLELIBREFOU3, A.GA_LIBREART2, A.GA_LIBREART5  FROM dbo.ARTICLE A, dbo.RTINFOS004 I, dbo.TIERSCOMPL T
WHERE A.GA_ARTICLE = I.RD4_CLEDATA AND A.GA_FOURNPRINC = T.YTC_AUXILIAIRE AND GA_LIBREART8 <> '21';") or die(print_r(sqlsrv_errors()));

while( $row = sqlsrv_fetch_array( $input_query_result_4, SQLSRV_FETCH_ASSOC))
{
	  If ((substr($row['RD4_BLOCNOTE'], 0, 5)) == '{\rtf')
	  {
			$cleanblocnote = rtf2text($row['RD4_BLOCNOTE']);
			$smallcleanblocnote = rtf2text($row['GA_BLOCNOTE']);
	  }
	  else
	  {
	        $cleanblocnote = $row['RD4_BLOCNOTE'];
			$smallcleanblocnote = $row['GA_BLOCNOTE'];
	  }
	  
	 $date_sortie = date_format($row['RD4_RD4LIBDATE1'], "Y/d/m");
	  /*$date_sortie = date('Y-d-m', $row['I.RD4_RD4LIBDATE1']);*/
	  /*echo strftime("%Y-%m-%d"), $row['RD4_RD4LIBDATE1'];/*
	  /*$date_sortie = substr($row['RD4_RD4LIBDATE1'], 0, 10);*/
	  echo $date_sortie;
	  $insert_result_4 = mysql_query ("INSERT INTO temp_cegid_article VALUES ('".$row['GA_CODEARTICLE']."','".$row['GA_CODEBARRE']."','".$row['GA_DESIGNATION1']."','".$row['GA_DESIGNATION2']."','".$row['GA_POIDSBRUT']."','".$row['GA_PVTTC']."','".$row['GA_PVHT']."','".$row['GA_VOLUME']."','".$row['GA_LINEAIRE']."','".$row['GA_SURFACE']."','".addslashes($cleanblocnote)."','".addslashes($smallcleanblocnote)."','".$row['GA_FAMILLENIV2']."','".$row['RD4_RD4LIBTEXTE0']."','".$row['RD4_RD4LIBTEXTE3']."','".$row['RD4_RD4LIBTABLE3']."','".$row['YTC_TABLELIBREFOU3']."','".$date_sortie."','".$row['GA_LIBREART2']."','".$row['GA_LIBREART5']."');");
	  $erreur = $insert_result_4;
	  echo mysql_error();
	  $nb_rows = $nb_rows + 1;
}

error_log("<br>".$nb_rows." lignes insérées dans temp_cegid_article</br>", 3, $exec_report);
$nb_rows = 0;
?>
Ces requêtes me remplissent une table temporaire, que j'agrège ensuite avec 5 autres pour obtenir ma table finale. Cela dit ça a peu d'importance ici: mon problème est présent déjà dans le champ BLOCNOTE de cette table temporaire.

J'oublierais donc un traitement sur ce blocnote? 8-|

Re: Problème de CHARSET / caractères ésotériques

Posté : 09 déc. 2010, 11:50
par jojolapine
Bonjour,

Est-ce que les erreurs sont sur les champs qui sont susceptibles de passer par rtf2text() ?
Si oui peux-tu nous montrer cette fonction?

Autre chose, il faudrait protéger ton insertion (mysql_real_escape_string()) même si tes données proviennent directement d'une autre table... (ça n'a rien à voir avec ton problème par contre)

Re: Problème de CHARSET / caractères ésotériques

Posté : 09 déc. 2010, 11:56
par chodaboy
Oui tout à fait, RTF2TEXT est une possibilité, c'est une fonction que j'ai trouvé sur le net qui supprime le formatage RTF de mon champ blocnote qui en contient parfois... je te met la fonction, et en même temps je vais rebondir sur ton idée pour voir si supprimer ce traitement règle mon problème! :)
<?php
function rtf_isPlainText($s) {
    $arrfailAt = array("*", "fonttbl", "colortbl", "datastore", "themedata");
    for ($i = 0; $i < count($arrfailAt); $i++)
        if (!empty($s[$arrfailAt[$i]])) return false;
    return true;
} 


function rtf2text($String) {
    /* Read the data from the input file.
    $text = file_get_contents($filename);
    if (!strlen($text))
        return "";*/
		
	$text = $String;

    // Create empty stack array.
    $document = "";
    $stack = array();
    $j = -1;
    // Read the data character-by- character…
    for ($i = 0, $len = strlen($text); $i < $len; $i++) {
        $c = $text[$i];

        // Depending on current character select the further actions.
        switch ($c) {
            // the most important key word backslash
            case "\\":
                // read next character
                $nc = $text[$i + 1];

                // If it is another backslash or nonbreaking space or hyphen,
                // then the character is plain text and add it to the output stream.
                if ($nc == '\\' && rtf_isPlainText($stack[$j])) $document .= '\\';
                elseif ($nc == '~' && rtf_isPlainText($stack[$j])) $document .= ' ';
                elseif ($nc == '_' && rtf_isPlainText($stack[$j])) $document .= '-';
                // If it is an asterisk mark, add it to the stack.
                elseif ($nc == '*') $stack[$j]["*"] = true;
                // If it is a single quote, read next two characters that are the hexadecimal notation
                // of a character we should add to the output stream.
                elseif ($nc == "'") {
                    $hex = substr($text, $i + 2, 2);
                    if (rtf_isPlainText($stack[$j]))
                        $document .= html_entity_decode("&#".hexdec($hex).";");
                    //Shift the pointer.
                    $i += 2;
                // Since, we’ve found the alphabetic character, the next characters are control word
                // and, possibly, some digit parameter.
                } elseif ($nc >= 'a' && $nc <= 'z' || $nc >= 'A' && $nc <= 'Z') {
                    $word = "";
                    $param = null;

                    // Start reading characters after the backslash.
                    for ($k = $i + 1, $m = 0; $k < strlen($text); $k++, $m++) {
                        $nc = $text[$k];
                        // If the current character is a letter and there were no digits before it,
                        // then we’re still reading the control word. If there were digits, we should stop
                        // since we reach the end of the control word.
                        if ($nc >= 'a' && $nc <= 'z' || $nc >= 'A' && $nc <= 'Z') {
                            if (empty($param))
                                $word .= $nc;
                            else
                                break;
                        // If it is a digit, store the parameter.
                        } elseif ($nc >= '0' && $nc <= '9')
                            $param .= $nc;
                        // Since minus sign may occur only before a digit parameter, check whether
                        // $param is empty. Otherwise, we reach the end of the control word.
                        elseif ($nc == '-') {
                            if (empty($param))
                                $param .= $nc;
                            else
                                break;
                        } else
                            break;
                    }
                    // Shift the pointer on the number of read characters.
                    $i += $m - 1;

                    // Start analyzing what we’ve read. We are interested mostly in control words.
                    $toText = "";
                    switch (strtolower($word)) {
                        // If the control word is "u", then its parameter is the decimal notation of the
                        // Unicode character that should be added to the output stream.
                        // We need to check whether the stack contains \ucN control word. If it does,
                        // we should remove the N characters from the output stream.
                        case "u":
                            $toText .= html_entity_decode("&#x".dechex($param).";");
                            $ucDelta = @$stack[$j]["uc"];
                            if ($ucDelta > 0)
                                $i += $ucDelta;
                        break;
                        // Select line feeds, spaces and tabs.
                        case "par": case "page": case "column": case "line": case "lbr":
                            $toText .= "\n";
                        break;
                        case "emspace": case "enspace": case "qmspace":
                            $toText .= " ";
                        break;
                        case "tab": $toText .= "\t"; break;
                        // Add current date and time instead of corresponding labels.
                        case "chdate": $toText .= date("m.d.Y"); break;
                        case "chdpl": $toText .= date("l, j F Y"); break;
                        case "chdpa": $toText .= date("D, j M Y"); break;
                        case "chtime": $toText .= date("H:i:s"); break;
                        // Replace some reserved characters to their html analogs.
                        case "emdash": $toText .= html_entity_decode("&mdash;"); break;
                        case "endash": $toText .= html_entity_decode("&ndash;"); break;
                        case "bullet": $toText .= html_entity_decode("&#149;"); break;
                        case "lquote": $toText .= html_entity_decode("&lsquo;"); break;
                        case "rquote": $toText .= html_entity_decode("&rsquo;"); break;
                        case "ldblquote": $toText .= html_entity_decode("&laquo;"); break;
                        case "rdblquote": $toText .= html_entity_decode("&raquo;"); break;
                        // Add all other to the control words stack. If a control word
                        // does not include parameters, set &param to true.
                        default:
                            $stack[$j][strtolower($word)] = empty($param) ? true : $param;
                        break;
                    }
                    // Add data to the output stream if required.
                    if (rtf_isPlainText($stack[$j]))
                        $document .= $toText;
                }

                $i++;
            break;
            // If we read the opening brace {, then new subgroup starts and we add
            // new array stack element and write the data from previous stack element to it.
            case "{":
                array_push($stack, $stack[$j++]);
            break;
            // If we read the closing brace }, then we reach the end of subgroup and should remove
            // the last stack element.
            case "}":
                array_pop($stack);
                $j--;
            break;
            // Skip “trash”.
            case '\0': case '\r': case '\f': case '\n': break;
            // Add other data to the output stream if required.
            default:
                if (rtf_isPlainText($stack[$j]))
                    $document .= $c;
            break;
        }
    }
    // Return result.
    return $document;
}

?>
EDIT: Mais je crois que j'avais déjà regardé et que certains textes sans RTF aucun sont affectés par le problème alors qu'ils ne sont pas censé passer par rtf2text :?

Re: Problème de CHARSET / caractères ésotériques

Posté : 10 déc. 2010, 11:26
par chodaboy
Je déprime, quand je cherche des solutions à mon problème sur google, je tombe sur mon propre topic #-o

J'ai enlevé le RTF2text, le résultat est bien entendu différent pour les champs en vu que le RTF reste, mais toujours le même souci pour ceux qui étaient en text normal depuis le début.

Je tente de faire un replace de &rsquo par ' pour voir... je sais plus trop quoi penser :(

EDIT: le replace fonctionne, plus qu'à identifier l'intégralité des caractères qui posent problème et à faire une fonction 'normalize' qui va bien. Cela dit j'aimerais bien comprendre quelle peut être l'origine de mon problème, c'est frustrant! :x