Extraction/insertion de conditions sql dans une requête

Contenu du snippet

Cette fonction permet de remplacer et/ou d'insérer des conditions SQL dans une requête.
Cela est pratique pour les formulaires dynamiques dont la mise à jour repose sur les valeurs uploadées par l'internaute.

Elle est composé d'une fonction de vérification de l'intégrité du tableau de critères passé en paramètre (Verif_Interg_Tbl) et de la fonction d'extraction et d'insertion proprement dite (Place_cond_SQL)

Un petit exemple :
$SQL='SELECT Toto FROM Tata WHERE Titi<>\'Gros Minet\'';
echo $SQL donnera 'SELECT Toto FROM Tata WHERE Titi<>'Gros Minet'

$Tbl_insert[0][0]='Champ1';$Tbl_insert[0][1]=0;$Tbl_insert[0][2]='';$Tbl_insert[0][3]='or';
$Tbl_insert[1][0]='Champ2';$Tbl_insert[1][1]='C\'était';$Tbl_insert[1][2]='\'';$Tbl_insert[1][3]='';
$Tbl_insert[2][0]='Champ3';$Tbl_insert[2][1]='le temps béni';$Tbl_insert[2][2]='\'';$Tbl_insert[2][3]='and';
$Tbl_insert[3][0]='Champ4';$Tbl_insert[3][1]='de la rengaine';$Tbl_insert[3][2]='\'';$Tbl_insert[3][3]='or';
$Tbl_insert[4][0]='Champ5';$Tbl_insert[4][1]='Serge';$Tbl_insert[4][2]='\'';$Tbl_insert[4][3]='and';
$Tbl_insert[5][0]='Champ6';$Tbl_insert[5][1]='Lama';$Tbl_insert[5][2]='\'';$Tbl_insert[5][3]='or';

echo Place_cond_SQL($SQL,$Tbl_insert,'AND Titi BETWEEN \'Toi AND Moi\'') donnera

SELECT Toto FROM Tata WHERE Champ1=0 AND Champ2='C\'était' AND Champ3='le temps béni' OR Champ4='de la rengaine' AND Champ5='Serge' OR Champ6='Lama' AND Titi BETWEEN \'Toi AND Moi\''

Source / Exemple :


<?php
function Verif_Interg_Tbl(&$Tbl,$Nbre_Col=0,$Nbre_Lignes=0)
{
  //Cette fonction vérifie que le nombre de colonnes et/ou de lignes attendues dans un tableau sont bien là
  $Lignes=sizeof($Tbl);
  if($Nbre_Lignes>0 & $Lignes!=$Nbre_Lignes) return false;//Les colonnes
  foreach($Tbl as $Colonne)
  {
    if($Nbre_Col>0 & sizeof($Colonne)!=$Nbre_Col)return false; //Les colonnes des lignes du tableau
  }
  return true;
}

function Place_cond_SQL($Source,$Tbl_insert=array(),$Filtre_insecable="")
{/*Place_cond_SQL permet d'ajouter ou de remplacer les conditions de filtre existant sur une requête SQL
tout en concervant les paramètres de tri initiaux.
$Tbl_insert est un tableau dont la structure est :
[x][0] : Nom du champ sur lequel s'opère le filtre
[x][1] : Valeur à appliquer au filtre
[x][2] : Caractère déterminant le type de valeur ' pour String et Date
[x][3] : Liaison avec le critère précédent. Si vide, il sera mis par défaut AND

$Filtre_insecable sera toujours interprêté comme une liaison AND même s'il commence par AND ou OR.

Règle des liaisons entre le champ n et le champ n+1 :

Liaison n = AND et Liaison n+1= AND => La laison sera champ n AND champ n+1
Liaison n = OR et Liaison n+1= AND => La laison sera champ n AND champ n+1
Liaison n = OR et Liaison n+1= OR => La laison sera champ n OR champ n+1
Liaison n = AND et Liaison n+1= OR => La laison sera champ n OR champ n+1

On extrait tout sauf les conditions de filtre
Au pire, une requête peut avoir la nomenclature suivante
[...]WHERE[...]GROUP BY[...]HAVING[...]ORDER BY[...]*/

if(sizeof($Tbl_insert)>0) if(!Verif_Interg_Tbl($Tbl_insert,4)) die('Le tableau d\'insertion de critères n\' a pas 4 colonnes partout !<br>Veuillez vérifier la deuxième dimension []<b><u>[]</u></b>');

$Pds_Mot=0;
$Pos_Mot_cle[0] = preg_match_all("~:space:+WHERE:space:+~i",$Source,$Occurrences[0])==0 ? 0: stripos($Source,"WHERE");
$Pos_Mot_cle[1] = preg_match_all("~:space:+GROUP:space:+BY:space:+~i",$Source,$Occurrences[1])==0 ? 0: stripos($Source,"GROUP");
$Pos_Mot_cle[2] = preg_match_all("~:space:+HAVING:space:+~i",$Source,$Occurrences[2])==0 ? 0: stripos($Source,"HAVING");
$Pos_Mot_cle[3] = preg_match_all("~:space:+ORDER:space:+BY:space:+~i",$Source,$Occurrences[3])==0 ? 0: stripos($Source,"ORDER");

//On vérifie qu'il n'y a pas plusieurs occurrences pour un même mot clé
$Nbre_Occ=sizeof($Occurrences[0][0]);
if($Nbre_Occ>1)die("Il y a ".$Nbre_Occ." WHERE dans votre SQL !");

$Nbre_Occ=sizeof($Occurrences[1][0]);
if($Nbre_Occ>1)die("Il y a ".$Nbre_Occ." GROUP BY dans votre SQL !");

$Nbre_Occ=sizeof($Occurrences[2][0]);
if($Nbre_Occ>1)die("Il y a ".$Nbre_Occ." HAVING dans votre SQL !");

$Nbre_Occ=sizeof($Occurrences[3][0]);
if($Nbre_Occ>1)die("Il y a ".$Nbre_Occ." ORDER BY dans votre SQL !");

//On détermine quels mots clés sont présents
for($a=0;$a<4;$a++)
{
  if($Pos_Mot_cle[$a]>0)
  {
    switch($a)
    {
      case 0:
      $Pds_Mot+=3;
      break;

      case 1:
      $Pds_Mot+=7;
      break;
      case 2:
      $Pds_Mot+=9;
      break;
      case 3:
      $Pds_Mot+=11;
      break;
    }
  }
}
/*En fonction des cas, on élabore le SQL
$SQL[0] est le début du SQL avant tout mot clé de tri
$SQL[1] contient tout le SQL de filtrage
$SQL[2] pour placer le GROUP BY
$SQL[3] pour placer le ORDER*/
$SQL[0] = ''; $SQL[2] = ''; $SQL[3] = '';

if(preg_match("~^:space:*(AND|OR):space:+~i",$Filtre_insecable)) $Filtre_insecable=preg_replace("~^:space:*(AND|OR):space:+~i",'',$Filtre_insecable);

switch($Pds_Mot)
{
  case 0:   //Aucun mot clé
  $SQL[0][0]=$Source;
  break;
  case 3:   //WHERE
  case 10:  //WHERE+GROUP
  case 12:  //WHERE+HAVING
  case 14:  //WHERE+ORDER
  case 19:  //WHERE+GROUP+HAVING
  case 21:  //WHERE+GROUP+ORDER
  case 23:  //WHERE+HAVING+ORDER
  case 30:  //WHERE+GROUP+HAVING+ORDER
    preg_match("~.+WHERE~is",$Source,$SQL[0]);
    $SQL[0][0]=substr($SQL[0][0],0,strlen($SQL[0][0])-5).' ';
  break;
  case 7:   //GROUP
  case 16:  //GROUP+HAVING
  case 18:  //GROUP+ORDER
  case 27:  //GROUP+HAVING+ORDER
    preg_match("~.+GROUP(:space:+)BY~is",$Source,$SQL[0]);
    $SQL[0][0]=substr($SQL[0][0],0,strlen($SQL[0][0])-7-strlen($SQL[0][1])).' ';
  break;
  case 9:   //HAVING
  case 20:  //HAVING+ORDER
    preg_match("~.+HAVING~is",$Source,$SQL[0]);
    $SQL[0][0]=substr($SQL[0][0],0,strlen($SQL[0][0])-6).' ';
  break;
  case 11:  //ORDER
    preg_match("~.ORDER+(:space:+)BY~is",$Source,$SQL[0]);
    $SQL[0][0]=substr($SQL[0][0],0,strlen($SQL[0][0])-7-strlen($SQL[0][1])).' ';
}

switch($Pds_Mot)
{
  case 7:
  case 10:
    preg_match("~GROUP.+~is",$Source,$SQL[2]);
    $SQL[2][0].=' ';
  break;
  case 16:
  case 19:
  case 27:
  case 30:
    preg_match("~GROUP.+HAVING~is",$Source,$SQL[2]);
    $SQL[2][0]=substr($SQL[2][0],0,strlen($SQL[2][0])-6).' ';
  break;
  case 18:
  case 21:
    preg_match("~GROUP.+ORDER~is",$Source,$SQL[2]);
    $SQL[2][0]=substr($SQL[2][0],0,strlen($SQL[2][0])-5).' ';
  break;
}

switch($Pds_Mot)
{
  case 9:
  case 10:
  case 11:
  case 14:
  case 18:
  case 20:
  case 21:
  case 23:
  case 27:
  case 30:
    preg_match("~ORDER.+~is",$Source,$SQL[3]);
  break;
}
$SQL[0][0] .= ' WHERE ';
//On génère les critères de filtrage
Foreach($Tbl_insert as $Cle => $Valeur)
{
  $Liaison=strlen($Tbl_insert[$Cle][3])==0 |(trim(strtoupper($Tbl_insert[$Cle][3]))!='AND' & trim(strtoupper($Tbl_insert[$Cle][3]))!='OR') ? 'AND':trim($Tbl_insert[$Cle][3]);
  if(strlen($Tbl_insert[$Cle][1])>0) $SQL[1] .= ' '.$Liaison.' '.$Tbl_insert[$Cle][0].'='.$Tbl_insert[$Cle][2].addslashes($Tbl_insert[$Cle][1]).$Tbl_insert[$Cle][2].' '.$Liaison.' ';
}
//On enlève tout le superflus
If(strlen($SQL[1])>0)
{
    $SQL[1]=preg_replace("~(AND|OR):space:+AND~i","AND",$SQL[1]);
    $SQL[1]=preg_replace("~(AND|OR):space:+OR~i","OR",$SQL[1]);
}
//On rajoute les critères à ne pas supprimer
$SQL[1] .= $Filtre_insecable;
//On enlève l'éventuel AND ou OR de fin s'il n'y a pas de filtre insécable
$SQL[1]=trim($SQL[1]);
$SQL[1]=preg_replace("~:space:+(AND|OR)$~i","",$SQL[1]);
//S'il aucune condition n'est appliquée, on enlève le WHERE mis par défaut précédemment.
$Check_WHERE=strtoupper(rtrim($SQL[0][0]));
if(substr($Check_WHERE,-5)=='WHERE' & strlen($SQL[1])==0) $SQL[0][0]=substr($Check_WHERE,0,strlen($Check_WHERE)-5);
$SQL[0][0]=$SQL[0][0].$SQL[1].' '.$SQL[2][0].$SQL[3][0];
$SQL[0][0]=preg_replace("~WHERE:space:+(AND|OR):space:+~i","WHERE ",$SQL[0][0]);

//On renvoie le tout
return $SQL[0][0];
}
?>

Conclusion :


Cette fonction est utilisée, entre autre sur la page http://www.vipere.lekod.com/Francais/Stats.php

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.