Registration check if username exists in the database

540 views
Skip to first unread message

Jason R

unread,
Sep 24, 2020, 7:50:09 PM9/24/20
to Joomla! General Development
I am trying to auto create a username for users based on the format xxx-123-xxx.  I am using the override com_users registraiton default.php file:

I had it working until I tried to do a start loop to make a new username until it was not found in the database.  Sorry, new to jquery, so any pointers would be nice.

Here is the full code:

<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_users
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('behavior.keepalive');
JHtml::_('behavior.formvalidator');
/*** Begin Registration Form Override ***/

$doc = JFactory::getDocument();
$js = "
        jQuery(document).ready(function($){
        
        let foo = function(length) { //length should be <= 7
                         return  (+new Date * Math.random()).toString(36).toUpperCase().substring(0,3);
        }
start: while(true) {
            var $testUsername = foo() + '-123-' + foo();
var $testUser = JFactory::getUser($testUsername);
if (@$testUser->id == 0) {
// the user doesn't exist
            break;
} else {
// it does run again until it doesn't
continue start
              }
            
            // Define the variables
            var regForm     = $('#member-registration');
            var username        = regForm.find('#jform_username');
            username.val(testUsername);
            username.prop('readonly', true);
        });
    ";
$doc->addScriptDeclaration($js);

/*** Finish Registration Form Override ***/

?>
<script> $(function(){
  $(#jform_username).val('test');
});
</script>
<div class="registration<?php echo $this->pageclass_sfx; ?>">
<?php if ($this->params->get('show_page_heading')) : ?>
<div class="page-header">
<h1><?php echo $this->escape($this->params->get('page_heading')); ?></h1>
</div>
<?php endif; ?>
<form id="member-registration" action="<?php echo JRoute::_('index.php?option=com_users&task=registration.register'); ?>" method="post" class="form-validate form-horizontal well" enctype="multipart/form-data">
<?php // Iterate through the form fieldsets and display each one. ?>
<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
<?php $fields = $this->form->getFieldset($fieldset->name); ?>
          <?php fwrite($myfile, $fields); ?>
<?php if (count($fields)) : ?>
<fieldset>
<?php // If the fieldset has a label set, display it as the legend. ?>
<?php if (isset($fieldset->label)) : ?>
<legend><?php echo JText::_($fieldset->label); ?></legend>
<?php endif; ?> 
<?php echo $this->form->renderFieldset($fieldset->name); ?>
</fieldset>
<?php endif; ?>
<?php endforeach; ?>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary validate">
<?php echo JText::_('JREGISTER'); ?>
</button>
<a class="btn" href="<?php echo JRoute::_(''); ?>" title="<?php echo JText::_('JCANCEL'); ?>">
<?php echo JText::_('JCANCEL'); ?>
</a>
<input type="hidden" name="option" value="com_users" />
<input type="hidden" name="task" value="registration.register" />
</div>
</div>
<?php echo JHtml::_('form.token'); ?>
</form>
</div>

Roger Creagh

unread,
Sep 25, 2020, 2:52:10 AM9/25/20
to joomla-de...@googlegroups.com
JFactory::getUser($testUsername); is a php function which you have placed in some javascript. I don't think you can do that.

On Thu, 2020-09-24 at 16:50 -0700, Jason R wrote:
JFactory::getUser($testUsername);

Viper

unread,
Sep 25, 2020, 2:57:34 AM9/25/20
to Joomla! General Development
Do $.get() request before form submit. See https://api.jquery.com/submit/

darrenf...@gmail.com

unread,
Sep 25, 2020, 3:11:51 AM9/25/20
to Joomla! General Development
I think looking at your code there is a few problems there...

Firstly let's look at this while loop as it seems this while loop would get stuck in a recursive loop and I think you may have overcomplicated things there...


start: while(true) 
{
    var $testUsername = foo() + '-123-' + foo();
    var $testUser = JFactory::getUser($testUsername);
    if (@$testUser->id == 0) 
        break;
    else 
        continue start ;
}

now looking at this what you are in effect telling Javascript to do here is enter a while loop until true is false, if it doesn't find the username then your telling it to break out of "that" while loop and drop back to what it was previously doing, but in this case if it even finds ONE username in the first place it will drop back out into it's own while loop and be stuck waiting till true is false because by telling it to "continue start;" you are in effect launching a whole new while statement and so when you tell it to "break" out of that while statement it drops back into the previous while statement - it would eventually break out of all the statements but it would be extremely wasteful and produce a lot more ids than you need - the proper way to do it would be something like..

found = true ;
while(found) 
{
   var $testUsername = foo() + '-123-' + foo();
   var $testUser = JFactory::getUser($testUsername);
   if (@$testUser->id == 0)
      found = false ;
}

now what this will do is at the beginning found is set to true to get us into the loop, it then generates a testusername and tries to get the testusername.  If it finds the testusername then it sets found to false.  It then hits the while statement and it's like yep found is no longer true... I will drop out of the loop.  You could go even better and put it into a recursive function like so...

function getUsername ()
{
   var $testUsername = foo() + '-123-' + foo();
   var $testUser = JFactory::getUser($testUsername);
   return ( $testUser->id == 0 ? $testUsername : getUsername () ) ;
}

suggestedUsername = getUsername () ;

The ? and : statement in the return bit of the function is basically like an if statement - so what it's basically saying is the same as
if ( $testUser->id == 0 )
   return $testUsername //return the username
else
  return getUsername () ; //call the function again and generate a new username

Now that is not your only problem I can see here...  The next problem is it would appear you are confusing Joomla's PHP functions for jQuery functions.

The above code still wouldn't work because you are using Javascript and you are combining it with PHP that is part of Joomla.  This is where it gets much more complicated if you want to do it the way you're trying to do it - but there might be a much more simpler way looking at your code.

If you want to use Javascript to generate the username like this on the fly you're going to need to use a thing called AJAX - AJAX is like a bridge between Javascript and PHP - this is one of the major differences between Javascript and PHP.  PHP is a server side language, where as Javascript is a client side language.  Javascript can access all sorts of data on the clients computer (the person looking at the site), things like their files, etc...   however PHP can access the data on the server, like for example the SQL database.  Javascript itself cannot query the SQL database, nor can it access the functions defined by PHP which is actually what you are asking it to do here.  JFactory is not a Jquery function even though it starts with J - it's a Joomla PHP function and so by calling JFactory in Javascript you are in effect mixing PHP and Javascript together and Javascript will look at that and go what the heck???  I don't know what JFactory is... it hasn't been defined in Javascript... and throw up an error.

The only way to actually access JFactory is to use Joomla's AJAX functions or you can use JQuery's own .ajax function to contact PHP (however bear in mind that if you use JQuery's AJAX function you wont have access to JFactory from the PHP file because JFactory is loaded by Joomla - you'll actually have to query the database yourself manually - I've done that myself a few times it's not too hard actually... but there is a far more simpler way than using any type of AJAX in this situation.  If you want to use AJAX then please check out the docs on it here... https://api.jquery.com/jquery.ajax/

The easier way though is to just generate the username in PHP and output it rather than using Javascript to try and generate the username - the first thing I'm a bit puzzled with is the function that creates the actual random username as it seems from what I'm reading is that it's getting todays date (in Unix epoch format), multiplying it by a random number, turning it into a string with the number 36 as a parameter (even though .toString doesn't take parameters??), transforming it to be all upper case (seems pointless as it's a number) and then getting a substring from 0 to 3 of that number so your random username would always be a 3 digit number created by the current date.

So here is some code that should work below...

<?php

function generateRandomString($length = 7) 
   $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';  //username random bit consists of these characters only
   $charactersLength = strlen($characters);  
   $randomString = ''; 

  /* for loop generates random characters up to $length (pre-defined as 7)     
 you can put braces {} around the for statement if you want to but as it's just one statement no braces are needed*/
   for ($i = 0; $i < $length; $i++)
     $randomString .= $characters[rand(0, $charactersLength - 1)]; 

   //returns random string     
   return $randomString;
}  

function generateUsername ()
{
  use Joomla\CMS\User; //uses namespace rather than JUserHelper
  $testUsername = generateRandomString ().'-123-'.generateRandomString () ; //Generates the test username
  $userId = UserHelper::getUserId($testUsername);  //uses UserHelper to see if username exists
  return ( $userId === false ? $testUsername : generateUsername () ) ; //if userId is equal to FALSE (not 0) then return username
 /* === means check if item is totally FALSE and not just 0 as the first userId in the database would return 0 which could cause problems */  
}

use Joomla/CMS/Factory ; //use the Factory namespace rather than JFactory - JFactory was deprecated in Joomla 2 it still works but is not right
$doc = Factory::getDocument(); //to use the namespace remove J from the beginning of the name

/*js code adds the username generated by PHP in the middle of the code*/
$js = "
        jQuery(document).ready(function($){
            // Define the variables
            var regForm     = $('#member-registration');
            var username        = regForm.find('#jform_username');
            username.val(".generateUsername().");

Jason R

unread,
Sep 25, 2020, 12:01:02 PM9/25/20
to Joomla! General Development
Darren,
Wow that is the best response and detailed response I have ever gotten!  I was looking into it more last night and noticed that.  But was not sure how to do it with jquery.  So now I know I should pick up a little AJAX.  But I was going to do the username part and makes sense to do the password in PHP also.  I was just not sure how to pass the var into javascript, but you showed me. 

Thanks again!
J

Jason R

unread,
Sep 25, 2020, 5:07:11 PM9/25/20
to Joomla! General Development
It doesn't seem to like this line:

 use Joomla\CMS\User; //uses namespace rather than JUserHelper
 syntax error, unexpected 'use' (T_USE)

I thought it was this line at first:
use Joomla/CMS/Factory;  You had it as: use Joomla/CMS/Factory ;

Do I need to load joomla\CMS\User?

Is there a way to get better debug info from joomla? 

Jason R

unread,
Sep 25, 2020, 5:46:17 PM9/25/20
to Joomla! General Development
Seems I had to move the use outside of the functions.  and add use Joomla\CMS\User\UserHelper;

Now it tries to run but seems to be stuck in a loop.  Of course I can't see anything as it runs to debug where it is stopping.

darrenf...@gmail.com

unread,
Sep 26, 2020, 2:21:55 AM9/26/20
to Joomla! General Development
Try changing userId === false to userId === 0 

it seems that the getUserId function does return 0 if the ID isn't found not false - how very interesting.  It seems joomla userids start at 1 and not 0 so it returns 0 as not found... how very strange as normally in programming counting always starts at 0 - clearly not with Joomla userids!

The information about it is here


(it does say it's from API17 which is out of date, but API17 provides more information about what is being returned than the API3 documentation)

API 3 docs can be seen here

Jason R

unread,
Sep 26, 2020, 11:51:28 AM9/26/20
to Joomla! General Development
Ok so it seems the issue in the jquery: username.val(".generateUsername().");  So far google says I can't call a php function form jquery.  I have to use ajax.  Is this another way that maybe has a typo?

darrenf...@gmail.com

unread,
Sep 26, 2020, 2:06:05 PM9/26/20
to Joomla! General Development
PHP should be replacing the word generateUsername() with whatever the generateUsername () function returns - I think what I might have missed off is, is the single quotes so it's trying to call username as a variable rather than a value.
if you change

username.val(".generateUsername().") ;

to 

username.val ('".generateUsername()."') ;

then if you look at the javascript code you should see

username.val('ABCDEFG-123-ABCDEFG');

(without the quotes you'll see username.val(ABCDEFG-123-ABCDEFG) and you get an error that ABCDEFG is not defined as what Javascript is then trying to do is give the username the value of ABCDEFG - 123 - ABCDEFG not "ABCDEFG-123-ABCDEFG" - ABCDEFG will be a random set of seven letters).


Alternatively you could try changing the function for a variable like so...
<?php

$username = generateUsername () ;
$js = "
        jQuery(document).ready(function($){
            // Define the variables
            var regForm     = $('#member-registration');
            var username        = regForm.find('#jform_username');
            username.val('$username');
            username.prop('readonly', true);
        });
    ";
$doc->addScriptDeclaration($js);

?>

as $js = "" is in double quotes PHP replaces the variable with it's value

if you want to quickly test this try this

<?php

/*remember the previous code generateUsername function $doc definition, etc...*/

$username = generateUsername () ;
$js = "alert('$username');" ;
$doc->addScriptDeclaration ( $js ) ;
?>

when you load up the website you should now have an alert box pop up with the username chosen.




Jason R

unread,
Sep 26, 2020, 3:59:51 PM9/26/20
to Joomla! General Development
I tried all of that.  Do I need to enable something?  The field is just blank and doesn't even pass the readonly since no value is set in jquery when I pass the function with:
'".generateUsername()."'

When I try the variable it throws an error 500 but doesn't tell me why.  Nothing in apache logs and nothing to the screen.   I also tried to just assign the static variable in php to skip the functions but throws a 500 error in apache.  But I never could get it to pass it anything from php to jquery.  I wonder if there is a module or something I have to enable.

darrenf...@gmail.com

unread,
Sep 27, 2020, 4:03:02 AM9/27/20
to Joomla! General Development
Got it now (the error was using / instead of \ in the use statements) - just tested it on my own website works fine - here is the full correct code with no errors...

<?php

use Joomla\CMS\User\UserHelper ;
use Joomla\CMS\Factory ; 

function generateRandomString($length = 7) 
   $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
   $charactersLength = strlen($characters);  
   $randomString = ''; 
   for ($i = 0; $i < $length; $i++)
     $randomString .= $characters[rand(0, $charactersLength - 1)]; 
   return $randomString;
}  

function generateUsername ()
{
  $testUsername = generateRandomString ().'-123-'.generateRandomString () ;
  return ( UserHelper::getUserId($testUsername) == 0 ? $testUsername : generateUsername () ) ;
}

$doc = Factory::getDocument();
$js = "
        jQuery(document).ready(function($){
            var regForm     = $('#member-registration');
            var username        = regForm.find('#jform_username');
            username.val('".generateUsername()."');
            username.prop('readonly', true);
        });
    ";
$doc->addScriptDeclaration($js);


?>

Jason R

unread,
Sep 27, 2020, 4:32:56 AM9/27/20
to joomla-de...@googlegroups.com
That fixed it:

You had: 
use Joomla\CMS\User

Changing that to:

use Joomla\CMS\User\UserHelper ;

Also moving those out of the functions and adding the double quotes.  It seems I had to remove the: 

use Joomla\CMS\User;

That seemed to throw and error.

Thank you for your help.  It is good to know I can pass from PHP into jquery without using Ajax.

J


--


You received this message because you are subscribed to a topic in the Google Groups "Joomla! General Development" group.


To unsubscribe from this topic, visit https://groups.google.com/d/topic/joomla-dev-general/F30NL0cYY3g/unsubscribe.


To unsubscribe from this group and all its topics, send an email to joomla-dev-gene...@googlegroups.com.


To view this discussion on the web, visit https://groups.google.com/d/msgid/joomla-dev-general/856ecb8b-3b48-44aa-a4ca-1521b54e417fn%40googlegroups.com.




Reply all
Reply to author
Forward
0 new messages