Note: this is part of a series.
The first part is here: Building a Big Project, Part 1
The second part is here: Building a Big Project, Part 2
The third part is here: Building a Big Project, Part 3
We now have a database that we can start storing data in. The next step will need to be handled somewhat carefully. My experience is that you should slowly build up your site's functionality, so that nothing you are trying to do depends on anything you haven't implemented yet. In this case, we have the following planned pieces of functionality:
A home page
Managing your profile
Managing your beta-reader profile
Looking for stories
Reading the forums
Reading about writing resources
Searching for stories
Logging in
Joining
Confirming a join request
Giving feedback
Reading the Terms of Service
Currently, there is NO data in our database. As a result, we can't find any stories to read, even if we wanted to. To submit a story, we will need to log in. To log in, we will need to register. Creating the registration functionality will be the first thing we implement.
Let's stop and think about how registration works at most sites. You pick a username and password, enter your email address, and either you are granted instant access, or you are sent a confirmation email to verify that you can actually use the email address you've submitted.
We're going to use the register/confirm model. This means we need to be able to test that our mail tool works. For that, we'll use Test Mail Server Tool. It's a free little utility that lets you catch outbound emails from a web server and open them with your default mail client. It's a very handy little tool for situations like this where you need to be able to send a lot of "emails" out, but don't want to harrass anybody.
To get a very basic registration form, we'll want something like this:
This is just a basic form that will request a username, password (twice), and email (twice). It looks a lot like this the attached image.Code:<h3>Join</h3>
<form name="application" action="index.php" method="put">
<input type="hidden" name="page" value="join">
<input type="hidden" name="action" value="confirm">
<table>
<tr>
<td>
User Name:
</td>
<td>
<input name="penname" type="text" maxlength="30" value=""></input>
</td>
</tr>
<tr>
<td>
Password:
</td>
<td>
<input name="password" type="text" maxlength="20" value=""></input>
</td>
</tr>
<tr>
<td>
Confirm Password:
</td>
<td>
<input name="passwordconf" type="text" maxlength="20" value=""></input>
</td>
</tr>
<tr>
<td>
Email:
</td>
<td>
<input name="email" type="text" maxlength="100" value=""></input>
</td>
</tr>
<tr>
<td>
Confirm Email:
</td>
<td>
<input name="emailconf" type="text" maxlength="100" value=""></input>
</td>
</tr>
</table>
<input type="submit" value="Submit">
</form>
Notice that we're using a post method. This is because you do NOT want email addresses or passwords being passed in a URL! That would be BAD! At some point, we'll want to ensure that we are dealing with both registrations and logins as a secure process. For now, we're just trying to get this working.
So, we collect all that wonderful data. What has to happen? First of all, we have to make sure the passwords match, and the emails match. If they don't we'll have to display an error message and let the user try again. If they do, we'll want to store that information and send an email to the new user with confirmation instructions. All the email will really need to do is give a special email address for the user to log in to. Let's get the validation going first.
We'll modify our basic form to display the value of variables. These will be $penname for the username, $password and $passwordconf for the password entries, and $email and $emailconf for the email entries. In addition, we'll use $valid to keep track of whether there was a problem, and $error to keep track of an error message to indicate the nature of the problem.
If the user hasn't submitted any data, valid will default to false so the login screen displays, and the other variables will default to an empty string.
Notice, this is only what we do if it is NOT a valid user. The following code handles the case where it IS a valid user. In it, I show some sample hashes for password "asdf". I'm using sha1 for the time being, even though I should really use sha512. Why? Because I'm lazy. I already set the password field of users to hold 50 characters. I don't feel like going through the hassle of changing it!Code:<?php
if ($_REQUEST["action"]=="confirm")
{
$penname = $_REQUEST["penname"];
$password = $_REQUEST["password"];
$passwordconf = $_REQUEST["passwordconf"];
$email = $_REQUEST["email"];
$emailconf = $_REQUEST["emailconf"];
$valid = true;
if ($password!=$passwordconf)
{
$valid = false;
$error = "Sorry, your passwords did not match!";
}
else if ($password=='')
{
$valid = false;
$error = "Sorry, your password cannot be blank!";
}
else if ($email!=$emailconf)
{
$valid = false;
$error = "Sorry, your emails did not match!";
}
else if ($email=='')
{
$valid = false;
$error = "Sorry, your emails cannot be blank!";
}
else
{
if (!($sourcedb = mysql_connect('localhost:3306','root','')))
{
die('Database error: could not connect!');
}
if (!mysql_select_db('MYFICTION',$sourcedb))
{
die('Cannot use database!');
}
$sql = "SELECT COUNT(*) AS MYCOUNT FROM USERS WHERE PENNAME='$penname'";
if (!($result = mysql_query($sql, $sourcedb)))
{
echo "DB error, could not query the database";
exit;
}
$row = mysql_fetch_assoc($result);
if ($row["MYCOUNT"] != 0)
{
$valid = false;
$error = "Sorry, that pen name is already in use!";
}
}
}
else
{
$penname="";
$password="";
$passwordconf="";
$email="";
$emailconf="";
$valid = false;
$error = "";
}
if (!$valid)
{
?>
<h3>Join</h3>
<?php echo $error ?>
<form name="application" action="index.php" method="put">
<input type="hidden" name="page" value="join">
<input type="hidden" name="action" value="confirm">
<table>
<tr>
<td>
User Name:
</td>
<td>
<input name="penname" type="text" maxlength="30" value="<?php echo $penname ?>"></input>
</td>
</tr>
<tr>
<td>
Password:
</td>
<td>
<input name="password" type="text" maxlength="20" value="<?php echo $password ?>"></input>
</td>
</tr>
<tr>
<td>
Confirm Password:
</td>
<td>
<input name="passwordconf" type="text" maxlength="20" value="<?php echo $passwordconf ?>"></input>
</td>
</tr>
<tr>
<td>
Email:
</td>
<td>
<input name="email" type="text" maxlength="100" value="<?php echo $email ?>"></input>
</td>
</tr>
<tr>
<td>
Confirm Email:
</td>
<td>
<input name="emailconf" type="text" maxlength="100" value="<?php echo $emailconf ?>"></input>
</td>
</tr>
</table>
<input type="submit" value="Submit">
</form>
By the way, I lied. I'm not that lazy. Change $encpassword = $sha1 to $encpassword = $sha512 and issue the following SQL:Code:<?php
}
else
{
//sample hashes are for password 'asdf'
$sha1=hash('sha1',$password);
//echo 'sha1::'.$password.'::'.$sha1.'::<br/>';
//40 chars 3da541559918a808c2402bba5012f6c60b27661c
$sha256=hash('sha256',$password);
//echo 'sha256::'.$password.'::'.$sha256.'::<br/>';
//64 chars f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b
$sha384=hash('sha384',$password);
//echo 'sha384::'.$password.'::'.$sha384.'::<br/>';
//96 chars a69e7df30b24c042ec540ccbbdbfb1562c85787038c885749c1e408e2d62fa36642cd0075fa351e822e2b8a59139cd9d
$sha512=hash('sha512',$password);
//echo 'sha512::'.$password.'::'.$sha512.'::<br/>';
//128 chars 401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1
$encpassword = $sha1
$confirmation = "";
srand(time());
for ($i = 1; $i<=20; $i++)
$confirmation = $confirmation . (rand()%10);
$sql = "INSERT INTO USERS (PENNAME, PASSWORD, CONFIRMATION, EMAIL) VALUES ('$penname','$encpassword','$confirmation','$email')";
$result = mysql_query($sql, $sourcedb);
if ($result)
{
?>
<h3>Thanks for joining!</h3>
<p>You should receive an email shortly to confirm your membership</p>
<?php
}
else
{
?>
<h3>Thanks for your interest!</h3>
<p>There was an error processing your request. Please try again later.</p>
<?php
}
}
if ($sourcedb)
{
mysql_close($sourcedb);
}
?>
Notice that we aren't quite done. No email is being sent. Also, there's the issue of that funny $confirmation variable. $confirmation is how we're going to validate the email of new users! That will be given as part of the confirm page URL. Something like: http://localhost/myfiction/index.php...78901234567890 When the user goes there, a username/password screen will be displayed. If the user types in the username/password correctly, we'll null out USERS.CONFIRMATION for that user. A user cannot log in through the usual screen when USERS.CONFIRMATION is not null. Finally, we can have an automated task to clean up unconfirmed users. We could simply add an additional field called USERS.REGISTRATION_DATE and delete all users with a REGISTRATION_DATE more than a week old that have CONFIRMATION is not null.Code:ALTER TABLE USERS MODIFY COLUMN PASSWORD VARCHAR(128);
For now, we're trying to keep this simple, however. Let's tackle the email problem and consider this pretty darned good. The email has to contain the URL listed above, and a nice thank you message. With a few lines for email, join.php becomes:
In the next part, we'll look at how to make this SAFE to put on the big bad internet.Code:<?php
if ($_REQUEST["action"]=="confirm")
{
$penname = $_REQUEST["penname"];
$password = $_REQUEST["password"];
$passwordconf = $_REQUEST["passwordconf"];
$email = $_REQUEST["email"];
$emailconf = $_REQUEST["emailconf"];
$valid = true;
if ($password!=$passwordconf)
{
$valid = false;
$error = "Sorry, your passwords did not match!";
}
else if ($password=='')
{
$valid = false;
$error = "Sorry, your password cannot be blank!";
}
else if ($email!=$emailconf)
{
$valid = false;
$error = "Sorry, your emails did not match!";
}
else if ($email=='')
{
$valid = false;
$error = "Sorry, your emails cannot be blank!";
}
else
{
if (!($sourcedb = mysql_connect('localhost:3306','root','')))
{
die('Database error: could not connect!');
}
if (!mysql_select_db('MYFICTION',$sourcedb))
{
die('Cannot use database!');
}
$sql = "SELECT COUNT(*) AS MYCOUNT FROM USERS WHERE PENNAME='$penname'";
if (!($result = mysql_query($sql, $sourcedb)))
{
echo "DB error, could not query the database";
exit;
}
$row = mysql_fetch_assoc($result);
if ($row["MYCOUNT"] != 0)
{
$valid = false;
$error = "Sorry, that pen name is already in use!";
}
}
}
else
{
$penname="";
$password="";
$passwordconf="";
$email="";
$emailconf="";
$valid = false;
$error = "";
}
if (!$valid)
{
?>
<h3>Join</h3>
<?php echo $error ?>
<form name="application" action="index.php" method="put">
<input type="hidden" name="page" value="join">
<input type="hidden" name="action" value="confirm">
<table>
<tr>
<td>
User Name:
</td>
<td>
<input name="penname" type="text" maxlength="30" value="<?php echo $penname ?>"></input>
</td>
</tr>
<tr>
<td>
Password:
</td>
<td>
<input name="password" type="text" maxlength="20" value="<?php echo $password ?>"></input>
</td>
</tr>
<tr>
<td>
Confirm Password:
</td>
<td>
<input name="passwordconf" type="text" maxlength="20" value="<?php echo $passwordconf ?>"></input>
</td>
</tr>
<tr>
<td>
Email:
</td>
<td>
<input name="email" type="text" maxlength="100" value="<?php echo $email ?>"></input>
</td>
</tr>
<tr>
<td>
Confirm Email:
</td>
<td>
<input name="emailconf" type="text" maxlength="100" value="<?php echo $emailconf ?>"></input>
</td>
</tr>
</table>
<input type="submit" value="Submit">
</form>
<?php
}
else
{
$encpassword=hash('sha512',$password);
$confirmation = "";
srand(time());
for ($i = 1; $i<=20; $i++)
$confirmation = $confirmation . (rand()%10);
$sql = "INSERT INTO USERS (PENNAME, PASSWORD, CONFIRMATION, EMAIL) VALUES ('$penname','$encpassword','$confirmation','$email')";
$result = mysql_query($sql, $sourcedb);
if ($result)
{
$message = 'Thank you for your interest in MyFiction.net.' . "\r\n" .
'Please confirm your registration at http://localhost/myfiction/index.php?page=confirm&confirmation=' . $confirmation;
$headers = 'From: registration@myfiction.net' . "\r\n" .
'Reply-To: registration@myfiction.net' . "\r\n";
mail($email,'Thanks for joining MyFiction.net',$message,$headers)
?>
<h3>Thanks for joining!</h3>
<p>You should receive an email shortly to confirm your membership</p>
<?php
}
else
{
?>
<h3>Thanks for your interest!</h3>
<p>There was an error processing your request. Please try again later.</p>
<?php
}
}
if ($sourcedb)
{
mysql_close($sourcedb);
}
?>
Last edited by WingedPanther; 02-23-2011 at 05:27 PM.
Very nicely done. You may also want to consider OpenID authentication.
You still have a lot to go, will you be working on it every weekend?
Maybe. I'm not going to mess with OpenID. That's a whole other bit of technology to play with. I'll try to get it done as fast as I can.
if you had enough time, would you have used JS to validate user-input?
yo homie i heard you like one-line codes so i put a one line code that evals a decrypted one line code that prints "i love one line codes"
www.amrosama.com | the unholy methods of javascriptCode:eval(base64_decode("cHJpbnQgJ2kgbG92ZSBvbmUtbGluZSBjb2Rlcyc7"));
Actually, adding JS validation is pretty easy. It won't stop someone using a milicious tool or old browser, however. JS is nice, but has a lot of limitations. My goal is to keep the JS to a minimum or not use it at all. That way, it will be functional on browsers with JS disabled (rare, I know).
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks