User registration using e-mail

There will be now only working version of user registration. Comments will be added later.

Note: This application was tested on the faculty user server (users.fsid.cvut.cz/~hlavavla/register.htm). For trying it, I had created following tables (only names of columns are shown):

user - table, where the user will be included after successfully registration:

id login pwd email

tempreg - table, where any attempt of registration is temporaly recorded - in the same time, an email is send to potential user. The random number (called in mail "key" and in table "tempkey") is send to user by e-mail and then compared on the third page to evaluate if user can read the supplied e-mail address:

login pwd email rfrom tmpkey id

id is useful when we like to delete a record (auto increment primary key, but the following code generate new id as a maximum value from this column increased by 1). The regmail.php script will write current date to the rfrom column; it could be used for checking, if response to registration is fresh, in this case it works only for rest of the day.


The first file is simple html page with form to write user data. It could have any name, but there are written name of the php it calls (regmail.php). The names passed to this php is in bold:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>

<head>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1250">
<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<title>New user regostration</title>
</head>

<body bgcolor="#FFE9A6">

<p><strong><u>New User Registration</u></strong></p>

<p>Warning: <strong>All comunication with this application,
including password sending, is in open form and anybody can read
it.</strong> So please, don't use password, that you are using on
any other server. For example, "aaaa" or
"12345" as a password is a good choice.</p>

<p>Note: Loginname and password should contain only numbers and
letters, and both are case sensitive.</p>

<p>Choose your login name, password and submit your real e-mail
address:</p>

<form method="POST" action="regmail.php">
    <table border="2">
        <tr>
            <td>Choose login name: </td>
            <td><input type="text" size="20" name="login"></td>
        </tr>
        <tr>
            <td>Your password:</td>
            <td><input type="text" size="20" name="pwd"></td>
        </tr>
        <tr>
            <td>Your e-mail address: </td>
            <td><input type="text" size="20" name="email"></td>
        </tr>
    </table>
    <p><input type="submit" name="Submit" value="Submit"></p>
</form>
</body>
</html>

Note, that the password in this application will be freely readable. If you like to hide it (the * will appear instead of letters), use the password type instead of the red marked text type.

This form (above) will call the regmail.php script bellow. This worked for me, I only changed the mysql_connect password to some nonsens. Please, use your own SQL server name, user and password (and database name on the next line - marked dark green and bold):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>

<head>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1250">
<title>New user regostration, step II.</title>
</head>

<body bgcolor="#FFE9A6">

<p><strong><u>New User Registration</u></strong></p>
<?php
mysql_connect('pc-308-15.fsid.cvut.cz','alik','tudlenudle')
 or die('Error: '.mysql_error() );
mysql_select_db('alik');

//random key generation - we use random number in the following range:
$key = rand(100000,999999);
echo "debug0: $key<br>";

//next two lines will read the maximum id from the table
$result=mysql_query('SELECT max(id) AS thelast FROM tempreg');
$cislo=intval(mysql_result($result,0,"thelast"));

//the next will be even bigger of one:
$cislo++;
echo "debug1: $cislo<br>";

//the same data will be inserted into the tempreg table and send to the mail
//the SQL commnad contain the CURDATE SQL function, which will enter current
//date, but this is not checked in the next - you can do it yourselve
$req = 'INSERT INTO tempreg VALUES("'.$_POST['login'].'","'.$_POST['pwd'].
          '","'.$_POST['email'].'",CURDATE(),"'.$key.'","'.$cislo.'");';
echo "debug1a: $req<br>";  //warning - delete this line, it will show the key!
$result=mysql_query($req);
if ($result) {  //written O.K., so we can continue...
echo "debug2:  ".mysql_affected_rows()."<br>";

// sending the mail
// first - prepare complete e-mail to some variable
// note - the $a .= $b is the same as $a = $a . $b
// to create formatted letter, we can use the \n as the end of the line
$ip = getenv('REMOTE_ADDR');
$mail1 = "Thank you for your registration.\nNow, copy the next address to your";
$mail1 .= " web browser to continue registration: \n\n";
// complete GET version of passing data will be reference begining with
// the name of the page, i.e.  http://server.domain/directoty/scriptname.php,
// followed by question mark, and variables separated by the & sign:
$mail1 .= "http://users.fs.cvut.cz/~hlavavla/";
$mail1 .= "confirm.php?login=".$_POST['login']."&pwd=".$_POST['pwd'];
$mail1 .= "&mail=".$_POST['email']."&key=".$key."\n\n";
// login, pwd, email and key will is passed, but only name and key will be read
mail($_POST['email'], "New user registration from ".$ip, $mail1); 
echo "debug3: $ip<br>" ;

// now - echo for user (independent with mail sending)
// (from the variables, only email and ip will be displayed)
echo "Mail with instructions where to continue has been send to ";
echo $_POST['email']." with the ip=$ip";

} else {echo "Internal error INSERT in MySQL: ".mysql_error();}

mysql_close(); 
?>

</body>
</html>

Note many "echo" commands. This scripts are only working versions, and this works like debug points (showing current data during debugging). Before use, all of them should be erased, or "uncommented" (insert double slash, // , before this). I have marked this with light green color.

This program will send an e-mail to user, where is the address of the confirm.php script, where user should finish the registration; parameters, most important is a "key" (random number), will be passed using the GET method:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>

<head>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1250">
<title>New user regostration, step III.</title>
</head>

<body bgcolor="#FFE9A6">

<p><strong><u>User being registered...</u></strong></p>

<?php
mysql_connect('pc-308-15.fsid.cvut.cz','alik','tudlenudle')
 or die('Error: '.mysql_error() );
mysql_select_db('alik');

echo "debug0: ".$_GET['key']."<br>";
$req = 'SELECT * FROM tempreg WHERE login="'.$_GET['login'].'" AND pwd="'.$_GET['pwd'];
$req .= '" AND tmpkey="'.$_GET['key'].'";';
echo "debug1: $req<br>";
$result=mysql_query($req);
if ($result) {  //we have value, so test, if it is a valid user...
$row=mysql_fetch_assoc($result);
if ($row["id"]>0){  //yes, if "id" is bigger then zero, it is valid user 
$email=$row["email"];
$login=$row["login"];
$pwd=$row["pwd"];

echo "debug2: $email, $login, $pwd<br>";
$result=mysql_query('SELECT max(id) AS thelast FROM user');
$id=intval(mysql_result($result,0,"thelast"));
$id++;
echo "debug3: new user id:$id<br>";

$req = 'INSERT INTO user VALUES("'.$id.'","'.$login.'","'.$pwd.'","'.$email.'");';
echo "debug4: $req<br>";
$result=mysql_query($req);
if ($result) {  //written O.K., so we can continue...

echo "debug5: just O.K.";

} else {echo "internal Error  in MySQL ii: ".mysql_error();}

} else {echo "internal Error  in MySQL oo: ".mysql_error();}

} else {echo "internal Error  in MySQL xx: ".mysql_error();}

mysql_close(); 
?>

</body>
</html>

Tested on the faculty user server (users.fsid.cvut.cz/~hlavavla/register.htm), May 2011.

Note: sometimes, older or used records from the tempreg table should be erased in a real application. For us, it is useful for the debugging to keep it. If you like to delete it from the tempreg table, you can use the same parameters, as in the select command for the delete command:

$req = 'DELETE FROM tempreg WHERE login="'.$_GET['login'].'" AND pwd="'.$_GET['pwd'];
$req .= '" AND tmpkey="'.$_GET['key'].'";';
echo "debug3a: $req<br>";
$result=mysql_query($req);

Not tested yet. The result should be type "row affected" (use the mysql_affected_rows() function), and the value should be 1.

You can erase any too old values from the table as well. For delete records older then today's date, you could use command like

$req = 'DELETE FROM tempreg WHERE rfrom<"'.$today_date.'";';
$result=mysql_query($req);

Then it is easy to warn a user, that the confirmation has to be done the same day (or "till midnight"). But the correct format of sending the date could depend on the server. Safe way to solve it is to write the CURDATE() function to another table and then read it. We can use a part of the second script and write a dummy record to our table, then read it and delete this working record immediately:

//random key generation - we use random number in the following range:
$key = rand(100000,999999);
//echo "debug3b: $key<br>";
//next two lines will read the maximum id from the table
$result=mysql_query('SELECT max(id) AS thelast FROM tempreg');
$cislo=intval(mysql_result($result,0,"thelast"));

//the next will be even bigger of one:
$cislo++;
//echo "debug3c: $cislo<br>";

//the data will be inserted into the tempreg table now
$req = 'INSERT INTO tempreg VALUES("aKa57537913","KaK113355","none",CURDATE(),"'.$key.'","'.$cislo.'");';
//echo "debug3d: $req<br>";  
//we will read it immediately and then delete line with just the same values
$result=mysql_query($req);
$req = 'SELECT * FROM tempreg WHERE login="aKa57537913" AND pwd="KaK113355" AND tmpkey="'.$key.'";';
//echo "debug3e: $req<br>";
$result=mysql_query($req);

$row=mysql_fetch_assoc($result);
$today_date=$row["rfrom"];
//echo "debug3f: CURDATE(): $today_date<br>";
$req = 'DELETE FROM tempreg WHERE login="aKa57537913" AND pwd="KaK113355" AND tmpkey="'.$key.'";';
//echo "debug3g: $req<br>";
$result=mysql_query($req);

$req = 'DELETE FROM tempreg WHERE rfrom<"'.$today_date.'";';
//echo "debug3h: $req<br>";
$result=mysql_query($req);

Note, that I skip any SQL error testing. This solution cannot be used for any real application. In this case, any possible error should be maintained.

BTW, for a commercial site is better to save the debug commands to an extra SQL table:

// instead of echo "debug3e: $req<br>":
$echo = "debug3e: $req<br>";
$rrr = 'INSERT INTO echo_table VALUES("'.$echo.'");';
//execute the SQL and then clear any possible error:
$result=mysql_query($rrr);
$black_hole = mysql_error();

I hope it could work. If you have any experience with it, please send me an e-mail.