My aim is to check that a Joomla username and password is valid from my external application. It is not necessary that the user is logged into the system, just that their account exists.
I decided to create my own authentication plugin based on the Joomla Authentication (JOOMLA_PATH/plugins/authentication/joomla). I only changed the name:
<?php
/**
* #version $Id: joomla.php 21097 2011-04-07 15:38:03Z dextercowley $
* #copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
* #license GNU General Public License version 2 or later; see LICENSE.txt
*/
// No direct access
defined('_JEXEC') or die;
jimport('joomla.plugin.plugin');
/**
* Joomla Authentication plugin
*
* #package Joomla.Plugin
* #subpackage Authentication.Webservice
* #since 1.5
*/
class plgAuthenticationWebservice extends JPlugin
{
/**
* This method should handle any authentication and report back to the subject
*
* #access public
* #param array Array holding the user credentials
* #param array Array of extra options
* #param object Authentication response object
* #return boolean
* #since 1.5
*/
function onUserAuthenticate($credentials, $options, &$response)
{
jimport('joomla.user.helper');
$response->type = 'Webservice';
// Joomla does not like blank passwords
if (empty($credentials['password'])) {
$response->status = JAUTHENTICATE_STATUS_FAILURE;
$response->error_message = JText::_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');
return false;
}
// Initialise variables.
$conditions = '';
// Get a database object
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('id, password');
$query->from('#__users');
$query->where('username=' . $db->Quote($credentials['username']));
$db->setQuery($query);
$result = $db->loadObject();
if ($result) {
$parts = explode(':', $result->password);
$crypt = $parts[0];
$salt = #$parts[1];
$testcrypt = JUserHelper::getCryptedPassword($credentials['password'], $salt);
if ($crypt == $testcrypt) {
$user = JUser::getInstance($result->id); // Bring this in line with the rest of the system
$response->email = $user->email;
$response->fullname = $user->name;
if (JFactory::getApplication()->isAdmin()) {
$response->language = $user->getParam('admin_language');
}
else {
$response->language = $user->getParam('language');
}
$response->status = JAUTHENTICATE_STATUS_SUCCESS;
$response->error_message = '';
} else {
$response->status = JAUTHENTICATE_STATUS_FAILURE;
$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_PASS');
}
} else {
$response->status = JAUTHENTICATE_STATUS_FAILURE;
$response->error_message = JText::_('JGLOBAL_AUTH_NO_USER');
}
}
}
I added one more file to my plugin to access the authentication, I called it test_auth.php and it goes like this:
<?php
define('_JEXEC', 1 );
define('JPATH_BASE', 'C:\xampp\htdocs\joomla');
define( 'DS', DIRECTORY_SEPARATOR );
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
include("Webservice.php");
$credentials = array(
'username' => 'test',
'password' => 'test');
$options = array();
$response = array();
$auth = new plgAuthenticationWebservice();
$auth->onUserAuthenticate($credentials, $options, &$response);
var_dump($response);
But when I call it, it get these errors:
Warning: Missing argument 1 for JPlugin::__construct(), called in
C:\xampp\htdocs\joomla\plugins\authentication\Webservice\test_auth.php
on line 25 and defined in
C:\xampp\htdocs\joomla\libraries\joomla\plugin\plugin.php on line 57
Fatal error: Call to a member function attach() on a non-object in
C:\xampp\htdocs\joomla\libraries\joomla\base\observer.php on line 41
What am I doing wrong?
I think I could place all php scripts outside and independent from joomla and work with require_once(JPATH_BASE .DS.'includes'.DS.'defines.php') etc.
Or I could write a plugin, install it with the extension manager and won't struggle with an unavailable joomla framework. But in fact it won't work if I leave out defines.php and framework.php.
I think a guide for plugin creation in Joomla 1.7 would be helpful.
OK, i completely dropped my first try.
Instead I use JOOMLA_ROOT/libraries/joomla/user/authentication.php now (insprired by JOOMLA_ROOT/libraries/joomla/application/application.php).
My test_auth.php looks like this now:
<?php
define('_JEXEC', 1 );
define('DS', DIRECTORY_SEPARATOR);
define('JPATH_BASE', dirname(__FILE__) . DS . '..' . DS . '..' . DS . '..'); // assuming we are in the authorisation plugin folder and need to go up 3 steps to get to the Joomla root
require_once (JPATH_BASE .DS. 'includes' .DS. 'defines.php');
require_once (JPATH_BASE .DS. 'includes' .DS. 'framework.php');
require_once (JPATH_BASE .DS. 'libraries' .DS. 'joomla'. DS. 'user' .DS. 'authentication.php');
$mainframe =& JFactory::getApplication('site');
$mainframe->initialise();
$credentials = array(
'username' => 'test',
'password' => 'test');
$options = array();
$authenticate = JAuthentication::getInstance();
$response = $authenticate->authenticate($credentials, $options);
if ($response->status === JAUTHENTICATE_STATUS_SUCCESS) {
echo('<br />It works<br />');
}
var_dump($response);
For any improvements I would be deeply grateful!
EDIT: I dismissed the plugin installation. It is a simple external script, which wouldn't be called from Joomla itself. I simply moved it to a new folder in the Joomla root.
Related
I have a Laravel API hitting a MS Nav instance to carry out some data shuffling and migration between two systems. I am able to create Customer records in Nav just fine, but am running into some issues with updating.
I am able to perform a single PATCH request to update a customer record by any subsequent requests return the following error message.
{
"odata.error":{
"code":"",
"message":{
"lang":"en-US",
"value":"Another user has already changed the record."
}
}
}
Here's what my PHP code looks like if that makes a difference.
/**
* #param string $navNo
* #param string $eTag
* #param array $data
* #return array
*/
public function updateCustomer($navNo = '', $eTag = '', $data = []) {
$url = $this->config['uri'] . ':' . $this->config['port'] . '/' . $this->config['server'] . '/' . $this->config['service'] . '/CustomerCardPage';
$url .= "('$navNo')" . '?$format=json&company=' . $this->config['company'];
$options = [
'auth' => $this->config['auth'],
'headers' => [
'Content-Type' => 'application/json',
'If-Match' => 'W/"\'' . $eTag . '\'"',
],
'json' => $data,
];
return $this->makeRequest('PATCH', $url, $options);
}
/**
* #param $method
* #param $url
* #param $options
* #return array
*/
private function makeRequest($method, $url , $options) {
$response = ['success' => true, 'data' => null, 'error' => null];
try {
$res = $this->client->request($method, $url, $options);
$body = json_decode($res->getBody(), true);
$response['data'] = $body;
} catch (BadResponseException $e) {
$res = $e->getResponse()->getBody()->getContents();
$response['success'] = false;
$response['error'] = $res;
}
return $response;
}
I haven't been able to dig up anything helpful in the Nav support forums. Has anyone else run into this type of issue with Laravel/PHP or any other back-end language/framework?
Disclaimer: I have absolutely 0 experience with MS Dynamic Nav, nor do I have direct access to the Nav dashboard or whatever you would call it.
Here are the versions of the relevant framework/packages/services I am working with:
Laravel: 5.6
Guzzle: 6.3
Nginx: 1.13.6
Nav: ...? Can bug someone to find out if this would help.
Figured it out. The ETag is updated each time the customer updates since it acts as a version control. The error was basically telling me that I can't update the version because it was already updated previously.
To fix, just make sure to update the customer ETag after updating.
Is the a trick to set my custom plugin to load the final plugin in joomla?
I want to set order on install and not after.
Is s there a custom params to set in xml like order="xxx" ?
I just found the answer by adding in the xml file
<scriptfile>script.php</scriptfile>
And in the script file
<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
/**
* Script file of yourplugin component.
*/
class plgSystemyourplginInstallerScript
{
/**
* method to run after an install/update/uninstall method.
*/
public function postflight($type, $parent)
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$fields = array(
$db->quoteName('ordering').' = '.(int) 999,
);
$conditions = array(
$db->quoteName('element').' = '.$db->quote('wraprotect'),
$db->quoteName('type').' = '.$db->quote('plugin'),
);
$query->update($db->quoteName('#__extensions'))->set($fields)->where($conditions);
$db->setQuery($query);
$db->execute();
// $parent is the class calling this method
// $type is the type of change (install, update or discover_install)
}
}
Don't forget to edit your plugin name
And in joomla 1.5 edit #__extensions to #__plugins
And delete the line $db->quoteName('type').' = '.$db->quote('plugin')
Anyone know of such a module?
Basically I want to dynamically load the users in certain usergroups inside an article with the loadmodule option.
Ended up building myself.
modfile:
<?php
defined('_JEXEC') or die;
// Include the latest functions only once
require_once __DIR__ . '/helper.php';
$shownumber = $params->get('shownumber', 10);
$groupnumber = $params->get('group', 4);
$names = ModUsersUsergroupHelper::getUsers($params);
$moduleclass_sfx = htmlspecialchars($params->get('moduleclass_sfx'), ENT_COMPAT, 'UTF-8');
require JModuleHelper::getLayoutPath('mod_users_usergroup', $params->get('layout', 'default'));
helper:
<?php
defined('_JEXEC') or die;
/**
* Helper for mod_users_usergroup
*
* #package Joomla.Site
* #subpackage mod_users_usergroup
*
* #since 1.6
*/
class ModUsersUsergroupHelper
{
/**
* Get users in a certain usergroup
*
* #param \Joomla\Registry\Registry $params module parameters
*
* #return array The array of users
*
* #since 1.6
*/
public static function getUsers($params)
{
$db = JFactory::getDbo();
$groupId = $params->get('group', 2);
$query = $db->getQuery(true)
->select($db->quoteName(array('u.id', 'u.name', 'u.username', 'u.registerDate')))
->order($db->quoteName('u.registerDate') . ' DESC')
->from('#__users AS u')
->join('INNER', '#__user_usergroup_map AS ugm ON ugm.user_id = u.id')
->where('ugm.group_id =' . $db->quote($groupId));
$db->setQuery($query, 0, $params->get('shownumber'));
try
{
return (array) $db->loadObjectList();
}
catch (RuntimeException $e)
{
JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
return array();
}
}
}
I am not aware of such an extension but you could include some code in a Custom HTML module using Sourcerer or similar to achieve the desired result.
The Custom HTML module can then be displayed in an article using loadmodule.
For some example code see: https://stackoverflow.com/a/20743966
When trying to install a component I am getting this error.
Component Install: DB function reports no errors
Error installing component
I am getting this error quite often on a test system when trying to install a component which uses SQL updates and causes first time when installing an error (even not SQL related, such a missing file from the manifest file).
Here are some steps on how to fix this, by manually uninstalling the component, as from the Extension manager the installation may / will fail.
Find the id of your extension (you may also find multiple entries)
SELECT *
FROM `#__extensions`
WHERE `name` LIKE '%myextensionname%'
LIMIT 0 , 30
Remove from #__schemas the entries for extension, where extension_id is the previous found id. Remove also any entries for non existing extensions:
Remove any assets for your extension:
SELECT *
FROM `#__assets`
WHERE `name` LIKE '%myextensionname%'
LIMIT 0 , 30
Remove any menu entries:
SELECT *
FROM #__menu
WHERE link LIKE '%myextensionname%'
LIMIT 0 , 30
Reinstall.
Not tested but this is the general idea I would use.
<?php
/**
* A JApplicationCli application built on the Joomla Platform
*
* To run this place it in the cli folder of your Joomla CMS installation (or adjust the references).
*
* #package Joomla.CleanupFailedInsall
* #copyright Copyright (C) 2013 Open Source Matters. All rights reserved.
* #license GNU General Public License version 2 or later; see LICENSE
*/
/*
* This application cleans up database leftovers from a failed install
*
* To run from the command line type
* php cleanupfailedinstall.php -e='extensionname'
*/
if (!defined('_JEXEC'))
{
// Initialize Joomla framework
define('_JEXEC', 1);
}
#ini_set('zend.ze1_compatibility_mode', '0');
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Load system defines
if (file_exists(dirname(__DIR__) . '/defines.php'))
{
require_once dirname(__DIR__) . '/defines.php';
}
if (!defined('JPATH_BASE'))
{
define('JPATH_BASE', dirname(__DIR__));
}
if (!defined('_JDEFINES'))
{
require_once JPATH_BASE . '/includes/defines.php';
}
// Get the framework.
require_once JPATH_LIBRARIES . '/import.php';
// Get the framework.
require_once JPATH_LIBRARIES . '/import.legacy.php';
// Bootstrap the CMS libraries.
require_once JPATH_LIBRARIES . '/cms.php';
// Import the configuration.
require_once JPATH_CONFIGURATION . '/configuration.php';
// Uncomment this if you want to log
/*
// Include the JLog class.
jimport('joomla.log.log');
// Add the logger.
JLog::addLogger(
// Pass an array of configuration options
array(
// Set the name of the log file
'text_file' => 'test.log.php',
// (optional) you can change the directory
'text_file_path' => 'logs'
)
);
// start logging...
JLog::add('Starting to log');
*/
/**
* Cleanup Failed Install
*
* #package Joomla.Shell
*
* #since 1.0
*/
class CleanupFailedInstall extends JApplicationCli
{
public function __construct()
{
// Note, this will throw an exception if there is an error
// System configuration.
$config = new JConfig;
// Creating the database connection.
$this->db = JDatabase::getInstance(
array(
'driver' => $config->dbtype,
'host' => $config->host,
'user' => $config->user,
'password' => $config->password,
'database' => $config->db,
'prefix' => $config->dbprefix,
)
);
// Call the parent __construct method so it bootstraps the application class.
parent::__construct();
require_once JPATH_CONFIGURATION . '/configuration.php';
}
/**
* Entry point for the script
*
* #return void
*
* #since 1.0
*/
public function doExecute()
{
// Long args
$extensionname = $this->input->get('extensionname', null,'STRING');
// Short args
if (!$extensionname)
{
$extensionname = $this->input->get('e', null, 'STRING');
}
$extensionTable = new JTableExtension();
$extensionId = $extensionTable->find(array('name', $extensionname));
// This block taken from the platform component install adapter with minor moifications
// Remove the schema version
$query = $db->getQuery(true)
->delete('#__schemas')
->where('extension_id = ' . $extensionId);
$db->setQuery($query);
$db->execute();
// Remove the component container in the assets table.
$asset = JTable::getInstance('Asset');
if ($asset->loadByName($extensionname))
{
$asset->delete();
}
$extenstionTable->delete($extensionId);
$this->removeAdminMenus($extensionId);
// Remove categories for this component
$query->clear()
->delete('#__categories')
->where('extension=' . $db->quote($exensionname), 'OR')
->where('extension LIKE ' . $db->quote($extensionname . '.%'));
$db->setQuery($query);
$db->execute();
// Clobber any possible pending updates
$update = JTable::getInstance('update');
$uid = $update->find(array('element' => $row->element, 'type' => 'component', 'client_id' => 1, 'folder' => ''));
if ($uid)
{
$update->delete($uid);
}
}
/**
* Taken from the core installer component adapter
* Method to remove admin menu references to a component
*
* #param object &$row Component table object.
*
* #return boolean True if successful.
*
* #since 3.1
*/
protected function _removeAdminMenus($extensionId)
{
$db = JFactory::getDbo();
$table = JTable::getInstance('menu');
// Get the ids of the menu items
$query = $db->getQuery(true)
->select('id')
->from('#__menu')
->where($db->quoteName('client_id') . ' = 1')
->where($db->quoteName('component_id') . ' = ' . (int) $extensionId);
$db->setQuery($query);
$ids = $db->loadColumn();
// Check for error
if (!empty($ids))
{
// Iterate the items to delete each one.
foreach ($ids as $menuid)
{
if (!$table->delete((int) $menuid))
{
$this->setError($table->getError());
return false;
}
}
// Rebuild the whole tree
$table->rebuild();
}
return true;
}
}
JApplicationCli::getInstance('CleanupFailedInstall')->execute();
This an error / typo free version of what #Elin proposed (in case somebody wants to take this further). This solution did NOT work for me, but I think it has something in it.
<?php
/**
* A JApplicationCli application built on the Joomla Platform
*
* To run this place it in the cli folder of your Joomla CMS installation (or adjust the references).
*
* #package Joomla.CleanupFailedInsall
* #copyright Copyright (C) 2013 Open Source Matters. All rights reserved.
* #license GNU General Public License version 2 or later; see LICENSE
*/
/*
* This application cleans up database leftovers from a failed install
*
* To run from the command line type
* php cleanupfailedinstall.php -e='extensionname'
*/
if (!defined('_JEXEC'))
{
// Initialize Joomla framework
define('_JEXEC', 1);
}
#ini_set('zend.ze1_compatibility_mode', '0');
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Load system defines
if (file_exists(dirname(__DIR__) . '/defines.php'))
{
require_once dirname(__DIR__) . '/defines.php';
}
if (!defined('JPATH_BASE'))
{
define('JPATH_BASE', dirname(__DIR__));
}
if (!defined('_JDEFINES'))
{
require_once JPATH_BASE . '/includes/defines.php';
}
// Get the framework.
require_once JPATH_LIBRARIES . '/import.php';
// Get the framework.
//require_once JPATH_LIBRARIES . '/import.legacy.php';
// Bootstrap the CMS libraries.
require_once JPATH_LIBRARIES . '/cms.php';
// Import the configuration.
require_once JPATH_CONFIGURATION . '/configuration.php';
// Uncomment this if you want to log
/*
// Include the JLog class.
jimport('joomla.log.log');
// Add the logger.
JLog::addLogger(
// Pass an array of configuration options
array(
// Set the name of the log file
'text_file' => 'test.log.php',
// (optional) you can change the directory
'text_file_path' => 'logs'
)
);
// start logging...
JLog::add('Starting to log');
*/
/**
* Cleanup Failed Install
*
* #package Joomla.Shell
*
* #since 1.0
*/
class CleanupFailedInstall extends JApplicationCli
{
public function __construct()
{
// Note, this will throw an exception if there is an error
// System configuration.
$config = new JConfig;
// Creating the database connection.
$this->db = JDatabase::getInstance(
array(
'driver' => $config->dbtype,
'host' => $config->host,
'user' => $config->user,
'password' => $config->password,
'database' => $config->db,
'prefix' => $config->dbprefix,
)
);
// Call the parent __construct method so it bootstraps the application class.
parent::__construct();
require_once JPATH_CONFIGURATION . '/configuration.php';
}
/**
* Entry point for the script
*
* #return void
*
* #since 1.0
*/
public function execute()
{
// Long args
$extensionname = $this->input->get('extensionname', 'urlaubsrechner', 'STRING');
// Short args
if (!$extensionname)
{
$extensionname = $this->input->get('e', null, 'STRING');
}
require_once JPATH_LIBRARIES . '/joomla/database/table/extension.php';
$extensionTable = new JTableExtension($this->db);
$extensionId = $extensionTable->find(array('name' => $extensionname));
if (! $extensionId)
{
throw new Exception('Could not find extension with name: ' . $extensionname);
}
// This block taken from the platform component install adapter with minor modifications
// Remove the schema version
$query = $this->db->getQuery(true)
->delete('#__schemas')
->where('extension_id = ' . $extensionId);
$this->db->setQuery($query);
$this->db->execute();
// Remove the component container in the assets table.
$asset = JTable::getInstance('Asset');
if ($asset->loadByName($extensionname))
{
$asset->delete();
}
$extensionTable->delete($extensionId);
$this->_removeAdminMenus($extensionId);
// Remove categories for this component
$query->clear()
->delete('#__categories')
->where('extension=' . $this->db->quote($extensionname), 'OR')
->where('extension LIKE ' . $this->db->quote($extensionname . '.%'));
$this->db->setQuery($query);
$this->db->execute();
// Clobber any possible pending updates
$update = JTable::getInstance('update');
$uid = $update->find(array('element' => $extensionTable->element, 'type' => 'component', 'client_id' => 1, 'folder' => ''));
if ($uid)
{
$update->delete($uid);
}
}
/**
* Taken from the core installer component adapter
* Method to remove admin menu references to a component
*
* #param object &$row Component table object.
*
* #return boolean True if successful.
*
* #since 3.1
*/
protected function _removeAdminMenus($extensionId)
{
$db = JFactory::getDbo();
$table = JTable::getInstance('menu');
// Get the ids of the menu items
$query = $db->getQuery(true)
->select('id')
->from('#__menu')
->where($db->quoteName('client_id') . ' = 1')
->where($db->quoteName('component_id') . ' = ' . (int) $extensionId);
$db->setQuery($query);
$ids = $db->loadColumn();
// Check for error
if (!empty($ids))
{
// Iterate the items to delete each one.
foreach ($ids as $menuid)
{
if (!$table->delete((int) $menuid))
{
$this->setError($table->getError());
return false;
}
}
// Rebuild the whole tree
$table->rebuild();
}
return true;
}
}
JApplicationCli::getInstance('CleanupFailedInstall')->execute();
I would like to get the cart Block outside of Magento. Here is my Code.
<?php
require_once ( $_SERVER['DOCUMENT_ROOT']."/app/Mage.php" );
umask(0);
Mage::app('base','website');
echo Mage::app()->getLocale()->getLocaleCode();
//Solution
Mage::getSingleton('core/translate')->setLocale('de_DE')->init('frontend', true);
Mage::getSingleton('core/session', array('name'=>'frontend'));
$block = Mage::getSingleton('core/layout')
->createBlock("checkout/cart_sidebar", "sidebar")
->setTemplate("checkout/cart/sidebar.phtml");
echo $block->toHtml();
?>
I have just the Problem that the output ist just english and translation doesn't work.
Thanks for Help
Any reason why you don't just specify a store code that has the german locale set in your call to Mage::app()?
Unrelated to your problem, but you may also be interested in a more solid approach of loading a block into another website.
Through this you can get all the cart details out side magneto. Now you can give any desired template to these elements.
umask(0);
Mage::app('default');
// This has to run to authenticate customer and checkout session calls.
Mage::getSingleton('core/session', array('name' => 'frontend'));
// Get any customer model you desire.
$oSession = Mage::getSingleton( 'customer/session' );
$oCustomer = $oSession->getCustomer();
$oCheckout = Mage::getSingleton( 'checkout/session' );
$oQuote = $oCheckout->getQuote();
var_dump( $oCustomer );
var_dump( $oSession );
var_dump( $oQuote );
var_dump( $oCheckout );
$oCart = $oQuote->getAllItems();
if( !empty( $oCart ) )
{
foreach ( $oCart as $oItem )
{
$sName = $oItem->getProduct()->getName();
$fPrice = $oItem->getProduct()->getPrice();
var_dump( $sName );
var_dump( $fPrice );
}
}
?>
namespace moduleName\addtobasket\Controller\Product;
class Index extends \Magento\Framework\App\Action\Action {
/**
* #var \Magento\Checkout\Model\Cart
*/
protected $cart;
/**
* #var \Magento\Catalog\Model\Product
*/
protected $product;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory,
\Magento\Catalog\Model\Product $product,
\Magento\Checkout\Model\Cart $cart
) {
$this->resultPageFactory = $resultPageFactory;
$this->cart = $cart;
$this->product = $product;
parent::__construct($context);
}
public function execute()
{
try {
$params = array();
$params['qty'] = '1';//product quantity
/* Get product id from a URL like /addtobasket/product?id=1,2,3 */
$pIds = explode(',',$_GET['id']);
foreach($pIds as $value) {
$_product = $this->product->load($value);
if ($_product) {
$this->cart->addProduct($_product, $params);
$this->cart->save();
}
}
$this->messageManager->addSuccess(__('Add to cart successfully.'));
} catch (\Magento\Framework\Exception\LocalizedException $e) {
$this->messageManager->addException(
$e,
__('%1', $e->getMessage())
);
} catch (\Exception $e) {
$this->messageManager->addException($e, __('error.'));
}
/*cart page*/
$this->getResponse()->setRedirect('/checkout/cart/index');
}
}