Using forum user management for my own website

They have: 426 posts

Joined: Feb 2005

Ok so im building a website and want to integrate a forum for it. I was wondering how difficult it could be to rather than build my own user system in my own website or use a forums user system / login / registration?

I will want a forum anyway so it makes sense to install a forum and use the login / registration of that particular forum - namely PHPBB seeing as i have already installed it?

Any tips info or information is well appreciated.

p.s im currently building a user system dont really feel confident about my abilities to get it right anyhow - any info on how to make my registration form secure / some sample code on security is greatly appreciated.

greg's picture

He has: 1,581 posts

Joined: Nov 2005

PHPBB is great forum software. I've tested PHPBB3 a bit and the new features in the admin CP are awesome.

Another option is use Drupal, which is what we are typing on right now. It feels like it's a part of the website, rather than a full forum system that feels seperate to the website.

If you just want a basic posting area for user comments then making your own is pretty simple.
But if you state you are not at the stage of writing a login user system yet maybe a forum style comments system is a big project for you (no offence intended) So you maybe better choosing Drupal or PHPBB.

You can always make your own at a lter date when you are more familiar with PHP.

As for tips on secure code, the best site IMHO for well explained and accurate info is:

http://www.ilovejackdaniels.com/php/writing-secure-php/

They pretty much cover all the issues too. It does go a bit indepth, and might lose the beginner from time to time, but keep refering to it and it will all become clear.

The main thing with secure scripts is exatly as it says on that site
Be completely and utterly paranoid and trust no-one.
A little over the top some might think, but it is true.

Forms, for example a login form that takes username and password.
When the user clicks send, it want to goto a page that checks the minimum of the following:

  • check for empty fields where input is mandatory - EMPTY
  • check for characters you dont want to allow i.e. slashes, quotes etc
    If any found, send back to form and tell them what chars are / are not allowed - EREG
  • check whatever they typed was within the max length you allow, you dont want users putting in lengths longer than what you have set your database to accept - STRLEN
  • and finally, before you run a db query, run all the variables through mysql_real_escape_string

The way I do it is take two pages
form.php and formprocess.php
on form.php you have the HTML form and the send button, when clicked it sends all the data to formprocess.php

formprocess.php gets the POST data from the form and adds the users input to variables
Then runs through the above checks I mentioned with those variables.

The trick is, if any of the checks returns true (i.e. they did something wrong) then set a variable to = something
$return ="yes";

Then before the mysql query code if any of the above checks found a problem, then send them back to the form page and tell them something was wrong - BEFORE the mysql query script is run
IMHO, this is important, as it's those checks that are stopping a dangerous mysql query, so if you find something bad you dont want to run one

EG after all checks on all variables for slashes, lengths, blank etc then have this before the mysql query

<?php
if ($return=="yes"){
exit (
header('Location: login.php'));
}
?>

that will simply send them back to the form without having done the mysql query

you want to tell them they did something wrong, so in each check you will have something like
if $username has slashes then:
$return="yes" (to send them back to the form)
$badusername = "slashes are not allowed"

then you can echo the $badusername in the form page
so it will tell them what they did wrong - slashes are not allowed
I use a session to remember their faults, but that gets complicated if you dont already know sessions and arrays.

Basically, whenever a user gives you data to do something with, check it for all possible bad things. check it contains or is data you are expecting.
And even after all that, or even if it's your own data, escape it before any mysql queries.

Is that classed as a mini-tutorial? Laugh

If you need anything explained (which I'm sure you will) just ask Laughing out loud

JeevesBond's picture

He has: 3,956 posts

Joined: Jun 2002

Nice tutorial Greg! Laughing out loud

They have: 426 posts

Joined: Feb 2005

Greg, thanks. Yes i have built my own user login but like you say im not that confident about security. Basically i have done what you suggested;

Check for blank fields
check for character length
addslashes()
mysql_real_escape_string()
htmlentities()

But i cannot seem to check for invalid characters. I have been trying to use regular expressions but seen as i dont understand them properly i have been finding scripts on the internet. I guessed that i need to use the preg_replace() function to match a pattern of characters to see if they appear in the form field. But it doesnt work, it just comes back whatever i put in as bad characters entered,

<?php
if(invalidchars($_POST['username'])){
   echo
'bad characters';
}else{
   echo
'it is ok';
}


function
invalidchars($string){
   
$thestring = preg_replace('/[\s ]+[\s ]/', ' ', $string);
    return
$thestring;
}
?>

greg's picture

He has: 1,581 posts

Joined: Nov 2005

Erm, grab a coffee I seem to have gone into depth again Laugh

The function you have is told to REPLACE chars. And the way you have it in an IF you will run into problems.

Do you want to REPLACE characters users enter?
preg_replace — Perform a regular expression search and replace

Or just check for chars they enter and tell them if some of the chars are not allowed ELSE let it pass?
ereg checks a string for regular expresssions
(ereg is case sensitive, eregi is not case sensitive use whichever suits your needs)

PREG_REPLACE example

<?php
$string
= 'greg uses preg';
$to_replace = '/preg/';
$replace_with = '/ereg/';
echo
preg_replace($replace_with, $to_replace, $string);
?>

That will echo "greg uses ereg".
It has taken the $to_replace as the pattern to search for, and has taken $replace_with as the replacement.
So as it did find the pattern I searched for (preg) it replaced it with "ereg".

EREG example

<?php
$string
= //see below

if (ereg('[^0-9]', $string)) {
echo
"You entered data OTHER THAN numbers";
} else {
echo
"You only entered numbers";
}
?>

$string = "0123456"; //Will echo "You only entered numbers"
$string = 0123456; //Will echo "You only entered numbers"
$string = "abcdef"; //Will echo "You entered data OTHER THAN numbers"

ANY chars other than 0-9 and it WILL return "You entered data OTHER THAN numbers".

I wont lie, EREG is a little confusing at first, especially with all the PHP syntax you need to make it work. One complication I found is checking for slashes and quotes, some things need to be in certain barckets {} [] and some dont. Some things need to be escaped within the check, soo instead of using " you have to escape it like this \\". The escape \\, the same as addslashes(), just tells PHP to use the following char (after the slash) as text.
Useful example of escape
$string = "greg wants a quote "I said hello"";
Now PHP will go crazy with that and return an error of unexpectes T_STRING, as you have opened and closed the string twice.
This will work:
$string = "greg wants a quote \\"I said hello\\"";
So \\ escapes the following char and thus takes the " as text, and not the PHP syntax (i.e. the end of the string's value)

So to give you some code that would be useful in your login scripts...
(this is used in the registration process, as it checks if username is taken, but you get the idea)

<?php
$username
= $_POST['username'];

//check $username only contains letters and numbers
if (ereg('[^A-Za-z0-9]', $username)) {
$alphanum = "Enter letters and numbers only please";
$return = "yes";

//check $username is no more than 20 characters long
} elseif
(
strlen($username) > 20){
$long = "No more than 20 chars please";
$return = "yes";

//check $username is no less than 3 characters long
}elseif
(
strlen($username) < 3){
$short = "At least 3 chars please";
$return = "yes";

}else {
$username = mysql_real_escape_string($username); //escape any bad chars

$query = "select username from TABLE where username = '".$username."';";
$querygo = mysql_query($query);
$rowsdone = mysql_num_rows($querygo);

if (
$rowsdone >= 1) {
$taken = "Sorry, username is taken";
$return = "yes";
}
}
//end of IF's and ELSES's for $username checks


if ($return == "yes") {
exit (
header('Location: register_form.php'));
} else {
//login them in or register them (whatever)
}
?>

So $username is the data the user entered.
The script FIRST checks for bad chars in $username, this is important to be first as if any bad chars you don't want to check for anything else or run a query, just send them back after checking all other inputs (password etc).
Then it checks for lengths, too short or too long. If those three checks returned false then it will SAFELY excecute the query to check if username is taken.
Notice I STILL used mysql_real_escape_string! I know the query will be safe as I have checked it before hand with ereg, but it's always good practice IMHO.

If any of the checks returned true, then the variables you asign to tell the user info on their input will have to be sent to the next page

These:
$alphanum = "Enter letters and numbers only please";
$long = "No more than 20 chars please";
$short = "At least 3 chars please";
$taken = "Sorry, username is taken";

Personally I use a SESSION. If you understand arrays already then SESSIONS are simple, if not they are worth learning.

And before the IF ($return=="yes") you want to check other inputs, email, date of birth etc, have those first and if any checks returned bad chars, then use the $return="yes" in them too. That way you catch all user inputs and send them back if it found any.

You mentioned you use addslashes(). You don't really need to use this, and if you don't fully understand it you will be escaping data more than once.
(Escpaing data means adding a backslash infront of a char so PHP/mysql will use it as a text rather than try to use it as syntax)

Most servers have what is called magic_quotes set to ON as default. Magic_quotes uses PHP's addslashes() function, and does it automatically.
So if it is on, magic_quotes is escaping (adding slashes), then YOU are escaping too. It wont hurt, but is bad practice, you should know your programming environment.
Read this - http://www.tizag.com/phpT/php-magic-quotes.php

And you should use mysql_real_escape_string INSTEAD of addslashes() to strings before you run them into ANY mysql query.
So if using the link above you determine your server uses magic_quotes, turn them off and use your own methods manually. Check strings for slashes (and other chars) yourself, then use mysql_real_escape_string before any DB queries.

You also metnion you use html_entities(). Really, for username and login you shouldn't need this. As with the EREG checks above, they wont be allowed to use chars such as < > " ', so EREG stops them from using any chars that HTML could pick up and display as BOLD, LINKs etc. As it's usernames you are doing, I wouldn't imagine you let them use anything other than letters and numbers anyway. If you do want to allow other chars then that's differen't.
IMHO, letters and numbers is enough for a username or you end up with users making names that make your site look like a geek/nerd convention Laughing out loud

If there is anything else you need to know just ask Laughing out loud

They have: 426 posts

Joined: Feb 2005

Greg, thanks you have provided more than enough information for me....i appreiciate it.

Ok, so now i will just summerise.

To check the username only has numbers and chars i can use this eregi function;

<?php
eregi
('[^A-Za-z0-9]', $username)
?>

Because my password will be md5() this should mean i dont really need to check it because a md5() value can do no harm?

As for addslashes() and mysql_real_escape_string(), they do the same thing? Only mysql_real_escape_string() is a mysql API?

I can do a register_globals check:

<?php
if(register_globals){
$username = $_POST['username'];
}else{
$username = addslashes($_POST['username']);
}
?>

or can i just do

<?php
$username
= mysql_real_escape_string($_POST['username']);
?>
in all cases?

To safely create a login form and registration form i should be doing the following:

1) check for invalid chars in the appropriate places - username, email, or any field that you can restrict characters. In a profile description i can use htmlEntities() to relieve myself of any <script> tags and in conjunction with mysql_real_escape_string() there should be no problem?

2) escape all quotes using addslashes() and mysql_real_string() making sure that register_globals is off.

3) My user input data should now be safe to either query the database or insert into the database?

Thanks for your help.

greg's picture

He has: 1,581 posts

Joined: Nov 2005

Don't forget whitespace (from space bar) is a character

<?php
//For allowing spaces
IF (ereg('[^a-z ]', $var)) { //there is a space after the z
//For no spaces allowed
IF (ereg('[^a-z]', $var)) { //no space afer z
?>

Remember EREG is case sensitive, EREGI is not.
So using a-z with EREGI it will allow also A-Z without having to specifying it.
Using EREG with just a-z will not allow A-Z. You can specify it though.

<?php
if (ereg('[^a-z]', $var)) { //uppercase is NOT allowed
if (ereg('[^a-zA-Z]', $var)) {// uppercase is allowed

if (eregi('[^a-z]', $var)) { // uppercase is allowed
if (eregi('[^a-zA-Z]', $var)) { // uppercase is allowed
?>

Strings that have been md5'd 'should' be safe to use in a mysql query as they will always be only numbers and letters and no other chars at all. As most of my queries generally have 4-5 strings anyway, I tend to run them through mysql_real_escape_string anyway.
Simply because people can hack scripts and use your variables to their advantage. It is hard to do, but for the sake of one extra line I feel it's worth it incase the hacker manages to change my variable value.

benf wrote: As for addslashes() and mysql_real_escape_string(), they do the same thing?

Almost, but not quite.
mysql_real_escape_string is more secure in the way it escapes specific characters in a string. Also, it is the recognised PHP function for cleaning data prior to a mysql query, so it is more likely that they will work on that updating and checking for security vulnerabilities.
You should use mysql_real_escape_string.

But as they both do almost the same thing don't use both, or you will be escaping data twice. It shouldn't cause a problem doing that, but it is utterly pointless and is more code for your server to read and process.

As for register_globals, you want to turn it off and don't use it. It's that simple IMHO. Unless you fully understand its usage you will run into security and major coding problems. It wont be available as of PHP 6.0.0 anyway, so it is better you get used to using them without.

I would only use the $_POST['username'] once in the whole script, and that is to get its value and add it to $username variable, then use the $username var
$username = $_POST['username'];

The main reason is it's much easier to read code in youre page when it says $username, $email rather than $_POST['username'] $_POST['email'] etc
Then use the $username variable to check all the ereg checks etc and then finally (if no probs found) real_escape it and use it in the query
$username = mysql_real_escape_string($username);

I'm sure it will be fine, but if you want to show the final code here when you are done, myself or someone else will be happy to check it for you.

They have: 426 posts

Joined: Feb 2005

Greg, thanks for your help. Perhaps i should add my code - it would be nice to see how i am progressing with my php skills. I find it easy to create almost anything i want using php, but i have a problem making sure it is secure....which is something i need to be aware of more and more.

Want to join the discussion? Create an account or log in if you already have one. Joining is fast, free and painless! We’ll even whisk you back here when you’ve finished.