2009-03-05 8 views
1

Ich versuche, eine Regex-Ausdruck in MySQL von einem Perl-Programm zu schreiben. Ich mag Abfrage haben, wie dies:Warum interpoliert meine Variable nicht korrekt, wenn ich eine Mysql-Abfrage erstelle?

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

jedoch in Perl, wenn ich diese Abfrage ich Störung erhalte, wenn verketten:

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

Wo, wie dies mir nicht gibt einen Fehler:

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

In der 'no error' Code beachten, dass es zusätzliche Leerzeichen gibt. Aber wenn ich extra Leerzeichen habe, dann bekomme ich nicht die resuls, die ich will, weil es in der DB keine 'extra spaces' gibt.

+0

Es ist immer hilfreich, um

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

Oder vielleicht vereinfacht werden, um die Fehler in der Nachricht enthalten. :) –

Antwort

2

Ich habe nie wirklich die Autoreplacement von Variablen in solchen Strings vertraut. Sie können explizit tun die Verkettung berücksichtigen wollen Sie so wollen:

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

EDIT: Als ephemient weist auf die allgemein akzeptierte Möglichkeit, diese Inline zu tun ist,

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

Persönlich finde ich die erster Weg besser lesbar, aber wie bei allen Dingen Perl, TIMTOWTDI

+0

Ich bekomme kognitive Dissonanz von sehen "offiziell korrekten Weg" und "TMTOWTDI" in der gleichen Post;) – ephemient

+0

Wird allgemein besser akzeptiert? :-p – Mykroft

6

Der Grund in diesem Fall ist, dass "$ andkeywords [$ i] [[::]:]") als interpretiert wird mehrdimensionales Array und:>: ist kein gültiger Array-Index.

Ich persönlich bevor Mykroft Ansatz, aber man könnte auch das gleiche Ergebnis erzielen, indem die endgültige Öffnung Klammer als so zu entkommen:

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

Nur der Vollständigkeit halber willen, das funktioniert auch:

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

${blah} ist außerhalb einer Zeichenfolge nicht gültig, aber innerhalb einer interpolierbaren Zeichenfolge entspricht sie $blah.

Ich hätte gedacht, dass dieses Muster häufiger als die anderen Antworten ist, obwohl ... wie auch sonst, möchten Sie "foo${var}bar" eingeben? Offensichtlich funktioniert "foo$var\bar" nicht, da \b eine erkannte Escape-Sequenz ist.

6

<Obligatory security moan>

Bitte einen DBI Parameter für jeden regex Wert verwenden, anstatt sie zu interpoliert werden. Warum?

  1. Es gibt keine Einschränkungen mehr, welche Zeichen zulässig sind. Wenn ein Element von @andkeywords ein Anführungszeichen, einen umgekehrten Schrägstrich oder ein spezielles Regex-Zeichen enthält, werden die Dinge zur Zeit zerbrechen. Z.B. Das Schlüsselwort "O'Reilly" verursacht einen Datenbankfehler.
  2. Die Menschen werden nicht in der Lage sein, bösartige Schlüsselwörter zu konstruieren, um Informationen zu enthüllen, die sie nicht sehen oder verheeren sollten. (Stellen Sie sich vor, ein Benutzer hat "'; drop database;" als Schlüsselwort eingegeben.) Dies wird eine SQL-Injektion Angriff genannt, und das Web ist rife mit schlecht codierten Websites, die für sie anfällig sind. Lass nicht zu, dass du einer von ihnen bist.

Auch wenn @andkeywords nicht vom Benutzer eingegebenen Daten gefüllt wird, dauert es fast keinen zusätzlichen Aufwand DBI Parameter zu verwenden, und der Code wird für den Einsatz in zukünftigen unbekannten Umgebungen sicher sein.

</Obligatory security moan>

+0

Danke, jrh, dass du darüber hinaus gehst und antwortest: "Wie interpoliere ich diese Zeichenfolge?", um hinzuzufügen, "aber du solltest wirklich keine Zeichenfolge dort interpolieren". –

0

Es wäre hilfreich, wenn Sie den Text von Fehlermeldungen umfassen würde.

Etwas sagt mir, dass

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

konnte

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