Injection SQL depuis un CSV...

Eléphanteau du PHP | 23 Messages

27 déc. 2011, 09:45

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

ViPHP
ViPHP | 2577 Messages

27 déc. 2011, 10:00

Pour mettre à jour des enregistrements, il faut daire un UPDATE au lieu d'un INSERT.

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

27 déc. 2011, 10:15

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. ;)

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

Eléphanteau du PHP | 23 Messages

27 déc. 2011, 12:17

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 ?

Eléphanteau du PHP | 23 Messages

27 déc. 2011, 12:18

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...

ViPHP
ViPHP | 2577 Messages

27 déc. 2011, 12:54

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.

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

27 déc. 2011, 14:13

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


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

ViPHP
ViPHP | 2577 Messages

27 déc. 2011, 15:21

Pour capturer les erreurs : mysql_errno()

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

27 déc. 2011, 16:00

avec la niveau d'erreur adéquat sinon E_WARNING ? :)

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

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

ViPHP
AB
ViPHP | 5818 Messages

27 déc. 2011, 21:48

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.

Eléphanteau du PHP | 23 Messages

28 déc. 2011, 10:02

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 ?

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

28 déc. 2011, 23:49

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 ;)

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

ViPHP
AB
ViPHP | 5818 Messages

29 déc. 2011, 05:01

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))

ViPHP
ViPHP | 2577 Messages

29 déc. 2011, 10:32

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.

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

29 déc. 2011, 12:37

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é )?


@+
Modifié en dernier par moogli le 29 déc. 2011, 21:25, modifié 1 fois.
Il en faut peu pour être heureux ......