get joomla4 login in external php script

2,416 views
Skip to first unread message

Emmanuel Ingelaere

unread,
Nov 17, 2021, 3:32:33 AM11/17/21
to Joomla! General Development
Hi everybody,

I'm writing a php database app in which I want to use joomla4 as login system. I think I remember using the following method succesfully in the past to check if a user is logged on:
--------------------
define( '_JEXEC', 1 );
define( '_VALID_MOS', 1 );
define('JPATH_BASE', dirname(__FILE__));
define( 'DS', DIRECTORY_SEPARATOR );
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
//JPluginHelper::importPlugin('system');
//$mainframe->triggerEvent('onAfterInitialise');

$user = JFactory::getUser();
------------------------
I got this from following post:

Does someone know how to achieve this in Joomla4? The above code throws an error in the line: $user = JFactory::getUser();

Any tips on doing this by the book are also very welcome!

Emmanuel Ingelaere

unread,
Nov 17, 2021, 3:36:06 AM11/17/21
to Joomla! General Development
The error thrown is " Failed to start application "

Op woensdag 17 november 2021 om 09:32:33 UTC+1 schreef Emmanuel Ingelaere:

Elvis

unread,
Nov 17, 2021, 7:44:27 AM11/17/21
to Joomla! General Development
Hi!

You are using old code, it won't work in J4, try this

<?php

define('_JEXEC', 1);
define('DS', DIRECTORY_SEPARATOR);
 
if (file_exists(dirname(__FILE__) . '/defines.php')) {
 include_once dirname(__FILE__) . '/defines.php';
}
 
if (!defined('_JDEFINES')) {
 define('JPATH_BASE', 'PATH_TO_YOUR_JOOMLA_SITE_ROOT_FOLDER');
 require_once JPATH_BASE.'/includes/defines.php';
}
 
require_once JPATH_BASE.'/includes/framework.php';

I didn't test it in J4, but it should work

Alex Chartier

unread,
Nov 17, 2021, 7:55:04 AM11/17/21
to Joomla! General Development
I have run into this myself and created a wrapper which will work on both J3 & J4. It does not actually log the user in but you could do that yourself. Please see the attached file.
ApplicationWrapper.php

Alex Chartier

unread,
Nov 17, 2021, 7:56:42 AM11/17/21
to Joomla! General Development
p.s. I should have sanitized it a bit. Remove the function and call for bootJmailqPlugin (unless you are running JmailQ which you probably are not).

Emmanuel Ingelaere

unread,
Nov 17, 2021, 9:57:19 AM11/17/21
to joomla-de...@googlegroups.com
Hi!

Thanks to both of you for the quick response! Both your suggested code works without errors.

However, in both cases, querying and displaying the user object results in an empty object, even when a user is logged in.

To test this I used the following setup:

-installed a joomla 4.0 testsite
-login in this testsite with a random user
-in a separate tab of firefox, run the php-script with your code (made one version for each of you), followed by: $user = JFactory::getUser(); print_r($user);
-this script sits in the root of the site
-the print_r gives following result in both cases:

Joomla\CMS\User\User Object ( [isRoot:protected] => [id] => 0 [name] => [username] => [email] => [password] => [password_clear] => [block] => [sendEmail] => 0 [registerDate] => [lastvisitDate] => [activation] => [params] => [groups] => Array ( ) [guest] => 1 [lastResetTime] => [resetCount] => [requireReset] => [_params:protected] => Joomla\Registry\Registry Object ( [data:protected] => stdClass Object ( ) [initialized:protected] => [separator] => . ) [_authGroups:protected] => [_authLevels:protected] => [_authActions:protected] => [_errorMsg:protected] => [userHelper:protected] => Joomla\CMS\User\UserWrapper Object ( ) [_errors:protected] => Array ( ) [aid] => 0 )

Am I missing something or doing something wrong? Thx!


Op wo 17 nov. 2021 om 13:56 schreef Alex Chartier <al...@thealgonquinclub.com>:
--
You received this message because you are subscribed to the Google Groups "Joomla! General Development" group.
To unsubscribe from this group and stop receiving emails from it, 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/c356ab28-bc6d-4bb5-9eb2-32aa64155e8en%40googlegroups.com.

Alex Chartier

unread,
Nov 17, 2021, 10:10:02 AM11/17/21
to Joomla! General Development
Two things. First you have not logged in, and second you have not provided a userID for the getUser. When calling the getUser as you have, without a user ID, Joomla will return a user object of the currently logged in user. Since no user is logged in you are getting an empty object. To log in the user take a look here: https://stackoverflow.com/questions/2075335/how-to-log-into-joomla-through-an-external-script

If you are using my script, you will want to place this in the doExecute function of your class. Once logged in the getUser will return the user object of that user.

Emmanuel Ingelaere

unread,
Nov 22, 2021, 11:21:40 AM11/22/21
to joomla-de...@googlegroups.com
Ok, thx, it works now! Thanks a lot for pointing me in the right direction. For others facing the same question, here's the complete solution I used:

error_reporting(E_ALL);
ini_set('display_errors', 1);

define('_JEXEC', 1);
define('JPATH_BASE', __DIR__);
require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';

// Boot the DI container
$container = \Joomla\CMS\Factory::getContainer();

/*
 * Alias the session service keys to the web session service as that is the primary session backend for this application
 *
 * In addition to aliasing "common" service keys, we also create aliases for the PHP classes to ensure autowiring objects
 * is supported.  This includes aliases for aliased class names, and the keys for aliased class names should be considered
 * deprecated to be removed when the class name alias is removed as well.
 */
$container->alias('session.web', 'session.web.site')
    ->alias('session', 'session.web.site')
    ->alias('JSession', 'session.web.site')
    ->alias(\Joomla\CMS\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\SessionInterface::class, 'session.web.site');

// Instantiate the application.
$app = $container->get(\Joomla\CMS\Application\SiteApplication::class);

// Set the application as global app
\Joomla\CMS\Factory::$application = $app;

After this you can login with:

$result_login = JFactory::getApplication()->login(
    [
        'username' => 'user01',
        'password' => 'secret'
    ],
    [
        'remember' => true,
        'silent'   => true
    ]
);

Or check if a user is already logged in or get the session info using:

$userInfo = \Joomla\CMS\Factory::getApplication()->getSession()->get('user');
$userSession = \Joomla\CMS\Factory::getApplication()->getSession();

var_dump($userInfo);
echo "<p>-</p>";
var_dump($userSession);


From a security point of view when you check if the user is already logged on:
-suppose a user installs his own joomla-site and on both sites the user 'admin' exists...
-An external script checking if the user is logged on, could be fooled in believing the user is logged on as admin? Or am I wrong? So how to check if the user is coming from the correct joomla-site?


Op wo 17 nov. 2021 om 16:10 schreef Alex Chartier <al...@thealgonquinclub.com>:

Campbell Morrison

unread,
Apr 24, 2023, 9:27:54 AM4/24/23
to Joomla! General Development
Has anyone got this working after updating to Joomla 4.3.0?  The solution above worked before, but after updating to 4.3.0 I get the error

ClassNotFoundError
Attempted to load class "Cookie" from namespace "Joomla\Plugin\Authentication\Cookie\Extension".
Did you forget a "use" statement for another namespace?

axel veerman

unread,
May 2, 2023, 4:12:22 PM5/2/23
to Joomla! General Development
Hi Campbell,

For me the external script worked again when I added these two lines:

        require_once JPATH_BASE . '/includes/defines.php';
        require_once JPATH_BASE . '/includes/framework.php';
        // added two lines to get it work in Joomla 4.3
        require_once JPATH_BASE . '/plugins/authentication/joomla/src/Extension/Joomla.php';
        require_once JPATH_BASE . '/plugins/authentication/cookie/src/Extension/Cookie.php';


Op maandag 24 april 2023 om 15:27:54 UTC+2 schreef Campbell Morrison:

Campbell Morrison

unread,
May 3, 2023, 10:33:31 AM5/3/23
to Joomla! General Development
Thanks.  That works for a valid user, though I think it's probably really only a circumvention.  I don't know enough about how Joomla works, but I assume the Joomla autoloader should really be loading those classes.

However for an invalid user I get the Joomla error:

Call to a member function _() on null in /home/****/public_html/joomla4/plugins/authentication/joomla/src/Extension/Joomla.php (line 104)

Viper

unread,
May 3, 2023, 10:57:02 AM5/3/23
to Joomla! General Development
Because just including a plugin file is not a way to use it. You need to load it via plugin helper at least. See /plugins/authentication/joomla/services/provider.php
Or trigger plugin event and check the result. Read https://www.dionysopoulos.me/book/plg.html

Campbell Morrison

unread,
May 3, 2023, 11:43:11 AM5/3/23
to Joomla! General Development
But why should we be loading a plugin at all?  These are standard plugins and surely Joomla should be loading them?  What has changed in Joomla 4 at Joomla 4.3.0?

Viper

unread,
May 3, 2023, 1:41:01 PM5/3/23
to Joomla! General Development
You right. But you need to trigger plugin event, not just include php file.

Campbell Morrison

unread,
May 3, 2023, 1:54:36 PM5/3/23
to Joomla! General Development
OK, I can understand that if I want to use a plugin I need to load it properly, but in the case above I just want to use Joomla.  The method above used to work up until Joomla 4.3.0, but has now stopped working for some reason.

axel veerman

unread,
May 4, 2023, 9:00:22 PM5/4/23
to Joomla! General Development
I found another solution: register extension namespaces, after setting the application as global app. I found this solution here: https://joomla.stackexchange.com/questions/32145/joomla-4-error-when-i-use-getarticleroute
... // Set the application as global app \Joomla\CMS\Factory::$application = $app; $app->createExtensionNamespaceMap();

Op woensdag 3 mei 2023 om 19:54:36 UTC+2 schreef Campbell Morrison:

Campbell Morrison

unread,
May 5, 2023, 5:35:30 AM5/5/23
to Joomla! General Development
Thanks.  Although that's a cleaner solution, I still get the error

Call to a member function _() on null in /home/****/public_html/joomla4/plugins/authentication/joomla/src/Extension/Joomla.php (line 104)

when I login as an invalid user.

axel veerman

unread,
May 5, 2023, 6:09:35 PM5/5/23
to Joomla! General Development
Same error here when login with an invalid user.

This error can be prevented by checking first if the username exists in the user tabel, and after that verify the user/password combination.
I have this code working now:

error_reporting(E_ALL);
ini_set('display_errors', 1);

define('_JEXEC', 1);
define('JPATH_BASE', __DIR__);

require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';

// Boot the DI container
$container = \Joomla\CMS\Factory::getContainer();

/*
 * Alias the session service keys to the web session service as that is the primary session backend for this application
 *
 * In addition to aliasing "common" service keys, we also create aliases for the PHP classes to ensure autowiring objects
 * is supported.  This includes aliases for aliased class names, and the keys for aliased class names should be considered
 * deprecated to be removed when the class name alias is removed as well.
 */
$container->alias('session.web', 'session.web.site')
    ->alias('session', 'session.web.site')
    ->alias('JSession', 'session.web.site')
    ->alias(\Joomla\CMS\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\SessionInterface::class, 'session.web.site');

// Instantiate the application.
$app = $container->get(\Joomla\CMS\Application\SiteApplication::class);

// Set the application as global app
\Joomla\CMS\Factory::$application = $app;

$app->createExtensionNamespaceMap();

//$result_login = JFactory::getApplication()->login(
//    [
//        'username' => 'user01',
//        'password' => 'secret'
//    ],
//    [
//        'remember' => true,
//        'silent'   => true
//    ]
//);

$username = 'user01';
$password = 'secret';

$credentials = array();
$credentials['username'] = $username;
$credentials['password'] = $password;

$db = \Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
$query = $db->getQuery(true)
->select('id, password')
->from('#__users')
->where('username=' . $db->quote($credentials['username']));

$db->setQuery($query);
$result = $db->loadObject();

if ($result)
{
$match = JUserHelper::verifyPassword($credentials['password'], $result->password, $result->id);

if ($match === true)
{
// Bring this in line with the rest of the system
$user = JUser::getInstance($result->id);
//echo 'Joomla! Authentication was successful!';

if (!$user->get('gid')){
$forcevars = array();
$forcevars['silent'] = true;
$forcevars['forecelogon'] = true;

$response = $app->login($credentials, $forcevars);
if($response){
echo "Login Successful userid:".$user->id.' name:'.$user->username;
//
// $session = JFactory::getSession();
// echo 'sessieid:'.$session->getId();
// $sessionState=$session->getState();
// $sessionExpiry=$session->getName();
}else{
echo "Login Unsuccessful. Check Username and Password. Give just Plain password.";
}
}


}
else
{
// Invalid password
// Primitive error handling
die('Invalid password');
}
} else {
// Invalid user
// Primitive error handling
die('Unknown user');
}

Op vrijdag 5 mei 2023 om 11:35:30 UTC+2 schreef Campbell Morrison:

Cristian Fonseca

unread,
Jun 21, 2023, 12:17:47 PM6/21/23
to Joomla! General Development
This is the right solution.

This is the code that i have in my "conector" file and now i added this two lines:

Finally i can keep Joomla updated.


define('_JEXEC', 1);
define('JPATH_BASE', __DIR__);
require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';
require_once JPATH_BASE . '/plugins/authentication/joomla/src/Extension/Joomla.php';
require_once JPATH_BASE . '/plugins/authentication/cookie/src/Extension/Cookie.php';


$container = \Joomla\CMS\Factory::getContainer();
$container->alias('session.web', 'session.web.site')
    ->alias('session', 'session.web.site')
    ->alias('JSession', 'session.web.site')
    ->alias(\Joomla\CMS\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\SessionInterface::class, 'session.web.site');

$app = $container->get(\Joomla\CMS\Application\SiteApplication::class);

\Joomla\CMS\Factory::$application = $app;

Campbell Morrison

unread,
Jun 24, 2023, 9:25:32 AM6/24/23
to Joomla! General Development
This only works if the username and password are correct.  Otherwise it throws a Joomla error, as stated above.

Campbell Morrison

unread,
Jun 24, 2023, 9:29:42 AM6/24/23
to Joomla! General Development
> This error can be prevented by checking first if the username exists in the user tabel, and after that verify the user/password combination.
I have this code working now:

But if the username is correct but the password wrong, then the error still occurs.  Besides, it should be possible to validate the user/password combination by using the Joomla `login()` method, rather than relying on low level access to the database.

Campbell Morrison

unread,
Jun 26, 2023, 12:52:03 PM6/26/23
to Joomla! General Development
I've temporarily got this working by wrapping the `login()` in a try/catch block, catching the Throwable and treating that as an unknown user.  But that doesn't seem like the best solution - I'm sure there must be a better way.

Campbell Morrison

unread,
Oct 6, 2023, 1:10:05 PM10/6/23
to Joomla! General Development
I've discovered that if you have the Joomla LDAP authentication plugin enabled you also need the three lines at the bottom (the order is important):

define('_JEXEC', 1);
define('JPATH_BASE', __DIR__);
require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';
require_once JPATH_BASE . '/plugins/authentication/joomla/src/Extension/Joomla.php';
require_once JPATH_BASE . '/plugins/authentication/cookie/src/Extension/Cookie.php';
require_once JPATH_BASE . '/plugins/authentication/ldap/src/Extension/Ldap.php';
require_once JPATH_BASE . '/plugins/authentication/ldap/src/Factory/LdapFactoryInterface.php';
require_once JPATH_BASE . '/plugins/authentication/ldap/src/Factory/LdapFactory.php';

I still can't believe this is the best solution though.  Surely there must be some autoloader that would handle this?
Message has been deleted

robbies....@gmail.com

unread,
Oct 15, 2023, 6:06:23 PM10/15/23
to Joomla! General Development
As mentioned earlier in the thread, I found that you don't need to require all those plugins if you do

$app->createExtensionNamespaceMap();

Also if you load the language then it avoids that other error Call to a member function _() on null
eg:
use Joomla\CMS\Language\Language;
...
$lang = Language::getInstance("en-GB");
$app->loadLanguage($lang);

Campbell Morrison

unread,
Oct 16, 2023, 10:42:00 AM10/16/23
to Joomla! General Development
Many thanks for those tips.  Both problems are now solved.

Confidant

unread,
Oct 20, 2023, 3:25:18 PM10/20/23
to Joomla! General Development
Great thread, thanks everyone.

Campbell Morrison

unread,
Oct 29, 2023, 12:32:24 PM10/29/23
to Joomla! General Development
And I think the proper fix, as opposed to the load of require statements, is necessary for Joomla 4.4.
Reply all
Reply to author
Forward
0 new messages