I'm adding an if
statement to my database abstraction layer to pick out any attempted queries to a handful of database tables.
Basically, if my application attempts to create, read or destroy data from a database table called either members
or members_profiles
I want to invoke my if
statement.
if (
preg_match('/INSERT INTO [members|members_profiles]/', $sql) ||
preg_match('/UPDATE [members|members_profiles]/', $sql) ||
preg_match('/DELETE FROM [members|members_profiles]/', $sql))
{
// do if statement stuff here...
}
I'm no regular expression/preg-match master, but will the above if
statement return true if a SQL query matches:
INSERT INTO members ...
or INSERT INTO members_profiles ...
UPDATE members ...
or UPDATE members_profiles ...
DELETE FROM members ...
or DELETE FROM members_profiles ...
Or is my preg-match syntax way off?
Just one regex will be enough:
if (preg_match('/(?i)(INSERT\s+INTO|UPDATE|DELETE\s+FROM)(?-i)\s+(members|members_profiles)/', $sql))
{
// do if statement stuff here...
}
note the ()
instead of []
and \s+
instead of spaces. because SQL is valid with any number of nay whitespace, and \s+
matches them all. The +
behind \s
means that it must be at least one whitespace, but it can be more. The (?i)
means that all following characters will be checked case insensitive, and the (?-i)
turn case sensitivity on again. Since SQL commands are case insensitive.
(abc|def)
matches abc
or def
[abc|def]
matches a
, b
, c
, |
, d
, e
or f
To try out a regular expression you can use http://rubular.com/, it says it's written in ruby for testing regex in ruby, but valid regex should be independent of language, so it can be used to test common regular expressions, that work in other languages, too.
The syntax is valid but won't do what you want.
For alternation of patterns, use
preg_match('/INSERT INTO (?:members|members_profiles)/', $sql) ||
// ^^^ ^
In PCRE, […]
defines a character class. This will match 1 character, given it appears inside the brackets. In your case [members|members_profiles]
will match 1 character if it is one of b
, e
, f
, i
, l
, m
, o
, p
, r
, s
, |
or _
.
Grouping is done using another kind of parenthesis, (?:…)
.
(BTW, please don't use Regex to detect database changing attempts. Restrict the permissions of the database user instead.)
This is correct
if (
preg_match('/INSERT\sINTO\s(members|members_profiles)/', $sql) ||
preg_match('/UPDATE\s(members|members_profiles)/', $sql) ||
preg_match('/DELETE\sFROM\s(members|members_profiles)/', $sql))
{
// do if statement stuff here...
}
LE: Changed white space escaping with white space(s) special character
The regex
[ab|cd]
does not match either ab
OR cd
but matches one of the following single (!) characters: a
, b
, |
, c
or d
.
What you need is a group instead of a character class:
(ab|cd)
which does match either ab
OR cd
.
More info on character classes: http://www.regular-expressions.info/charclass.html
Apart the errors already reported by other users, your regular expression is too restrictive, if you need to detect when a query is trying to alter the tables members
, and members_profiles
.
I would not use such approach, but if you need to really do that then consider that
INSERT INTO /* little trick */ members …
, or INSERT /* into */ INTO /* table */ members …
.