Enable Login By Username With Hooks

Hi Experts :grin:

I want to enable username login on 4.9.x .

I've changed the fn.users.php and its fn_auth_routines function and it will work perfectly but I want to do it by a hook without core files modification .

All I want is to add 3 lines after $user_data variable :

	$user_data = db_get_row("SELECT * FROM ?:users WHERE $field = ?s" . $condition, $user_login);
// added below 3 lines
    if (empty($user_data)) {
		$user_data = db_get_row("SELECT * FROM ?:users WHERE user_login = ?s" . $condition, $user_login);
    }

Is there anyway to do it by hook ?

For example override all of the function or do the same as function by hook and skip anything after the hook ?

the whole function code is as below :

function fn_auth_routines($request, $auth)
{
    $status = true;
$user_login = (!empty($request['user_login'])) ? trim($request['user_login']) : '';
$password = (!empty($request['password'])) ? $request['password']: '';
$field = 'email';

$condition = '';

if (fn_allowed_for('ULTIMATE')) {
    if (Registry::get('settings.Stores.share_users') == 'N' && AREA != 'A') {
        $condition = fn_get_company_condition('?:users.company_id');
    }
}

/**
 * Selects user data
 *
 * @param array $request Query parameters
 * @param array $auth Authentication data
 * @param string $field SQL field to select user by
 * @param string $condition String containing SQL-query condition possibly prepended with a logical operator (AND or OR)
 * @param string $user_login Value to select user by
 */
fn_set_hook('auth_routines', $request, $auth, $field, $condition, $user_login);

$user_data = db_get_row("SELECT * FROM ?:users WHERE $field = ?s" . $condition, $user_login);

if (empty($user_data)) {
    $user_data = db_get_row("SELECT * FROM ?:users WHERE $field = ?s AND user_type IN ('A', 'V', 'P')", $user_login);
}

if (!empty($user_data)) {
    $user_data['usergroups'] = fn_get_user_usergroups($user_data['user_id']);
}

if (
    !empty($user_data)
    && (!fn_check_user_type_admin_area($user_data) && AREA == 'A' || !fn_check_user_type_access_rules($user_data))
) {
    fn_set_notification('E', __('error'), __('error_area_access_denied'));
    $status = false;
}

if (!empty($user_data['status']) && $user_data['status'] == 'D') {
    fn_set_notification('E', __('error'), __('error_account_disabled'));
    $status = false;
}

$salt = isset($user_data['salt']) ? $user_data['salt'] : '';

return array($status, $user_data, $user_login, $password, $salt);

}

Sure, use auth_routines hook to change value of the $field variable from email to user_login

Sure, use auth_routines hook to change value of the $field variable from email to user_login


Thanks for checking it 8) , I've tested it but I think there is a problem on hooking , does not change the value of parent function variable.

The hook will calling correct but not change anything .

This is the hook :

function fn_my_addon_auth_routines($request, $auth, $field, $condition, $user_login)
{
	$field = 'user_login';
}

With this , if I print the $field value in fn.users , it's just the same as before .

Hello,

You will need to make sure you accept your variable by reference (memory location), as it now copies the literal memory and then clears it, hence not updating the variable in the previous stack frame.

This simple requires you to place an ampersand before the parameter you want to change:

function fn_my_addon_auth_routines($request, $auth, &$field, $condition, $user_login)
{
	$field = 'user_login';
}

Kind regards

Thanks @eComLabs & @poppedweb .

Is there anyway to hook auth_routines that can login with " email or username " like the first post ?

Without core modification .

Try something like
function fn_my_addon_auth_routines($request, $auth, &$field, $condition, $user_login)
{
    $is_email = db_get_field("SELECT user_id FROM ?:users WHERE email = ?s", $user_login);
    if (empty($is_email)) {
        $field = 'user_login';
    }
}