Labtec;11008687 wrote:
The reason I didn't want any special characters inserted is because I was under the impression any of those characters could potentially damage my code/database.
They can damage nothing if dealt with properly. You are of course free to make any restrictions on input you see fit (although it may be more user friendly to allow input and then escape it properly), but never just strip things out. If I input "john" as my username and "\doe" as my passwrod and you strip slashes, both when the account is created and when I log in, I will be able to login using either "doe" or "\doe". Since I thought you stored "\doe", this is what I use. Should you one day start allowing slashes, I'd no longer be able to login.
Always inform the user of invalid input, tell them what would be valid and present the input back to the user so that they may correct it.
Labtec;11008687 wrote:
Is that only the case with double and single quotes? I also wanted it 'easy-to-read' from the database, rather than having the converted html chars.
Sometimes yes, sometimes no. It always depend on where you try using them. Some databases will have issues with both, others with either and some depending on settings. SQL Standard dictates that strings be delimited only by single quotes, thus meaning that double quotes are never an issue inside a string literal. However, iirc MySQL can allow double quoted string literals unless running in strict mode.
The standard states that single quotes are escaped by single quotes inside string literal, i.e. this is one string literal containin one single quote
'a string with '' single quote'
But once again, MySQL may be doing other stuff unless running in strict mode (always do run it in strict mode by the way), by allowing single quotes to be escaped by .
The reason you need to connect to the DB before using mysqli_real_escape_string is that it will ask that particular db about what to escape and how to escapeit.
Labtec;11008687 wrote:
The reason I connect to the host within the function is because when I host my website on my domain, it is running a different version of PHP than my WAMP server.
I fail to see the reason for this. Wether you use the same PHP version or not, you should still be able to connect to the DB in the exact same manner. While ot works doing so inside the function, this also means connecting once every time you run the function. It could be fixed by
function lots_of_stuff_happening($input)
{
# Notice the use of mysqli, rather than mysql
# Personally I prefer PDO, but use either that or mysqli, never mysql
static $con = mysqli_connect('...');
}
Inside a function, use of the static keyword means the variable is initiated once and then retains it value between calls. However, it's still bad to do it this way, since, as brad points out, your function is called "check_input". If it's called "check_input", it should check input. If it's called connect_to_db_check_input_and_save_stuff_to_file, it should do those things. And apart from making for long and hard to read names, it makes the functions long and hard to read (and maintain) as well, which is why you should try to keep functions focused on doing one thing or one group of things. For example, function check_input($input, $type) might deal with string, date, integer and float data types. But unless it does, you should listen to brad and rename it check_string.
Next issue with check_input is that it doesn't check input for just any reason. It applies first htmlchars to it, which means the input will only ever be suitable for use as output in html pages, and secondly it escapes it for insertion into a particular MySQL database. Apply htmlspecialchars or htmlentities only when you output stuff in an html page, do not store it that way. Escape it for db insertion (or updates) just before you insert (or update) into the db.
Personally I usually go with prepared statements when inserting things, since that means I don't have to worry about how to escape particular data or when it's done. Example using PDO
$string = "Some input containing ' single quote";
$date = "2001-10-15";
$int = 10;
$db = new PDO('connection stuff here');
$db->prepare('INSERT INTO tbl(string_col, date_col, int_col) VALUES(:arraykey_one, :arraykey_two, :third_name)');
$db->execute(array('arraykey_one' => $string, 'arraykey_two' => $date, 'third_name' => $int));
This way you send the data separately from the query and the DB will know how to handle the specifics of each item. You may also prepare a query once, then iterate over execute multiple times using different array data for insertion/update.
But, as long as you either escape data as the very last thing before a direct query or use prepared statements, you're fine. Some people might tell you not to use prepared statement unless you will execute more than once. I've never bothered to check if preparing a statement takes more time than escaping arguments, but I suspect it's too little differerence to matter. Use which ever method you prefer (but do go with either PDO or mysqli)!
Labtec;11008687 wrote:
connect to the server/host before trying to use mysql_real_escape_string
Which as I explained above is that it needs to ask the DB what to escape and how to escape it since it depends on server settings.
What I have decided to do is go back to my main index.php page, and the 2 forms (register and login) will have their action files re-written. All the flaws you pointed out really concerns me. If I am going to go live, I want it to be coded as robust as possible.
Labtec;11008687 wrote:
Are there any tips/advice you would give someone who is writing an action file. What things would you do first? Are there any 'must-do' things that you do within your action files before doing anything else??
I usually have an require file which deals with things I need in most, if not all scripts. That file may contain all of the stuff that needs to be done, or it may in turn require other files. Do note that I rarely include a file, since if it's missing, I'd expect something to be very wrong, and thus I use require instead.
For example, you might find this at the top of all my script files that are intended to be executed rather than included by something else
require 'settings.php';
And then settings.php might look like
# Deal with autoloading files when classes are referenced
# This means that if I reference SomeClass, then the file "SomeClass.php" is automatically required (once)
function __autoload($class_name) {
require_once '/path/to/phpclasses/'.$class_name . '.php';
}
# and perhaps
$db = new mysqli(...);
# Then you might have all your functions dealing with validation and sanitation in
require 'validation.php';
require 'sanitation.php';
And now that you have a connection to your DB, you should also change your functions to take the connection as a parameter instead
function dbstring($input, $db) {
return $db->real_escape_string($input);
}
Labtec;11008687 wrote:
Apart from my function, what else is wrong with my code? Is it an absolute shambles? Can it be saved and modified slightly or would it be best to actually start from scratch?
Do whatever you feel more confortable with or believes will take less time. You'll learn either way 🙂
I'd also like to add that I believe it's bad having a redirect inside a function like "check_input" for the same reasons as discussed before. Have the function check input and return false if the check fails. Then have the calling code decide what to do. Sometimes you may wish for a redirect, other times you might wish to redisplay the same page with user input redisplayed to the user along with an error message...
And on the notion of redirect and pages processing form posts, you might wish to always redirect the user after a successful post, since the user might otherwise reload the same page and send the same data again (rather than reload the page they were redirected to which posts no new data). Do note that you might actually redirect them to the exact same page (depending on how you build things).