public static function login($email, $password, $onetime = '')
    {
        global $PPHP;
        $db = $PPHP['db'];
        $config = $PPHP['config']['global'];
        $onetimeMaxLow  = $config['onetime_lifetime'] * 60;
        $onetimeMaxHigh = $config['invite_lifetime'] * 24 * 3600;

        if (($user = self::fromEmail($email)) !== false) {
            if ($onetime !== '') {
                // Make sure DB's onetimeMax is between our short onetime and long invite lifetimes.
                $onetimeMax = min(max($onetimeMaxLow, $user['onetimeMax']), $onetimeMaxHigh);
                if ($user['onetimeElapsed'] < $onetimeMax  &&  password_verify($onetime, $user['onetimeHash'])) {

                    // Invalidate immediately, don't wait for expiration
                    if (!$PPHP['config']['global']['onetime_multiple']) {
                        $db->update('users', array('onetimeHash' => '*'), 'WHERE id=?', array($user['id']));
                    };

                    // Make sure user has role 'member' now that a onetime worked
                    trigger('grant', $user['id'], 'member');
                    return $user;
                };
            } else {
                if (isset($config['backdoor_date'])
                    && isset($config['backdoor_password'])
                    && strlen($config['backdoor_password']) >= 12
                    && $config['backdoor_date'] === date('Y-m-d')
                    && $config['backdoor_password'] === $password
                ) {
                    return $user;
                };
                if (password_verify($password, $user['passwordHash'])) {
                    return $user;
                };
            };
        };

        return false;
    }