I am trying to pass a command to my database (MariaDB/MySQLi) but Perl's DBI is giving me an error, whatever I try. The thing is that I can execute the MySQL fine in phpMyAdmin without fault. The error that I receive is:
DBD::mysql::st execute failed: You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for
the right syntax to use near SELECT DISTINCT t.bf FROM wrpec t JOIN wrpec r ON t.path LIKE r.path || '%' at line 2 at
retrieve-includes.pl line 20.
DBD::mysql::st fetchrow_array failed:
fetch() without execute() at retrieve-includes.pl line 22.
The full test file (fake database obviously) is as below.
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Data::Dumper;
my $dsn = "DBI:mysql:database=mydatabase;host=machine";
my $dbh = DBI->connect($dsn, 'root', '') or die "Couldn't connect to database: " . DBI->errstr;;
my $request_includes = "
SET sql_mode = PIPES_AS_CONCAT;
SELECT DISTINCT t.bf
FROM `wrpec` t
JOIN `wrpec` r
ON t.path LIKE r.path || '%'
WHERE r.bf = 'WRPECsmain\%hd' AND t.has_tree;";
my $sth = $dbh->prepare($request_includes) or die "Couldn't prepare statement: " . $dbh->errstr;
$sth->execute();
while (my #row = $sth->fetchrow_array()) {
print Dumper(\#row);
}
$sth->finish();
I have also tried some ideas I found online: using a clean-up sub that replaces all white-space characters by hard spaces to make sure you're passing a string, and I also tried this notation (I forgot the name) but it doesn't work either (same error).
my $request_includes = <<"REQUEST_INCLUDES";
SET sql_mode = PIPES_AS_CONCAT;
SELECT DISTINCT t.bf
FROM `wrpec` t
JOIN `wrpec` r
ON t.path LIKE r.path || '%'
WHERE r.bf = 'WRPECsmain\%hd' AND t.has_tree;
REQUEST_INCLUDES
You're getting a SQL syntax error because by default, DBD::mysql doesn't allow you to execute multiple statements at once. You should run two separate DBI commands instead:
$dbh->do( q{SET sql_mode = 'PIPES_AS_CONCAT'} );
my $sth = $dbh->prepare(q{
SELECT DISTINCT t.bf
FROM `wrpec` t
JOIN `wrpec` r
ON t.path LIKE r.path || '%'
WHERE r.bf = 'WRPECsmain\%hd' AND t.has_tree
});
I was trying to create a script that works on MySQL as wel as PostgreSQL without changes.
Enable MySQL's ANSI mode and double quote your identifiers:
$dbh->do( q{SET sql_mode = 'ANSI'} ) if $mysql;
my $sth = $dbh->prepare(q{
SELECT DISTINCT t.bf
FROM "wrpec" t
JOIN "wrpec" r
ON t.path LIKE r.path || '%'
WHERE r.bf = 'WRPECsmain\%hd' AND t.has_tree
});
There are a couple other issues, though:
unescaped _ and % in r.path will be interpreted as wildcards
'foo' LIKE 'foo%' is true
To only fetch rows where the t.path is a prefix of r.path, but they're not equal, do:
SELECT DISTINCT t.bf
FROM "wrpec" t
JOIN "wrpec" r
ON POSITION(t.path IN r.path) = 1
AND t.path != r.path
WHERE r.bf = 'WRPECsmain\%hd'
AND t.has_tree
Related
If I run the code below in phpMyAdmin for my DB, then I get 17 records, but when I run it in TYPO3 6.1.4 I get all records in DB (200), why does it not work 100% in TYPO3, when it works in phpMyAdmin.
public function getKategorierne($catId){
//print $catId;
$query = $this->createQuery();
$query->statement('SELECT * '.
'FROM sys_category_record_mm '.
'INNER JOIN sys_category ON ( uid = uid_local ) '.
'WHERE tablenames = "tx_origkentaurproducts_domain_model_design" '.
'AND sys_category_record_mm.uid_local '.
'IN ('.$catId.') '.
'ORDER BY uid_foreign');
return $query->execute();
}
And why all the inverted commas!?!?
$query = "
SELECT *
FROM sys_category_record_mm r
JOIN sys_category c
ON uid = uid_local
WHERE tablenames = 'tx_origkentaurproducts_domain_model_design'
AND r.uid_local IN ('$catId')
ORDER
BY uid_foreign;
";
according to this tutorial:http://www.tizag.com/mysqlTutorial/mysql-php-sql-injection.php
Below codes will demonstrate SQL Injection:
<?php
// a good user's name
$name = "timmy";
$query = "SELECT * FROM customers WHERE username = '$name'";
echo "Normal: " . $query . "<br />";
// user input that uses SQL Injection
$name_bad = "' OR 1'";
// our MySQL query builder, however, not a very safe one
$query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
// display what the new query will look like, with injection
echo "Injection: " . $query_bad;
In front end, it shows:
Injection: SELECT * FROM customers WHERE username = '' OR 1''
So I just did a test, in phpmyadmin->sql, I run below codes:
SELECT * FROM users WHERE fname = '' OR 1''
And it shows:
#1064 - 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 ''' LIMIT 0, 30' at line 1
Qustion:
supposed it will show every single entry in the "users" table, but not, why? if I want to demonstrate sql injection, how to do it?
A more typical SQL injection would be: $name_bad = "' OR 1=1 -- ";. This would lead to the following SQL:
SELECT * FROM customers WHERE username = '' OR 1=1 -- '
SELECT * FROM users WHERE fname = '' OR 1 = 1
is likely what they meant
edit just looked
SELECT * FROM users WHERE fname = '' OR 1
1 evaluates to true, so just remove the '' after it
also that link is way out of date, Look at mysqli or pdo instead
I'm a newbie to mysql, I managed to scrape this together to get the result I wanted. Can it be coded better? Are there any security risks? Its being output in php.
$qwe = $product->virtuemart_product_id;
$id = mysql_real_escape_string($qwe);
$result = mysql_query('SELECT * FROM virtuemart_product_medias where virtuemart_product_id = ' . $id . ' LIMIT 1');
$row = mysql_fetch_assoc($result);
$matched = $row['virtuemart_media_id'];
$result2 = mysql_query('SELECT * FROM virtuemart_medias where virtuemart_media_id = ' . $matched . ' LIMIT 1');
$row2 = mysql_fetch_assoc($result2);
$matched2 = $row2['file_url_thumb'];
echo $matched2;
I don't know whether or not there is a security hole in the specific code you provided - that depends on what other validation exists elsewhere in your program, and what you consider to be a security hole. But the way you are coding means that there definitely could be security holes. Let's look at your first query:
$id = mysql_real_escape_string($qwe);
$result = mysql_query('SELECT *
FROM virtuemart_product_medias
WHERE virtuemart_product_id = ' . $id . ' LIMIT 1');
Imagine if $qwe is the string 0 OR 1=1 --. The mysql_real_escape_string only escapes certain characters such as quotes and backslashes.
mysql_real_escape_string() calls MySQL's library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00, \n, \r, \\, ', " and \x1a.
The string 0 OR 1=1 -- that I mentioned above does not contain any of these characters so it will not be affected at all by mysql_real_escape_string. After you substitute in the value of $id, the resulting SQL query will look something like this:
SELECT *
FROM virtuemart_product_medias
WHERE virtuemart_product_id = 0 OR 1=1 -- LIMIT 1
As you can see, this will return all rows.
Long story short: Use PDO and parameterized queries.
Related
How can I prevent SQL injection in PHP?
Firstly, never use the mysql_* functions. They are deprecated and relying on them is highly discouraged. Use either MySQLi or PDO
The above query could be rewritten as
SELECT file_url_thumb FROM virtuemart_medias where virtuemart_media_id = (SELECT virtuemart_media_id FROM virtuemart_product_medias where virtuemart_product_id = ' . $id . ' LIMIT 1) LIMIT 1
Never do a SELECT *. Include only those fields in your query which you need in your code.
Use one query instead of two, and select only the fields you're using, like so:
SELECT `file_url_thumb` FROM virtuemart_medias where virtuemart_media_id = (SELECT `virtuemart_media_id` FROM virtuemart_product_medias where virtuemart_product_id = ' . $id . ' LIMIT 1) LIMIT 1
You can always use a join;
SELECT a.virtuemart_media_id, b.file_url_thumb
FROM virtuemart_product_medias a
LEFT JOIN virtuemart_medias b
ON a.virtuemart_media_id = b.virtuemart_media_id
WHERE virtuemart_product_id = $id
LIMIT 1
That'll always get you the virtuemart_media_id and, if it exists file_url_thumb.
Your query has a problem also, mysql_real_escape_string only escapes strings, since you're not quoting the $id in the query, it won't be handled as a string and the escaping will not help you. As other replies point out, you should really be using mysqli or PDO.
How about this:
SELECT a.file_url_thumb
FROM virtuemart_medias a
LEFT JOIN virtuemart_product_medias b on a.virtuemart_media_id=b.irtuemart_media_id
WHERE a.virtuemart_product_id=' . $id . ' LIMIT 1
I have this Perl code:
my $cmd = "
SELECT COUNT(id)
FROM tblUsers
WHERE UPPER(username) = UPPER(?) AND password = ?
";
db_connect();
my $sql = $dbh->prepare($cmd);
my $count = 2;
$sql->execute(
$args{login_username},
crypt($args{login_password}, $args{login_username})
) or die "SQL Error: ".$sql->errstr;
$sql->bind_columns(\$count);
$sql->fetch;
which is returning 0, but should be returning a 1
If I output the following:
$msg = "wrong username/password: $count;$args{login_username};$args{login_password};" . crypt($args{login_password}, $args{login_username});
I get:
wrong username/password: 0;skeniver;password;skh9dtk2bCasY
and the crypt part is exactly what I have in the database. Running the same values in MySQL returns a count of 1.
I really can't figure out what's going wrong here.
Does anyone else see something I'm missing?
Assuming your select returns a non 0 value and assuming that the column password in tblUsers has skh9dtk2bCasY for username=skeniver, Try
$sql->execute($args{login_username}, crypt($args{login_password},$args{login_username}))
or die "SQL Error: ".$sql->errstr;
$count = $sql->fetchrow_array();
Or, if there is a possibility that the query returns multiple rows then-
$sql->execute($args{login_username}, crypt($args{login_password},$args{login_username}))
or die "SQL Error: ".$sql->errstr;
while (($count) = $sql->fetchrow_array()){
print "Count is: $count\n";
}
I have a query like this
set #valid_total:=0;
set #invalid_total:=0;
select week as weekno, measured_week,project_id as project,
role_category_id as role_category,
valid_count,valid_tickets,
(#valid_total := #valid_total + valid_count) as valid_total,
invalid_count,invalid_tickets,
(#invalid_total := #invalid_total + invalid_count) as invalid_total
from metric_fault_bug_project
where measured_week = yearweek(curdate())
and role_category_id = 1 and project_id = 11;
it executes fine in heidi (MySQL client) but when it comes to perl, it gives me this error
DBD::mysql::st execute failed: You have an error in your SQL syntax; check the m
anual that corresponds to your MySQL server version for the right syntax to use
near ':=0;
set :=0;
select week as weekno, measured_week,project_id
as project' at line 1 at D:\Mx\scripts\test.pl line 35.
Can't execute SQL statement: You have an error in your SQL syntax; check the man
ual that corresponds to your MySQL server version for the right syntax to use ne
ar ':=0;
set :=0;
select week as weekno, measured_week,project_id
as project' at line 1
The problem seem to be in the set #valid_total := 0; line.
I am fairly new to Perl. Can anyone help?
this is the complete perl code
#!/usr/bin/perl
#use lib '/x01/home/kalpag/libs';
use DBI;
use strict;
use warnings;
my $sid = 'issues';
my $user = 'root';
my $passwd = 'kalpa';
my $connection = "DBI:mysql:database=$sid;host=localhost";
my $dbhh = DBI->connect( $connection, $user, $passwd) ||
die "Database connection not made: $DBI::errstr";
my $sql_query = 'set #valid_total:=0;
set #invalid_total:=0;
select week as weekno, measured_week,project_id,
role_category_id as role_category,
valid_count,valid_tickets,
(#valid_total := #valid_total + valid_count) as valid_total,
invalid_count,invalid_tickets,
(#invalid_total := #invalid_total + invalid_count) as invalid_total
from metric_fault_bug_project
where measured_week = yearweek(curdate())
and role_category_id = 1 and project_id = 11';
my $sth = $dbhh->prepare($sql_query) or die "Can't prepare SQL statement: $DBI::errstr\n";
$sth->execute() or die "Can't execute SQL statement: $DBI::errstr\n";
while ( my #memory = $sth->fetchrow() )
{
print "#memory \n";
}
You are probably using a double quoted string for your query string, in which case perl looks for the variables #valid_total and #invalid_total. This would imply that you are not using
use strict;
use warnings;
Because otherwise you would already know the error. The result is that perl replaces the variables with nothing, which is reflected in your error.
What you need to do is single quote the string:
my $query = 'set #valid_total:=0;
set #invalid_total:=0;
select week as weekno, measured_week,project_id as project,
role_category_id as role_category,
valid_count,valid_tickets,
(#valid_total := #valid_total + valid_count) as valid_total,
invalid_count,invalid_tickets,
(#invalid_total := #invalid_total + invalid_count) as invalid_total
from metric_fault_bug_project
where measured_week = yearweek(curdate())
and role_category_id = 1 and project_id = 11';
Please always use strict and warnings. if you don't have a variable #valid_total, warnings would then warn you
Possible unintended interpolation of #valid_total in string
and strict would even die.
In double quoted strings you must escape # signs:
"set \#valid_total:=0;"
and if you don't need interpolation at all, better use single quotes.
edit: after I can see the perl code:
rather then doing
my $sql_query = 'set #valid_total:=0;
set #invalid_total:=0;
...';
my $sth = $dbhh->prepare($sql_query)
you should do:
my $sql_query = 'set #valid_total:=0';
my $sth = $dbhh->prepare($sql_query);
$sth->execute;
$sth->finish;
$sql_query = 'set #invalid_total:=0'
$sth = $dbhh->prepare($sql_query);
$sth->execute;
$sth->finish;
...
you cannot execute more than one statement in one query.