Perl, HTML and MySQL where did my program break? [closed] - mysql

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
Yes I am a student, yes this is an assignment but I just need some help clearing things up. I don't intend for someone to do my homework for me.
So I have a database with 5 books in it with 6 different columns of data. I'm trying to make a perl program that can search that database and return the results in tables. I have to add a way to add them to a cart but that will come later.
The problem with Perl is I have no idea how to check why I'm getting "Internal Server Error." The application makes it to the Perl page so I'm guessing its not that.
#!/usr/bin/perl
use warnings; # allow for warnings to be sent if error's occur
use CGI qw( :standard ); # not a 100% sure what the rest of these mean but they are like #includs in C++, libraries for reference in the code
use DBI;
use DBD::mysql; #database data will come from mysql
my $dbh = DBI->connect( "DBI:mysql:DATABASE NAME", "USERNAME", "PASS REMOVED" ) or
die( "Could not make connection to database: $DBI::errstr" ); # connect to the database with address and pass or return error
$term = $SEARCHTERM[]; #set the search char to $term
$term =~ tr/A-Z/a-z/; #set all characters to lowercase for convenience of search
$sql = "SELECT * FROM Books WHERE Title LIKE %$term% OR Description LIKE %$term% OR Author LIKE %$term%" or die ("$term may have not worked"); #set the query string to search the database
$sth = $dbh->prepare($sql); # prepare to connect to the database
$sth->execute # connect to the database
or die "SQL Error: $DBI::errstr\n"; #or return an error
while (#data = $sth->fetchrow_array) { #while we are grabbing he queried data do a table setup and set variables for table
print "<table width=\"100%\" border=\"0\"> ";
$title = $data[0];
$desc = $data[1];
$author = $data[2];
$pub = $data[3];
$isbn = $data[4];
$photo = $data[5];
print "<tr> <td width=50%>Title: $title</td> <td width=50% rowspan=5>$photo</td></tr><tr><td>Discreption Tags: $desc</td></tr><tr><td></td></tr><tr><td>Author: $author</td></tr><tr><td>ISBN: $isbn</td>
</tr></table> \n";
}
Please help!

Earlier, someone suggested,
my $sql = "
SELECT *
FROM Books
WHERE Title LIKE '%$term%'
OR Description LIKE '%$term%'
OR Author LIKE '%$term%'
";
my $sth = $dbh->prepare($sql);
$sth->execute();
Assuming he's right about your problem, that's incorrect. Consider what happens if someone is search for the title "Foo's Bar"...
Option 1:
my $sql = '
SELECT *
FROM Books
WHERE Title LIKE '.$dbh->quote("%$term%").'
OR Description LIKE '.$dbh->quote("%$term%").'
OR Author LIKE '.$dbh->quote("%$term%").'
';
my $sth = $dbh->prepare($sql);
$sth->execute();
Option 2:
my $sql = '
SELECT *
FROM Books
WHERE Title LIKE ?
OR Description LIKE ?
OR Author LIKE ?
';
my $sth = $dbh->prepare($sql);
$sth->execute("%$term%", "%$term%", "%$term%");

First, may I also HIGHLY recommend adding use strict; to the top of the script and then fix the errors you will get, mostly declaring your variables with my.
Also may I suggest using a modern framework, like say Mojolicious rather than using the very outdated CGI module. They all can run under CGI-like environment and are FAR easier to use!
Finally, you should avoid interpolating variables into SQL strings since its a huge security risk! Try this site for more on the topic: http://bobby-tables.com/

Your select is invalid. Change
$sql = "SELECT * FROM Books WHERE Title LIKE %$term% OR Description LIKE %$term% OR Author LIKE %$term%"
to
$sql = "SELECT * FROM Books WHERE Title LIKE '%$term%' OR Description LIKE '%$term%' OR Author LIKE '%$term%"'
Pattern literals for LIKE should be quoted.

Related

perl DBI, fastest way to get a single scalar value

I have this code to get a value count.
Short way:
my $count = $dbh->selectrow_array("SELECT COUNT(name) AS RESCOUNT FROM users");
Long way
my $sth = $dbh->prepare("SELECT COUNT(name) AS RESCOUNT FROM users");
$sth->execute() or die "$DBI::errstr";
my $count = $sth->fetchrow_array();
$sth->finish;
selectrow_array, fetchrow_array --> but I don't need an array. I checked the docs, but found nothing for scalars. Just methods for arrays and hashes.
The method I use is fast enough, but I was just curious if there is a better, fastest way to get a single value from the call. Or this is the fastest possible way?
The fastest way is to use fetchrow_arrayref or selectrow_arrayref, depending on how many executes you have. This only really makes a difference if executed in a loop and you have thousands (or rather hundreds of thousands) of rows.
When using fetchrow_array, it will make a copy every time, which slows you down. Also keep in mind that the behaviour for scalar context is only partly defined.
If called in a scalar context for a statement handle that has more than one column, it is undefined whether the driver will return the value of the first column or the last. So don't do that.
You can also do bind_col, which works with references.
There used to be a good presentation on DBI speeds from about 10 or more years ago that I can't find right now. Also take a look at this very old Perlmonks post, that explains quite a bit about performance.
Keep in mind that you should only do optimisation when you really know you need it. Most of the time you won't.
If "modern" means "I only heard of it recently", I'm feeling all modern with DBI's bind_col and bind_columns. Cribbing from a post by DBI hero Tim Bunce...
For your case:
my $sth = $dbh->prepare("SELECT COUNT(name) AS RESCOUNT FROM users");
my $count = 0;
$sth->bind_col(1,\$count); # bind to a reference to the variable
$sth->execute() or die "$DBI::errstr";
$sth->fetch;
print $count;
In a loop for a SELECT statement returning multiple records:
my $sth = $dbh->prepare(qq{SELECT name FROM users WHERE zip_code == '20500'});
my $name = '';
$sth->bind_col(1,\$name); # bind to a reference to the variable
$sth->execute() or die "$DBI::errstr";
while ($sth->fetch) {
print $name, "\n";
}
And with bind_columns this works:
my $sth = $dbh->prepare(qq{SELECT name,phone,address FROM users WHERE zip_code == '20500'});
my #fields = qw/name phone address/;
# With a 'SELECT All * ...', get all columns with #{$sth->{NAME_lc}}
my %data;
$sth->bind_columns( \( #data{#fields} ) ); # \(...) gives references to its elements
$sth->execute() or die "$DBI::errstr";
while ($sth->fetch) {
print "$data{name} lives at $data{address}, with phone $data{phone}.", "\n";
}
Once the setup is handled, the looping is simple to write and fast to run. (But, benchmark).
HTH, apologize if this diverges too much from the OP's problem statement. But it's the simplest and most direct way to get your returned data into the form of variable(s) you want, so you can move on to doing something with it...

Retrieving email addresses with special characters using MySQL query

I am fairly new to PHP and Mysql. The question I am going to ask will be begging for someone to tell me to use prepared statements so first of all let me say I am learning this, but not quite there yet. I have a query that looks to see if an email address is in the database. The email addresses may contain unusual characters like - , / | "" etc etc. I can't seem to retrieve them - here is my code (the repeatemail is coming from a form). Works perfectly with email addresses without this characters.
$checkemail = $_POST['repeatemail'];
$checkemail = mysqli_real_escape_string($con, $checkemail);
//Perform database to see if email exists
$query = "SELECT email FROM scorers WHERE email = '{$checkemail}'";
$result = mysqli_query($con, $query);
$row = mysqli_fetch_row($result);
if ($row[0] == $checkemail){
echo "found";
} else {
echo "not found";
}
As it stands I have wondered if the escape string is stripping the unusual characters and therefore once its queried it been altered but that doesn't seem to be the case. Also, I have no problem entering addresses like simon.o'malley#nhs.uk but just can't check them with the above code. Looked up many explanations regarding UTF etc but its a bit above my head at this point. Could someone give me a solution to this....how do I alter the code above so it will pick out these funky email addresses? Many thanks
Got it...this works fine but if any of you have major concerns let me know. Its the magic quotes issue that seemed to be the only problem. All other characters seem fine
$checkemail = $_POST['repeatemail'];
$check_email_no_slashes = $checkemail;
$checkemail = mysqli_real_escape_string($con, $checkemail);
echo $check_email_no_slashes . "</br>";
//Perform database to see if email exists
$query = "SELECT email FROM scorers WHERE email = '{$checkemail}'";
$result = mysqli_query($con, $query);
$row = mysqli_fetch_row($result);
if ($row[0] == $check_email_no_slashes){ etc etc etc .......}
Thanks for your input Tim.
You really need to use prepared statements. If you don't, you're asking for SQL injection issues (see http://en.wikipedia.org/wiki/SQL_injection). For example, I could send you an email address that would delete all the rows in your table.
Prepared statements aren't hard; here's an example:
$stmt = $mysqli->prepare("SELECT email FROM scorers WHERE email = ?")
// use the string in $checkemail in place of the ?
$stmt->bind_param("s", $checkemail);
// run the query
$stmt->execute();
// put the result into $email
$stmt->bind_result($email);
if ($stmt->fetch()) {
// found a matching email; do something about it
}
$stmt->close();
You can read more about prepared statements in the PHP docs: http://php.net/manual/en/mysqli.prepare.php

Multiple PHP variables in MYSQL query with AND condition

This is my first code-question! I'm a beginner at both MySQL and PHP, so this might be really simple! Here is my code:
This is a file included in my Index.php...:
<?php
$query="SELECT * FROM wines WHERE Type='$type' AND Country='$country'";
$products=mysql_query($query);
?>
And these are the variables set with the $_GET function:
<?php
$type=$_GET['type'];
$fruit=$_GET['fruit'];
$country=$_GET['country'];
?>
And then later I'll fetch the array and work with it.
The problem is that my $query works fine with just the '$type'-variable, but not with the $country -variable - - - - or any other variable I've tried.
I use Microsoft Webmatrix and it tells me that the issue arises the very moment I type in the $-sign in the second variable...
So confused! Hope you can help a newcomer :)
EDIT: I found out the problem was with the "ticks" around my variables. The correct way to do it is with backticks ( `` ). Also, I started using PDO and MySQLi instead of mysql. For beginners, MySQLi is probably the easiest. Started sanitizing too.
Just a couple of (important) points to note...
You should probably be using the mysqli_* functions in the place of the mysql_ functions, as they are going to be deprecated in a following release.
start sanitizing your input before making DB queries. It's a good habit to get into early, and will save you a lot of headaches in the long run!
a good habit it to use sprintf and mysqli_real_escape_string to build your SQL before executing it on the db:
$sql = sprintf("SELECT * FROM wines WHERE Type='%s' AND Country='%s'" ,
mysqli_real_escape_string($db_object, $type),
mysqli_real_escape_string($db_object, $country));
$results = mysqli_query($db_object, $sql);
ps. in my example $db_object is coming from the call to mysqli_connect()
EDIT:
Using the (soon-to-be-defunct) mysql_ functions would be something like the following for the above example:
$sql = sprintf("SELECT * FROM wines WHERE Type='%s' AND Country='%s'" ,
mysql_real_escape_string($type),
mysql_real_escape_string($country));
$results = mysql_query($sql);
If you don't send a $type in your query string, the query is
SELECT * FROM wines WHERE Type='' AND [other stuff];
which will give back only wines with type = '';
Try:
<?php
$wheres=array();
if (isset($type)){$wheres['Type']=$type;}
if (isset($type)){$wheres['Country']=$country;}
// and so forth for each parameter
$query="SELECT * FROM wines";
if (count($wheres) != 0){
$query.=" WHERE ";
foreach ($wheres as $k => $v){$query.="$k='$v' AND ";}
$query.=" 1=1;"
}
$products=mysql_query($query);
?>

PHP/MySQL - Best use and practice of escaping strings [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Best way to prevent SQL Injection in PHP
What is the best way to escape strings when making a query?
mysql_real_escape_string() seems good but I do not exactly know how to use it in properly.
Does this code do the job properly?
<?php
/* Let's say that the user types "'#""#''"\{(})#&/\€ in a textfield */
$newStr = mysql_real_escape_string($str);
$query = "INSERT INTO table username VALUES ($str)";
mysql_query($query);
?>
EDIT:
Now I have this code:
$email = $_POST['email'];
$displayName = $_POST['displayName'];
$pass = $_POST['pass1'];
$email = mysqli_real_escape_string($link, $email);
$displayName = mysqli_real_escape_string($link, $displayName);
$pass = mysqli_real_escape_string($link, $pass);
$insert = "INSERT INTO profiles (email, displayName, password)
VALUES ('$email', '$displayName', md5('$pass'))";
mysqli_query($link, $insert)
or die(mysqli_error($link));
But I get this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '!"#!#^!"#!"#!"#^'''''' at line 1
If the user enters:
'**!"#!#^!"#!"*#!"#^''''
The best way is not to escape the string at all, but instead use a parameterized query, which does it for you behind the scenes.
Using mysql_real_escape_string like that will work, but you need to:
Add quotes around the value.
Use the result $newStr, not the original value $str.
Change the tablename to a name that isn't a reserved keyword.
Add parentheses around the column list.
Try this:
$query = "INSERT INTO yourtable (username) VALUES ('$newStr')";
I also suggest that you check the result of mysql_query($query) and if there is an error, you can examine the error message:
if (!mysql_query($query))
{
trigger_error(mysql_error());
}
You should also consider using one of the newer interfaces to MySQL. The old mysql_* functions are deprecated and should not be used in new code.

How can I insert strings with quotes into Perl DBI queries?

What is the preferred way to insert strings that can contain both single and double quotes (",') into MySql using DBI? For example, $val1 and $val2 can contain quotes:
my $dbh = DBI->connect( ... );
my $sql = "insert into tbl_name(col_one,col_two) values($val1, $val2)";
my $sth = $dbh->prepare($sql);
$sth->execute();
Use a bound query using
$sth = $dbh->prepare("insert into tbl_name(col_one,col_two) values(?,?)");
$sth->execute($val1, $val2);
If you use bound variables, everything is escaped for you.
Update: Changed my example to correspond with the example edited into the question.
Update: I don't know why Adam deleted his answer, but if for some reason you can't use bound variables (aka "placeholders"), you can also use $dbh->quote($var) on the variable. For example:
$sql = sprintf "SELECT foo FROM bar WHERE baz = %s",
$dbh->quote(q("Don't"));
Use the quote() method. It will intelligently handle the quoting for you. Example from the docs:
$sql = sprintf "SELECT foo FROM bar WHERE baz = %s",
$dbh->quote("Don't");
Slightly modified to have both types of quotes:
$sql = sprintf "SELECT foo FROM bar WHERE baz = %s",
$dbh->quote(q("Don't"));
One small caveat on the bound placeholders, I build a rather large database-loading script that initially used bound placeholders in an older version of Perl/DBI and found what appears to be a memory leak in the placeholder implementation, so if you're looking at using them in a persistent process/daemon or in a high-volume context you may want to make sure process size doesn't become an issue. Switching over to building the query strings using the quote() method eliminated the issue for me.
DBI placeholders are awesome. They shine when you need to execute the same query in a loop. Consider this:
my $dbh = DBI->connect(...);
my $name_pairs = get_csv_data("data.csv");
my $sth = $dbh->prepare("INSERT INTO t1 (first_name, last_name) VALUES (?,?)");
for my $pair (#$name_pairs) {
unless ($sth->execute(#$pair)) {
warn($sth->errstr);
}
}
In this case, having the prepared statement handle is, er, handy.
However, barring this sort of tight-loop cases, I like to see the actual statement that was sent to the server. This is where I lean heavily on quote and frankly sprintf.
# Here, I am confident about the hash keys, less so about the values
$sql = sprintf("INSERT INTO t1 (%s) VALUES (%s)",
join(",", keys(%hash)),
join("," map { $dbh->quote($_) } values(%hash))
);
$sth = $dbh->prepare($sql);
unless ($sth->execute) {
warn($sth->{Statement});
}
Note that you do have to set RaiseError => 0 on $dbh so that you can see the SQL that failed, but this has helped me a great deal in the past.
Cheers.