I am writing a code snippet to send a email notification with a dynamic link that includes a db token. I am receiving the email which is handled by different code but for some reason I the button will not hyperlink and I think it's because this code block is not generating the link properly.
Can anyone point me in the right direction here?
public function sendVerification2($writerID, &$errors) {
$sql = "SELECT
user.`user_id` id,
user.`email_1` email,
user.`usr_verify_email_token` vtoken
FROM
`writer_split` split,
`writer`,
user
WHERE
split.`writer_id` = writer.`writer_id`
AND
writer.`user_id` = user.`user_id`
AND
split.`writer_id` = ?
LIMIT 1
";
$user = $this->db->select($sql, array($writerID), $errors);
if (count($errors) > 0 || count($user) === 0) {
return;
}
$user = $user[0];
//Add the change url to the the user array
$user[0]['verifyUserLink'] = $this->authconfig['verifyUser'] . $user['vtoken'];
//Send an e-mail to the user with the token
$this->mailer->sendTemplate($user[0]['email'], 'new_user', $user[0], $errors);
return count($errors) === 0;
}
Related
Im a newb to PHP and coding in general. Im following a tutorial. It includes building a registration form with a 'mobile or email' input, something typical of Facebook or Amazon. The code is an IF/ELSE statement. IF user inputs a phone number, validate everything, ELSE user inputs an email, validate everything.
While the password validation works with a mobile number, the password validation (literally the same code block) does not work with an email. Instead a user can register with an email with only 1 character in the password field. However, the username is still validated, as is checking if the email is already in the database. This is a problem within the tutorial's code itself too, not just my own. I've tried reworking the code a number times over a few days but I'm just too inexperienced to know what to do. I've searched through stackoverflow for similar problems but didnt find anything that was relevant to my specific issue. Any help would be greatly appreciated.
require 'connect/DB.php';
require 'core/load.php';
/**
* If first-name is left blank, the submit button is not active.
* If it isnt empty, variables will be created from the form input.
*/
if( isset($_POST['first-name']) && !empty($_POST['first-name']))
{
$upFirst = $_POST['first-name'];
$upLast = $_POST['last-name'];
$upEmailMobile = $_POST['email-mobile'];
$upPassword = $_POST['up-password'];
$birthDay = $_POST['birth-day'];
$birthMonth = $_POST['birth-month'];
$birthYear = $_POST['birth-year'];
if(!empty($_POST['gen']))
{
$upgen = $_POST['gen'];
}
// create birth variable, made up of the three variables for year, month and day
$birth = ''.$birthYear.'-'.$birthMonth.'-'.$birthDay.'';
// Validate that the form fields are not empty. If they are, return error msg.
if(empty($upFirst) or empty($upLast) or empty($upEmailMobile) or empty($upgen))
{
$error = 'All feilds are required';
}
/**
* Now that the form is filled, check the input of each field with the following variable
* Create screenname variable from first name and last name.
*/
else
{
$first_name = $loadFromUser->checkInput($upFirst);
$last_name = $loadFromUser->checkInput($upLast);
$email_mobile = $loadFromUser->checkInput($upEmailMobile);
$password = $loadFromUser->checkInput($upPassword);
$screenName = ''.$first_name.'_'.$last_name.'';
/**
* Check if the user's screenname is already in the database, if so, assign a random digit to their screenname
* Create userlink variable from screenname and random digit.
*/
if(DB::query('SELECT screenName FROM users WHERE screenName = :screenName', array(':screenName' => $screenName )))
{
$screenRand = rand();
$userLink = ''.$screenName.''.$screenRand.'';
}
else
{
$userLink = $screenName;
}
/**
* Now we know a user has filled out the form, we've assigned them a screenName. Time to validate
* Check if a user entered an email that meets validation criteria
*/
if(!preg_match("^[_a-z0-9-]+(\.[_a-z0-9]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$^",$email_mobile))
{
/**
* If the email format is not correct, check to see if a mobile format is correct.
* If neither is correct, send user an error message
*/
if(!preg_match("^[0-9]{11}^", $email_mobile))
{
$error = 'Email id or Mobile number is not correct. Please try again.';
}
/**
* If the email or mobile format is correct, check to see which one they entered.
* if its the correct format for a mobile number then validate password
*/
else
{
$mob = strlen((string)$email_mobile);
if($mob > 11 || $mob < 11)
{
$error = 'Mobile number is not valid';
}
else if(strlen($password) <5 || strlen($password) >= 60)
{
$error = 'Password is not correct';
}
/**
* If password passes validation, check to see if mobile number is already in use
* If it is, send error message to user
*/
else
{
if(DB::query('SELECT mobile FROM users WHERE mobile=:mobile', array(':mobile'=>$email_mobile)))
{
$error = 'Mobile number is already in use.';
}
/**
* Now phone number and password pass validation, create a user including user ID.
* Create token, set cookie and redirect the user to index.php
*/
else
{
$user_id=$loadFromUser->create('users', array('first_name'=>$first_name,'last_name'=>$last_name, 'mobile' => $email_mobile, 'password'=>password_hash($password, PASSWORD_BCRYPT),'screenName'=>$screenName,'userLink'=>$userLink, 'birthday'=>$birth, 'gender'=>$upgen));
$loadFromUser->create('profile', array('userId'=>$user_id, 'birthday'=> $birth, 'firstName' => $first_name, 'lastName'=>$last_name, 'profilePic'=>'assets/image/defaultProfile.png','coverPic'=>'assets/image/defaultCover.png', 'gender'=>$upgen));
$tstrong = true;
$token = bin2hex(openssl_random_pseudo_bytes(64, $tstrong));
$loadFromUser->create('token', array('token'=>sha1($token), 'user_id'=>$user_id));
setcookie('FBID', $token, time()+60*60*24*7, '/', NULL, NULL, true);
header('Location: index.php');
}
}
}
}
/**
* Now after checking if the email or mobile format is correct, check to see which one they entered
* if its the correct format for an email and validate first name
*/
else
{
if(!filter_var($email_mobile))
{
$error = "Invalid Email Format";
}
else if(strlen($first_name) > 20)
{
$error = "Name must be between 2-20 character";
}
/*
* If the user entered the correct email and name format, validate password
*/
else if(strlen($password) <5 || strlen($password) >= 60)
{
$error = "The password is either too short or too long";
}
/**
* If password passes validation, check to see if email is already in use
* If it is, send error message to user
*/
else
{
if((filter_var($email_mobile,FILTER_VALIDATE_EMAIL)) && $loadFromUser->checkEmail($email_mobile) === true)
{
$error = "Email is already in use";
}
/**
* Now email and password pass validation, create a user including user ID.
* Create token, set cookie and redirect the user to index.php
*/
else
{
$user_id = $loadFromUser->create('users', array('first_name'=>$first_name,'last_name'=>$last_name, 'email' => $email_mobile, 'password'=>password_hash($password, PASSWORD_BCRYPT),'screenName'=>$screenName,'userLink'=>$userLink, 'birthday'=>$birth, 'gender'=>$upgen));
$loadFromUser->create('profile', array('userId'=>$user_id, 'birthday'=>$birth, 'firstName' => $first_name, 'lastName'=>$last_name, 'profilePic'=>'assets/image/defaultProfile.png','coverPic'=>'assets/image/defaultCover.png', 'gender'=>$upgen));
$tstrong = true;
$token = bin2hex(openssl_random_pseudo_bytes(64, $tstrong));
$loadFromUser->create('token', array('token'=>sha1($token), 'user_id'=>$user_id));
setcookie('FBID', $token, time()+60*60*24*7, '/', NULL, NULL, true);
header('Location: index.php');
}
}
}
}
}
?> ```
I have a registration form which posts data to save.php. But occasionally the data is getting posted multiple times.
Below is my code for save.php
<?php
session_start();
//save registration details in my table
include('connect_database.php');
include('my_functions.php');
$_SESSION['newUser'] = '0'; // new user
//POSTED DATA--------------------------
$t_email = $_POST['email'];
$t_psw = $_POST['psw'];
$t_first_name = addslashes($_POST['first_name']);
$_SESSION['lastname'] = $t_last_name = addslashes($_POST['last_name']);
$t_mobile = $_POST['mobile'];
$_SESSION['licNum'] = $t_lic_no = $_POST['lic_no'];
$t_dob = $_POST['dob'];
$t_abn = $_POST['abn'];
$tx_expiry = $_POST['tx_expiry'];
$drv_for = $_POST['driven_for'];
$lng_drv = $_POST['long_driven'];
//referred by
$ref_drLic = $_POST['ref_driLic'];
$ref_drName = $_POST['ref_driName'];
$t_dr_front = get_image('dr_front',$_POST['last_name'].'_dr_front');
$t_dr_bck = get_image('dr_bck',$_POST['last_name'].'_dr_bck');
//if tx required-------
if($_SESSION['ce_cr_tx'] == 1){
$t_tx_front = get_image('tx_front',$_POST['last_name'].'_tx_front');
$t_tx_bck = get_image('tx_bck',$_POST['last_name'].'_tx_bck');
}
else{
$t_tx_front = "";
$t_tx_bck = "";
}
//store data in logfile
$nwtxt = "Email is - ".$_POST['email'].". Mobile no - ".$_POST['mobile'];
writeFile($nwtxt);
//---------------------------------------
//query to save data in my table
$ad_sql = "INSERT INTO myTable (email, password, firstname, lastname, mobile, licence, drfront, drbck, txfront, txbck, cnfrm, dob, abnf, texpiry, drifor, driven, reLic, reNname)
VALUES('".$t_email."','".$t_psw."','".$t_first_name."','".$t_last_name."','".$t_mobile."','".$t_lic_no."','".$t_dr_front."','".$t_dr_bck."','".$t_tx_front."','".$t_tx_bck."','0','".$t_dob."','".$t_abn."','".$tx_expiry."','".$drv_for."','".$lng_drv."','".$ref_drLic."','".$ref_drName."')";
if(!empty($t_email)){
if($conn->query($ad_sql) == true){
//echo'Success';
$lst_id = $conn->insert_id;
$_SESSION['ls_id'] = $lst_id;
$_SESSION['s_email'] = $t_email;
$_SESSION['s_code'] = mt_rand(11111,99999);
//email code to user--------------------------
$subjct = "Email Verification Code";
$usr_msg = "Hi ".$_POST['first_name']." ".$_POST['last_name'].",<br><br>
A new account has been requested at 'Portal'
using your email address.<br><br>
To confirm your new account, please enter this code in the web page:<br>
<h3>".$_SESSION['s_code']."</h3><br><br>
If you need help, please call us<br><br>
Thank you,
Administrator";
sendEmail($t_email, $usr_msg, $subjct); //sends and email
writeFile('Code is :'.$_SESSION['s_code']); // write a log in file
//--------------------------------------------
//redirect to verify email page----------------------
header("location: verifyEmail.php");
exit();
}
else{
echo'Error creating account- '.$conn->error.'. Please try again.';
$gbck = "cr=".$_SESSION['ce_cr_id']."&crs=".$_SESSION['ce_cr_nm']."&tx=".$_SESSION['ce_cr_tx']."&erms=Error creating account. Please try again";
header('location: Enroll.php?'.$gbck);
exit();
}
}
else{
echo'Error creating account. Please try again.';
$gbck = "cr=".$_SESSION['ce_cr_id']."&crs=".$_SESSION['ce_cr_nm']."&tx=".$_SESSION['ce_cr_tx']."&erms= EMPTY data. Error creating account. Please try again";
header('location: Enroll.php?'.$gbck);
exit();
}
?>
I checked my code multiple times but couldn't find anything that is triggering it. When someone registers, the page keeps loading for sometime and I receive multiple entries in database and user receives multiple verification emails.
Is something wrong in my code?
The code itself looks fine, but i get the growing suspicion that it might be a config issue or whats happening before this executes. If your looking for a patchwork fix i would probably put a condition near your if(!empty($t_email)) that checks if the sql table row already exists dont execute, which would rectify the fact that multiple requests are coming in.
After doing my SQL Schema (Different types of users redirected to same page (index.php) with different content), I'm starting to make my login system.
I now have this:
function login($email,$password){
$mysqli = $this ->dbConnect();
if($mysqli){
$strQuery = "SELECT USERS.ID, USERS.EMAIL, TYPES.NAME FROM `USERS` LEFT JOIN `TYPES` ON USERS.TYPEID = TYPES.ID WHERE `EMAIL` = '$email' AND `PASSWORD` = '$password'";
$recordSet = $mysqli->query($strQuery);
$row = $recordset->fetch_assoc();
if($recordset->num_rows>0){
$_SESSION['auth'] = $row['ID'];
$_SESSION['username'] = $row['EMAIL'];
$_SESSION['type'] = $row['NAME'];
header ("location:"index.php");
return true;
}
//....
}
}
Does this look good? Is the query right? Any suggestions for improvement?
UPDATE
I have my login working now. And it's redirecting to index.php. But in index php I don't have acess to the $_SESSIONS variables i have stored on my function login. Is there any problem with the attribuitions? Placing the header inside the function not good?
Thanks :)
I summarized the previous comments.
1. Issue: you didn't used the same variables
function login($email,$password){ and $strQuery = " ... WHERE EMAIL = '$email' AND PASSWORD = '$password'";
2. Recomendation: use the same namming convention
On your SQL request you used two way to use fields: USERS.EMAIL and EMAIL = (with ` arround).
Use the same. This will be easier for later & debugging.
i.e.: of course, you should not use table.field each time. Not mandatory for example if you have only one table OR if the fields are not shared between them. For my perosnnal usage, I always use this table.field. This will prevent any future issue :)
3. Protect your data from any injection
Example:
$post_email = isset($_POST['email']) ? htmlspecialchars($_POST['email']) : null;
Alter call
$this->login($post_email, ...)
And finally use something like this to protect your data:
$email = $mysqli->real_escape_string($email);
and you are ready for your request:
" SELECT [..] FROM users as u [...] WHERE u.email = '$email' "
4. Or use specific functions
Example (real_escape_string not needed anymore):
$stmt = $dbConnection->prepare('SELECT * FROM users WHERE email = ? AND password = ?');
$stmt->bind_param('s', $email);
$stmt->bind_param('s', $password);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
http://php.net/manual/fr/class.mysqli.php
5. Sessions
If you want to activate sessions on a spacific page, the first code (at the first line) should be session_start().
Calling this method will activate the sessions and load the $_SESSION variable with content.
<?php // index.php
session_start(); // first line
// ... code
var_dump($_SESSION);
?>
&
<?php // page.php
session_start(); // first line
// ... code
$_SESSION['test'] = time();
Header('Location: index.php');
?>
Visit index.php -> nothing on the debug
Visit page.php -> you will be redirected on index.php
On index.php -> you will have data
Enjoy session :p
6. Handle specific data
To begin with, you should coose a way to store the credential access (ACL) for each user. For example, store on the database some values as 100001, and each number is a yes/no access for a specific action (binary access mode) ; another system is to store the level '1,2,3,4,5' ... or 'member,customer,admin, ...'. So many ways :)
I will choose the USER.ACCESS = member|customer|admin solution
On the login page
// is user successfully logged
$_SESSION['access'] = $row['access']; // member|customer|admin
// Header('Location: index.php');
On any page of your site:
if( in_array($_SESSION['access'], ['member', 'admin']) ) {
echo 'You are a member, you can see this part';
}
if( in_array($_SESSION['access'], ['customer', 'admin']) ) {
echo 'You are a customer, you can see this part';
}
Or
if( checkAccess() ) {
echo 'Welcome user !';
if( checkAccess(['member', 'customer']) ) {
echo 'This is a section for member, customer or admin :)';
}
if( checkAccess('member') ) {
echo 'You are a member, you can see this part';
}
if( checkAccess('customer') ) {
echo 'You are a customer, you can see this part';
}
}
function checkAccess($types = null) {
if( !isset($_SESSION['access']) )
return false; // not logged
if( is_null($types) )
retun true; // if empty, provide info about loggin.
// admin has always access to all sections of the website
$hasAccess = in_array($_SESSION['access'], ((array) $types) + ['admin']);
return $hasAccess; // user is logged + has accessor not ?
}
Of course, you can also use includes
if( checkAccess('member') ) {
include 'secret_page_for_member.php';
}
Or, at the begening of the included page:
<?php
if( !checkAccess('admin') ) {
return '403 - Not authorized';
// die('403');
// throw new Exception('403');
}
// your code
?>
When a customer or user registers, I want to capture the address details in one click and save that in ps_address table , ie when he clicks on the register button his address details must be also saved to the ps_address table , how to do this?
I have managed to customize the registration form and able to plug the address details form to my registration form as shown in the attached image :
Now what I am stuck with is : when am clicking on the Register button ,the address field details are not saved in the database and I am getting server error
What I tried to do is ,I created a new function called processPostAddress and I am calling processPostAddress from processSubmitAccount() in controller/front/Authcontroller.php page before the redirection to the account page.
$this->processPostAddress(); //// custom function call
Tools::redirect('index.php?controller='.(($this->authRedirection !== false) ? urlencode($this->authRedirection) : 'my-account'));
Below is the custom function which i created in controller/front/Authcontroller.php page
public function processPostAddress()
{
if($this->context->customer->id_customer!=''){
$address = new Address();
$address->id_customer = 40;
$address->firstname = trim(Tools::getValue('firstname'));
$address->lastname = trim(Tools::getValue('lastname'));
$address->address1 = trim(Tools::getValue('address1'));
$address->address2 = trim(Tools::getValue('address2'));
$address->postcode = trim(Tools::getValue('postcode'));
$address->city = trim(Tools::getValue('city'));
$address->country = trim(Tools::getValue('country'));
$address->state = trim(Tools::getValue('state'));
$address->phone = trim(Tools::getValue('phone'));
$address->phone_mobile = trim(Tools::getValue('phone_mobile'));
$address->add(); // This should add the address to the addresss table }
}
Please help me or tell me if I am doing anything wrong or how to achieve this
I solved it by adding $address->alias, since alias was required and was validated .
Also in order to save in the database I modified $address->add(); to $address->save();
public function processPostAddress()
{
///Address::postProcess(); // Try this for posting address and check if its working
// Preparing Address
$address = new Address();
$this->errors = $address->validateController();
$address->id_customer = (int)$this->context->customer->id;
$address->firstname = trim(Tools::getValue('firstname'));
$address->lastname = trim(Tools::getValue('lastname'));
$address->address1 = trim(Tools::getValue('address1'));
$address->address2 = trim(Tools::getValue('address2'));
$address->postcode = trim(Tools::getValue('postcode'));
$address->city = (int)trim(Tools::getValue('city'));
$address->country = (int)trim(Tools::getValue('country'));
$address->state = (int)trim(Tools::getValue('state'));
$address->phone = trim(Tools::getValue('phone'));
$address->alias = "My Default Address";
// Check the requires fields which are settings in the BO
$this->errors = array_merge($this->errors, $address->validateFieldsRequiredDatabase());
// Don't continue this process if we have errors !
if (!$this->errors && !$this->ajax) {
return;
}else{
// Save address
$address->save();
}
}
I am having a bit of difficulty with form tokens. I have a global file that i require at the top of all of the controllers.
/*
*----------------------------------------------
* VERIFY FORM TOKENS
*----------------------------------------------
*/
if ($_POST) {
// Define and Sanitize
$formToken = $sanitize->input($utilities->getVar('formToken', 'session'));
$authenticityToken = $sanitize->input($utilities->getVar('authenticityToken'));
// Validate
if ($authenticityToken !== $formToken) {
$errors[] = 'There was a token mismatch error submitting your form. Please try again.';
}
}
// Generate Form Token
$formToken = $forms->token();
$_SESSION['formToken'] = $formToken;
When echo'ing the vars out right after being declared they match. But when i check the db ( I save sessions to db ) every db refresh displays a new formtoken that was saved. I only call the $forms->token(); class once this is what it looks like
class Forms {
public __construct(){}
function token() {
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$token = '';
for ($i = 0; $i < 60; $i++) { $token .= $characters[ rand( 0, strlen( $characters ) - 1 ) ]; }
$hash = substr(str_shuffle($token), 0, 32);
return $hash;
}
}
I have been working on this issue for a while now, i am confused as to why this occurs. I am also using mod_rewrite in my .htaccess file. I read that rewrites affect sessions but all other session data is ok ( session login data etc. ) it is just these tokens that are giving me a hard time.
I think you need to wrap an else around where you generate the token. As you have it, it looks like you get the token, then create a new one each time.
if ($_POST)
{
// Define and Sanitize
$formToken = $sanitize->input($utilities->getVar('formToken', 'session'));
$authenticityToken = $sanitize->input($utilities->getVar('authenticityToken'));
// Validate
if ($authenticityToken !== $formToken)
{
$errors[] = 'There was a token mismatch error submitting your form. Please try again.';
//UPDATE: MAYBE PUT IT HERE TOO:
$formToken = $forms->token();
$_SESSION['formToken'] = $formToken;
}
}
else
{
//----putting in an else so this is not done again on POST--------
// Generate Form Token
$formToken = $forms->token();
$_SESSION['formToken'] = $formToken;
}