Espace en trop PHP

Résolu/Fermé
DAG - 8 oct. 2008 à 11:16
 toto - 8 oct. 2008 à 17:31
Bonjour,
J'ai un probleme avec l'importation de données d'un fichier Excel CSV dans une base MySQL...
Je lis un fichier au format CSV du type "champs1;champs2;champs3\n".
Je trouve quelque fois des champs du genre : "champs1 ;champs2 ;champs3 \n"...
Je voudrais virer tous les espaces en trop à la fin de mes champs.
Voici mon code :
	foreach($lignes as $ligne)
	{
			$values = explode(";",$ligne);
			$statement = "INSERT INTO ma_table(mes_champs) VALUES(";
			foreach($values as $value)
			{
				$value=str_replace('  ','',$value);
				$value=str_replace('   ','',$value);
				$value=str_replace('    ','',$value);
				$value=addslashes($value);
				$value = trim($value);
				$statement .= "TRIM('$value'),";
			}
			$statement = substr($statement,0,strlen($statement)-1);
			$statement.= ");";
			mysql_query($statement) or die('<br>Erreur base de donnée !<br>'.$statement.'<br>'.mysql_error());
			echo $statement . "<br>";
	}

Comme vous pouvez le voir j'ai essayé plusieurs manips avec addslashes, trim et str_replace pour essayer d'enlever les espaces en fin de chaine. Le probleme c'est qu'il reste sur certains champs un espace à la fin !! Je n'arrive pas à le virer !
Si quelqu'un à un idée...
A voir également:

19 réponses

Bonjour

Quelques remarques :
- $values = explode(";",$ligne); En général,on ne récupère pas un fichier CSV comme ça. Et s'il y a un ; dans un de tes champs, voire un champ sur plusieurs lignes ? Il y a des fonctions spécifiques CSV en PHP.
- $value=str_replace(' ','',$value); et s'il y a quelques espaces à l'intérieur d'un champ, il seront virés aussi ?
- le trim en PHP et celui en sql font double emploi, mais je me doute bien que c'est en désespoir de cause que tu as cumulé les fonctions
- une insertion sans une base mysql doit toujours se faire avec un mysql_real_escape_string sur tous les champs texte (et pas un addslashes comme on le voit souvent sur ce forum)

Pour ce qui est d'avoir un espace en trop, n'aurais-tu pas des champs de longueur fixe, genre VARCHAR (10) ? Si tu fournis des données trop courtes, mysql complète au nombre de caractères avec des espaces.
0
pardon, c'est CHAR(10) qui est de dimension fixe, pas VARCHAR !
0
Merci pour ta réponse.
- $values = explode(";",$ligne); Le fichier CSV ce n'est pas moi qui le génère il m'est fournis comme ça... Il faut donc l'ouvrir avec Excel et remplacer (ctrl+f) les ";" par des "," s'il y en a, avant de le rentrer dans mon appli... C'est la seule solution que j'ai pu trouver.
- $value=str_replace(' ','',$value); il n'y a pas qu'un espace dans le premier paramètre ' ' il y en a plusieurs. Car non je ne veux pas que tous les espaces soit virer !
- le trim en PHP et celui en sql font double emploi, Oui c'était vraiment car je ne sais plus quoi faire !!...
- mysql_real_escape_string Ok je vais remplacer mon addslashes !

Dans MySQL le type de mes champs est varchar(50), ça ne devrait pas poser de problèmes si ?

J'ai essayer d'autre choses, j'ai fait un $value=str_replace(' ','',$value); pour supprimer TOUS les espaces comme tu disais. Voici le FOREACH (bon il faudra virer le addslashes !) :
$value=str_replace(' ','',$value);
$value=addslashes($value);
$statement .= "'$value',";

Constatation : il ne supprime pas les espaces !! Il sont tous là dans ma base !!

Je me demande donc s'il ne faut travailler sur le $values plutot que $value. Et ainsi faire le trim sur $values[x] ?

Soit je ne comprend pas bien soit il y a un truc que je ne vois pas !!

Si quelqu'un voit ou est le problème !?
0
Le fichier CSV ce n'est pas moi qui le génère Je m'en doute bien... ça ne change rien au fait qu'il y a des fonctions adaptées au traitement des fichiers CSV, qui t'éviteraient de passer par excel comme intermédiaire. Ton fichier de départ est bien en CSV ? De plus, en CSV, tu as tout à fait le droit d'avoir un ; dans un champ, ça marche très bien alors qu'en utilisant explode tu interdis cette possiblilité.

il n'y a pas qu'un espace dans le premier paramètre J'avais bien vu. C'est bien pourquoi j'avais mis "quelques espaces" dans ma remarque, que je maintiens.

str_replace(' ','',$value); pour supprimer TOUS les espaces comme tu disais Ah bon, où ai-je dit ça ? Tu as besoin d'un trim, et seulement d'un trim

et dépêche-toi de remplacer le addslashes par un mysql_real_escape_string !

Sinon, le type VARCHAR(50) me semble tout à fait correct.
Comment constates-tu la présence d'un espace en trop dans ta base ? avec phpmyadmin ? avec un lstrlen() sur une variable relue par un script ? Visuellement sur une page générée d'après la base ?
As-tu remarqué dans quel cas l'espace est là ? toujours dans le même champ ou dans n'importe lequel ? Quand il y a un nombre impair de caractères ?
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
En fait pour expliquer clairement la situation, j'ai plusieurs sources de données que je reçois. Ces sources sont au format Excel XLS. Il y a donc plusieurs source données qui viennent de différents organismes mais qui contiennent en gros les mêmes données (du genre nom prénom adresse... et d'autres qui sont la ou pas).

Le but de l'application, c'est de créer une base de données de référence avec toutes ces sources.

Il y a donc une première manip à faire (pour moi) : transformer le XLS en CSV... Une fois cette manip faite je rentre le fichier CSV dans mon appli qui rentre ce même fichier dans une base dite "tampon".
Ensuite je compare les champs de toutes les base tampon (image de mes ficher CSV) à ma base de donnée de référence.

Le probleme c'est que j'ai remarqué que si je rentre 2 fois le même fichier Excel, la base de donnée de référence grossie. Alors qu'elle ne devrait pas car si les utilisateurs sont déjà dedans, il n'y en a pas de nouveau, il ne doit pas en ajouter.
Pour voir si mes utilisateurs sont déjà dans la base de reférence, je fais un test sur le NOM+PRENOM+DATE DE NAISSANCE.
Du genre SELECT #champs# FROM table_tampon INNER JOIN table_reference ON (table_tampon.NOM = table_reference.NOM AND table_tampon.PRENOM = table_reference.PRENOM AND table_tampon.DATENAISSANCE = table_reference.DATENAISSANCE

Voila pour la description.

Je me suis donc penché sur le fichier CSV que je reçoit (je l'est ouvert avec un éditeur de texte afin de voir les ";") et j'ai remarquer que la plupart des lignes étaient formée de la façon suivante "chmps1;champs2...\n" SAUF quelques unes ou on peut trouver un ou plusieurs espaces entre la fin du champs et le ";" . J'ai donc utiliser TRIM pour virer les espaces en trop.
Mais lorsque j'ai refais des tests j'ai vu qu'il y avait encore des personnes qui s'ajoute en trop (en quelque sorte des doublons) dans la bas de référence.
J'ai donc affiché ma variable $valeur (celle dont on parle au dessus) en prennant soit de la souligner... Pour voir si le trait va plus loin que le text. Je me suis apperçu que certaine $valeur sont comme ça :
nom  
Je suis aussi allé voir dans phpMyAdmin, et je peux voir que en effet il y a des espaces à la fin des mêmes NOMS que j'avais repéré avec ma méthode de soulignage... Et aussi que ces même noms sont en "doublons" puisqu'ils ont été rentrés au préalable avec un autre fichier CSV, mais sans les espace.

Donc pour résumer mes tests, je rentre un fichier CSV dont je suis sur que mes routine marches. J'ai dont une base de référence avec 5000 entrées. Je rentre un deuxieme fichier CSV (celui sur lequel je travail) il me trouve 100 nouvelle personnes. OK.
Si je rerentre ce même fichier, il me trouve 50 personnes en plus. Et si je le rererentre, il me retrouve ces même 50 personnes....

Voila j'espère que je suis clair... Et désolé pour les longueurs... Si tu as une idée je suis preneur, car je débute, et je commence un peu à galèrer là...

Et sinon quelque chose qui n'a rien a voir : si tu as des infos sur les fonction CSV qui permettraient de ne pas passer par excel pour vider les ";" en trop je suis preneur !

Merci d'avance !
0
PS : J'ai essayer ça :
			foreach($values as $value)
			{
				echo "La valeur qui va être analysée est : " . $value . ".<br>";
				$derCarac = substr($value, -1);
				echo "Le dernier caratere de la valeur est : " . $derCarac . ".<br>";
				if(substr($value, -1) == "&#32;")
				{
					echo "Le dernier caractere est bien un espace. <br>";
					$value = substr($chaine,0,strlen($chaine)-1);
					$value=mysql_real_escape_string($value);
					$value = trim($value);
					echo "Voici la nouvelle valeur : <u>" . $value . "</u><br><br>";
					$statement .= "TRIM('$value'),";
				}
				else
				{
					echo "Le dernier caractere n'est pas un espace.<br>";
					$value=mysql_real_escape_string($value);
					$value = trim($value);
					echo "Voici la valeur finale : <u>" . $value . "</u><br><br>";
					$statement .= "TRIM('$value'),";
				}
			}

Pour les ligne du CSV qui posent problème il m'affiche "Le dernier caractère de la valeur est : .".
J'en déduit que le dernier caractère n'est pas un espace. Ou en tous cas pas un " ".
0
Pas facile de te suivre ...
post 3 : Le fichier CSV ce n'est pas moi qui le génère
post 5 :première manip à faire (pour moi) : transformer le XLS en CSV
Alors, le CSV, c'est toi qui le génère ou pas ?

j'ai remarqué que si je rentre 2 fois le même fichier Excel, la base de donnée de référence grossie. ça n'est peut-être pas ce que tu veux, mais ça a l'air tout à fait normal d'après le script que tu as montré. Il n'y a rien qui empêche d'insérer deux fois la même information.

si tu as des infos sur les fonction CSV . Elles ont dans le manuel de référence du PHP. Tu en as un , ou tu fais partie de ces génies qui travaillent toujours sans doc tellement ils connaissent tout par coeur ?

Autre question, les espaces , es-tu sûr qu'ils sont dans les nouveaux noms que tu insères, pas dans ceux déjà présents dans la base ? Je n'ai jamais vu que php ou mysql ajoutaient des espaces.
Peux-tu redonner une copie du script (avec trim et mysql_real_escape_string) où le problème se pose ?
0
Pour les fichiers CSV, en fait c'est un peu moi qui les gères ! Comme je l'est dis, je reçois un fichier au format XLS et je le transforme en CSV....
Donc voila le cheminement.
1- Je transforme le fichier XLS en un fichier CSV comme celui-ci : (il y a normalement 7000 lignes et des fois plus de champs comme l'adresse, la situtation de famille...)
ID DES PARENTS;NOM;PRENOM;DATE DE NAISSANCE\n
56;mamie;papy;01/02/1980\n
120;tata   ;tonton;08/10/1958\n
79;mémé;pépé ;06/07/1985\n

2- je rentre le fichier CSV qui "passe" dans le code suivant :
include '../bdd/bdd.php';
$file = "/tmp/child_file.csv";
$content = file_get_contents($file,'r');
$lignes = split("\n", $content);
$handle = fopen($file, "r");

while (($data = fgetcsv($handle, 0, ";")) !== FALSE) 
{
        $last_line++;
}
unset($lignes[0]);
unset($lignes[$last_line]);
foreach($lignes as $ligne)
{
	$values = explode(";",$ligne);
	$statement = "INSERT INTO tabletampon (#CHAMPS#) VALUES(";
	foreach($values as $value)
	{
		$value=mysql_real_escape_string($value);
		$value = trim($value);
		$statement .= "TRIM('$value'),";
	}
	$statement = substr($statement,0,strlen($statement)-1);
	$statement.= ");";
	mysql_query($statement) or die('<br>Erreur base de donnée !<br>'.$statement.'<br>'.mysql_error());
	}
	fclose($handle);

A ce moment là, le fichier est extrait dans une base tampon.

3- Il y a alors une fonction qui passe sur la base tampon pour récupérer les gens qui ne sont pas dans la base de référence afin de les ajouter :
$statementsOne = "SELECT #CHAMPS# FROM tabletampon WHERE (
tabletampon.NOM NOT IN (SELECT nom FROM table_ref)
AND 
tabletampon.PRENOM NOT IN (SELECT prenom FROM table_ref)
AND 
tabletampon.DATENAISSANCE NOT IN (SELECT date_anniv) FROM table_ref)
);";
$requOne = mysql_query($statementOne) or die(mysql_error());	
	
$date = date("d/m/Y");
while($data = mysql_fetch_array($requAdHorusOne))
{
	$statemenTwo = "INSERT INTO table_ref (#CHAMPS#) 
        VALUES (
        (SELECT ID FROM tableRefParent WHERE nom = '" . $data[NOM] . "' AND prenom = '" . $data[PRENOM] . "' AND         date_naissance = '" . $data[DATENAISSANCE] . "'), 
        '" . addslashes(trim($data[NOM])) . "', 
        '" . addslashes(trim($data[PRENOM])) . "', 
        '" . addslashes(trim($data[DATENAISSANCE])) . "', 
        '" . $date . "');";
        mysql_query($statementAdHorusTwo) or die('mysql_error());	
}

Et suite à cette fonction il y en a une autre qui suit pour comparer tous les champs de la table tampon à ceux de la table de référence pour relever ou sont les différences et les noter dans une autre table....Bref tu as là ce qu'il se passe en gros lorsque je rentre un fichier, et se qui peut faire qu'il y est certains champs qui est des espaces...
Et donc je pense que le probleme vient du premier script PHP. C'est à dire celui qui rentre le fichier CSV dans la base Tampon.
Et lorsque je rentre un nouveau fichier Exel, je vide la base tampon avant de la reremplir. Les différences, je les vois donc dans la base de référence. Si je rentre 2 fois le même fichier, il y a plus de monde que dans mon fichier et des "doublons" (qui n'en sont pas des vrais) dans la base de référence...
Voila
0
Désolé pour les addslashes et les trim dans le dernier bout de code, ils sont normalement pas là, c'était pour des tests....
0
ton début me semble un peu bizarre (je suis gentil). Tu lis le fichier 2 fois : une fois comme un simple fichier texte, c'est à dire mal puisqu'il s'agit de CSV, et une seconde fois comme du CSV. Mais de cette seconde lecture, tu ne retiens que le nombre de lignes, qui n'est d'ailleurs pas forcément compatible avec celui de la première lecture...
Bref, je verrais plutôt :
include '../bdd/bdd.php';
$file = "/tmp/child_file.csv";

$handle = fopen($file, "r");

while (($data = fgetcsv($handle, 0, ";")) !== FALSE) 
{
	$statement = "INSERT INTO tabletampon (#CHAMPS#) VALUES(";
	foreach($data as $value)
	{
		$value = trim($value);
		$value=mysql_real_escape_string($value); // l'ordre trim / mysql... est plus logique comme ça
		$statement .= "'$value',";
	}
	$statement = substr($statement,0,strlen($statement)-1);
	$statement.= ");";
	mysql_query($statement) or die('<br>Erreur base de donnée !<br>'.$statement.'<br>'.mysql_error());
	}
	fclose($handle);



Peux-tu préciser si c'est dans la tabletampon que tu vois tes caractères en trop ?
Peux-tu vérifier si le caractère en trop est un espace ou une tabulation ?
0
Je pense avoir trouvé l'erreur...
J'ai ouvert le fichier avec OpenOffice. Et j'ai découvert plein de caractères bizarres et surtout des � et ᅠ en fin de champs.
Donc tous les accents son remplacés par leur code HTML et il y a, à la fin de certains champs des caractères bizarres � et ᅠ
0
� =
&#65533; 
et
ᅠ =
&#65440;
0
Méfie toi de ce que tu vois avec Open Office.org quand tu ouvres un fichier texte. OOo est un traitement de texte, il fait ce qu'il peut avec les caractères qui ne lui plaisent pas et il peut les modifier sans te prévenir...

Si tu veux être absolument sûr de ce qu'il y a dans ton fichier initial, il faut l'ouvrir avec un éditeur hexadéciamal (ou l'ouvrir toi-même en binaire à partir d'un script)

Mais ton problème d'espaces, c'est bien que tes caractères bizarres ne sont pas des espaces.

Ce qui n'ôte rien à mes remarques sur le CSV et l'emploi de mysql_real_eascape_string.
0
Comment faire alors ?
J'ai essayé de le faire comme ça :
if(substr($value, -8) == "&#65533;" ||  substr($value, -8) == "&#65440;" ||  substr($value, -1) == " ")
	{
	echo "Le dernier caractere est bien bizarre. <br>";
	$value = substr($chaine,0,strlen($chaine)-1);
	$value = trim($value);
	$value=mysql_real_escape_string($value);
	echo "Voici la nouvelle valeur : <u>" . $value . "</u><br><br>";
	$statement .= "'$value',";
}

Sans succès...
Il y a toujours cet "espace" en fin de champs.
Je suis à la recherche de fonction php permettant de "lisser" ma chaîne de caractère mais je ne trouve pas...
Je ne te cache pas que ça commence à devenir un peu lourdingue tout ça !
0
J'ai ouvert mon fichier avec un éditeur hexadécimal (Ghex), mes champs cachés sont des points... "." -> A0
Je ne comprend plus rien, je n'arriverais jamais à me débarrasser des caractères en trop ???
0
Pourquoi ce test substr($value, -8) == "�" ? Ces 8 caractères sont parfaitement lisibles, et, s'ils étaient présents dans ton texte initial, tu les aurais vus.

Repère un nom qui a ces caractères bizarres. Supposons que ce soit dupond. Tu peux ajouter à l'intérieur de la boucle :
(exemple où c'est le nom, c'est à dire le 2ème champ de $value, c'est à dire celui d'indice 1)

if (substr($value[1],0,6)=="dupond") { // pour ne pas afficher toutes les lignes !!!
for ($k=0,$k<strlen($value[1]),$k++) echo ord(substr($value[1],k,1)),','; // affiche tous les codes ASCII
echo '<BR />';
}

comme ça, tu verras ce qu'il y a VRAIMENT comme codes bizarres

Et tu pourras ensuite les virer facilement avec un str_replace comme tu faisais au début
0
ça devrait le faire ...
$value=str_replace(chr(0xA0,'',$value);
$value=str_replace(chr(0xFD),'',$value);
0
ça marche ce coup ci ! J'ai pu voir les fameux caractères !
Merci beaucoup toto, vraiment !
J'aurais passé ma journée la dessus ! J'ai intérêt à rester tard ce soir pour rattraper mon retard...
Mais bon je progresse et c'est le principale.

Merci encore pour ton aide toto

A+
0
Au plaisir :)
0