2010-09-03 5 views
4

des questions similaires:
Some characters in CSV file are not read during PHP fgetcsv(),
fgetcsv() ignores special characters when they are at the beginning of linefgetcsv() supprime les caractères avec des signes diacritiques (c'est-à-dire non-ASCII) - comment résoudre ce problème?

Mon application a une forme où les utilisateurs peuvent télécharger un fichier CSV (ses 5 utilisateurs internes ont toujours téléchargé un fichier valide - délimité par des virgules , quoted, records finit par LF), et le fichier est ensuite importé dans une base de données en utilisant PHP:

$fhandle = fopen($uploaded_file,'r'); 
while($row = fgetcsv($fhandle, 0, ',', '"', '\\')) { 
    print_r($row); 
    // further code not relevant as the data is already corrupt at this point 
} 

Pour raisons que je ne peux pas changer, les utilisateurs téléchargent le fichier codé dans le charset Windows-1250 - un codage de caractères de 8 bits à un octet.

Le problème: et certains caractères (pas tous!) Au-delà de 127 ("ASCII étendu") sont supprimés dans fgetcsv(). données Exemple:

"15","Ústav" 
"420","Špičák" 
"7","Tmaň" 

devient

Array (
    0 => 15 
    1 => "stav" 
) 
Array (
    0 => 420 
    1 => "pičák" 
) 
Array (
    0 => 7 
    1 => "Tma" 
) 

(Notez que č est conservée, mais Ú est abandonné)

La documentation fgetcsv dit que « depuis 4.3.5 fgetcsv() est maintenant binary safe ", mais on dirait que ce n'est pas le cas. Est-ce que je fais quelque chose de mal, ou cette fonction est-elle cassée et je devrais chercher une manière différente d'analyser CSV?

+0

Je vais répondre tout de suite, ce bug m'a mordu plus tôt et a trouvé la cause; Je voulais partager cela avec SO, car le bug est * subtil *. – Piskvor

+0

(juste pour clarifier, Win-1250 est juste le codage d'entrée.Les données sont ensuite converties et stockées dans la base de données comme UTF-8, cette partie fonctionne bien.Les données initiales lues était le problème.) – Piskvor

Répondre

12

Il s'avère que je n'ai pas assez lu la documentation - fgetcsv() est seulement quelque peu binaire-sûr. Il est sûr pour ASCII < 127, mais the documentation also says:

Note:

paramètres régionaux est pris en compte par cette fonction. Si LANG est par exemple en_US.UTF-8, les fichiers dans un octet codage sont mal lus par cette fonction

En d'autres termes, fgetcsv() essaie d'être binaire de sécurité, mais il est en fait pas (parce qu'il est aussi jouer avec le jeu de caractères en même temps), et il va probablement déformer les données qu'il lit (comme ce paramètre n'est pas configuré dans php.ini, mais plutôt lire à partir de $LANG).

J'ai éludé la question en lisant les lignes avec fgets (qui fonctionne sur les octets et non en caractères) et en utilisant a CSV function from the comment in the docs pour les analyser dans un tableau:

$fhandle = fopen($uploaded_file,'r'); 
while($raw_row = fgets($fhandle, 0)) { // fgets is actually binary safe 
    $row = csvstring_to_array($raw_row, ',', '"', "\n"); 
    // $row is now read correctly 
} 
+0

+1 belle prise! –

Questions connexes