8725 sujets

Développement web côté serveur, CMS

Bonjour à tous
J'ai un programme PHP qui exporte des données en .csv en utilisant la fonction putcsv

Tout fonctionne très bien, sauf pour les numéros de téléphone qui sont compris comme des nombres entiers.
Je n'ai pas trouvé dans https://www.php.net/manual/fr/function.fputcsv.php une façon de dire qu'une chaîne de caractères numériques ne doit pas être confondue avec un nombre.
J'ai essayé de modifier la chaîne de caractère en ajoutant un espace avant ou après, cela ne change rien.
Ce n'est pas un très gros problème mais j'aimerais savoir comment faire.
Merci de votre aide
J’utilise heredoc à foison, c’est une façon de définir une chaîne de caractères. fputcsv prend comme paramètre Fields un array de chaînes de caractères, peu importe la façon de définir ces chaînes de caractères.
Le code en question est dans la partie admin de mon site, il faudrait que je fasse un ficher de test pour pouvoir le partager. Je vais essayer de faire ça.
Modifié par PapyJP (15 Apr 2024 - 09:55)
Administrateur
Bonjour,

Est-ce que c'est le fichier CSV lui-même qui a un souci ou bien ensuite son utilisation dans, au hasard (non), Excel ?

Idées comme ça :
un préfixe +33 peut-être (+33612345678) ? Ceci dit un + est aussi numérique
Sinon "0612345678" avec les guillemets (ou single quotes) ?
Le test est dans https://www.alma-musica.net/tests/csv-test.php
Le code :

<?php
	$TABLE = [
		["Nom", "Prénom", "Téléphone"],
		["Dupont", "Jacques", "0612345678"],
		["Duval", "Armand", "+33123456789"]
	];
	$csvTable = mb_convert_encoding($TABLE, 'Windows-1252', 'UTF-8');
	header('Content-Type: application/csv');
	header('Content-Disposition: attachment; filename="' . "Tests.csv" . '";');
	$f = fopen('php://output', 'w');
	foreach($csvTable as $row) fputcsv($f, $row, ';');
	die();
?>

ça demande où enregistrer le fichier Tests.csv
Quand on ouvre le fichier sous Excel (version française, d'où le ';' dans fputcsv($f, $row, ';');)
on obtient
upload/1712667670-48769-tests-csv.png
Si j'écris

<?php
	$TABLE = [
		["Nom", "Prénom", "Téléphone"],
		["Dupont", "Jacques", "\"0612345678\""],
		["Duval", "Armand", "\"+33123456789\""]
	];
	$csvTable = mb_convert_encoding($TABLE, 'Windows-1252', 'UTF-8');
	header('Content-Type: application/csv');
	header('Content-Disposition: attachment; filename="' . "Tests1.csv" . '";');
	$f = fopen('php://output', 'w');
	foreach($csvTable as $row) fputcsv($f, $row, ';');
	die();
?>

j'obtiens
upload/1712667937-48769-tests1-csv.png

C'est à peine mieux.
Modifié par PapyJP (09 Apr 2024 - 15:06)
Modérateur
Bonjour,

Tu peux tenter d'ajouter une apostrophe devant (mais pas derrière) les chaines qui ne doivent pas être comprises comme des nombres (sans garantie que ça marche avec toutes les versions d'excel). Par exemple :
	$TABLE = [
		["Nom", "Prénom", "Téléphone"],
		["Dupont", "Jacques", "'0612345678"],
		["Duval", "Armand", "'+33123456789"]
	];


EDIT: ça peut aussi dépendre de la manière dont on importe le csv dans le tableur. Y a des options du genre "champs entre guillemets considérés comme texte". Il peut y avoir aussi d'autres options dans le tableur qui selon qu'elles sont activées ou pas perturbent le processus genre "Nombres mis en forme en tant que texte ou précédés d’une apostrophe". Et tout ça peut aussi dépendre du tableur (excel ? ou logiciel lisant des fichiers excel comme OpenOffice ?) et de leurs versions.

Amicalement,
Modifié par parsimonhi (09 Apr 2024 - 16:21)
J’ai aussi essayé le guillemet simple comme tu le proposes. Ça ne marche pas mieux.
Encore une fois ce n’est pas très important pour ce que j’en fais, c’est plutôt par curiosité pour voir s’il existerait une solution. Je suis assez doué pour ne pas voir les choses évidentes !!
Modifié par PapyJP (09 Apr 2024 - 17:21)
Modérateur
Bonjour,

PapyJP a écrit :
J’ai aussi essayé le guillemet simple comme tu le proposes. Ça ne marche pas mieux.

Il ne faut pas s'arrêter au dialogue montrant le "tableau" initial d'importation (dans OpenOffice, ils appellent ce dialogue "Import de texte"). Il faut continuer et cliquer sur un bouton genre "OK" (je ne sais pas comment c'est sur excel, mais dans OpenOffice, c'est "OK"), et ainsi afficher le csv dans le tableur.

Amicalement,
Modifié par parsimonhi (09 Apr 2024 - 19:18)
Modérateur
Bonjour,

Je t'invite à générer le fichier csv sans jamais l'ouvrir avec Excel. Ensuite, ouvres-le avec Notepad ou un éditeur de texte simple. Tu seras alors fixé si c'est ton code le problème ou Excel qui s'amuse à interpréter et changer le contenu. Je parierais que c'est Excel.
Bonjour,
Si tu ouvres ton fichier avec LibreOffice tu peux définir le type de chaque colonne (texte, nombre, date, etc...). Excel fait la même chose mais il faut changer l'extension du fichier csv.
Renommé le fichier .csv en .txt
Merci de vos réponses.
Apparemment il n’est pas possible de faire ça en .csv. Bien sûr on peut changer le type des cellules d’une colonne dans les tableurs, mais c’est une information qui ne pqqe pas en .csv
Bonsoir,

En fait c'est l'import par défaut d'excel qui est complètement stupide. ON ne peut juste pas lui faire confiance. J'ai déjà vu les choses suivantes:

- IL change des dates du format anglais ou ISO au format français, puis sauvegarde en format français (ce n'est pas juste de l'affichage)
- Il supprime les zéros en préfixe ou en suffixe dans des numéros à usage administratif du genre "045.390" car il les interprète incorrectement comme nombre, et il le fait parfois même pour les adresse IP v4 ou v6 (donc pas étonnant qu'il fasse la même chose avec des numéros de téléphone)
- IL change des trucs genre "60%" en "0.6"
- Il impose l'encodage Windows-1252 en entrée comme en sortie (en 2024 ça ne devrait plus exister, ça devrait être UTF-8 pour tout le monde)


En réalité, le format CSV n'est pas ou très très peu normé. IL n'y a pas (à ma connaissance en tout cas) un standard officiel comme on en a en XML, JSON, YAML, TOML, et tant d'autres formats de données structurées. Pas surprenant, donc, que chacun interprète à sa sauce !
Tout le monde n'est même pas d'accord sur le séparateur ! Dans le monde anglophone on utilise "," alors qu'en francophonie on utilise plutôt ";".
Quand on a des données qui contiennent elles-mêmes plusieurs lignes, le séparateur ou des guillemets, ça devient carrément l'enfer...

Si le but est de faire des transferts de base de donnée à l'autre, le plus simple est encore d'exporter du SQL. D'expérience personnelle, c'est 100 fois plus interopérable.
Merci de ces remarques que je partage entièrement.
À remarquer que si j'exporte des numéros de téléphone en .csv depuis une feuille Excel et que je la recharge, j'ai exactement le même résultat, c'est bien la preuve que je ne peux rien faire de plus.

Mon but est de permettre à certains utilisateurs de charger éventuellement le contenu d'une table sous Excel.
Je ne suis pas sûr que ce soit très utile dans la pratique, c'est juste au cas où.
Dans la plupart des cas j'utilise bien entendu le format .sql pour exporter ce type de données,
mais si je fais ça dans ce cas précis je vais perturber les utilisateurs.

Je vais laisser les choses en l'état.
Bonsoir,

Si tu vise spécifiquement un export excel, il serait certainement plus intéressant d'investir dans une bibliothèque qui peut générer des fichiers au format excel directement, car comme tu l'as constaté, le CSV c'est pas génial pour cet usage.

Il en existe des gratuites. Par exemple, apache POI en Java. IL doit aussi y en avoir en python, PHP et JavaScript.
Merci, je n'y avais pas pensé, mais ça veut dire apprendre une nouvelle techno pour quelque chose de marginal, je ne vais pas me lancer là-dedans.
Modifié par PapyJP (17 Apr 2024 - 19:42)
Une solution à laquelle j'aurais dû penser : comme il s'agit de numéros français, parfois sous la forme +33.... j'ai modifié le calcul de la chaîne de caractères à afficher

if(preg_match('#^\d+$#', $val)) $val = preg_replace('#^(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)#', '$1.$2.$3.$4.$5', $val);
elseif(preg_match('#^\+#', $val)) $val = preg_replace('#^(\+\d\d)(\d)(\d\d)(\d\d)(\d\d)(\d\d)#', '$1-$2.$3.$4.$5.$6', $val);