2

There seems to be a major issue on several v2.5.7 sites I've been asked to help with, where emails are not being validated when entered into the built-in com_contact component on a standard contact-us form.

The contact form will error out when the TLD used by the submitter ends with any value using more than 4 characters at the 'dot' end of the domain name... i.e., 5 characters of '.cloud' will not be accepted, while the 3 characters as '.com' work as expected. I've verified that this is a repeatable issue with every form submitted when using the new/extended domain names in an email address. The forms all work perfectly otherwise.

This site will not be upgraded to anything newer just yet, and the core code has been heavily patched to cover bugs and security issues otherwise - so - it will need another patch to accommodate a fix for this too. In other words, nothing but hand coding can be done.

From what I've uncovered so far, the validation code responsible for the email address itself is in: /libraries/joomla/form/rules/email.php

The code doing the validating seems to be the regex at line #27... and I loathe and don't understand enough about regex to be able to proffer a sure fix.

Can someone familiar give me a pointer on whether my assumption is correct - that this is the problem code... or where it might be located if this isn't the right file? And - if it is the right place, what changes can be made to allow for a much longer TLD to be acceptable in an email address.

Here's the entire function code in email.php:

class JFormRuleEmail extends JFormRule
{
    /**
     * The regular expression to use in testing a form field value.
     *
     * @var    string
     * @since  11.1
     */
    protected $regex = '^[\w.-]+(\+[\w.-]+)*@\w+[\w.-]*?\.\w{2,4}$';

    /**
     * Method to test the email address and optionally check for uniqueness.
     *
     * @param   JXMLElement  &$element  The JXMLElement object representing the <field /> tag for the form field object.
     * @param   mixed        $value     The form field value to validate.
     * @param   string       $group     The field name group control value. This acts as as an array container for the field.
     *                                  For example if the field has name="foo" and the group value is set to "bar" then the
     *                                  full field name would end up being "bar[foo]".
     * @param   JRegistry    &$input    An optional JRegistry object with the entire data set to validate against the entire form.
     * @param   object       &$form     The form object for which the field is being tested.
     *
     * @return  boolean  True if the value is valid, false otherwise.
     *
     * @since   11.1
     * @throws  JException on invalid rule.
     */
    public function test(&$element, $value, $group = null, &$input = null, &$form = null)
    {
        // If the field is empty and not required, the field is valid.
        $required = ((string) $element['required'] == 'true' || (string) $element['required'] == 'required');
        if (!$required && empty($value))
        {
            return true;
        }

        // Test the value against the regular expression.
        if (!parent::test($element, $value, $group, $input, $form))
        {
            return false;
        }

        // Check if we should test for uniqueness.
        $unique = ((string) $element['unique'] == 'true' || (string) $element['unique'] == 'unique');
        if ($unique)
        {

            // Get the database object and a new query object.
            $db = JFactory::getDBO();
            $query = $db->getQuery(true);

            // Build the query.
            $query->select('COUNT(*)');
            $query->from('#__users');
            $query->where('email = ' . $db->quote($value));

            // Get the extra field check attribute.
            $userId = ($form instanceof JForm) ? $form->getValue('id') : '';
            $query->where($db->quoteName('id') . ' <> ' . (int) $userId);

            // Set and query the database.
            $db->setQuery($query);
            $duplicate = (bool) $db->loadResult();

            // Check for a database error.
            if ($db->getErrorNum())
            {
                JError::raiseWarning(500, $db->getErrorMsg());
            }

            if ($duplicate)
            {
                return false;
            }
        }

        return true;
    }
}
  • My issue is I can't find where client side validation is done. The stupid form fields always show red and forms can't be submitted. Changed a couple of regexes to no avail. Any idea where client side validation is done? – akostadinov Apr 1 '18 at 11:22
  • As Richard B pointed out... if you're only option is to edit the core files, then you need to change the values in email.php at the end of the regex string. The two numbers in curly brackets can be modified from the default of 2,4 to 2,16. That gives you 16 total characters for the top level domain name instead of 4. – J-Extra Apr 1 '18 at 15:24
  • I believe email.php is for server side validation. But it does no effect on browser side validation which makes the email field red and form cannot be submitted. Even if I put .* in email.php that makes no difference. I found 2-3 other places where js is doing regexp validation of fields with validate-email class but changing them didn't help. That's why I'm asking where the ..heck is this validation taking place. – akostadinov Apr 1 '18 at 21:27
  • There are a heck of a lot email validation regular expressions throughout the stupid thing. Talk to me about DRY. Anyway, after going through all places I detected by grep -r '@\(' I finally got rid of this validation trouble by fixing media/system/js/validate.js and media/system/js/validate-uncompressed.js. – akostadinov Apr 1 '18 at 21:58
  • Actually, email.php is for the client side in-browser validation. In my original post you'll find the line number to search for, and as I noted, the only change necessary is editing the 2 comma-seperated values in the curly brackets. I didn't need any edits to the js files or anything else - as far as I remember. I also needed to clear my browser cache after editing to get emails without errors. – J-Extra Apr 2 '18 at 0:35
0

You have identified the issue correctly. The bug was raised here: https://developer.joomla.org/joomlacode-archive/issue-28128.html

Joomla now uses the following regex.

protected $regex = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$";

You could probably just swap out the regex line, but you really should be patching the sites and not touching core code. There have been loads of security patches since 2.5, so your site is vulnerable.

  • I had a chance to try a fix after looking through all the linked material. I thought it would be better to start off conservatively for now and just modify what was explained as the character count limiters (i.e., {2,4}) and not try to change to the newer/fuller regex expression, or to swap out files from any patches. A change to {2,16} seemed to satisfy the form and allowed for a successful sending of mail. I'll have to wait until Monday to get a definitive answer about it arriving intact. My instincts tell me it will, but I've thought that before too. – J-Extra Jul 28 '17 at 22:36
  • I should also mention that if I was the site owner or had the authority to invest the money and time into a full-on upgrade - I would opt for that as a fix too. As it stands now, I can only make that recommendation and see what the answer will be. – J-Extra Jul 28 '17 at 22:46
  • Simply changing the character count values did indeed work, so emails are being received without further issues or errors reported. Thanks for pointing me in the right direction. – J-Extra Aug 1 '17 at 19:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.