2009-03-05 11 views
1

J'essaye d'écrire une expression regex dans mysql d'un programme de Perl. Je veux avoir la requête comme celle-ci:Pourquoi ma variable ne interpole pas correctement lorsque je crée une requête Mysql?

WHERE a.keywords REGEXP '[[:<:]]something[[:>:]]' 

Cependant, en Perl quand je fais cette requête, je reçois erreur lorsque concaténer:

for($i=0;$i<$count;$i++){ 
    $where = $where . "'[[:<:]]$andkeywords[$i][[:>:]]' "; #errors 

Où que cela ne me donne pas une erreur:

for($i=0;$i<$count;$i++){ 
    $where = $where . "'[[:<:]] $andkeywords[$i] [[:>:]]' "; #no error 

Dans le code 'aucune erreur', notez qu'il y a des espaces supplémentaires. Mais si j'ai des espaces supplémentaires, je ne reçois pas les résultats que je veux parce que dans la DB il n'y a pas d'espaces supplémentaires.

+0

Il est toujours utile d'inclure les erreurs dans votre message. :) –

Répondre

2

Je n'ai jamais vraiment fait confiance à l'auto-placement de variables dans des chaînes comme ça. Vous voudrez peut-être envisager de faire explicitement la concaténation que vous voulez comme ceci:

for($i=0;$i<$count;$i++){ 
    $where=$where . "'[[:<:]]" . $andkeywords[$i] . "[[:>:]]' "; 

EDIT: Comme ephemient indique le chemin généralement accepté de le faire en ligne est

for($i=0;$i<$count;$i++){ 
    $where=$where . "'[[:<:]]${andkeywords[$i]}[[:>:]]' "; 

Personnellement, je trouve la première façon plus lisible, mais comme avec toutes les choses Perl,

+0

Je reçois la dissonance cognitive de voir "officiellement correct" et "TMTOWTDI" dans le même post;) – ephemient

+0

Est-ce généralement mieux accepté? :-p – Mykroft

6

La raison dans ce cas est que "$ andkeywords [$ i] [[:>:]]" est interprété comme un tableau multidimensionnel et:>: n'est pas un index de tableau valide.

Personnellement, je préfère l'approche de Mykroft, mais vous pouvez également obtenir le même résultat en échappant le support d'ouverture finale si:

$where=$where."'[[:<:]]$andkeywords[$i]\[[:>:]]' "; 
7

Juste pour être complet, cela fonctionne aussi:

for ($i = 0; $i < $count; $i++) { 
    $where .= "'[[:<:]]${andkeywords[$i]}[[:>:]]' "; 
} 

${blah} n'est pas valide en dehors d'une chaîne, mais à l'intérieur d'une chaîne interpolable, elle équivaut à $blah.

J'aurais pensé que ce modèle est plus commun que les autres réponses, bien que ... après tout, comment voulez-vous taper "foo${var}bar"? Évidemment "foo$var\bar" ne fonctionne pas, puisque \b est une séquence d'échappement reconnue.

6

<Obligatory security moan>

S'il vous plaît utiliser un paramètre DBI pour chaque valeur regex au lieu de interpoler il. Pourquoi?

  1. Il n'y a plus aucune contrainte sur les caractères autorisés. Actuellement, si un élément de @andkeywords contient un guillemet, une barre oblique inverse ou un caractère rationnel spécial, les choses vont se casser. Par exemple. le mot clé "O'Reilly" provoque une erreur de base de données.
  2. Les personnes ne seront pas en mesure de construire des mots-clés malveillants pour révéler des informations qu'ils ne devraient pas voir ou faire des ravages. (Imaginez si un utilisateur a entré "'; drop database;" comme mot clé.Ceci est appelé une attaque par injection SQL, et le web est avec des sites Web mal codés qui sont sensibles à eux. Ne laissez pas le vôtre être l'un d'entre eux.

Même si @andkeywords n'est pas remplie à partir des données saisies par l'utilisateur, il prend presque aucun effort supplémentaire pour utiliser les paramètres DBI et votre code sera sans danger pour l'utilisation dans les futurs environnements inconnus.

</Obligatory security moan>

+0

Merci, jrh, d'aller au-delà de répondre "comment puis-je interpoler cette chaîne" pour ajouter "mais vous ne devriez vraiment pas interpoler une chaîne là-bas en premier lieu". –

0

Il serait utile que vous inclure le texte des messages d'erreur.

Quelque chose me dit que

for($i=0;$i<$count;$i++){ 
    $where=$where . "'[[:<:]]" . $andkeywords[$i] . "[[:>:]]' "; 
    ... 
} 

pourrait être simplifié pour

for (@andkeywords) { 
    $where .= qq('[[:<:]]${_}[[:>]]'); 
    ... 
} 

Ou peut-être

$where .= join ' ', map { qq('[[:<:]]${_}[[:>:]]') } @andkeywords; 
Questions connexes