Page 1 sur 1

regex en lot

Posté : 13 sept. 2009, 13:39
par Ricou
Bonjour,

Je m'exerce au php depuis quelques temps et grâce au nombreuses doc, j'arrive à peu près à m'en sortir, mais là je tombe sur un problème dont je ne suis pas sur qu'il existe une solution, j'ai donc besoin d'aide.
J'ai un formulaire avec une soixantaine de champs à remplir. Tous les champs ne peuvent contenir que des nombres entier. Existe-t-il une solution simple qui permette de vérifier que tous les champs ne contiennent que des chiffres, ou suis-je obligé de créer une regex pour chaque valeur postée (ce qui va être long à écrire et long à traiter pour le serveur) ?

Re: regex en lot

Posté : 13 sept. 2009, 13:52
par FuZZyLine
Salut,
Bonjour,
Je m'exerce au php depuis quelques temps et grâce au nombreuses doc, j'arrive à peu près à m'en sortir, mais là je tombe sur un problème dont je ne suis pas sur qu'il existe une solution, j'ai donc besoin d'aide.
J'ai un formulaire avec une soixantaine de champs à remplir. Tous les champs ne peuvent contenir que des nombres entier. Existe-t-il une solution simple qui permette de vérifier que tous les champs ne contiennent que des chiffres, ou suis-je obligé de créer une regex pour chaque valeur postée (ce qui va être long à écrire et long à traiter pour le serveur) ?
La fonction

Code : Tout sélectionner

(boolean)is_int(TA_VARIABLE);
ferait-elle l'affaire?

http://www.manuelphp.com/php/function.is-int.php

@+ ;)

Re: regex en lot

Posté : 13 sept. 2009, 14:05
par niuxe
Hello,

Bien que la réponse de FuZZyLine soit excellente afin d'éviter de réinventer la roue, tu peux passer par une RegEx bien sûr.

Ce qui donnerai ceci à vue de nez :
$pattern = "#^\d$#";
ou :
$pattern = "#^[0-9]$#";
++

Re: regex en lot

Posté : 13 sept. 2009, 14:33
par Ricou
Merci de vos réponse
Salut,
La fonction

Code : Tout sélectionner

(boolean)is_int(TA_VARIABLE);
ferait-elle l'affaire?

http://www.manuelphp.com/php/function.is-int.php

@+ ;)
Oui et non je pense. ;)
Oui car elle teste ce que je veux mais non car il faut quand meme que je l'écrive pour chaque champs du formulaire.
En fait pour l'instant j'ai ça :

Code : Tout sélectionner

mysql_query("UPDATE rent_arme SET arbalete='".$_POST['arbalete']."' , arc_acier='".$_POST['arc_acier']."' , arc_bois='".$_POST['arc_bois']."' etc... WHERE nom='".$nom."'");
sur différente table pour un total d'une soixantaine de valeurs différentes.

Et donc j'aimerais que si la valeur entrée est un nombre ça l'enregistre, sinon soit ça ne fait rien ou on met 0.
Hors si j'ai bien compris meme avec la fonction is_int, la seule manière c'est de faire comme ça :

Code : Tout sélectionner

if (is_int($_POST['arbalete'])) { $arbalete = $_POSt['arbalete']; } else { $arbalete = 0; }
Ce qui est long vu le nombre à faire, y'a-t-il plus simple ?

Re: regex en lot

Posté : 13 sept. 2009, 15:31
par FuZZyLine
Re,
Merci de vos réponse
Salut,
La fonction

Code : Tout sélectionner

(boolean)is_int(TA_VARIABLE);
ferait-elle l'affaire?

http://www.manuelphp.com/php/function.is-int.php

@+ ;)
Oui et non je pense. ;)
Oui car elle teste ce que je veux mais non car il faut quand meme que je l'écrive pour chaque
champs du formulaire. En fait pour l'instant j'ai ça :
[...]
sur différente table pour un total d'une soixantaine de valeurs différentes.
Et donc j'aimerais que si la valeur entrée est un nombre ça l'enregistre, sinon soit ça ne fait rien ou on met 0.
Hors si j'ai bien compris meme avec la fonction is_int, la seule manière c'est de faire comme ça :

Code : Tout sélectionner

if (is_int($_POST['arbalete'])) { $arbalete = $_POSt['arbalete']; } else { $arbalete = 0; }

Ce qui est long vu le nombre à faire, y'a-t-il plus simple ?
Si ce n'est qu'une question de boucle il suffit de faire:
// Tableau pour les éléments faux
//
$arrayListError = Array();

// Compteur d'erreur
//
$iCount = 0;

// Boucle sur tous les éléments recus. Tu peux aussi passer par un while(true) et t'arréter
// au premier élément invalide mais la c'est plus... complêt
//
foreach($_POST AS $key => $value)
{
   // Test ta variable, les Exemple_XX sont les valeurs que tu ne veux pas traiter.
   // Par exemple les champs de formulaires hidden etc...
   //
   if (!is_int($value))
   {
      switch($key)
      {
         case Exemple_01:
            // Valeur ne devant pas être traitée.
            //
         break;

         case Exemple_02:
            // Autre valeur ne devant pas être traitée.
            //
         break;

         [...]

         default:
            // Enregistre la clef de la variable incriminée
            //
            $arrayListError[$key] = false;

            // Incrémente le compteur à chaque erreur
            //
           $iCount++;
      }
   }
}

// Test si le compteur indique une ou plusieurs erreurs et les traite
//
if ($iCount > 0)
{
   // Le tableau comprend toutes les valeurs indésirables
   // 
   // l'intérêt est que tu sais (par conséquence) les éléments qui sont "valides" donc
   // tu peux renvoyer le formulaires en les indiquant. (en les passant par session par exemple).
   .
   .
   .
}

// Tout est OK, poursuite du script normalement
//
else
{
   // Continue, no error
   //
   .
   .
   .
}
Fait en direct et à vue de nez, à toi d'adapter ...et d'améliorer.

Y a beaucoup plus simple. Je laisse mes collegues t'en dire plus ;)

@+ ;)

PS: Je parle session mais c'est un autre débat, je peux juste t'inviter à lire ceci: http://fr.php.net/manual/fr/book.session.php

Re: regex en lot

Posté : 13 sept. 2009, 18:07
par Aureusms
En mélangeant un peu avec les réponses précédentes :
<?php
$tab_cle_autorise = array ("arbalete", "arc_acier", "arc_bois");

foreach ($_POST as $cle => $valeur)
{
  if (in_array($cle,$tab_cle_autorise))
  {
    $tab_sortie[$cle] = (is_int($valeur)) ? $valeur : 0;
  }
}
//il est vrai que je ne connais pas toutes ta requète mais essaye cela :
$requete = "UPDATE rent_arme SET";
foreach ($tab_sortie as $cle => $valeur)
{
  $requete .= $cle." = '".$valeur."'",
}
//on retire la dernière virgule
$requete = substr ($requete,0,-1);
mysql_query ($requete) or die(mysql_error());
?>
Qu'en penses-tu ?

Re: regex en lot

Posté : 14 sept. 2009, 02:12
par Ricou
Ben j'ai bien fait de demander, car ça dépasse mes compétences, mais je crois avoir compris.
La dernière proposition me plait bien, assez courte, il me suffit de la répéter pour chaque table, 8 en tout.

j'ai juste besoin de 2 confirmations :

Code : Tout sélectionner

$tab_sortie[$cle] = (is_int($valeur)) ? $valeur : 0;
Cette ligne remplit un array avec en clé le nom de la variable et en valeur la nombre posté ou si ce n'est pas un nombre, par 0. Donc le point d'interrogation permet de dire l'un ou l'autre ?
Est-ce qu'il serait possible de remplacer le zéro par la valeur présente dans la table (comme j'ai fait ci-dessous) ?

Par contre ça je ne comprends pas :

Code : Tout sélectionner

$requete = "UPDATE rent_arme SET"; foreach ($tab_sortie as $cle => $valeur) { $requete .= $cle." = '".$valeur."'", }
si $requete contient le début de la requete sql, comment peut-elle contenir aussi les valeurs de la boucle ?
j'aurais plutot tendance à créer le début de la requete en brut, puis insérer les valeurs de l'array au mileu
Je mets en dessous le code complet comme je le comprends, est-ce que c'est correct ?

comme ça c'est bon :
$sql = mysql_query('SELECT * FROM arme') or die(mysql_error()); //au tout début du code je met la requete pour récupérer les infos avant modification
$resultat = mysql_fetch_array($req_rent_info) //ce qui donne par exemple : $resultat['arbalete'] pour avoir la valeur

//ensuite le code donné par aureusms
$tab_cle_autorise = array ("arbalete", "arc_acier", "arc_bois");

foreach ($_POST as $cle => $valeur)
{
  if (in_array($cle,$tab_cle_autorise))
  {
    $tab_sortie[$cle] = (is_int($valeur)) ? $valeur : $resultat['$cle']; //donc là je remplace le zéro par la variable
  }
}

foreach ($tab_sortie as $cle => $valeur)
{
  $requete .= $cle." = '".$valeur."'", //n'y a-t-il pas d'erreurs dans les points et guillemets ?
}
//on retire la dernière virgule
$requete = substr ($requete,0,-1);

mysql_query ("UPDATE rent_arme SET ($requete) WHERE nom='".$nom."'" or die(mysql_error()); //la requete me semble mieux comme ça, mais je ne sais pas si elle fonctionnera
Là il est tard, je vois vos réponses demain et je testerai le tout demain soir si j'ai le temps.

Re: regex en lot

Posté : 17 sept. 2009, 23:01
par Ricou
Après 2 jours de dur labeur à corriger des parse error et des erreurs sql en pagaille, j'ai enfin trouvé le juste mot.
Merci à tous les contributeurs, qui m'avez inspiré cette solution, je n'aurais pas réussi sans vous.
Voici donc la requête finale :
	$sql = mysql_query('SELECT objet_code FROM rent_info WHERE categorie="arme"') or die(mysql_error()); //table où est écrit la structure des autres tables (arbalete, arc_acier, etc)
	$tab_cle_autorise = array();
	while ($resultat = mysql_fetch_array($sql)) //création d'un array ayant en clé le nom des armes et sans valeur
        {
		$resultat = $resultat['objet_code'];
		$tab_cle_autorise[$resultat] = "";
	}
        $sql2 = mysql_query('SELECT * FROM rent_arme WHERE nom="'.$nom.'"') or die(mysql_error()); //Récupération des valeurs avant qu'elle ne soient modifiées
	$resultat2 = mysql_fetch_array($sql2); //ce qui donne par exemple : $resultat['arbalete'] pour avoir la valeur

	foreach($tab_cle_autorise AS $key => $value) //pour chaque ligne de l'array, soit chaque arme
	{
		if (is_numeric($_POST[$key])) //il faut vérifier que la valeur postée ($key contient le nom des armes), est un nombre
		{
			$tab_cle_autorise[$key] = $_POST[$key]; //si c'est un nombre, je le rajoute dans l'array avec toujours l'arme en clé
		}
		else
		{
			$tab_cle_autorise[$key] = $resultat2[$key]; //si ce n'est pas un nombre, je mets le chiffre déjà dans la base dans l'array
		}
	}

	//Création de la requete, si j'ai bien compris, le point avant le signe égal veut dire que l'on rajouter quelque chose dans la variable
	$requete = "UPDATE rent_arme SET "; //début de la requete sql
	foreach ($tab_cle_autorise as $cle => $valeur) //toujours pour chaque ligne dans l'array, mais cette fois j'enlève l'array pour faire une variable contenant la clé=la valeur,
	{
		$requete .= $cle.'='.$valeur.',';
	}
	//on retire la dernière virgule
	$requete = substr ($requete,0,-1);
	$requete .= ' WHERE nom="'.$nom.'"'; //fin de la requete sql

	mysql_query ($requete) or die(mysql_error()); //requete finale qui modifie la base
Par contre j'ai encore des questions :
Etant donné que je n'autorise que des nombres, faut-il tout de même en plus protéger les champs d'injection sql ?
Ais-je d'autres précautions à prendre avant l'enregistrement de données postées dans la base ?

Re: regex en lot

Posté : 18 sept. 2009, 08:42
par FuZZyLine
Salut,
Après 2 jours de dur labeur à corriger des parse error et des erreurs sql en pagaille, j'ai enfin trouvé le juste mot.
Merci à tous les contributeurs, qui m'avez inspiré cette solution, je n'aurais pas réussi sans vous.
Voici donc la requête finale :
Par contre j'ai encore des questions :
Etant donné que je n'autorise que des nombres, faut-il tout de même en plus protéger les champs d'injection sql ?
Ais-je d'autres précautions à prendre avant l'enregistrement de données postées dans la base ?
Pour un code propre je te consei: (ca reste un conseil tu fais ce que veux)

> Déclarer convenablement le type de ton champ de table (dans ton cas un entier : INT ou de même famille)
> Tester avant l'enregistrement la valeur que tu veux enregistrer

Si tu veux renseigner un champs de table MySql avec un type différent de déclaration l'enregistrement se
fera pas aussi le test qui précède n'est pas "obligé" mais vivement conseillé si tu tiens à ce que ton code
soit propre. Une image me vient à l'esprit:

Tu ne reussiras jamais à faire entrer un éléphant par un trou de souris mais t'auras perdu un temps
conséquent à essayer...

Désolé pour l'image mais j'adore ce type de comparaisons débiles lol et désolé si j'ai répondu à côté... ;)

@+ bon code ;)

Re: regex en lot

Posté : 18 sept. 2009, 21:02
par Ricou
Salut,
Pour un code propre je te consei: (ca reste un conseil tu fais ce que veux)

> Déclarer convenablement le type de ton champ de table (dans ton cas un entier : INT ou de même famille)
Déjà fait, et je me suis rendu compte au début de mes test que effectivement les lettres ne sont pas enregistrées, mais je me suis dit que au point où j'en étais il valait mieux que je finisse le code pour tester les valeurs. :mrgreen:
> Tester avant l'enregistrement la valeur que tu veux enregistrer
et bien c'est ce que j'ai mis au-dessus.

Mais est-ce que ce code suffit à éviter l'injection sql ?
Et ais-je encore d'autres précaution à prendre ?

Et pour finir, peu importe le temps passé à essayer de faire rentrer l'éléphant, au moins la prochaine fois on ne perdra pas de temps, étant donné que l'on saura déjà. ;)

Re: regex en lot

Posté : 19 sept. 2009, 09:02
par FuZZyLine
Salut,
Mais est-ce que ce code suffit à éviter l'injection sql ?
Et ais-je encore d'autres précaution à prendre ?
Me semble que ca suffit... ;)

Au pire tu peux ajouter un test, mais ca va surcharger un brin ton code. Bref, voila la requête
que tu peux ajouter:

> SHOW COLUMNS FROM table_name LIKE 'col_name';

Tu récupéres par cette ligne les infos concerant le type du champ puis tu le compares à ce que tu
veux enregistrer et s'ils sont différents (mais j'en doute au vu du test précédent) tu lèves une alerte.
Perso, j'essaie de le mettre lors de tous mes enregistrements mais... je suis un peu parano ;)

En tous cas, ca risque de surcharger ton code mais bon... à toi de voir ;)

@+ bon code ;)