Code:
# Receive SQL query from form
my $sql = param('sql_query');
This is about the worst thing you could possibly do.
When a form submission comes in, the other user can fill out any field any way they please. So in this case, the user can send any SQL statement to your database, and it is possible, with SQL, to completely take over your system.
And if it's for your personal use, or you're just experimenting, or whatever: lots of people could read this post, and some of them will inevitably copy and paste your code without thinking.
If you need to experiment with different queries, incidentally, it's easier to use
DBI Shell than to muck about with a CGI mysteriously returning 500 Internal Server Error because you forgot a semicolon.
So, the right way:
I'll have to guess at the SQL, but this is generally how you'd do it:
(See
this if the q{ } is confusing.)
Code:
my $sql = q{
SELECT FieldA, FieldB, FieldC
FROM Jobs
WHERE Department = ?
};
my $department = param('department');
# Prepare SQL statement for execution
my $sth = $dbh->prepare($sql) or die "Cannot prepare: " . $dbh -> errstr();
# Execute prepared statement
$sth->execute($department) or die "Cannot execute: " . $sth->errstr();
The question mark is a placeholder. You'll notice that execute now takes a parameter. This is called a "bind value."
Perl allows you to "interpolate" variables into your SQL. This is almost always a bad idea because it allows for SQL injection. If at all possible, use bind variables. One case where it is difficult is if you using an IN expression in a where clause. A reasonable compromise is this:
Code:
my(@inArray) = ('this', 'that', 'whatever');
my $inList = join(', ', map($dbh->quote($_), @inArray));
# Or if that's confusing:
my @inArrayQuoted = ();
foreach my $item (@inArray) {
push @inArrayQuoted, $dbh->quote($item);
}
my $inList = join(', ', @inArrayQuoted);
my $sql = qq{
SELECT Foo, Bar FROM Qux WHERE Foo IN ($inList)
};
But if you forget to quote in just one place, you open the possibility of SQL injection. If you never interpolate, it's much, much harder for some joker to run his code on your DBMS.
There are more advanced binding techniques that let you carefully specify the parameter type. But DBI usually gets it right, so there's not much call for it unless you're trying to tweak performance or do something complicated with BLOBs.