From 262cb8d5bb1398e03a9511ab6f9c8cb649d1384a Mon Sep 17 00:00:00 2001 From: Tim Clark <eclipse@sucs,org> Date: Tue, 1 Sep 2009 19:42:34 +0000 Subject: [PATCH] UI and validation for the new signup system, actual backend functionality is started but mostly missing --- components/signup.php | 124 ++++++++++++++++++++++++++++-- components/signupajax.php | 80 +++++++++++++++++++ lib/member_functions.php | 2 + lib/sanitization.php | 8 ++ lib/validation.php | 158 ++++++++++++++++++++++++++++++++++++++ lib/validationData.php | 35 +++++++++ templates/signup.tpl | 91 ++++++++++++++++++++++ 7 files changed, 493 insertions(+), 5 deletions(-) create mode 100644 components/signupajax.php create mode 100644 lib/member_functions.php create mode 100644 lib/sanitization.php create mode 100644 lib/validationData.php create mode 100644 templates/signup.tpl diff --git a/components/signup.php b/components/signup.php index 56b1571..c53f362 100644 --- a/components/signup.php +++ b/components/signup.php @@ -1,10 +1,124 @@ <?php -/* Temporary Component to get the signup stuff working with new SUCS site */ +//ob_start(); +//include("../member/signup.php"); +//$output = ob_get_contents(); +//ob_end_clean(); -ob_start(); -include("../member/signup.php"); -$output = ob_get_contents(); -ob_end_clean(); +//set defaults +$mode = 'login'; + +//login +if(isset($_REQUEST['signupid'])&&isset($_REQUEST['signuppw'])){ + //set signup details + $signupid = $_REQUEST['signupid']; + $signuppw = $_REQUEST['signuppw']; + // connect to sucs database + $sucsDB = NewADOConnection('postgres8'); + + // ------------------------------------------------- + // TODO: CHANGE THIS TO dbname=sucs BEFORE DEPLOYING + // ------------------------------------------------- + $sucsDB->Connect('dbname=eclipse'); + + + $sucsDB->SetFetchMode(ADODB_FETCH_ASSOC); + // get row(s) + $query = "SELECT * FROM signup WHERE id=? AND password=?"; + $array = array($signupid,$signuppw); + $data = $sucsDB->GetAll($query,$array); + // if data was returned and it was exactly 1 row + if(is_array($data)&&sizeof($data)==1){ + $row=$data[0]; + // if the id hasnt already been used + if(!(isset($row[activated])&&isset($row[username]))){ + // pass on the id and passwd + $smarty->assign("signupid",$signupid); + $smarty->assign("signuppw",$signuppw); + $smarty->assign("usertype",$row[type]); + // if accepting the form + if(isset($_REQUEST['username']) && isset($_REQUEST['realname']) && isset($_REQUEST['email']) && isset($_REQUEST['phone'])){ + require_once("../lib/validation.php"); + $valid=true; + $errors=array(); + $fields=array(); + if(!validUsername($_REQUEST['username'])){ + $valid=false; + $errors['username']=$error; + } + $fields['username']=$_REQUEST['username']; + if(!validSignupEmail($_REQUEST['email'])){ + $valid=false; + $errors['email']=$error; + } + $fields['email']=$_REQUEST['email']; + if(!validPhone($_REQUEST['phone'])){ + $valid=false; + $errors['phone']=$error; + } + $fields['phone']=$_REQUEST['phone']; + if($row[type]!=2){ + if(!validAddress($_REQUEST['address'])){ + $valid=false; + $errors['address']=$error; + } + $fields['address']=$_POST['address']; + if(!validRealName($_REQUEST['realname'])){ + $valid=false; + $errors['realname']=$error; + } + $fields['realname']=$_REQUEST['realname']; + } + else{ + if(!validRealName($_REQUEST['contact'])){ + $valid=false; + $errors['contact']=$error; + } + $fields['contact']=$_REQUEST['contact']; + if(!validSocName($_REQUEST['realname'])){ + $valid=false; + $errors['realname']=$error; + } + $fields['realname']=$_REQUEST['realname']; + } + if($row[type]==1){ + if(!validSID($_REQUEST['studentid'])){ + $valid=false; + $errors['studentid']=$error; + } + $fields['studentid']=$_REQUEST['studentid']; + } + + if($valid){ + $mode='result'; + //TODO: add membership add code here + $smarty->assign("post",$_POST); + } + else{ + //re-show form + $script = "<script language='javascript' type='text/javascript' src='".$baseurl."/js/jquery.js'></script>\n"; + $script .= "<script language='javascript' type='text/javascript' src='$baseurl/js/signup.js'></script>\n"; + $smarty->assign("fields",$fields); + $smarty->assign("errors",$errors); + $smarty->append('extra_scripts', $script); + $mode='re-form'; + } + } + else{ + // display the form + $script = "<script language='javascript' type='text/javascript' src='".$baseurl."/js/jquery.js'></script>\n"; + $script .= "<script language='javascript' type='text/javascript' src='$baseurl/js/signup.js'></script>\n"; + $smarty->append('extra_scripts', $script); + $mode='form'; + } + } + else trigger_error("Signup ID already used",E_USER_WARNING); + } + else trigger_error("Invalid ID or Password", E_USER_WARNING); + +} +//Set smarty Variables +$smarty->assign("mode", $mode); +$output = $smarty->fetch("signup.tpl"); $smarty->assign("title", "Sign Up"); $smarty->assign("body", $output); diff --git a/components/signupajax.php b/components/signupajax.php new file mode 100644 index 0000000..dd45591 --- /dev/null +++ b/components/signupajax.php @@ -0,0 +1,80 @@ +<? +require_once("../lib/validation.php"); +// don't output the site template +$no_template = TRUE; +header("Content-type: text/plain"); +if (isset($_GET['key'])){ + switch($_GET['key']){ + case "sid": + $sid=$_GET['value']; + if(validSID($sid)){ + echo "OK:".lookupSID($_GET['value']); + } + else{ + echo "ERROR:".$error; + } + break; + case "postcode": + $postcode=implode("", explode(" ", $_GET['value'])); + echo json_encode(lookup_postcode($postcode)); + break; + case "username": + $username = $_GET['value']; + if(validUsername($username)){ + echo "OK"; + } + else{ + echo $error; + } + break; + case "realname": + $realname = $_GET['value']; + if(validRealName($realname)){ + echo "OK"; + } + else{ + echo $error; + } + break; + case "socname": + $socname = $_GET['value']; + if(validSocName($socname)){ + echo "OK"; + } + else{ + echo $error; + } + break; + + + case "address": + $address = $_GET['value']; + if(validAddress($address)){ + echo "OK"; + } + else{ + echo $error; + } + break; + + case "email": + $email = $_GET['value']; + if(validSignupEmail($email)){ + echo "OK"; + } + else{ + echo $error; + } + break; + case "phone": + $phone = $_GET['value']; + if(validPhone($phone)){ + echo "OK"; + } + else{ + echo $error; + } + break; + } +} +?> diff --git a/lib/member_functions.php b/lib/member_functions.php new file mode 100644 index 0000000..471f06d --- /dev/null +++ b/lib/member_functions.php @@ -0,0 +1,2 @@ +<? +?> diff --git a/lib/sanitization.php b/lib/sanitization.php new file mode 100644 index 0000000..04c444c --- /dev/null +++ b/lib/sanitization.php @@ -0,0 +1,8 @@ +<? +function sanitizePhone($phone){ + return ereg_replace("[ ()]", "", $phone); +} +function sanitizeAddress($address){ + return str_replace(array("\r\n","\r"),array("\n","\n"),$address); +} +?> diff --git a/lib/validation.php b/lib/validation.php index 43136e9..37ded27 100644 --- a/lib/validation.php +++ b/lib/validation.php @@ -1,4 +1,6 @@ <? +require_once("validationData.php"); +require_once("sanitization.php"); /* useful validation functions */ //check for a valid email address @@ -94,5 +96,161 @@ function weakPassword($password) if ($answer == "") return("Empty password"); return $answer; } +// check if username is an alias +function isAlias($username){ + $ok=false; + // check its not an alias + $aliasesfile = file ('/etc/aliases'); + foreach ($aliasesfile as $aliasline) + { + if(trim($aliasline) && $aliasline[0]!="#") + { + $anAlias = explode(":", trim($aliasline)); + if($anAlias[0] && !posix_getpwnam($anAlias[0]) && ($anAlias[0] == $username)){ + $ok=true; + return true; + } + } + } + return $ok; +} +//check if a user with a sid already exsists +function sidUsed($sid){ + $sucsDB = NewADOConnection('postgres8'); + $sucsDB->Connect('dbname=sucs'); + $sucsDB->SetFetchMode(ADODB_FETCH_ASSOC); + $query = "SELECT * FROM members WHERE sid=?"; + $data = $sucsDB->GetAll($query,$sid); + return (sizeof($data) > 0); +} + + +function validUsername ($username){ + global $error; + // check if uname is sytactically valid + $syntax = ereg("^[a-z][a-z0-9_]*$", $username); + if(!$syntax || (strlen($username) < 2)){ + $error = "Usernames must start with a letter, only contain lowercase letter, numbers 0-9 and underscores (_) and be at least 2 characters."; + return false; + } + // check if the username already exsists + elseif(posix_getpwnam($username)) + { + $error = "Username already taken"; + return false; + } + // check if its a mail alias + elseif(isAlias($username)){ + $error ="Username is a mail alias"; + return false; + } + else{ + return true; + } +} +function validSID($SID){ + global $error; + if(!eregi("^[0-9]*$", $SID) || strlen($SID) != 6){ + $error = "Invalid student ID"; + return false; + } + elseif(sidUsed($SID)){ + $error = "A user with that student ID already exsists, email <a href=\"mailto:admin@sucs.org\">admin@sucs.org</a> if this is an error."; + return false; + } + elseif(lookupSID($SID)==" "){ + $error = "Student not found, email<a href=\"mailto:admin@sucs.org\">admin@sucs.org</a> if this is an error."; + return false; + } + else{ + return true; + } +} +function validRealName($realName){ + global $error; + //check for enough names for real name (we insist on at least 2 + if(count(explode(" ",$realName)) < 2) + { + $error = "Too few names given, please give at least two."; + return false; + } + //check for a sane realname, see comment below + elseif (!ereg("^([A-Z]([.]+ +[A-Z])*([\']+[A-Z])*[a-z]+[ -]*)+$", $realName)) + { + $error = "Name incorrectly formated, email <a href=\"mailto:admin@sucs.org\">admin@sucs.org</a> if this is an error."; + return false; + } +/* + * This should force sane real names, with capitals for the first letter of each word, + * Whist alowing for complex names such as Robin M. O'Leary + * + * break down of regexp + * + * ( + * [A-Z] - start with a single capital + * ([.]+ +[A-Z])* - zero or more of, (at least one "." followed by at least one space then another single capital) //we dont expect people to have initals at the end of there names so this is alright + * ([\']+[A-Z])* - zero or more of, (at least one "'"s followed by a single capital letter) + * [a-z]+ - One or more lower case letters, this forces initals to be followed by a "." + *[ -]* - zero or more " "s or "-"s so double barreled names are supported + * ) + * + * In its current state + * Robin M. O'Leary is valid + * Robin M O'Leary is not + * Robin M. OLeary is Not + * Robin M. O'LeaRy is valid (though its not ment to be.. bad side effect of not requireing at least one space...) + * BUT... this alows for McSmith's... which is rather nice :)... and of course delibrate + * RObin M O'Leary is not + * + */ + else{ + return true; + } +} +function validSocName($socname){ + global $error; + if(!ereg('^[A-Z1-9]',$socname) || strlen($socname) < 2){ + $error = "Must start with a capital letter or a number and be more than 1 character"; + return false; + } + else{ + return true; + } +} + +function validAddress($address){ + global $error; + $address = sanitizeAddress($address); + if(!ereg("^([A-Z0-9]([[:alnum:]]|[ .'])*\n)+[A-Z0-9]([[:alnum:]]|[ .'])*$",$address)){ + $error = "Please supply at least two valid lines of address."; + return false; + } + else{ + return true; + } +} +function validPhone($phone){ + global $error; + $phone=sanitizePhone($phone); + if(!ereg("^\+?[0-9-]+$",$phone)){ + $error = "Must be all numbers"; + return false; + } + return true; +} +function validSignupEmail($email){ + global $error; + if(ereg('@sucs\.org$',$email)){ + $error = "SUCS email addresses are not allowed"; + return false; + } + elseif(!validEmail($email)){ + return false; + } + else{ + return true; + } + +} ?> diff --git a/lib/validationData.php b/lib/validationData.php new file mode 100644 index 0000000..6221e08 --- /dev/null +++ b/lib/validationData.php @@ -0,0 +1,35 @@ +<? +// lookup real names from sid's useing campus ldap +function lookupSID($sid) { + $ds=ldap_connect("nds-stud.swan.ac.uk"); + $sr=ldap_search($ds, "ou=Students,o=uws", "cn=".$sid); + $info = ldap_get_entries($ds, $sr); + ldap_unbind($ds); + return ucwords(strtolower($info[0]['givenname'][0]." ".$info[0]['sn'][0])); +} +// lookup addresses from postcodes useing the univeritys website +function lookup_postcode($postcode = "") +{ + $url = "https://intranet.swan.ac.uk/common/postcodeLookup.asp?pCode=".$postcode; + $referer = "https://intranet.swan.ac.uk/common/postcodeaddresslookup.asp"; + + $req = curl_init($url); + curl_setopt($req, CURLOPT_HEADER, false); + curl_setopt($req, CURLOPT_REFERER, $referer); + curl_setopt($req, CURLOPT_RETURNTRANSFER, true); + curl_setopt($req, CURLOPT_SSL_VERIFYPEER, false); + $page = curl_exec($req); + curl_close($req); + + $scrape = explode("returnAddress(\"", $page); + + $addresses = array(); + for ($i = 1; $i < count($scrape); $i++) { + if (preg_match("/^[^,\"].+?\"/", $scrape[$i], $address)) { + $addr = str_replace("<BR>\"", "", $address[0]); + array_push($addresses, str_replace("<BR>", ", ", $addr)); + } + } + return $addresses; +} +?> diff --git a/templates/signup.tpl b/templates/signup.tpl new file mode 100644 index 0000000..57ff3e4 --- /dev/null +++ b/templates/signup.tpl @@ -0,0 +1,91 @@ +{if $mode=='login'} +<form action="{$componentpath}" method="post"> + <div class="box" style="width: 70%; margin: auto;"> + <div class="boxhead"><h2>Membership Signup</h2></div> + <div class="boxcontent"> + + <p>Please enter the details from your signup receipt</p> + + <div class="row"> + <label for="signupid">Signup ID:</label> + <span class="textinput"><input type="text" size="20" name="signupid" id="signupid" /></span> + </div> + <div class="row"> + <label for="signuppw">Password:</label> + <span class="textinput"><input type="text" size="20" name="signuppw" id="signuppw" /></span> + </div> + <div class="row"><span class="textinput"> + <input type="submit" name="submit" value="Sign Up" /></span> + </div> + <div class="clear"></div> + <div class="note">If you wish to renew an existing account instead, please login to <a href="https://sucs.org/Options">Membership Options</a> using your existing account details.</div> + </div> + <div class="hollowfoot"><div><div></div></div></div> + </div> +</form> +{elseif $mode=='form' || $mode=="re-form"} + <h1>Signup</h1> + <form action="{$componentpath}" method="post"> + {if $usertype==1} + <div class="row" id="studentiddiv"> + <label for="studentid">Student Number</label> + <span class="textinput"><input type="text" id="studentid" name="studentid" size="30" {if $mode=='re-form'}value='{$fields.studentid}'{/if} /></span> + <div id="studentidmessage"{if $mode=='re-form'}{if isset($errors.studentid)} style="color:red">{$errors.studentid}{else} style="color:green">OK{/if}{else}>{/if}</div> + </div> + {/if} + <div class="row" id="usernamediv"> + <label for="username">Username</label> + <span class="textinput"><input type="text" id="username" name="username" size="30" {if $mode=='re-form'}value='{$fields.username}'{/if}/></span> + <div id="usernamemessage"{if $mode=='re-form'}{if isset($errors.username)} style="color:red">{$errors.username}{else} style="color:green">OK{/if}{else}>{/if}</div> + </div> + <div class="row" id="realnamediv"> + <label for="realname">{if $usertype!=2}Real Name{else}Society Name{/if}</label> + <span class="textinput"><input type="text" id="realname" name="realname" size="30" {if $mode=='re-form'}value='{$fields.realname}'{/if}/></span> + <div id="realnamemessage"{if $mode=='re-form'}{if isset($errors.realname)} style="color:red">{$errors.realname}{else} style="color:green">OK{/if}{else}>{/if}</div> + </div> + {if $usertype!=2} + <div class="row" id="postcodediv" style="display:none"> + <label for="postcode">Post Code</label> + <span class="textinput"><input type="text" id="postcode" size="10" value=""/></span> + <div id="postcodemessage"></div> + </div> + <div class="row" id="addseldiv" style="display:none"> + <label for="addsel">Address Selector</label> + <span class="textinput"><select id="addsel" value=""></select></span> + </div> + <div class="row" id="addressdiv"> + <label for="address">{if $usertype==1}Term Time {/if}Address</label> + <span class="textinput"><textarea id="address" name="address" cols="35" rows="4">{if $mode=='re-form'}{$fields.address}{/if}</textarea></span> + <div id="addressmessage"{if $mode=='re-form'}{if isset($errors.address)} style="color:red">{$errors.address}{else} style="color:green">OK{/if}{else}>{/if}</div> + </div> + {else} + <div class="row" id="contactdiv"> + <label for="contact">Contact Name</label> + <span class="textinput"><input type="text" id="contact" name="contact" size="30" {if $mode=='re-form'}value='{$fields.contact}'{/if}/></span> + <div id="contactmessage"{if $mode=='re-form'}{if isset($errors.contact)} style="color:red">{$errors.contact}{else} style="color:green">OK{/if}{else}>{/if}</div> + </div> + {/if} + <div class="row" id="emaildiv"> + <label for="email">Email Address</label> + <span class="textinput"><input type="text" id="email" name="email" size="30" {if $mode=='re-form'}value='{$fields.email}'{/if}/></span> + <div id="emailmessage"{if $mode=='re-form'}{if isset($errors.email)} style="color:red">{$errors.email}{else} style="color:green">OK{/if}{else}>{/if}</div> + </div> + <div class="row" id="phonediv"> + <label for="phone">Phone Number</label> + <span class="textinput"><input type="text" id="phone" name="phone" size="30" {if $mode=='re-form'}value='{$fields.phone}'{/if}/></span> + <div id="phonemessage"{if $mode=='re-form'}{if isset($errors.phone)} style="color:red">{$errors.phone}{else} style="color:green">OK{/if}{else}>{/if}</div> + </div> + <input type="hidden" id="signupid" name="signupid" value="{$signupid}" /> + <input type="hidden" id="signuppw" name="signuppw" value="{$signuppw}" /> + <div class="row" id="submitdiv"> + <input type="submit" id="submit" value="Submit" /> + </div> + </form> +{elseif $mode=='result'} +<table> +<tr><th>Key</th><th>Value</th></tr> +{foreach from=$post key=key item=value} +<tr><td>{$key}</td><td>{$value}</td></tr> +{/foreach} +</table> +{/if} -- GitLab