2010-10-23 5 views
3

Supposons que je la chaîne suivante:Comment briser les requêtes en utilisant php regex en

insert into table values ('text1;'); insert into table values ('text2') 

Comment puis-je briser ces requêtes (obtenir chaque requête) en utilisant des expressions régulières?

J'ai rencontré un problème très similaire: Use regex to find specific string not in html tag ... mais il utilise une solution spécifique à .NET: derrière la recherche (en PHP il se plaint que la longueur n'est pas fixe).

Je serais très reconnaissant si quelqu'un pouvait me donner quelques conseils sur la façon de résoudre ce problème.

Répondre

0

Comment vous voulez casser?

Vous pouvez utiliser explode ('', $ query) pour transformer en tableau.

Ou si vous voulez obtenir les valeurs text1 et text2 avec regexp, vous pouvez utiliser preg_match ('/ (\' ([\ w] +) \ ') /', $ query, $ matches) où $ correspond [1 ] est votre valeur. Preg_match_all ('/ ([\ w] + ([\ w \';] +))/', $ requêtes, $ correspondances) vous donnera toutes les correspondances avec ce motif de requête.

+0

je dois briser le; mais il y a le problème de l'avoir; citations intérieures. Il est possible d'écrire un petit code pour le faire mais je me demandais si c'était possible en utilisant des expressions régulières. – Rafael

+0

La solution preg_match_all peut vous aider. – ReinaldoNS

+0

ouais !!! preg_match_all est la chose cool! – krico

1

L'astuce consiste à compter le nombre caractères de guillemets non échappés que vous avez réussi. En supposant que le SQL est syntaxiquement correct, les points-virgules après un nombre pair de caractères de guillemets non échappés seront ceux que vous voulez, et les points-virgules après un nombre impair de caractères guillemets non échappés feront partie d'un littéral de chaîne. (N'oubliez pas que les littéraux de chaîne peuvent contenir des caractères de guillemets correctement échappés.)

Si vous voulez une fiabilité à 100%, vous aurez besoin d'un vrai analyseur SQL, comme this. (Je viens de googlé « analyseur SQL en PHP » Je ne sais pas si cela fonctionne ou non..)


EDIT:

Je ne pense pas qu'il soit possible de trouver des paires de caractères de guillemets sans échappement en utilisant rien mais regex. Peut-être un gourou de la regex me prouvera-t-il que je me trompe, mais il semble juste trop sacrément difficile de faire la distinction entre des guillemets échappés et des caractères de guillemets non échappés dans autant de combinaisons possibles. J'ai essayé des assertions et des backrefs sans succès.

Ce qui suit est pas une solution pure regex, mais je pense que cela fonctionne:

preg_match_all("/(?:([^']*'){2})*[^']*;/U", str_replace("\\'", "\0\1\2", $input), $matches); 
$output = array_map(function($str){ return str_replace("\0\1\2", "\\'", $str); }, $matches[0]); 

Fondamentalement, nous remplaçons temporairement des guillemets se sont échappés avec une chaîne d'octets qui est extrêmement improbable, dans ce cas \0\1\2. Après cela, tous les caractères de citation qui restent sont les unsescaped. L'expression régulière sélectionne les points-virgules précédés d'un nombre pair de caractères de citation. Ensuite, nous restaurons les caractères de guillemets échappés. (J'ai utilisé une fermeture ici, donc c'est PHP 5.3 seulement.)

Si vous n'avez pas besoin de traiter les caractères de guillemets à l'intérieur des littéraux de chaîne, oui, vous pouvez facilement le faire avec regex pure.

+0

Bien, mais le point de la question est comment faire cela en utilisant des expressions régulières (si c'est possible, bien sûr). Merci quand même. – Rafael

1

En supposant une syntaxe SQL correcte, il serait probablement préférable de diviser le point-virgule.

L'expression rationnelle suivante fonctionnera mais seulement si toutes les citations viennent par paires.

/.+?\'.+?\'.*?;|.+?;/

Pour éviter échappèrent guillemets simples:

/.+?[^\\\\]\'.+?[^\\\\]\'.*?;|.+?;/

Pour gérer plusieurs paires de guillemets simples.

/.+?(?:[^\\]\'.+?[^\\]\')+.*?;|.+?;/

Testé contre l'ensemble de données suivant:

insert en valeurs de la table ('Text1; \' », '2'); insérer dans les valeurs de la table ('text2'); insérer dans la valeur test3 ('cookie \' ',' fly ');

Retours:

insert en valeurs de table ('TEXT1; \' », '2');

insérer dans les valeurs de table ('text2');

insérer dans la valeur test3 ('cookie \' ',' fly ');

Je dois admettre que c'est une regexp assez sale. Cela ne gèrerait pas du tout les erreurs de syntaxe SQL. J'ai bien aimé le défi de trouver une regex pure.

+0

+1 Beau travail avec ça! – mellowsoon

0

Les Regex ne sont pas toujours bons pour ce genre de choses. La fonction suivante devrait fonctionner si:

function splitQuery($query) { 
    $open = false; 
    $buffer = null; 
    $parts = array(); 
    for($i = 0, $l = strlen($query); $i < $l; $i++) { 
     if ($query[$i] == ';' && !$open) { 
      $parts[] = trim($buffer); 
      $buffer = null; 
      continue; 
     } 
     if ($query[$i] == "'") { 
      $open = ($open) ? false: true; 
     } 

     $buffer .= $query[$i]; 
    } 

    if ($buffer) $parts[] = trim($buffer); 
    return $parts; 
} 

Utilisation:

$str = "insert into table values ('text1;'); insert into table values ('text2')"; 
$str = splitQuery($str); 
print_r($str); 

Sorties:

Array 
(
    [0] => insert into table values ('text1;') 
    [1] => insert into table values ('text2') 
)