XF 2.3 Encountered Issues with External User Registration in Xenforo

Majdev

Active member
Hello,

I am encountering an issue with external user registration using PHP. When the "Enable email confirmation" option is enabled, I receive the following error:

An exception occurred: [LogicException] Template email:user_email_confirmation did not render to anything. It must provide either a text or HTML body. in community/src/XF/Mail/Mailer.php on line 174
  1. XF\Mail\Mailer->renderMailTemplate() in community/src/XF/Mail/Mail.php at line 420
  2. XF\Mail\Mail->renderTemplate() in community/src/XF/Mail/Mail.php at line 492
  3. XF\Mail\Mail->getSendableEmail() in community/src/XF/Mail/Mail.php at line 568
  4. XF\Mail\Mail->send() in community/src/XF/Service/User/AbstractConfirmationService.php at line 89
  5. XF\Service\User\AbstractConfirmationService->sendConfirmationEmail() in community/src/XF/Service/User/AbstractConfirmationService.php at line 67
  6. XF\Service\User\AbstractConfirmationService->triggerConfirmation() in community/src/XF/Service/User/RegistrationService.php at line 417
  7. XF\Service\User\RegistrationService->sendRegistrationContact() in community/src/XF/Service/User/RegistrationService.php at line 339
  8. XF\Service\User\RegistrationService->_save() in community/src/XF/Service/ValidateAndSavableTrait.php at line 42
  9. XF\Service\User\RegistrationService->save() in devs/register.php at line 16

1722608556198.webp

However, if I disable this option, the user registration process completes successfully. Is this an issue with my code, or could it be a bug?
Although it gives this error, the user is successfully registered.

Here is my code:
PHP:
<?php
define('XF_ROOT', dirname(__DIR__));
require_once(XF_ROOT . '/community/src/XF.php');
XF::start(XF_ROOT);
$app = XF::setupApp('XF\Pub\App');
$app->start();
$registration = $app->service('XF:User\Registration');
$input['username'] = "xx";
$input['email'] = "xxx@gmail.com";
$input['password'] = "xxxx";
$registration->setFromInput($input);
$user = $registration->save();
print_r($user);

Thank you for your assistance.
Best regards
 
At a glance, your XF_ROOT appears to be defined incorrectly. It should be dirname(__DIR__) . '/community', assuming your script is in a sibling directory and the XF root directory is community.
 
At a glance, your XF_ROOT appears to be defined incorrectly. It should be dirname(__DIR__) . '/community', assuming your script is in a sibling directory and the XF root directory is community.
My apologies for overlooking this. The issue has been resolved. Thank you.
 
@Jeremy P The code is functioning, but are there any potential security vulnerabilities or errors?

PHP:
<?php
define('XF_ROOT', dirname(__DIR__) . '/community');

if (!is_dir(XF_ROOT) || !is_file(XF_ROOT . '/src/XF.php')) {
    die("XenForo could not be found.");
}

require_once(XF_ROOT . '/src/XF.php');
XF::start(XF_ROOT);
$xenforo = XF::setupApp('XF\Pub\App');
$xenforo->start();

function xfLogin($username, $password) {
    global $xenforo;
    $error = "";
    $userIP = $xenforo->request->getIp();
    $loginService = $xenforo->service('XF:User\Login', $username, $userIP);
    $currentUser = $loginService->validate($password, $error);

    if ($currentUser && isset($currentUser->user_id)) {
        $xenforo->session->changeUser($currentUser);
        XF::setVisitor($currentUser);

        $rememberRepo = $xenforo->repository('XF:UserRemember');
        $key = $rememberRepo->createRememberRecord($currentUser->user_id);
        $value = $rememberRepo->getCookieValue($currentUser->user_id, $key);
        
        $cookieParams = session_get_cookie_params();
        setcookie(
            'xf_user',
            $value,
            [
                'expires' => time() + (24 * 60 * 60),
                'path' => '/',
                'domain' => $cookieParams['domain'],
                'secure' => $cookieParams['secure'],
                'httponly' => true,
                'samesite' => 'Strict'
            ]
        );
        return $currentUser;
    }
    return false;
}

function xfRegister($username, $email, $password) {
    global $xenforo;
    $registerService = $xenforo->service('XF:User\Registration');
    $registerService->setFromInput([
        'username' => $username,
        'email' => $email,
        'password' => $password
    ]);

    $currentUser = $registerService->save();
    if ($currentUser && isset($currentUser->user_id)) {
        return $currentUser;
    }
    return false;
}
 
I'm afraid I'm unable to audit the code comprehensively or provide any specific guarantees, nor do I have any understanding of the surrounding context of where and how this code is used.

I can say that it doesn't check if the login has been rate limited, which means it may allow passwords to be brute-forced, it appears to bypass 2FA checks, it doesn't display error messages, and it doesn't use the XF response object to return a response. Whether any of those are relevant or should be addressed is up to you.

It's typically safer and easier to use the REST API to interface with XF from external scripts and programs.
 
Back
Top Bottom