It is strange for me that for MySQL '1kdasa' AND '1' seem to be the same thing. I ran the following query
SELECT *
FROM `applications`
WHERE user_id = '1dadawdq'
AND uni_id = '3'
LIMIT 0 , 30
And the result was a row where user_id = 1. Well this is really strange. I want to check whether user with particular id exists but if MySQL doesn't understand that '1ada' is not '1' I have to write:
public function user_exists($user_id){
if(!is_numeric($user_id)){
return FALSE;
}
$query = $this->CI->db->get_where('user', array('id'=>$value));
return $query->num_rows() === 1;
}
Is this the only possible solution? I don't think it's very smart to check everytime if the passed variables are numeric or not.
Update
If i don't escape the data that is :
SELECT * FROM `applications` WHERE user_id = eqewq and uni_id = 2
There shows up an error :
#1054 - Unknown column 'eqewq' in 'where clause'
SELECT 1='1';
+-------+
| 1='1' |
+-------+
| 1 |
+-------+
SELECT 1='1a';
+--------+
| 1='1a' |
+--------+
| 1 |
+--------+
SELECT '1'='1a';
+----------+
| '1'='1a' |
+----------+
| 0 |
+----------+
You are trying to pass a string through an int field. This causes MySQL to only parse the first numerical characters. You can try to seacrh for a1dadawdq and you will have zero results because the first character is not numeric.
So it is very important you always check your input and prepare your queries before you send it to MySQL. You can try using MySQLi or PDO for this.
PDO or MySQLi are not directly a solution to your problem but they can help you since you can use their prepare() method. But verifying your input data will definitely help you. If you only want an integer to be passed through to MySQL try something like:
if (!is_int($idUser)) {
$idUser = null;
}
Or:
if (!is_int($idUser)) {
return false;
}
In the case of your update you can use PDO's bindParam() or bindValue() to pass only variables and no query string. By doing so, MySQL will never mistake a value for a column. Read the documentation and see whether you'll prefer PDO or MySQLi.
Personaly I use PDO becasue of the wide support of different database types.
Related
So I have a table with 6 columns, each column corresponds to a certain product type. Each column holds a number that corresponds to the number of times people have chosen that product type.
A | B | C | D | E | F
---------------------
0 | 0 | 0 | 0 | 0 | 0
So if the user picks type A, then I want to update column A's number from 0 to 1. So here's the SQL code I wrote:
$link = new PDO('***;dbname=***;charset=UTF-8','***','***');
$stmt = $link->prepare("UPDATE table SET :column=:num");
$stmt->bindParam(':column', $column);
$stmt->bindParam(':num', $num);
$stmt->execute();
But it's not updating anything at all. So i'm guessing there is something wrong with the SQL code, most likely having to do with the column placeholder :column. Can anyone tell me the right SQL code?
First make sure, $column is in an accepted list of values. Next, you can't bind :column you will have assign it like so:
$stmt = $link->prepare('UPDATE table SET ' . $column .' = :num');
$stmt->bindParam(':num', $num);
$stmt->execute();
If you were going to check for a valid $column I would use
$valid_column = preg_match('/[a-z0-9_]/i, $column);
or a sufficient replace (preg_replace). Though you would likely wrap it in a try/catch and set exceptions to be thrown in your PDO instance to make sure it's even legit.
I'm working on an application where users are searched for by multiple different criteria. One of the available criteria is searching by name. Names are stored in the database with HTML characters stripped, eg. a ' is stored as '. The problem with this is that if a user searches by name inputting the regular english name, it looks for the english name rather than the HTML-stripped name in the database. I have tried using htmlspecialchars($string, ENT_QUOTES), but for some reason it won't always replace the single quote correctly. Can anyone think of why this would happen, or recommend a better way? Thank you!
You don't need to replace single quotes. All you need to do is to use either PDO or MySQLi extension. Example of PDO,
$stmt = $pdo->prepare('SELECT * FROM tableName WHERE name = :name');
$stmt->execute(array(':name' => $name));
foreach ($stmt as $row)
{
// do something with $row
}
In that way, it allows you to search even if the value has single quote.
try using this html_entity_decode($string) instead of htmlspecialchars($string, ENT_QUOTES);
both ans are good but you can also try this...
function change_text($in, $out, $text){
$input = array($in);
$change = array($out) ;
$result = #str_replace ($input ,$change, $text);
return $result;
}
$change_text = change_text("'", '',$text);
hope it will help
on your query, replace your ' (quote) to ''. first quote will sign that caracter after this quote will be use as is.
bellow sample code:
mysql> select * from activities where activity='aku''kamu';
+----+----------+---------+
| id | activity | user_id |
+----+----------+---------+
| 1 | aku'kamu | 3 |
+----+----------+---------+
1 row in set (0.00 sec)
mysql> update activities set activity='aku''kamu' where id=2
Query OK, 1 row affected (0.06 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from activities where activity='aku''kamu';
+----+----------+---------+
| id | activity | user_id |
+----+----------+---------+
| 1 | aku'kamu | 3 |
| 2 | aku'kamu | 3 |
+----+----------+---------+
2 rows in set (0.00 sec)
mysql>
I have the following query
SELECT * FROM (`user_profiles`) WHERE `user_id` = $user_id LIMIT 1
$user_id is a URI segment. For instance $user_id = 64 would produce
SELECT * FROM (`user_profiles`) WHERE `user_id` = '64' LIMIT 1
If I add alphabetical characters to the user id, e.g. http://www.mysite.com/profile/64kjdsg
I get:
SELECT * FROM (`user_profiles`) WHERE `user_id` = '64kjdsg' LIMIT 1
which still returns the correct data although there is no user id equal to 64kjdsg. The user id column in my table is int(11). The query seems to automatically grab the numeric value from 64kjdsg and match that in the db table. Is this a MYSQL function I'm not aware of?
How is this happening? I'm querying using the Codeigniter framework if that makes ant difference.
UPDATE: found a similar question MySQL integer comparison ignores trailing alpha characters
As you are comparing to a numeric column, MySQL casts your string to a number (so it removes everything from the occurance of the first non-number character). It's its default behavior:
mysql> select '23andthensome' + 4;
+---------------------+
| '23andthensome' + 4 |
+---------------------+
| 27 |
+---------------------+
1 row in set, 1 warning (0.02 sec)
mysql> show warnings;
+---------+------+---------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '23andthensome' |
+---------+------+---------------------------------------------------+
1 row in set (0.02 sec
So, make more proper queries, check beforehand wether something is a number (filter_var(FILTER_VALIDATE_INT,$id);), only use it when it is, and then: don't send it as a string to MySQL: if you want to compare numbers, send the number, which should not be quoted.
Alternatively, you can let MySQL do the work, but it seems a waste:
mysql> select 23 = '23andthensome';
+----------------------+
| 23 = '23andthensome' |
+----------------------+
| 1 |
+----------------------+
1 row in set, 1 warning (0.00 sec)
mysql> select cast(23 as CHAR) = '23andthensome';
+-------------------------------------+
| cast(23 as CHAR) = '23andthensome' |
+-------------------------------------+
| 0 |
+-------------------------------------+
1 row in set (0.02 sec)
Check in your script is urlsegment integer. You can use ctype_digit to do it. If isn't, don't touch your db. Say "No such user"
Check this out: http://ideone.com/khpEv, it is called type juggling. If you '64kjdsg' string will be converted to integer (64) because user_id is INT else it will produce syntax error.
PHP example:
<?php
echo (int) '64kjdsg'; // 64
?>
this is security hole
however, if
$user_id = 5;
result is
SELECT * FROM (`user_profiles`) WHERE `user_id` = 5 LIMIT 1
not
SELECT * FROM (`user_profiles`) WHERE `user_id` = `5` LIMIT 1
try to use intval()
$user_id = intval($user_id);
In some PHP code, I have an mysql_real_escape_string()'d term, like foo\'s. I search that in my database (where it is also stored as foo\'s) like so:
mysql_query("SELECT * FROM coupons WHERE retailerName LIKE '%" . $searchTerm . "%'");
The query should look like this without variables:
SELECT * FROM coupons WHERE retailerName LIKE '%foo\'s%'
If I search f, fo, or foo, then the search works. But if I search foo's then the search doesn't work (keep in mind that the actual query takes an escaped string, so everything should match up).
Perhaps the interface from you program to mysql (JDBC or similar) is adding extra escape characters to your string. If the same mechanism is not what put the data into the database, try doing an insert to see how the data gets stored.
Mysql can handle the query through it's own interface
mysql> describe test_table;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| col1 | varchar(20) | YES | | NULL | |
| col2 | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
mysql> insert into test_table (col1, col2) values ('col1value', 'foo\'s');
Query OK, 1 row affected (0.04 sec)
mysql> select * from test_table where col2 like '%foo\'s%';
+-----------+-------+
| col1 | col2 |
+-----------+-------+
| col1value | foo's |
+-----------+-------+
1 row in set (0.00 sec)
If it's stored as foo\'s in DB, then there are 2 options - either you are double-escaping (i.e., using mysql_real_escape_string() twice), or you are escaping values that "something" (e.g., magic quotes) has already slashed.
Check if you have magic_quotes_gpc enabled.
Here's PHP5.3 code for stripping "magic quotes" automatically (can be used in config file). For older PHP, callback function would look differently, but you should get the idea from this.
// remove slashes, if they are being automatically added
if ( get_magic_quotes_gpc () ) {
$stripslashes = function($value) use(&$stripslashes) {
if ( is_array($value) ) {
return array_map($stripslashes, $value);
}
return stripslashes($value);
};
$_GET = array_map($stripslashes, $_GET);
$_POST = array_map($stripslashes, $_POST);
$_COOKIE = array_map($stripslashes, $_COOKIE);
unset($stripslashes);
}
Consider these three mysql statements:
select * from Users;
select id, title, value from Blogs;
select id, feelURL, feelTitle from Feeds where id = 1;
Now im not very good at REGEX, but i want to get the table name from the mysql query. Could someone possibly create one for me with a little explanation.
Thanks,
You can actually use MySQL as the parser and get the tablenames in your query no matter how complex your SQL syntax.
(Sorry that this is a late response to your question - I just had the same problem today and found this solution.)
Simply prefix your query with the word EXPLAIN and the results set returned to PHP will include id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra. The third column is the name of each table in your query.
For example, if your query was:
select count(*) from ey_def left join ey_rels on def_id=item_id;
Use:
explain select count(*) from ey_def left join ey_rels on def_id=item_id;
And MySQL will return this to PHP:
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | ey_def | index | NULL | PRIMARY | 4 | NULL | 87 | Using index |
| 1 | SIMPLE | ey_rels | ALL | NULL | NULL | NULL | NULL | 123 | |
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+
Now you can simply process the results like any other query.
Try:
preg_match('/\bfrom\b\s*(\w+)/i',$query,$matches)
This will not work if the query has more than 1 table.
Basically the regex searchs for the complete word FROM in the query and picks the following word as the table name.
A naive implementation would be this:
preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
echo $query . " => " . $match[1] . "\n";
This will break when you have a subquery in your SELECT field list (and probably in a few other cases). Or when your table name contains characters beside a-z, numbers and underscores.
Parsing SQL correctly isn't trivial.
For the query string you gave, the following should do:
preg_match_all('/from (\w+)/', $query, $tables);
print_r($tables[1]);
[0] => Users
[1] => Blogs
[2] => Feeds
But like pointed out in a comment already, creating a full fledged SQL parser is a non-trivial task. Don't expect this to be usable on any and all queries you throw against it.
Wish I would have seen this earlier... Like the people above me stated, it's non-trivial parsing sql statements. To pick out the table names from a sql string, it would be a better idea to get all the table names first, then find matches in the sql (providing you don't have a million tables in your database). I just so happen to have a function on hand that does just that:
/*
Takes a sql statement and attempts to get a table name from it.
This assumes a database is already specified in the connection.
[$sql]: string; SQL statement that was executed
[$conn]: resource; MySQLi connection resource
returns table name string
*/
function get_table_names($sql,$conn){
//declare variables
$table_array = array();
$table_string = "";
//get all the table names in the selected database
$sql2 = "SHOW TABLES";
$result = mysqli_query($conn, $sql2);
//display an error if something went wrong
if (!$result) {
echo "DB Error, could not list tables\n";
echo 'MySQL Error: ' . mysqli_error($conn);
exit;
}
//fetch the rows and push the table names into $table_array
while ($row = mysqli_fetch_row($result)) {
array_push($table_array, $row[0]);
}
//loop through all the tables in the database
foreach($table_array as $table){
if(strpos($sql,$table)){ //if match is found append to string
$table_string .= " $table ";
}
}
//return a string of table name matches
return $table_string;
}
Hope that helps someone...
This should do it:
(SELECT|DELETE|UPDATE|INSERT INTO) (\*|[A-Z0-9_]+)(FROM)?([A-Z0-9_, ]+)
It will works with select delete update and insert. If you use tablename1, tablename2 it will return it as a array