For a search feature I wrote a MySQL query to be executed by a PHP script. I'm not doing a fulltext search. Instead, I'm doing a search using the following method:
... WHERE field LIKE '%etc%' AND field REGEXP '[[:<:]]etc[[:>:]]'
Now, my idea is to prepare these dynamic values in PHP, like:
$word = '2*3%5_1^0'; // just an example
$wordLike = strtr($word,array('\\'=>'\\\\','%'=>'\\%','_'=>'\\_'));
// instead of my old solution:
// $wordLike = preg_replace('~([%_])~', '\\\\$1', $word);
$wordLike = $db_con->escape('%' . $wordLike . '%');
$spaces = '[[:blank:]]|[[:punct:]]|[[:space:]]';
// I'm not sure about the difference between blank & space, though
$wordRX = preg_quote($word);
$wordRX = $db_con->escape('(^|'.$spaces.')'.$wordRX.'($|'.$spaces.')');
// instead of my old solution:
// $wordRX = $db_con->escape('[[:<:]]' . $wordRX . '[[:>:]]');
and then use these values like in…
... WHERE field LIKE '$wordLike' AND field REGEXP '$wordRX'
which, with this example input, results in
...
WHERE field LIKE '%2*3\\%5\\_1^0%' AND
field REGEXP '[[:<:]]2\\*3%5_1\\^0[[:>:]]`
A couple of notes…
In my actual code I'm making it handle multiple words, this is just the pseudo code.
The method I'm using to search the word(s) -with LIKE & REGEXP together- was the fastest one among the approaches I tried.
I know I should use PDO instead, please don't input anything about that unless it's relevant to my issue
Q1: Is this the right way to go?
Q2: Is this secure enough against SQL injections?
Some additional info
About MySQL REGEXP…
Following characters are escaped by preg_quote()
. \ + * ? [ ^ ] $ ( ) { } = ! < > | : -
Following is the list of [occasionally] special characters in REGEXP
. \ + * ? [ ^ ] $ ( ) { } | -
There are also additional constructs in REGEXP but they're all surrounded by single/double brackets, and because I know all the brackets will be escaped by preg_quote() I feel like I shouldn't be concerned about them.
About MySQL LIKE…
The only 2 special characters in LIKE are
_ %
So escaping them seems enough a workaround.
Please correct me if I'm missing anything.
Appart from what you mention mysql_real_escape_string() function should do fine for sanitization against SQL injection.
You just have to properly escape whatever user input using the appropiate escaping function(s), if you picture it as chained processing blocks processing this user input you will know in which order (from last to first) and what to escape/unescape and when, and you should be okay as far as securing a clean input goes (validation is a different issue).
And, as you already seem to know, quote() on PDO or Mysqli prepare() are a better approach.
try this use mysql_real_escape_string()
$word = '2*3%5_1^0';
$query = 'SELECT * FROM TABLE_NAME WHERE field REGEXP "(.*)[[:<:]]'.mysql_real_escape_string($word).'[[:>:]](.*)" ';
function clean($str) {
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
then:
$word = clean($_POST['whatever post']);
then trim word and your good to go. what this php function does is take all literals and turns them into strings so no one can lets say delete your db etc
Related
I want some real life scenario in programming where we can use this solr util method i.e. SolrUtils::escapeQueryChars().
Now I am using it for escaping query chars from query in solr.
q:+popularity:[10 TO *] +section:0
And I am using
escapeQueryChars(+popularity:[10 TO *] +section:0)
But I am unable to get the result after escaping.
SolrUtils::escapeQueryChars is usually used to escape characters in the Query which have special meaning in Solr.
The current list of characters are + - && || ! ( ) { } [ ] ^ " ~ * ? : \ which have special meaning in Solr and the behaviour would be different if not escaped.
for example if you are searching for 5* unless escaped it would behave as a wildcard search and return results with tokens starting from 5.
It shall be used in query values only.
Most of the time you will be accepting queries from a user. So its essential to escape these characters to avoid exceptions
a user search query can be: "Thomas' Calculus (12th Edition)"
The user query above would certainly lead to unwanted results
$query = new SolrQuery('product_name:'.SolrUtils::escapeQueryChars($userQuery));
I have a PHP script that is generating a MySQL select statement:
select * from words where word = 'Classic'
There is exactly one word in the words table with the variable word equal to Classic.
When my PHP page executes, I get no results from the query. If I echo the string that is being used to execute the query, cut and paste that into the SQL window in PHPMyAdmin in the database, I also get no results. However, if I re-type that EXACT string into the SQL window in PHPMyAdmin (with the same quote characters), I get the proper result of one row.
The word Classic from the select statement is gotten from a PHP GET (see code below). I can echo the $word variable, and get the correct result of 'Classic'. What am I doing wrong?
Here is my code:
<?php
require ('dbconnect.php');
$word = $_GET["word"];
$selectStr = "SELECT * FROM words WHERE word = '" . $word . "'";
if ($results = MySQL($dbName, $selectStr))
{
$rowCount = MySQL_NUMROWS($results);
}
$resultRow = MYSQL_FETCH_ROW($results);
$wordID = $resultRow[0];
?>
Please, please, please sanitize that word. mysql_real_escape_string() should do the trick.
$selectStr = "SELECT * FROM words WHERE word LIKE '" . $sanitized_word_i_promise . "'"; should work :)
Just to explain: "=" should work for exact matches. This includes uppercase / lowercase, spaces etc. You should probably trim that result first too, before using it in the query.
If you have foo stored in the database (note the space at the end) - it won't match foo, without a space. You'll want to use LIKE 'foo%' - probably.
Either way, Sourabh is right, although performance wise, this isn't a big hit when trying to match exact strings, you should look for the problem in other places first (such as, is the item in the database an exact match?).
First off you should not take any user input and directly input it into a query without sanitizing it, or using a prepared statement.
Now that we've gotten that out of the way: have you tried doing a strcmp() with the variable and your string written in? Such as
echo strcmp($_GET['word'], "Classic")
If you get a result other than 0 it means they are not the same, most likely there will be a whitespace of some sort in the $_GET variable. use trim() on it to take out whitespace. Also could be a case sensitivity issue as well.
I'm having trouble with the ampersand symbol, because I've to allow user to insert page_title within database.
The problem is that in my mother language many companies have the symbol in their names like per example "Santos & Filhos".
The question is, how can I insert this, without break my database and without opening security issues?
using this the database gets broken
$title = preg_replace('/&/', '&', $title);
$final_title = utf8_encode($title);
I'm using utf8_encode because of the other accents like á or ã
Thanks, hope you can help me here
EDIT
ok, first thanks to all, most of you were wright, mysql_real_escape_string is indeed one of the best options, if not the best.
I discovered that I was missing one escape (in query) before post my variables to be processed by php and inserted within the database.
So I manage to get my & but now I can't manage to have accents...
So far my php code looks like this
$title = mysql_real_escape_string($_POST['title']);
$sql = "UPDATE bodytable SET body_title = '".utf8_encode($title)."'";
and then in my frontage I've
utf8_decode($row['body_title']);
the result is
<title>Santos & Filhos - Repara?es de autom?veis</title>
Escape characters going into the database with something like mysql_real_escape_string() or PDO and use htmlentities() when displaying it.
This covers securing user input: What's the best method for sanitizing user input with PHP?
Try using an escape character in front of all your special characters you want to insert in the database. Encoding is ok but for example, if the following string was to be added to mysql string field you would get an error.
"special characters don't work"
And you can do this to prevent these errors
"special characters don\'t work"
I belive there is a methods called addslashes(string x) and stripslashes(string x) that will do that for you.
$title_to_insert_in_database = $str = addslashes($title);
$title_for_page = htmlspecialchars($title_from_database);
The user has a search box.
I need to give him flexibility so he ca do a search like client and the sql for this will be
name like '%client%'
The problem is I don't want to give the user the possibility to search with % or _ wildcards.
I know I can escape them .. but is there a function to do this for any wildcard/ or other solution ?
create or replace function escape_like(text)
returns text language sql immutable strict as
$q$
select regexp_replace($1, $$([\\%_])$$, $$\\\1$$, 'g')
$q$;
Try it:
=> select escape_like($$foo%bar\foo__bar$$);
quote_like
----------------------
foo\%bar\\foo\_\_bar
(1 row)
So your query should look similar to:
select * from tablename where columnname like '%' || escape_like(?) || '%';
In MySQL you can do it with PHP:
$text_escaped = addcslashes($text, '%\\_');
I guess the same applies to PostgreSQL, but I remeber reading something on their mailing list that you need to double escape the backward slashes in order for it to work properly, I'm not sure though...
Why don't you use full text search?
I want to grab a random sample of data out of my database using CakePHP. Here's my function:
function categories_list()
{
$this->paginate['limit'] = 6;
$this->paginate['order'] = '';
$this->paginate['conditions'] = '';
// Sort Randomly Start
if ($this->Session->check('Category.randomSeed'))
{
$seed = $this->Session->read('Category.randomSeed');
} else {
$seed = mt_rand();
$this->Session->write('Category.randomSeed', $seed);
}
$this->paginate['order'] = sprintf('RAND(%d)', $seed);
// Sort Randomly End
$this->set('cat_ajax_items', $this->paginate('Category'));
}
The problem is, the query that Cake sends to the DB always does this to the RAND() portion, sending MySQL into a hissy fit:
ORDER BY RAND(`1235123412341`)
Testing on a manual query, it works just fine, and returns a sample when it's formatted like this:
ORDER BY RAND(1235123412341)
Is there any way to get Cake to back off of the autoformatting? Anything I put into that RAND() function gets dumped into string quotes.
Anything I put into that RAND() function gets dumped into string quotes.
No, this isn't correct. If it used string quotes then it would work fine, however backticks aren't string quotes. The problem is that CakePHP is quoting the number as if it were a column name. Try quoting the value using single quotes instead:
"RAND('%d')"
This should result in the following SQL being produced:
ORDER BY RAND('1235123412341')
This gives the same result as when you don't include the quotes.
many applications and frameworks try to use a so called smart determination of the type of variable before they insert them into a database
however, many of these also fail with integers and strings :)
because of PHP's automatic typecasting, you can do a following check: is_int('01234') and that would return TRUE - but that actually is not true - the "number" is actually a string, starting with 0 - and so it should be handled (unless manually converted into an integet before, if that's what it should be)
you will need to adjust CakePHP's database class where it checks for data types
I'm not familiar with CakePHP, but CodeIgniter did use a following check in its escape() function:
if (is_string($str))
... which I've changed to:
if (is_string($str) && (mb_strlen((int) $str) != strlen($str)))
... and now it all works :)
P.S.: I've tried using (int) $str === $str, however that always yielded incorrect result