views:

380

answers:

5

Maybe I'm doing something wrong right from the beginning, and if so I'll work on that too...

I have a menu item that as part of the URL passes an Event ID#. In my specific case it takes the user to an information page for that Event. Then there is a button that lets them sign up for the Event. Click and they're signed up for the Event and taken back to the same information page which now says they're signed up and lets them see a few extra things.

The first time they hit the page I use a $_GET to figure out the Event ID# which is then passed back to the page if they click the sign up button as a hidden input field. But this time I need to use $_POST to figure out the Event ID#. So the code in my query has a boolean part which looks like

SELECT stuff FROM ... WHERE eventID = ($_GET["ID"] ? $_GET["ID"] : $_POST["ID"])

It works, but it just feels like it can be done better...

+3  A: 

It surely can be done better. First of all, sanitize user input before querying the database like you have. You have opened yourself up to SQL Injection.

Sev
+8  A: 
  1. Sanitize your database inputs. mysql_real_escape_string() is a quick and easy way to achieve this (or, if the ID is always numeric, you could just use intval()). Don't be like the school who fell for Bobby Tables.
  2. If you're not sure which request method was used, use the $_REQUEST superglobal, which contains both GET and POST variables (example: $_REQUEST['ID']). I normally don't use $_REQUEST, since I like to be clear about where my data comes from, but this would be a perfect situation to use it.

As Nick Presta pointed out, $_REQUEST also includes cookie variables, and as a matter of fact, the default* order of precedence for name conflicts is $_COOKIE, $_POST, and then $_GET. In light of this, before you plug data into the query, you could either do what you're doing now, or use $_SERVER['REQUEST_METHOD'] instead:

// You can use mysql_real_escape_string() instead if you want
$id = ($_SERVER['REQUEST_METHOD'] == 'POST') ? intval($_POST['id']) : intval($_GET['id']);

Also, as outis noted, keep in mind that you have the option of using prepared statements instead of just raw SQL queries.

* — The ordering is configurable via the variables_order configuration directive, as Stewart mentioned in the comments.

htw
The modern alternative to sanitizing is to use prepared statements: http://us2.php.net/manual/en/pdo.prepared-statements.php
outis
Using $_REQUEST makes it far easier to hack. One should always be specific.
Noah Goodrich
And remember to disable gpc_magic_quotes, one of the most stupid "security" features ever invented.
Adam Byrtek
$_REQUEST also masks $_COOKIE, probably something you DON'T want to happen.
Nick Presta
@Nick: That is a very good point that I had not realized. I tested it out, and if a GET var, POST var, and cookie with the same name exist, the cookie takes precedence. Very nice catch.
htw
@htw: Actually, that this order of precedence is configurable. Seehttp://uk2.php.net/manual/en/reserved.variables.request.php. So any code that depends on $_REQUEST may change its behaviour when you move it to another server.
Stewart
@Stewart: Thanks for pointing that out. I've incorporated the new information into the existing answer.
htw
+1  A: 

As well as htw's answer, if the Event ID's available shown to users are based on permissions, make sure you revalidate that they are allowed that particular ID.
Just because it is in a hidden field, doesn't mean they can't change it.

Dan McGrath
+2  A: 

For simplicities sake, combining previous suggestions for you:

"SELECT stuff FROM ... WHERE eventID = '" . mysql_real_escape_string($_REQUEST['id']) . "';"

And for the record, don't use double quotes for the array key unless you are going to include any variables or escapes that need to be parsed, it takes longer to process. For example:

$_POST['id'] and not $_POST["id"] unless you're doing something like $_POST["post_$id"]

Hope that helps.

Nathan Kleyn
You seem to have a typo: in the SQL statement there should be a single quote either on both sides or on neither, depending on whether eventID is a string or a number. (This also becomes a non-issue if you use a prepared statement and bind the value.)
Stewart
Darn good pick up that, thanks for the spot! That's what happens when I try to type whilst juggling a drink and watching TV. xDAs the question didn't necessarily stipulate whether the id was string or numeric, I thought it best to quote the value for somebody who wasn't protecting against SQL injection. ;]
Nathan Kleyn
A: 

You should separate the selection of the provided ID from where it gets put into the database. Put another way, as soon as the page knows whether it's been called via GET or POST it will know the correct super-global to retrieve the ID from. In fact, there may be some pages that will always be called with POST and others always with GET.

If it truly doesn't matter which it gets the ID from, use $_REQUEST.

staticsan