MySql sauvegarder enregistrement avant suppression

Eléphanteau du PHP | 21 Messages

15 janv. 2008, 02:50

Bonjour,

je tente de sécuriser une table de ma base de données... je voudrais m'arranger pour que, si un utilisateur supprime un enregistrement de la table prog, cet enregistrement va s'insérer dans la table prog_supp id_show étant la clé primaire int auto-incrément sur les 2 tables.

J'ai pensé à quelque chose dans ce genre...
	if ($_GET['delete_id']){  $id = $_GET['delete_id'];

// Voici la requête select pour trouver l'enregistrement à supprimer:

SELECT * FROM prog WHERE prog.id_show= $id LIMIT 1

	$copie = mysql_query("INSERT INTO prog_supp (id_show,titre_show,image_show,categorie,date_numerique,hre_show,prix_show,desc_show,url_show,billetech) VALUES  
//// et là je bloque //////
	
	$succes = mysql_query("DELETE FROM prog WHERE id_show = $id") or die ("impossible de supprimer l'enregistrement");
		if ($succes){ header("Location:supp.php"); 
  exit;
		}					
}
Dans quelle direction aller ? Requêtes imbriquées ? SELECT ... INTO OUTFILE ?

Comme vous voyez... je suis assez débutante il me semble que ça doit être super simple... alors voilà, je demande de l'aide sur ce forum car j'y ai toujours obtenu un précieux support.

Merci pour votre aide.
Émilie

Mammouth du PHP | 1885 Messages

15 janv. 2008, 02:56

Est-ce qu'insérer un champ supplémentaire portant le nom "status" ou "supprime" serait une solution envisageable?

Il serait donc possible de "supprimer" un enregistrement tout en conservant un backup qui pourrait être restoré en un rien de temps.
La programmation est l'expression de la poésie d'un programmeur
Génération PHP

ViPHP
AB
ViPHP | 5818 Messages

15 janv. 2008, 03:57

Si tu veux faire dans ta première idée avec une autre table qui sert de "poubelle sauvegarde" tu as oublié de récupérer les éléments de l'id à supprimer pour les insérer ensuite. Sur le principe tu peux faire quelque chose comme ça :
$id =  !empty($_GET['delete_id'])? intval($_GET['delete_id']) : 0;

if (!empty($id)
{
$cible = "SELECT * FROM prog WHERE prog.id_show = $id LIMIT 1";
$req_cible = mysql_query($cible) or die(mysql_error());

if ($result = mysql_fetch_assoc($req_cible)) 
 {

    $copie = "INSERT INTO prog_supp (id_show,titre_show,image_show,categorie,date_numerique,hre_show,prix_show,desc_show,url_show,billetech) VALUES ($result['id_show'],$result['titre_show'],$result['image_show'],$result['categorie'],$result['date_numerique'],$result['hre_show'],$result['prix_show']
,$result['desc_show'],$result['url_show'],$result['billetech'])";
    if (mysql_query($copie))
    {
    $delete = mysql_query("DELETE FROM prog WHERE id_show = $id") or die ("impossible de supprimer l'enregistrement");
        if ($delete){ header("Location:supp.php"); exit; }
    }                 
}
}
(pas testé, évidemment)

Sinon la suggestion de Xenon_54 est à étudier car très facile à mettre en oeuvre.
Avec un champ statut pour chaque ligne, tu update simplement ce champs avec une valeur spécifique ex 0 ou null pour dire qu'elle est supprimée. Et dans tes requêtes tu fais SELECT ... WHERE statut = 1; en considérant que la valeur par défaut de cette colonne est 1

Si tes tables ne sont pas trop importantes tu ne devrais pas trop perdre en performances. Ou sinon tu pourrais aussi envisager d'enregistrer la date de supression dans le champ status ce qui pourrais te permettre de faire automatiquement ou manuellement du ménage de temps en temps.

ViPHP
AB
ViPHP | 5818 Messages

15 janv. 2008, 15:34

Sinon niveau sécurité, c'est pas terrible. A moins que ce ne soit destiné à un espace administrateur donc avec des gens responsables sinon un utilisateur malveillant pourrait "s'amuser" à passer n'importe quelle valeur dans $_GET['delete_id'] et supprimer ainsi n'importe quelle ligne au hasard.

Si c'est pour un espace public il serait plus prudent de mettre l'identifiant de la ligne à supprimer dans une variable de session.

Eléphanteau du PHP | 21 Messages

15 janv. 2008, 16:45

Bonjour et merci à tous pour votre aide

Il s'agit effectivement d'un espace d'administration sécurisé avec des sessions.

J'ai ajouté une colonne à ma table (quelle bonne idée) et je teste la présence de delete_id comme vous me l'avez suggéré:
$id =  !empty($_GET['delete_id'])? ($_GET['delete_id']) : 0;
Avec le intval() ça tronquait les zéros devant l'id et sa valeur ($id) n'était plus vérifiable.

Ensuite je fais ceci:
if (!empty($id))
	{ 
$req_supp = 'UPDATE prog SET date_supp=now() WHERE id_show='.$id.' LIMIT 1';
$supression=mysql_query($req_supp)or die (mysql_error());
	if ($supression){
$selectsupp = 'SELECT titre_show FROM prog WHERE id_show='.$id.' LIMIT 1';		
		$titresupp = mysql_query($selectsupp)or die (mysql_error());
		$enregistrementsupprime = mysql_fetch_assoc($titresupp);
		echo "ligne supprimée: ".$id." - Titre: ".$enregistrementsupprime['titre_show'];
		}
	}
Et ça fonctionne impeccable !

J'ajoute que j'ai beaucoup de misère à écrire une requête correctement... la syntaxe les virgules apostrophes guillements... tout ça me déroute. Faut que j'étudie.

Encore merci pour votre aide précieuse et bonne journée à tous !
Émilie

ViPHP
AB
ViPHP | 5818 Messages

15 janv. 2008, 19:50

J'ajoute que j'ai beaucoup de misère à écrire une requête correctement... la syntaxe les virgules apostrophes guillements... tout ça me déroute. Faut que j'étudie.

Encore merci pour votre aide précieuse et bonne journée à tous !
Et bien continues à les écrire comme tu viens de le faire. Tu es sur la bonne voie.

Cela dit tu devrais prendre l'habitude de protéger les variables dans une requête par mysql_real_escape_string() d'autant que dans ce cas comme tu ne castes pas les variables avec intval() rien ne te dis que c'est forcément une valeur numérique qui sera reçue. Il suffit de faire
if (!empty($id))
    { 
$req_supp = 'UPDATE prog SET date_supp=now() WHERE id_show=' . mysql_real_escape_string($id) . ' LIMIT 1';
$supression=mysql_query($req_supp)or die (mysql_error());
    if ($supression){
$selectsupp = 'SELECT titre_show FROM prog WHERE id_show=' . mysql_real_escape_string($id) . ' LIMIT 1';        
        $titresupp = mysql_query($selectsupp)or die (mysql_error());
        $enregistrementsupprime = mysql_fetch_assoc($titresupp);
        echo "ligne supprimée: ".$id." - Titre: ".$enregistrementsupprime['titre_show'];
        }
    } 
C'est la syntaxe recommendée par le manuel php

Sinon j'avais jamais vu des id avec des zero devant le nombre? Ta colonne id est de type int autoincrémenté ?

Eléphanteau du PHP | 21 Messages

16 janv. 2008, 01:40

Encore merci AB

Mon champ id_show est de type smallint(3) UNSIGNED ZEROFILL auto_increment

C'est une petite table... j'imagine que j'aurais pas dû mettre zerofill... :?

Dans l'état actuel, c'est comme je te disais, je perds la valeur réelle de mon id_show par l'enlevement des 0 devant le nombre.

Sinon... j'utilise la fonction que voici sur les INSERT et les UPDATE pour les protéger:
function quote_smart($value)
{
   // Stripslashes
   if (get_magic_quotes_gpc()) {
      $value = stripslashes($value);
   }
   // Protection si ce n'est pas un entier
   if (!is_numeric($value)) {
      $value = "'" . mysql_real_escape_string($value) . "'";
   }
   return $value;
}
Je l'utilise comme ceci:

if ($_POST['submitted'])  {
	
	// Exemple de fabrication d'une requête sécurisée
	$query = sprintf("INSERT into pages (id_page,titre,mots_cles,description,contenu,urlpage,id_parent) 
VALUES (%d, %s, %s, %s, %s, %s, %d)",
	quote_smart($_POST['id_page']),
	quote_smart($_POST['titre']),
	quote_smart($_POST['mots_cles']),
	quote_smart($_POST['description']),
	quote_smart($_POST['contenu']),
	quote_smart($_POST['urlpage']),
	quote_smart($_POST['id_parent']));
	
	mysql_query($query)or die (mysql_error());	
	print "requête exécutée";
	mysql_close();
	
}

else { print "formulaire non transmis";}
En passant... à propos de ce dernier script... je me demandais si c'était obligé d'utiliser la fonction quote_smart() pour les champs 'id_page' et 'id_parent' dans la mesure où ce sont des int qui sont déclarés comme tels dans la 2e partie du sprintf() (%d) ?

Pour finir, ton encouragement me fait grand plaisir. Ça fait des années que je tente de me débrouiller et que j'y arrive de façon plus ou moins heureuse, mais j'avais pas encore assez pratiqué je crois... et maintenant que je m'y mets... ça rentre plus vite que je pensais et tu me donnes le goût de continuer encore et encore jusqu'à comprendre.

Étudier le PhP en plus du SQL HTML CSS JS les BLOGS sans parler des connaissances de base que ça prend en graphisme... c'est un luxe que j'ai parfois de la difficulté à me permettre en tant que travailleuse-autonome-webmaster-qui-a-tout-appris-«sul'tas» comme on dit au Québec. :wink:

Encore merci !
Émilie

ViPHP
AB
ViPHP | 5818 Messages

16 janv. 2008, 05:00

ah bah oui comme ça c'est blindé.

Concernant tes dernières questions, j'utilisais sprintf avant mais plus trop maintenant (faut dire aussi qu'y un piaf tout bleu qu'arrête pas de me tanner avec ça et qui dit que ça sert à rien si on extrait ses variables... :lol: ) et je fais plutôt comme le code plus haut. C'est un peu plus facile à gérer quand il y beaucoup de variables à insérer.
Mais garde ta méthode si tu es habituée, y'a aucun souci et cela suit d'ailleurs le modèle du manuel.

Sinon dans l'absolu, tu pourrais certainement t'éviter d'utiliser ta fonction quote_smart() sur les entiers puisqu'ils sont déclarés comme tel par sprintf mais perso je me pose pas tant de questions: deux précautions valent mieux qu'une (tant qu'elle ne rentrent pas en conflit et ce n'est pas le cas ici).

D'ailleurs, je prend également moins d'attention que toi pour optimiser mes champs de table ID. Comme je fais du code transposable, c'est du INT partout. Cela n'a finalement qu'une importance marginale comparé au reste (organisation des tables, optimisation des requêtes, bonnes indexation etc)

Pour UPDATE, si tu es amenée à en faire beaucoup en une seule fois sur de nombreuses lignes, fait une recherche google sur mysql_query("LOCK TABLES table WRITE") ça peut servir. Je dis ça parce que j'ai découvert cette fonction y'a pas si longtemps (l'est pas trop conviviale la doc SQL, c'est pas mon livre de chevet...)

Sinon j'ai tout appris sul'tas moi aussi :wink: Et je viens là pour aider mais aussi pour en apprendre toujours plus, toujours plus... C'est sans fin d'autant que comme toi je fais aussi du graphisme, de la photo et mes sites de A à Z. Bonne continuité collègue :wink:

Eléphanteau du PHP | 21 Messages

16 janv. 2008, 15:05

donc... je pourrais modifier mon champ id_show et en faire un INT sans zerofill et ça chamboulera pas ma table ? anyway je travaille sur une copie de la table (of course) car le script de ce site web est programmé depuis 1 an mais je vois venir le client avec sa nouvelle programmation et je veux que mes tables et mes scripts soient meilleurs cette année.

C'est pas des jokes, sur l'ancienne table j'avais un champ: pour le nom du jour, un autre (varchar) qui recevait le mois et l'année ... parce que j'ai besoin d'interroger la table sur ces critères et que j'arrivais pas à construire des requêtes sélectives sur une partie de la date.

Hier j'ai appris à faire ça toute seule:
$sql = "SELECT DISTINCT DATE_FORMAT( date_numerique, '%m-%Y') AS dates 
FROM prog ORDER BY DATE_FORMAT( date_numerique , '%Y-%m')"; 
Autant te dire que c'est déjà un exploit pour moi... mais là où je m'épate moi-même (ne riez pas les autres) c'est que je réussis à insérer le résultat dans une liste déroulante avec des substr() sur mes dates et je rends ça lisible avec des swicth - case 01 = Janvier...

Sinon à propos des champs int si j'ai pris l'habitude de faire ce genre de déclaration au début de mes scripts... je devrais pas avoir de soucis non ?
$contenu =($_POST['contenu']);
$urlpage = ($_POST['urlpage']);
$id_parent =intval($_POST['id_parent']);
$id=intval($_GET['modify_id']); 
Concernant la doc SQL, faut dire qu'elle me décourage puisque je ne maitrîse la syntaxe ni du php ni du sql, c'est un joyeux festin que je me tape pour créer des requêtes qui fonctionnent... :cry:

Voilà ! j'ai assez abusé du forum pour aujourd'hui. Encore un gros merci :merci: et te gêne pas de me le signaler si tu vois des écueils.... tu sais pas combien j'voudrais t'avoir proche du pays de l'érable certains jours :)

Bonne route cher collègue
Émilie