1
robstockley
Allow user to change primary email with email confirmation

In response to this thread I've been working at extending the functionality of the system module to include confirmation emails with user initiated email changes. It's been pretty straightforward except that I've come up against an object handler or database concurrency issue that I simply can't get my head around.

The bulk of the hack is in edituser.php (extract below) and is modelled on the activation process in register.php. I'm up to testing the database interaction. I haven't tested the mailer. Setting up a pending email change works and is properly reflected in the users table. Cancelling and/or activating the change produces this error.
Quote:
Warning: Insert failed in method 'cleanVars' of object 'XoopsUser' in file /class/model/write.php line 265

I can't see for the code what is different in the method I've used to update the user record. Any help, advice or pointers to tutorials would be appreciated.
// confirmed email change - Rob Stockley -----------------------------
if ($op == 'processpending'){
    
// get to here after form is submitted
    
if (!$GLOBALS['xoopsSecurity']->check()) {
        
redirect_header('index.php'3_US_NOEDITRIGHT "<br />" implode('<br />'$GLOBALS['xoopsSecurity']->getErrors()));
        exit();
    }
    
$uid = (!empty($_POST['uid'])) ? intval($_POST['uid']) : 0;
    
$pemail = (!empty($_POST['pending_email'])) ? $myts->stripSlashesGPC(trim($_POST['pending_email'])) : '';
    
$pwd_txt = (!empty($_POST['pwd_txt'])) ? $myts->stripSlashesGPC(trim($_POST['pwd_txt'])) : '';
    
// check sanity of user
    
if (empty($uid) || $xoopsUser->getVar('uid') != $uid) {
        
redirect_header('index.php'3_US_NOEDITRIGHT);
        exit();
    }
    
// check format of proposed email
    
if ($pemail == '' || ! checkEmail($pemail)) {
        
$errors[] = _US_INVALIDMAIL;
    }
    
// check user password
    
if ($pwd_txt == '') {
        
$errors[] = _US_ENTERPWD;
    } elseif (
strcmp($xoopsUser->getVar('pass'), md5($pwd_txt)) != 0) {
        
$errors[] = _US_INVALIDPWD;
    }
    
// if there were form errors display these and rerun the form.
    
if (count($errors) > 0) {
        include 
$GLOBALS['xoops']->path('header.php');
        echo 
'<div>';
        foreach (
$errors as $er) {
            echo 
'<span style="color: #ff0000; font-weight: bold;">' $er '</span><br />';
        }
        echo 
'</div><br />';
        
$op 'changeemail';
    } else {
        
// no errors so update the user record
        
$pkey substr(md5(uniqid(mt_rand(), 1)), 08);
        
$member_handler =& xoops_gethandler('member');
        
$edituser =& $member_handler->getUser($uid);
        
$edituser->setVar('pending_email'$pemail);
        
$edituser->setVar('pending_key'$pkey);
        if (! 
$member_handler->insertUser($edituser)) {
            include 
$GLOBALS['xoops']->path('header.php');
            echo 
$edituser->getHtmlErrors();
            include 
$GLOBALS['xoops']->path('footer.php');
        } else {
            
//invoke the mailer
            
$xoopsMailer =& xoops_getMailer();
            
$xoopsMailer->useMail();
            
$xoopsMailer->setTemplate('changeemail.tpl');
            
$xoopsMailer->assign('SITENAME'$xoopsConfig['sitename']);
            
$xoopsMailer->assign('ADMINMAIL'$xoopsConfig['adminmail']);
            
$xoopsMailer->assign('SITEURL'XOOPS_URL "/");
            
$xoopsMailer->setToEmails(array($pemail));
            
$xoopsMailer->setFromEmail($xoopsConfig['adminmail']);
            
$xoopsMailer->setFromName($xoopsConfig['sitename']);
            
$xoopsMailer->setSubject(sprintf(_US_USERKEYFOR$uname));
#            if (! $xoopsMailer->send()) {
#                echo _US_PMAILFAIL;
#            } else {
#                echo _US_PMAILSUCCESS;
#            }
            
redirect_header('userinfo.php?uid=' $uid1_US_PROFUPDATED);
        }
        exit();
    }
}
if (
$op == 'changeemail'){
    
// get to here when change email button is clicked
    
include_once $GLOBALS['xoops']->path('header.php');
    include_once 
$GLOBALS['xoops']->path('include/comment_constants.php');
    include_once 
$GLOBALS['xoops']->path('include/xoopscodes.php');
    
$uid $xoopsUser->getVar('uid');
    echo 
'<a href="userinfo.php?uid=' $uid '">' _US_PROFILE '</a>&nbsp;<span style="font-weight:bold;">&raquo;&raquo;</span>&nbsp;' _US_CHANGEEMAIL '<br /><br />';
    
$form = new XoopsThemeForm(_US_CHANGEEMAIL'userinfo''edituser.php''post'true);
    
$email = new XoopsFormLabel(_US_EMAIL$xoopsUser->getVar('email'));
    
$form->addElement($email);
    
$pending_email = new XoopsFormText(_US_NEWEMAIL'pending_email'3060$xoopsUser->getVar('pending_email''E'));
    
$form->addElement($pending_email);
    
// inlcude password to avoid account hijacking
    
$pwd_text = new XoopsFormPassword(_US_PASSWORD'pwd_txt'1032);
    
$form->addElement($pwd_text);
    
$form->addElement(new XoopsFormHidden('op''processpending'));
    
$form->addElement(new XoopsFormHidden('uid'$uid));
    
$form->addElement(new XoopsFormButton('''submit'_SUBMIT'submit'));
    
$form->display();
    include 
$GLOBALS['xoops']->path('footer.php');
}
if (
$op == 'actvemail' || $op == 'cancelpending'){
    
// get to here if cancel button clicked or through email link 
    
$uid = (!empty($_GET['uid'])) ? intval($_GET['uid']) : 0;
    
$pkey = (!empty($_GET['pending_key'])) ? trim($_GET['pending_key']) : '';
    
$pemail $xoopsUser->getVar('pending_email''E');
    
// user sanity check
    
if (empty($uid) || $xoopsUser->getVar('uid') != $uid) {
        
redirect_header('index.php'3_US_NOEDITRIGHT);
        exit();
    }
    
// get ready to update the user record
    
$member_handler =& xoops_gethandler('member');
    
$edituser =& $member_handler->getUser($uid);
    if (
$op == 'actvemail') {
        
// if we're being activated then check the key
        
if ($pkey == '' || strcmp($pkey$xoopsUser->getVar('pending_key')) != 0) {
            
redirect_header('index.php'3_US_NOEDITRIGHT "<br />" implode('<br />'$GLOBALS['xoopsSecurity']->getErrors()));
            exit();
        }
        
// key was good copy pending email into primary email field
        
$edituser->setVar('email'$pemail);
    }
    
// always cancel the pending email if we get to here
    
$edituser->setVar('pending_email''');
    
$edituser->setVar('pending_key''');
    if (! 
$member_handler->insertUser($edituser)) {
        include 
$GLOBALS['xoops']->path('header.php');
        echo 
$edituser->getHtmlErrors();
        include 
$GLOBALS['xoops']->path('footer.php');
    } else {
        
redirect_header('userinfo.php?uid=' $uid1_US_PROFUPDATED);
    }
    exit();
}
// confirmed email change - Rob Stockley -----------------------------

2
ghia
Re: Allow user to change primary email with email confirmation
  • 2009/12/14 1:46

  • ghia

  • Community Support Member

  • Posts: 4953

  • Since: 2008/7/3 1


What is the workflow of this procedure (actions by user and XOOPS)?

3
robstockley
Re: Allow user to change primary email with email confirmation

Thanks in advance for your help ghia.

changeemail -> processpending -> actvemail -> cancelpending

changeemail
get data from user
check password

processpending
check user authority to make change
check data
if data wrong then back to changeemail
else store data and send confirmation email

actvemail
this step may be skipped
check confirmation link
update user record

cancelpending
clear pending request

Modified File List
./edituser.php
./userinfo.php
./kernel/user.php
./modules/system/templates/system_userinfo.html
./language/english/mail_template/changeemail.tpl
./language/english/user.php
./class/xoopsmailer.php
./sql/mysql.sql

File: ./edituser.php
Includes code for the change email form, processing the change, cancelling the change and activating the change.

File: ./userinfo.php

Assigns extra variables needed to put the change email button on the system_userinfo template.

File: ./kernel/user.php

xoopsUser class extended to include variables pending_email and pending_key, functions for their return and a function isEmailChangePending().

File: ./modules/system/templates/system_userinfo.html
Updated to include the change email button.

File: ./language/english/user.php
Added defines for the buttons and captions.

File: ./language/english/mail_template/changeemail.tpl
New mail template for email activation.

File: ./class/xoopsmailer.php
Added decode for pending link and pending email tags in template.

File: ./sql/mysql.sql
Adds two new fields to users table.

4
robstockley
Re: Allow user to change primary email with email confirmation

Right! I'm not sure if this is relevant but it might mean something to a developer. The warnings are triggered by this instance of insertUser near the end of my code fragment.
// always cancel the pending email if we get to here
    
$edituser->setVar('pending_email''');
    
$edituser->setVar('pending_key''');
    if (! 
$member_handler->insertUser($edituser)) {
        include 
$GLOBALS['xoops']->path('header.php');
        echo 
$edituser->getHtmlErrors();
        include 
$GLOBALS['xoops']->path('footer.php');
    } else {
        
redirect_header('userinfo.php?uid=' $uid1_US_PROFUPDATED);
    }

Curiously, if I change the values for pending_email and pending_key to anything longer than an empty string I get a different warning.
Quote:
Warning: Database updates are not allowed during processing of a GET request in file /class/database/mysqldatabase.php line 400

I should add that $member_handler->insertUser() returns true despite the database values not being updated. The warnings come from the inline debug
I'm stumped.

5
robstockley
Re: Allow user to change primary email with email confirmation

Figured it out. It seems the insertUser method can't occur while there's a server GET request. Solution is to extend the member handler and do the database updates in there using _uHandler->insert.

I have no idea why this works but it does work It appears this hack will work with a little more tinkering.

6
robstockley
Re: Allow user to change primary email with email confirmation

Okay. I've got this working well and tested on my internal site. I tried to post instructions the other day and Protector locked me out. Thanks to Mamba for the rescue.

I can't seem to attach anything here so instead I've placed the instructions on Google Docs for now. You can get them at this link.

This is Alpha. Works on my 2.4.2 system. I've tested it from the perspective of a regular user and an admin. I have tried to break it but not found any problems so far. Your thoughts and suggestions welcomed.

7
robstockley
Re: Allow user to change primary email with email confirmation

This hack is set up and working on this site.

Login

Who's Online

164 user(s) are online (115 user(s) are browsing Support Forums)


Members: 0


Guests: 164


more...

Donat-O-Meter

Stats
Goal: $100.00
Due Date: Apr 30
Gross Amount: $0.00
Net Balance: $0.00
Left to go: $100.00
Make donations with PayPal!

Latest GitHub Commits