Page 1 sur 2

Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 09:45
par FURAX69
Bonjour à tous,

Voila, je dois injecter des data dans une base SQL, mais je dois enrichir des enregistrements existants et non pas simplement en ajouter (ce que je maitrise).

Je dois lire un fichier CSV (issue d'Excel) dans lequel, j'ai un numéro de compte et un budget. Chaque fiche déjà présente dans la BDD contient un champ
avec ce même numéro de compte et je dois renseigner le champ budget de la BDD au moyen de cette importation...

Je sais que c'est possible, mais je ne vois pas comment faire... Et plus je parcours le web, moins je trouve...

Si quelqu'un peux m'aider ce serais très sympa

Merci d'avance,
Thierry

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 10:00
par Mazarini
Pour mettre à jour des enregistrements, il faut daire un UPDATE au lieu d'un INSERT.

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 10:15
par moogli
Salut,

le terme d'injection SQL est ici mal choisit en règle générale il s'agit d'une excploitation de faiblesse des requêtes (via la non sécurisation de formulaire) pour "pirater un serveur".

Dans ton cas tu peux regarder du côté du replace de mysql mais Perso je m'orienterais vers une procédure stockée à de. Paramètres. Cette procédure fait un sélect count pour savoir si la ligne existe, si oui iodate si non insert.

Je te conseil aussi l'utilisation de pdo et des requêtes préparée. ;)

@+

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 12:17
par FURAX69
Pour mettre à jour des enregistrements, il faut daire un UPDATE au lieu d'un INSERT.
Ca je le sais... Mais comment faire des update sélectifs sur une clé trouvée et dans la BDD et dans mon fichier CSV ?

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 12:18
par FURAX69
Salut,
Dans ton cas tu peux regarder du côté du replace de mysql mais Perso je m'orienterais vers une procédure stockée à de. Paramètres. Cette procédure fait un sélect count pour savoir si la ligne existe, si oui iodate si non insert.
Je te conseil aussi l'utilisation de pdo et des requêtes préparée. ;)
@+
Rien compris de tout ça... Mais je vais chercher...

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 12:54
par Mazarini
Je suppose que tu sais lire le fichier.

Il faut faire une tentative d'update avec les données lues et regarder combien de lignes modifiées - mysql_affected_rows() - et faire l'insert si pas de lignes modifiée.

Une option est de commencer par l'insert et de faire un update en cas d'erreur duplicate key.

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 14:13
par moogli
Hum tu va être obliger d'indiquer comment capturer les erreurs ;)

Plus sérieusement, pour plus d'info sur SQL => sqlpro sur développez.com.

Une procédure stockée ce n'est pas compliqué à mettre en oeuvre ;)

Pour pdo http://www.php.net/pdo


@+

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 15:21
par Mazarini
Pour capturer les erreurs : mysql_errno()

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 16:00
par moogli
avec la niveau d'erreur adéquat sinon E_WARNING ? :)

enfin s'pa grave y a deux possibilités a exploiter la ;)

@+

Re: Injection SQL depuis un CSV...

Posté : 27 déc. 2011, 21:48
par AB
Je suppose que tu sais lire le fichier.

Il faut faire une tentative d'update avec les données lues et regarder combien de lignes modifiées - mysql_affected_rows() - et faire l'insert si pas de lignes modifiée.

Une option est de commencer par l'insert et de faire un update en cas d'erreur duplicate key.
Heu... n''est-ce pas là tout l'intérêt de la syntaxe : INSERT INTO ... ON DUPLICATE KEY UPDATE
Avec ça tu fais l'équivalent de tes deux requêtes en une seule.

Re: Injection SQL depuis un CSV...

Posté : 28 déc. 2011, 10:02
par FURAX69
Merci de vos réponses, mais étant débutant, je n'ai pas compris grand chose...

Rien de plus parlant qu'un exemple de code, donc si quelqu'un sait où je peux trouver ça ?

Re: Injection SQL depuis un CSV...

Posté : 28 déc. 2011, 23:49
par moogli
heu http://dev.mysql.com/doc/refman/5.0/en/ ... icate.html ?

1er lien de cette recherche

sinon pour la méthode avec procédure stockée

La table de test:
CREATE TABLE `furax69` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `numero` int(11) NOT NULL,
  `budget` decimal(8,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
La procédure Stockée
-- --------------------------------------------------------------------------------
-- Routine DDL
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `procFurax69`(
  IN num INT,
	IN bud decimal(10,2),
	out ret boolean)
BEGIN
 declare nb int;
 declare tmp boolean;
 set @tmp := false;
 select count(*) into nb from furax69 where numero = num ;
 if nb = 0 then
	insert into furax69 (numero,budget) value(num,bud);
	set @tmp := true;
 else 
	update furax69 set budget=bud where numero = num;
	set @tmp := true;
 end if;
 select @tmp into ret;
END$$

DELIMITER ;
Le code php avec PDO
<?php
$fichiercsv = file('furax69.csv');
try {
    $pdo = new PDO("mysql:host=localhost;dbname=test;charsey=utf8","root","yyRu2TKEvyYpzFLK");
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $stmt = $pdo->prepare('call procFurax69(:numero,:budget,@sortie)');
    foreach($fichiercsv as $line){
        $csv = str_getcsv($line, ';');
        /*
        $num = 12;
        $bud = 45550.52;
        */
        $stmt->bindParam(':numero', $csv[0], PDO::PARAM_INT);
        $stmt->bindParam(':budget', $csv[1], PDO::PARAM_INT);
        //$stmt->bindParam(':sortie', $retour, PDO::PARAM_STR,5);
        $stmt->execute();
        $s = $pdo->query('select @sortie')->fetch(PDO::FETCH_OBJ);
        echo 'La procédure à retourné : ', $s->{'@sortie'};
    }
}
catch (PDOException $e){
    echo '<pre style="word-wrap:break-word;">';
    echo $e->getMessage();
    echo '</pre>';
}
?>
Le fichier de test

Code : Tout sélectionner

123456;45789.8 456789;789.5 7832;486.48 159753;486.58 458652;965.12 546;456.25 456.15;48996.52
résultat

Code : Tout sélectionner

mysql> select * from furax69; +----+--------+----------+ | id | numero | budget | +----+--------+----------+ | 1 | 123456 | 45789.80 | | 2 | 456789 | 789.50 | | 3 | 7832 | 486.48 | | 4 | 159753 | 486.58 | | 5 | 458652 | 965.12 | | 6 | 546 | 456.25 | | 7 | 456 | 48996.52 | +----+--------+----------+ 7 rows in set (0.00 sec)
un tuto sur les procédure stockée pour mysql
un tuto sur PDO

Ce code à le mérite d'être a peux prêt standard, donc fonctionnel quelque soit le SGBD ;)

@+

Re: Injection SQL depuis un CSV...

Posté : 29 déc. 2011, 05:01
par AB
Je vois pas trop l'intérêt d'une procédure stockée. En même temps comme je n'ai pas encore eu à les utiliser... ceci explique peut-être cela :)
Y a-t-il a un avantage de ce système par rapport à un tout bête :
$req = "INSERT INTO furax69 (numero,budget)  
                   VALUES ('123456','45789.8') 
		   ON DUPLICATE KEY UPDATE 
		   budget = VALUES(budget)
	";


dans cet exemple il suffit que "numero" soit déclaré comme unique et ça devrait aller, non ?

ah oui je viens de trouver l'avantage de ton code : il doit être compatible PostgreSQL alors que le mien ne doit fonctionner qu'avec mysql.
Bah finalement, il reste encore des avantages à travailler avec mysql alors :)
(Et c'est pas demain que je vais changer car mes code sont truffés de INSERT INTO ... ON DUPLICATE KEY UPDATE (car c'est hyper pratique))

Re: Injection SQL depuis un CSV...

Posté : 29 déc. 2011, 10:32
par Mazarini
Travailler avec des procédures stockées permet de sortir le SQL du PHP et de n'avoir que les procédures stockées à modifier pour porter d'un système à l'autre.

Re: Injection SQL depuis un CSV...

Posté : 29 déc. 2011, 12:37
par moogli
Exactement c'est une couche de plus pour séparer logique métier de l'affichage ;)

Ceci dit si le code est voué à rester sur mysql ce n'est pas problème.
Après je n'ai pas regarder en détails le on duplicate key, la question qui me vient c'est : ça se passe lorsque la clef unique n'est pas la clef primaire ? (j'imagine un numéro de compte alphanumérique et une clef auto incrémenté )?


@+