I've always done validation by pulling the entirety of a SQL table into an array, and searching it for the value I was validating. (Is Joe Smith already in my list of users?)
Is it more effective to do a more specific SQL query looking for that value, and returning true or false?
If so, I would like to see a code example, please.
I've been attempting to do this, but keep running into "Unknown column 'variablename' in 'where clause'"
(edit:)
For example sake, here is some code. I'm attempting to query a SQL table for a specific variable (a user). I then just need to know if it did or did not find the user in the table.
//$value = "Joe Smith"
$result = mysql_query("SELECT * FROM usernames WHERE fullname= $value",$db);
$rowcheck = mysql_num_rows($result);
if ($rowcheck > '0') {
// The value was found in the table.
}
Pulling the entire table is a bad idea. If you happen to have a few million rows in your database, good luck validating this in code. Always narrow down the data transfered with a WHERE clause. If you have the correct indexes, the statement will be fast and your frontend code will be simpler.
SELECT id FROM users WHERE name='Joe Smith'
Check if this returns any rows. Concerning your error, I guess you used the wrong quotes (single quotes).
Edit: You need quotes around string literals
mysql_query("SELECT * FROM usernames WHERE fullname='$value'",$db);
Related
I am trying to display the data from 'table' if a key inputted by the user is found in the database. Currently I have it set up so that the database checks if the key exists, like so:
//Select all from table if a key entry that matches the user specified key exists
$sql = 'SELECT * FROM `table` WHERE EXISTS(SELECT * FROM `keys` WHERE `key` = :key)';
//Prepare the SQL query
$query = $db->prepare($sql);
//Substitute the :key placeholder for the $key variable specified by the user
$query->execute(array(':key' => $key));
//While fetched data from the query exists. While $r is true
while($r = $query->fetch(PDO::FETCH_ASSOC)) {
//Debug: Display the data
echo $r['data'] . '<br>';
}
These aren't the only SQL statements in the program that are required. Later, an INSERT query along with possibly another SELECT query need to be made.
Now, to my understanding, using WHERE EXISTS isn't always efficient. However, would it be more efficient to split the query into two separate statements and just have PHP check if any rows are returned when looking for a matching key?
I took a look at a similar question, however it compares multiple statements on a much larger scale, as opposed to a single statement vs a single condition.
#MarkBaker Join doesn't have to be faster than exists statement. Query optymalizer is able to rewrite the query live if it sees better way to accomplish query. Exists statement is more readable than join.
Fetching all the data and making filtering directly in PHP is always bad idea. What if your table grow up to milions of records? MySQL is going to find the best execute plan for you. It will automaticaly cache the query if it is going to improve performance.
In other words, your made everything correctly as far as we can see your code now. For futher analyse show us all of your queries.
I was running a site I purchased that I thought was fairly unhackable. However, after having an attack, I found it was not. He informed me of the vulnerability, however my question is what user input could have been done to get all the users usernames like he did? Here is the code...
$un=$_GET['username'];
$q=$db->query("SELECT * FROM users WHERE login_name='$un' OR username='$un'");
I realize that this is highley hackable. Therefore, I changed the site over to prepared statements to prevent this from happening again. I just want to know what he could have entered to get all the users usernames.
Someone posted the script on github, you can find it here:
https://github.com/sat312/Mafia-Game-Script/blob/master/checkun.php
' OR 1=1;
In the URL:
/yourScript.php?username=%27%20OR%201%3D1%3B
The idea is that since data is mixed with the command, you can just finish the command with data.
You get $un from the user, so I can type anything I want and it'll get substituted into your query. It's called a SQL Injection attack.
Lets say $un = ' OR 1 = 1;-- then your query becomes:
SELECT * FROM users WHERE login_name='' OR 1 = 1;--' OR username='' OR 1 = 1;--'
What will happen? this gets executed:
SELECT * FROM users WHERE login_name='' OR 1 = 1;
This will return every row in the table.
He may have used the GROUP_CONCAT statement in MySql which basically groups a column in multiple rows into a single row (see Can I concatenate multiple MySQL rows into one field? for more information). He may have terminated the original SQL statement or UNIONED it with his own and added a LIMIT and ORDER BY to ensure his result got returned and commented out the remained of the original statement.
This is one possibility, but there are probably a few others.
This question already has answers here:
Get table column names in MySQL?
(19 answers)
Closed 9 years ago.
As I am still learning PHP and MySQL, I would like to know if it is possible to query a table without knowing it's name. Knowing the table I am querying and the column I would like to retrieve, I can write something like
$book_title=$row['book_title'];
Then I can use the resulting variable later in the script. In each case, each book category table will have a column of interest with a different name. I have several tables on which I am running queries. I am able to query any table by using a variable that always evaluates to the correct table name, because all the input from users corresponds to the tables in the database, so the $_POST super global will always carry a correct table name. The problem is for me to have a
$variable=$row['column'];
in cases where I do not know a column name before hand even though I know the table name.
My queries are simple, and look like
query="select * FROM $book_categories WHERE id=$id";
$row = mysqli_fetch_array ($result);
$variable=$row['?'];
The question mark say, I do not know what column to expect, as it's name could be anything from the tables in the database!
Since I have several tables, the query will zero on a table, but the column names in each table varies so I would like to be able to use one query that can give me an entry from such a column.
I hope my question is clear and that I am not asking for the impossible. If it's ambiguous, I care to elucidate (hope so).
I'm not sure what you mean, but it is possible to reference specifc columns by typing index (starting with 0) something like this: $row[0], $row[1] where 0 indicates the first column, and 1 indicates the second column from the returned recordset.
Example:
If you have a select-statement like this:
SELECT title, author FROM books
You could reference these two columns with $row[0], $row[1]
If you try to get the value of $row[2] you will get an unassigned value because there are only two columns (0 and 1) from the recordset.
If you have a select-statement like this:
SELECT * FROM book_categories
and the recordset returns three columns, then you could access these with $row[0], $row[1] and $row[2]. $row[3] does not exist because there are only three columns (0,1 and 2)
Since you are learning maybe we could take some time to explain why this is possible but many people (including myself) would say this is bad -- or at least dangerous
Why you can
Your SQL query is basically a text string you send to the DB server, which decode that string trying to interpret it as SQL in order to execute the query.
Since all you send to the DB server is text string, you could build that string however you want. Such as using string interpolation as you did:
select * FROM $book_categories WHERE id=$id
That way, you could replace any part of your query by the content of a variable. You could even go further:
$query FROM $book_categories WHERE id=$id
Where $query could by SELECT * or DELETE.
And, why not initializing all those variables from a form:
$book_categories = $_POST['book_categories'];
$id = $_POST['id'];
$query = $_POST['query'];
Great, no? Well, no...
Why you shouldn't
The problem here is "could you trust those variables to only contain acceptable values?". That is, what would append if $book_categories somehow resolve to one table you didn't want to (say myTableContainigSecretData)? And what if $id resolve to some specially crafted value like 1; DELETE * FROM myImportantTable;?
In these conditions, your query:
select * FROM $book_categories WHERE id=$id
Will become as received by the DB server:
select * FROM myTableContainigSecretData WHERE id=1; DELETE * FROM myImportantTable;
Probably not what you want.
What I've tried to demonstrate here is called SQL injection. This is a very common bug in web application.
How to prevent that?
The best way to prevent SQL injection is to use prepared statement to replace some placeholders in your query by values properly shielded against SQL injection. There was an example posted a few minutes ago as a response to an other question: https://stackoverflow.com/a/18035404/2363712
The "problem" regarding your initial question is that will replace values not table or columns identifiers.
If you really want to replace table/columns identifiers (or other non-value part of your query) by variables contents, you will have to check yourself the content of each of these variables in order to prevent SQL injection. This is quite feasible. But that's some work...
Ok, let say we have two rows:
member_id, name
Let say member_id = 15 and name = 'John';
I want to UPDATE this data and do the following query:
mysql_query("UPDATE members SET member_id = 14, name = 'Peter' WHERE member_id = 15
This is just an example, but is it possible that mysql would fail and UPDATE for example only name row. So, after completing mysql_query above, it would become member_id = 15 and name = 'Peter';
It is just an example. Today, a similar situation happened in my website and I checked my code hundred times and I see no errors and there hadn't been no same errors before it at all.
So, should I recheck my code one hundred times more, or it can happen?
Thank you very much.
According to the spec, single UPDATE statements are atomic; ie: either it updates all columns or it doesn't update any of them.
So no, it shouldn't happen. But of course there could be a bug with MySQL.
Put or die(mysql_error()); after your query so that if this really is happening then you would at least know about it.
I think it should not happen that it would become member_id = 15 and name = 'Peter'. The SQL syntax is right as far as i can see and it seems all good. If something wrong happens to your database and your query is executed in that moment God only knows what could happen. Despite this, most of the time either the query is executed entirely or it is not, making mysql_query() return false.
You should, as already suggested at least check if there where any error with a code such as the following if you are in an online business website:
mysql_query($sql) or die('An error occurred');
or something like as follows if you are in debug mode:
mysql_query($sql) or die(mysql_error());
I'm not as sure as everyone else that single-row updates are atomic. MySQL differs from standard SQL in that it does the column assignments of a single-table UPDATE left-to-right. That means member_id = 14 is done before name = 'Peter'. If name = 'Peter' violates a constraint, or triggers another update that fails, then that assignment will fail. However, whether the statement as a whole fails or not may depend on various factors, including whether the table is using a transaction-safe engine.
This question already has an answer here:
Syntax error due to using a reserved word as a table or column name in MySQL
(1 answer)
Closed 8 years ago.
So I have a primary key column called key. I'm trying to select the row with key = 1 via this code:
$query ="SELECT * FROM Bowlers WHERE key = '1'";
$result = mysql_query($query) or die(mysql_error());
For some reason, I'm getting this result:
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 'key = '1'' at line 1
The mysql statement works for using other keys, ie WHERE name = 'djs22'.
Any ideas?
key is a reserved word, try putting ticks around it:
$query ="SELECT * FROM `Bowlers` WHERE `key` = '1'";
$result = mysql_query($query) or die(mysql_error());
To see all the reserved words, go here and scroll down:
http://dev.mysql.com/doc/refman/5.1/en/reserved-words.html
'key' is a reserved keyword, put backtick quotes around it:
"SELECT * FROM Bowlers WHERE `key` = '1'"
Without checking, it's likely that "key" is a reserved word in MySQL.
Try wrapping it in backticks
$query ="SELECT * FROM Bowlers WHERE `key` = '1'";
You should write the column name key in quotes
$query ="SELECT * FROM Bowlers WHERE `key` = '1'";
Otherwise it is a keyword
I run into that all the time. MySQL has a crap load of reserved words. And when you come across one, the mysql error function is not even nice enough to let you know what is wrong.
The only thing you can do is change the column name. I accidentally used "date, to and from" the other day. Was pulling my hair out when it dawned on me, DuHH!!! those are DB reserved.
You can wrap all kind of quotes around it, it does not matter when it references a column name. Reserved is reserved!
It is common practice to to do a couple of things.
1) When making tables: Split resource type with resource name using underscore. Example: xref_userMessages
This would mean it is a cross reference table for User messages.
2) Other examples of table names: msg_Messages | sys_Settings | cli_Logins
So any other table made related to messages would be called msg_??? , not only does this keep them grouped together in phpMyadmin but makes remembering the names easier too.
3) When Making columns: Never use a reserved. Thus causing key columns to always be 6 didgets. Example: admkey | usrkey | msgkey | clikey grpkey
Obviously Admin Key | User Key | Message Key | Client Key | Group Key
So this means "msg_Messages" keys are "msgkey" and the xref table would be xref_Messages and its keys are xref_msgkey. Following this logic you not only know what to name everything without even thinking about it, but you never run into any reserved words doing it.
4) Examples of Column names: dateInsert dateStart timeCreate admName admAddress admPhone admCell
Just like above there is a logic to it. Placing purpose/owner and noun/item together makes the name and again avoids reserved words.
Last Example:
Table: users_Admins users_Clients
Key: admkey usrkey
Table: msg_Messages
Columns: msgkey admkey usrkey msgRead msgMessage msgTitle
Just in this short example I avoided 2 reserved words. Key and Read
So in short, your problem is not reading a primary key. It is a problem with column names.
MySQL is seeing your code as having a syntax that has commands out of place. SELECT read ... or SELECT key ... it doesnt matter if you put quotes around it or not. MySQL is basically seeing ...
SELECT (SELECT,WHERE,FROM) FROM select,from,where
WHERE SELECT = WHERE & FROM = SELECT. hehehehehehehe
Putting a different kind of quote around this will not change the confusion level you just sent to MySQL.
Mixing my mistake and your mistake together looks like this...
SELECT key,from,to,date FROM my_table WHERE key='1';
// Same as...
SELECT SELECT,SELECT,SELECT,SELECT FROM my_table WHERE SELECT='1';
The first one you can't really tell by looking at it there is anything wrong with it. The second one it is obvious that it is not right and won't work. However, according to MySQL they are the SAME THING.
MySQL receives this syntax as so... SELECT? You told me to SELECT 5 times, never told me what to even select. You get the FROM right, but then you ended with a left hook telling to select something else, not only did you not tell me what to select again but you threw in an NULL='1'; what the heck is that all about?
This is why when you make these kinds of errors the error function doesn't even report what the heck happened. There were so many errors it can't throw you an error number so it just stops.
So this means your syntax is like this
SELECT * FROM Bowlers WHERE SELECT = '1';
Sometimes I get frustrated and say, "I wish MySQL was smarter than this!!!" But then I realize i would have to trade the key words in for a lesser valued database. Each one of those reserved words represents a word that is doing a whole lot more work on the database side for me. When I first started to learn programming I had to write my own text input field sub routines, so I appreciate all the neat things MySQL does for me.