pb upload (changement : caractère spéciaux et UTF-8)

Eléphant du PHP | 188 Messages

11 sept. 2011, 21:22

Mais comme tu utilises PDO autant faire ta requête suivant le modèle PDO.
J'utilise PDO, dans le code que j'ai mit j'ai bien mit la connexion a ma BDD avec PDO, l'execution de ma requette est faite par :
$connexion->exec($sql)
avec $connexion comme ressource de connexion BDD.

merci :)

ViPHP
AB
ViPHP | 5818 Messages

11 sept. 2011, 21:54

Tu aurais pu essayer ce que j'ai écris, ça aurait fonctionner quand même.

Mais bon soit, faisons tout avec pdo c'est plus logique (et recommandé). Donc prends la requête que je t'ai indiquée et transforme la pour la syntaxe PDO.

Eléphant du PHP | 188 Messages

11 sept. 2011, 22:14

Oui je préfere PDO :)
$sql = "('INSERT INTO chansons(titre, artiste, id_artiste, date_envoi, vues, note, description, adresse_chanson) VALUES('".$fichier."', '".$artiste."', '".$id_artiste."', NOW(), '".$vues."', '".$note."', '".$adresse_chanson."')')";

$connexion->exec($sql);
C'est ça ?

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

11 sept. 2011, 23:55

quote pour "sécuriser" la requête.

Au final a tu testé l'upload dans un coin et la requête dans un coin ?

@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 188 Messages

12 sept. 2011, 20:55

$sql = "INSERT INTO chansons(titre, artiste, id_artiste, date_envoi, vues, note, description, adresse_chanson) VALUES('".$connexion->quote($fichier)."', '".$connexion->quote($artiste)."', '".$connexion->quote($id_artiste)."', NOW(), '".$connexion->quote($vues)."', '".$connexion->quote($note)."', '".$connexion->quote($adresse_chanson)."')";
                                 
                                 // Ligne temporaire pour vérification
                                 echo $sql;
                                 
                                 // exécution de la requête
                                 $connexion->exec($sql);
L'upload fonctionne, rien dans la BDD. Aussi, le echo $sql; ne retourne rien ! --'
Oui, l'upload fonctionne parfaitemment, l'enregistrement BDD par contre je ne l'ai pas testé seul car il dépend du résultat de l'upload.

Merci :D

ViPHP
AB
ViPHP | 5818 Messages

13 sept. 2011, 04:52

Testes ta requête dans une page séparée en mettent des mots quelconque à la place du nom de fichier et des autres variables.

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

13 sept. 2011, 11:08

on va reprendre le code depuis le début (enfin le dernier code entier), après remise en forme ça donne ceci (histoire que l'on parle de la même chose)
<?php
// Enregistrement en bdd des valeurs récupérées par le post
if (isset($_POST['form1'])){
                 // Récupération des valeurs du transfert de fichiers
                 $transfert = $up->Get_Tab_upload();
                 // Si un fichier a été transférer
	 if (!empty ($transfert)){
		 // Récupération du non du fichier transféré
		 $resultat = $transfert['resultat'];//tableau à trois dimensions (c.f. Doc de la class pour plus de détails)

		 foreach ($resultat as $num => $rep){
			 foreach ($rep as $key => $value){
				 $fichier =  $value['nom'];// Nom du fichier transféré
				 $dossier =  $key; // Nom du dossier                      
			}    
		}
		 // Récupération de tes autres valeurs
		//on regarde si la description est remplie
	if ((isset($_POST['description'])) AND (!empty($_POST['description'])))
			{
			$description = $_POST['description'];
			}
	else
			{
			$description = '';
			}
	if ((isset($_POST['style'])) AND (!empty($_POST['style'])))
			{
			$style = $_POST['style'];
			}
	else
			{
			$style = '';
			$_SESSION['info_style'] = 0;
			}
		 
		 // Connexion à ta bdd
		// connexion BDD par PDO

	$PARAM_hote='localhost';      // le chemin vers le serveur
	$PARAM_port='3306';
	$PARAM_nom_bd='monsite';          // le nom de votre base de données
	$PARAM_utilisateur='root';    // nom d'utilisateur pour se connecter
	$PARAM_mot_passe='';          // mot de passe de l'utilisateur pour se connecter

	try{
			$connexion = new PDO('mysql:host='.$PARAM_hote.';port='.$PARAM_port.';dbvalue='.$PARAM_nom_bd, $PARAM_utilisateur, $PARAM_mot_passe);
			/* BDD connectee */
	}
	catch(Exception $e){
	/* erreur connection */
	echo 'Une erreur est survenue !';
	echo 'Erreur : '.$e->getMessage().'<br />';
	echo 'N° : '.$e->getCode();
	die();
	}
	//   /fin de la connexion BDD par PDO-->
	//exemple de requête avec mysql (protéger les valerurs par mysql_real_escape_string) ou utiliser PDO --> j'utilise PDO
	 $artiste = $_SESSION['pseudo'];
	 $id_artiste = $_SESSION['id'];
	 $vues = 0;
	 $note = 0; 
	 $adresse_chanson = $dossier.'/'.$fichier;
	$sql = "INSERT INTO chansons(titre, artiste, id_artiste, date_envoi, vues, note, description, adresse_chanson) 
	VALUES('".$connexion->quote($fichier)."', 
	'".$connexion->quote($artiste)."',
	'".$connexion->quote($id_artiste,PDO::PARAM_INT)."', NOW(), 0,0, 
	'".$connexion->quote($adresse_chanson)."')";
	 // Ligne temporaire pour vérification
	 echo $sql;
	 // exécution de la requête
	 $connexion->exec($sql);
	  // Rechargement de la page pour éviter un multi upload        
	  $up->Get_Reload_page();
	}
}
?>
donc ligne 11 à 16 il y a un foreach qui est prévue pour traiter les infos de sortie de la classe
<?php
foreach ($resultat as $num => $rep){
			 foreach ($rep as $key => $value){
				 $fichier =  $value['nom'];// Nom du fichier transféré
				 $dossier =  $key; // Nom du dossier                      
			}    
		}
?>
or quelque soit le nombre de fichier uploadé avec la classe il est certain que tu n'aura qu'un seul retour vu que tu écrase à chaque fois $fichier et $dossier !
pour un fichier cela ne pose pas de problème, mais dans ce cas autant virer le foreach ;)

Connexion au sgbd :
<?php
$connexion = new PDO('mysql:host='.$PARAM_hote.';port='.$PARAM_port.';dbvalue='.$PARAM_nom_bd, $PARAM_utilisateur, $PARAM_mot_passe);
?>
le port est facultatif car le 3306 est le port par défaut pour mysql.
ce n'est pas dbvalue mais dbname
exemple
<?php
$db = new PDO('mysql:host=localhost;dbname=test','root');
$db -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
?>
le mot de passe est optionnel car vide, ceci dit je ne pense pas que cela soit le cas sur ton hébergement en ligne donc le mieux c'est de le garder :)
la ligne setattribute, sert a indiquer le mode d'erreur, plus d'info sur la doc
Pourquoi warning ? parce que tu n'utilise pas de try / catch pour le query donc autant prendre les devants ;)
ta table :
lorsque le vois artiste et id_artiste dans la même table j'y vois une redondance, c'est a éviter, supprime la colonne artiste, je suppose que ceci est récupérable via l'id_artiste qui fait la jointure avec une quelconque table utilisateur ?

$vue et $note étant fixe pas la peine d'utiliser des variables utilise directement la valeur dans la requête.
vue qu'il s'agit de nombre pas besoin de ' ce ne sont pas des chaine de caractère.

//exemple de requête avec mysql (protéger les valerurs par mysql_real_escape_string) ou utiliser PDO --> j'utilise PDO

Pas du tout d'accord PDO c'est pas la boite à miracle si tu ne l'utilise pas correctement, il existe un "équivalent" à mysql_real_escape_string qui est la méthode quote.
lorsque tu utilise une requête préparée (à la limite justifiable en cas d'upload multiples, bien qu'une requete insert correctement formulée fait la même chose en utilisant moins de ressource (pour 400 insertions on utilise prépare hein, mais 3 ou 4 pas la peine ^^).

au final cela donne
<?php
// Enregistrement en bdd des valeurs récupérées par le post
if (isset($_POST['form1'])){
                 // Récupération des valeurs du transfert de fichiers
                 $transfert = $up->Get_Tab_upload();
                 // Si un fichier a été transférer
	 if (!empty ($transfert)){
		 // Récupération du non du fichier transféré
		 $resultat = $transfert['resultat'];//tableau à trois dimensions (c.f. Doc de la class pour plus de détails)

		foreach ($resultat as $num => $rep){
			 foreach ($rep as $key => $value){
				 $fichier =  $value['nom'];// Nom du fichier transféré
				 $dossier =  $key; // Nom du dossier                      
			}    
		}
		 // Récupération de tes autres valeurs
		//on regarde si la description est remplie
	if ((isset($_POST['description'])) AND (!empty($_POST['description'])))
			{
			$description = $_POST['description'];
			}
	else
			{
			$description = '';
			}
	if ((isset($_POST['style'])) AND (!empty($_POST['style'])))
			{
			$style = $_POST['style'];
			}
	else
			{
			$style = '';
			$_SESSION['info_style'] = 0;
			}
		 
		 // Connexion à ta bdd
		// connexion BDD par PDO

	$PARAM_hote='localhost';      // le chemin vers le serveur
	$PARAM_port='3306';
	$PARAM_nom_bd='monsite';          // le nom de votre base de données
	$PARAM_utilisateur='root';    // nom d'utilisateur pour se connecter
	$PARAM_mot_passe='';          // mot de passe de l'utilisateur pour se connecter

	try{
			$connexion = new PDO('mysql:host='.$PARAM_hote.';port='.$PARAM_port.';dbname='.$PARAM_nom_bd, $PARAM_utilisateur, $PARAM_mot_passe);
			$db -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
			/* BDD connectee */
	}
	catch(Exception $e){
		/* erreur connection */
		echo 'Une erreur est survenue !';
		echo 'Erreur : '.$e->getMessage().'<br />';
		echo 'N° : '.$e->getCode();
		die();
	}
	//   /fin de la connexion BDD par PDO-->
	//exemple de requête avec mysql (protéger les valerurs par mysql_real_escape_string) ou utiliser PDO --> j'utilise PDO::quote
	 $artiste = $_SESSION['pseudo'];
	 $id_artiste = $_SESSION['id'];
	 $adresse_chanson = $dossier.'/'.$fichier;
	$sql = "INSERT INTO chansons(titre, artiste, id_artiste, date_envoi, vues, note, description, adresse_chanson) 
	VALUES('".$connexion->quote($fichier)."', 
	'".$connexion->quote($artiste)."',
	'".$connexion->quote($id_artiste,PDO::PARAM_INT)."', NOW(), 0,0, 
	'".$connexion->quote($adresse_chanson)."')";
	 // Ligne temporaire pour vérification
	 echo $sql;
	 // exécution de la requête
	 $nbAffect = $connexion->exec($sql);
	 if ($nbAffect === 0 ) {
		//message d'erreur il ne pas y avoir zéro insertion !
	 }
	 else {
		// Rechargement de la page pour éviter un multi upload        
		$up->Get_Reload_page();
	  }
	}
}
?>
pour info, lorsque l'on debug il faut virer tout ce qui est redirection et die car dans ce cas on ne peux pas forcément voir les éventuels messages d'erreurs.

je pense que ton soucis est, au final, le mauvais "dsn" de PDO ! (le test a part comme l'indique AB l'aurais indiqué je pense).


@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 188 Messages

13 sept. 2011, 17:36

Bon alors d'abord j'ai testé la requette :
// Connexion à ta bdd
                 // connexion BDD par PDO

         $PARAM_hote='localhost';      // le chemin vers le serveur
         $PARAM_port='3306';
         $PARAM_nom_bd='monsite';          // le nom de votre base de données
         $PARAM_utilisateur='root';    // nom d'utilisateur pour se connecter
         $PARAM_mot_passe='';          // mot de passe de l'utilisateur pour se connecter

         try{
                         $connexion = new PDO('mysql:host='.$PARAM_hote.';port='.$PARAM_port.';dbname='.$PARAM_nom_bd, $PARAM_utilisateur, $PARAM_mot_passe);
                         $connexion -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
                         /* BDD connectee */
         }
         catch(Exception $e){
                 /* erreur connection */
                 echo 'Une erreur est survenue !';
                 echo 'Erreur : '.$e->getMessage().'<br />';
                 echo 'N° : '.$e->getCode();
                 die();
         }
         //   /fin de la connexion BDD par PDO-->
         //exemple de requête avec mysql (protéger les valerurs par mysql_real_escape_string) ou utiliser PDO --> j'utilise PDO::quote
          $artiste = 'artiste';
          $id_artiste = 23;
		  $titre = 'mamusique';
		  $description = 'super description !';
          $adresse_chanson = 'monadresse';
		  $fichier = 'fichier';
         $sql = "INSERT INTO chansons(titre, artiste, id_artiste, date_envoi, vues, note, description, adresse_chanson) 
         VALUES('".$connexion->quote($fichier)."', 
         '".$connexion->quote($artiste)."',
         '".$connexion->quote($id_artiste,PDO::PARAM_INT)."', NOW(), 0,0, 
         '".$connexion->quote($adresse_chanson)."')";
          // Ligne temporaire pour vérification
          echo $sql;
          // exécution de la requête
          $nbAffect = $connexion->exec($sql);
		  ?>
Dans une page a part, le résultat est :
( ! ) Warning: PDO::exec() [pdo.exec]: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'fichier'', ''artiste'', ''23'', NOW(), 0,0, ''mo' at line 2 in C:\wamp\www\Code\pages\test.php on line 53
Call Stack
# Time Memory Function Location
1 0.0017 375928 {main}( ) ..\test.php:0
2 0.0149 383600 PDO->exec( ) ..\test.php:53
Je comprends que j'ai fait une erreur de syntaxe dans ma requette SQL ? mais où ?

donc ligne 11 à 16 il y a un foreach qui est prévue pour traiter les infos de sortie de la classe
<?php
foreach ($resultat as $num => $rep){
			 foreach ($rep as $key => $value){
				 $fichier =  $value['nom'];// Nom du fichier transféré
				 $dossier =  $key; // Nom du dossier                      
			}    
		}
?>
or quelque soit le nombre de fichier uploadé avec la classe il est certain que tu n'aura qu'un seul retour vu que tu écrase à chaque fois $fichier et $dossier !
pour un fichier cela ne pose pas de problème, mais dans ce cas autant virer le foreach ;)
J'ai laissé le foreach car j'ai copié le code de AB sans chercher a modifier pour ne pas risquer de retirer quelquechose d'essentiel, mais je me doutais bien que ces foreachs étaient inutiles car je n'upload qu'un seul fichier à la fois.

je pense que ton soucis est, au final, le mauvais "dsn" de PDO !
Le dsn ? c'est quoi ?

Enfin, j'ai testé ton dernier code que tu ma donné dans ma page d'upload, et rien dans la BDD mais aucune message d'erreur non plus ...

Merci beaucoup pour vos réponses :D

ViPHP
AB
ViPHP | 5818 Messages

13 sept. 2011, 19:59

Le double foreach pour la récupération du résultat vient du fait que l'on peut avoir un upload multiple avec plusieurs redimensionnements par fichier (en cas d'images) vers des répertoires distincts. Et comme qui peut le plus, peut le moins, je garde cette structure générique quelque soit le type d'upload, en cas d'évolution du code c'est plus simple à gérer.

Si tu tiens à enlever le double foreach, dans ton cas on pourrait écrire :
if (isset($_POST['form1']))
  {
	// Récupération des valeurs du transfert de fichiers
	$transfert = $up->Get_Tab_upload();
		
	// Si un fichier a été transférer ($repertoire_destination est la même variable que celle déclarée dans la classe d'upload)
	if (isset($transfert) && !empty($transfert['resultat'][0][$repertoire_destination]['nom']))
	   {
                
                $fichier = $transfert['resultat'][0][$repertoire_destination]['nom'];
                
                // suite du code
Sinon pour ta requête tu n'en as pas une autre qui fonctionne sur ton site ? Si oui tu pourrais prendre modèle dessus.

Eléphant du PHP | 188 Messages

13 sept. 2011, 20:50

Et bien je ne ne tiens pas forcémment a retiré le foreach il ne change rien au résultat de l'upload donc oui autant le laissé sais-t-on jamais s'il me sert plus tard ^^
Si j'utilise beaucoup d'autres requettes, et par exemple pour l'inscription (donc avec INSERT) j'utilise une requette préparée. Je fais celle ci avec une prep ?

ViPHP
AB
ViPHP | 5818 Messages

14 sept. 2011, 01:00

Si j'utilise beaucoup d'autres requettes, et par exemple pour l'inscription (donc avec INSERT) j'utilise une requette préparée. Je fais celle ci avec une prep ?
Que la requête soit préparée n'est pas nécessaire sur le principe dans ton cas, mais cela ne gêne pas et est normalement un peu plus sécurisé. Donc oui prends modèle sur ce qui fonctionne après tu pourras toujours modifier pas à pas si besoin pour comprendre ce qui ne fonctionnait pas dans le code précédent.


Sinon il y avait une petite erreur dans mes précédents code au niveau du commentaire "// Si un fichier a été transféré".
En effet la ligne qui suit : if (!empty ($transfert)) ne garanti pas qu'un fichier a été transféré (car $transfert est un tableau à plusieurs dimensions). Donc la bonne façon de faire le test est de tester la variable $fichier comme ci-dessous (ou de prendre exemple sur le code sans foreach que je t'ai donné dans mon précédent message).

// Enregistrement en bdd des valeurs récupérées par le post
if (isset($_POST['form1']))
{

      // Récupération des valeurs du transfert de fichiers
      $transfert = $up->Get_Tab_upload();//tableau à plusieurs dimensions (c.f. Doc de la class pour plus de détails)
                 
      // définition d'une valeur par défaut
      $fichier = null;

      if (isset($transfert['resultat']))
           {
               foreach ($transfert['resultat'] as $num => $rep)
                    {
                         foreach ($rep as $key => $value)
                             {
                                  if(!empty($value['nom'])) $fichier =  $value['nom'];// Nom du fichier transféré
                                  $dossier =  $key; // Nom du dossier 
                             }                     
                    }    
           }

       
     if(isset($fichier))
           {
                  // là on est certain que le code entre ces accolades ne s'exécutera que si un fichier à été téléchargé
				
	          // suite du code récupération des autres variables et enregistrement en bdd
			 
				
	          // En fin de code : Rechargement de la page pour éviter un multi upload en cas de rafraichissement de la page	
	         $up->Get_Reload_page();
           }				
			
				 
}

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

14 sept. 2011, 03:35

au final je pense qu'il est complétement perdu et attend une solution complètement fonctionnelle avec un copier coller ?

une erreur de syntaxe, oui j'ai laissé trainer les ' alors que j'ai utiliser quote, donc y a des '' pour les chaines
$sql = "INSERT INTO chansons(titre, artiste, id_artiste, date_envoi, vues, note, description, adresse_chanson)
VALUES(".$connexion->quote($fichier).",
".$connexion->quote($artiste).",
".$connexion->quote($id_artiste,PDO::PARAM_INT).", NOW(), 0,0,
".$connexion->quote($adresse_chanson).")";

le "dsn" c'est la partie où tu indique le sgbd que tu utilise (la mysql) l’hôte, le port et le nom de la base.

je te conseil vivement de lire et tester un tuto sur PDO (par exemple http://www.siteduzero.com/tutoriel-3-34 ... x-bdd.html) afin de bien comprendre ce qui se trame dans ton code.

d'ailleurs pour le foreach a laisser parce que heu c'est comme ça, si jamais tu essai d'utiliser un upload multiple cela en fonctionnera pas comme tu le souhaite (voir mon message précédent).

@+
Il en faut peu pour être heureux ......

ViPHP
AB
ViPHP | 5818 Messages

14 sept. 2011, 12:56

d'ailleurs pour le foreach a laisser parce que heu c'est comme ça, si jamais tu essai d'utiliser un upload multiple cela en fonctionnera pas comme tu le souhaite (voir mon message précédent).
@+
...il aurait juste à remplacer la ligne
if(!empty($value['nom'])) $fichier =  $value['nom'];
par
$fichier[] =  $value['nom'];
et ensuite, à la suite de "if(isset($fichier))" il suffirait de lister le tableau $fichier pour valider les formulaires qui contiennent ou non un fichier et qui peuvent être enregistrés en bdd.

En laissant la structure telle qu'elle est, je trouve qu'on voit plus facilement les petites modifs à faire pour une future évolution... sans avoir besoin de retrouver le mode d'emploi.
Mais bon peu importe, je lui ai donné également l'exemple sans les foreach, il choisira bien ce qu'il veut, et ce n'est pas vraiment un souci puisque l'upload fonctionne. C'est la requête qui pose pb :)

Eléphant du PHP | 188 Messages

14 sept. 2011, 14:47

au final je pense qu'il est complétement perdu et attend une solution complètement fonctionnelle avec un copier coller ?
Oui je suis perdu, mais non je n'attends pas forcémment du clé en main parce que je sais bien que ça ne me fera pas avancé ^^ Cependant votre aide, comme vous me l'apportez depuis le début de ce sujet, me fera progresser tout en trouvant une solution à ce code.
d'ailleurs pour le foreach a laisser parce que heu c'est comme ça, si jamais tu essai d'utiliser un upload multiple cela en fonctionnera pas comme tu le souhaite (voir mon message précédent).
Ne vous embétez pas avec cette histoire de multi-upload, je ne le ferais jamais je fait qu'un seul upload à la fois, ça correspond mieux à mes besoins sur mon site.


La requette
$sql = "INSERT INTO chansons(titre, artiste, id_artiste, date_envoi, vues, note, description, adresse_chanson)
 VALUES(".$connexion->quote($fichier).",
 ".$connexion->quote($artiste).",
 ".$connexion->quote($id_artiste,PDO::PARAM_INT).", NOW(), 0,0,
 ".$connexion->quote($adresse_chanson).")";
          // Ligne temporaire pour vérification
          echo $sql;
          // exécution de la requête
          $nbAffect = $connexion->exec($sql);
Dans ma page d'upload ne fonctionne toujours pas, et dans une page a part j'ai :
( ! ) Warning: PDO::exec() [pdo.exec]: SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesn't match value count at row 1 in C:\wamp\www\Code\pages\test.php on line 53
Call Stack
# Time Memory Function Location
1 0.0010 375656 {main}( ) ..\test.php:0
2 0.0127 383288 PDO->exec( ) ..\test.php:53
Que faire ? Merci :)

ViPHP
AB
ViPHP | 5818 Messages

15 sept. 2011, 01:15

Je te l'ai déjà dit, dans une page séparée tu mets une requête qui fonctionne déjà sur ton site (préparée ou non peu importe) avec des valeurs bidon en guise de variables (pour éviter d'avoir à faire un post pour renseigner ces valeurs).
Quand ça fonctionne tu change le nom de ta table et des champs pour que cela corresponde à la requête que tu veux. En y allant progressivement tu devrais pouvoir y arriver ou au moins connaître l'origine du problème. Et inutile de tester ta requête avec le script de l'upload si elle ne fonctionne pas déjà toute seule.