3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2014
37 * Joomla specific stuff goes here
39 class CRM_Utils_System_Joomla
extends CRM_Utils_System_Base
{
43 public function __construct() {
45 * deprecated property to check if this is a drupal install. The correct method is to have functions on the UF classes for all UF specific
46 * functions and leave the codebase oblivious to the type of CMS
50 $this->is_drupal
= FALSE;
54 * Create a user of Joomla.
56 * @param array $params associated array
57 * @param string $mail email id for cms user
59 * @return uid if user exists, false otherwise
62 public function createUser(&$params, $mail) {
63 $baseDir = JPATH_SITE
;
64 require_once $baseDir . '/components/com_users/models/registration.php';
66 $userParams = JComponentHelper
::getParams('com_users');
67 $model = new UsersModelRegistration();
70 // get the default usertype
71 $userType = $userParams->get('new_usertype');
76 if (isset($params['name'])) {
77 $fullname = trim($params['name']);
79 elseif (isset($params['contactID'])) {
80 $fullname = trim(CRM_Contact_BAO_Contact
::displayName($params['contactID']));
83 $fullname = trim($params['cms_name']);
86 // Prepare the values for a new Joomla user.
88 $values['name'] = $fullname;
89 $values['username'] = trim($params['cms_name']);
90 $values['password1'] = $values['password2'] = $params['cms_pass'];
91 $values['email1'] = $values['email2'] = trim($params[$mail]);
93 $lang = JFactory
::getLanguage();
94 $lang->load('com_users', $baseDir);
96 $register = $model->register($values);
98 $ufID = JUserHelper
::getUserId($values['username']);
103 * Change user name in host CMS
105 * @param integer $ufID User ID in CMS
106 * @param string $ufName User name
108 public function updateCMSName($ufID, $ufName) {
109 $ufID = CRM_Utils_Type
::escape($ufID, 'Integer');
110 $ufName = CRM_Utils_Type
::escape($ufName, 'String');
113 $user = JUser
::getInstance($ufID);
115 $values['email'] = $ufName;
116 $user->bind($values);
122 * Check if username and email exists in the drupal db
124 * @param array $params array of name and mail values
125 * @param array $errors array of errors
126 * @param string $emailName field label for the 'email'
130 public function checkUserNameEmailExists(&$params, &$errors, $emailName = 'email') {
131 $config = CRM_Core_Config
::singleton();
133 $dao = new CRM_Core_DAO();
134 $name = $dao->escape(CRM_Utils_Array
::value('name', $params));
135 $email = $dao->escape(CRM_Utils_Array
::value('mail', $params));
136 //don't allow the special characters and min. username length is two
137 //regex \\ to match a single backslash would become '/\\\\/'
138 $isNotValid = (bool) preg_match('/[\<|\>|\"|\'|\%|\;|\(|\)|\&|\\\\|\/]/im', $name);
139 if ($isNotValid ||
strlen($name) < 2) {
140 $errors['cms_name'] = ts('Your username contains invalid characters or is too short');
144 $JUserTable = &JTable
::getInstance('User', 'JTable');
146 $db = $JUserTable->getDbo();
147 $query = $db->getQuery(TRUE);
148 $query->select('username, email');
149 $query->from($JUserTable->getTableName());
150 $query->where('(LOWER(username) = LOWER(\'' . $name . '\')) OR (LOWER(email) = LOWER(\'' . $email . '\'))');
151 $db->setQuery($query, 0, 10);
152 $users = $db->loadAssocList();
160 $dbName = CRM_Utils_Array
::value('username', $row);
161 $dbEmail = CRM_Utils_Array
::value('email', $row);
162 if (strtolower($dbName) == strtolower($name)) {
163 $errors['cms_name'] = ts('The username %1 is already taken. Please select another username.',
167 if (strtolower($dbEmail) == strtolower($email)) {
168 $resetUrl = str_replace('administrator/', '', $config->userFrameworkBaseURL
) . 'index.php?option=com_users&view=reset';
169 $errors[$emailName] = ts('The email address %1 is already registered. <a href="%2">Have you forgotten your password?</a>',
170 array(1 => $email, 2 => $resetUrl)
177 * Sets the title of the page
179 * @param string $title title to set
180 * @param string $pageTitle
184 public function setTitle($title, $pageTitle = NULL) {
189 $template = CRM_Core_Smarty
::singleton();
190 $template->assign('pageTitle', $pageTitle);
192 $document = JFactory
::getDocument();
193 $document->setTitle($title);
199 * Append an additional breadcrumb tag to the existing breadcrumb
201 * @param $breadCrumbs
203 * @internal param string $title
204 * @internal param string $url
208 public function appendBreadCrumb($breadCrumbs) {
209 $template = CRM_Core_Smarty
::singleton();
210 $bc = $template->get_template_vars('breadcrumb');
212 if (is_array($breadCrumbs)) {
213 foreach ($breadCrumbs as $crumbs) {
214 if (stripos($crumbs['url'], 'id%%')) {
215 $args = array('cid', 'mid');
216 foreach ($args as $a) {
217 $val = CRM_Utils_Request
::retrieve($a, 'Positive', CRM_Core_DAO
::$_nullObject,
221 $crumbs['url'] = str_ireplace("%%{$a}%%", $val, $crumbs['url']);
228 $template->assign_by_ref('breadcrumb', $bc);
233 * Reset an additional breadcrumb tag to the existing breadcrumb
235 * @internal param string $bc the new breadcrumb to be appended
239 public function resetBreadCrumb() {
244 * Append a string to the head of the html file
246 * @param null $string
248 * @internal param string $head the new string to be appended
252 public static function addHTMLHead($string = NULL) {
254 $document = JFactory
::getDocument();
255 $document->addCustomTag($string);
262 * @param $url: string, absolute path to file
263 * @param $region string, location within the document: 'html-header', 'page-header', 'page-footer'
265 * Note: This function is not to be called directly
266 * @see CRM_Core_Region::render()
268 * @return bool TRUE if we support this operation in this CMS, FALSE otherwise
270 public function addScriptUrl($url, $region) {
275 * Add an inline script
277 * @param $code: string, javascript code
278 * @param $region string, location within the document: 'html-header', 'page-header', 'page-footer'
280 * Note: This function is not to be called directly
281 * @see CRM_Core_Region::render()
283 * @return bool TRUE if we support this operation in this CMS, FALSE otherwise
285 public function addScript($code, $region) {
292 * @param $url: string, absolute path to file
293 * @param $region string, location within the document: 'html-header', 'page-header', 'page-footer'
295 * Note: This function is not to be called directly
296 * @see CRM_Core_Region::render()
298 * @return bool TRUE if we support this operation in this CMS, FALSE otherwise
300 public function addStyleUrl($url, $region) {
301 if ($region == 'html-header') {
302 $document = JFactory
::getDocument();
303 $document->addStyleSheet($url);
310 * Add an inline style
312 * @param $code: string, css code
313 * @param $region string, location within the document: 'html-header', 'page-header', 'page-footer'
315 * Note: This function is not to be called directly
316 * @see CRM_Core_Region::render()
318 * @return bool TRUE if we support this operation in this CMS, FALSE otherwise
320 public function addStyle($code, $region) {
321 if ($region == 'html-header') {
322 $document = JFactory
::getDocument();
323 $document->addStyleDeclaration($code);
330 * Generate an internal CiviCRM URL
332 * @param $path string The path being linked to, such as "civicrm/add"
333 * @param $query string A query string to append to the link.
334 * @param $absolute boolean Whether to force the output to be an absolute link (beginning with http:).
335 * Useful for links that will be displayed outside the site, such as in an
337 * @param $fragment string A fragment identifier (named anchor) to append to the link.
338 * @param $htmlize boolean whether to convert to html eqivalant
339 * @param $frontend boolean a gross joomla hack
341 * @param bool $forceBackend
343 * @return string an HTML string containing a link to the given path.
345 function url($path = NULL, $query = NULL, $absolute = TRUE,
346 $fragment = NULL, $htmlize = TRUE,
347 $frontend = FALSE, $forceBackend = FALSE
349 $config = CRM_Core_Config
::singleton();
350 $separator = $htmlize ?
'&' : '&';
353 $path = CRM_Utils_String
::stripPathChars($path);
355 if ($config->userFrameworkFrontend
) {
356 $script = 'index.php';
357 if (JRequest
::getVar("Itemid")) {
358 $Itemid = "{$separator}Itemid=" . JRequest
::getVar("Itemid");
362 if (isset($fragment)) {
363 $fragment = '#' . $fragment;
366 if (!isset($config->useFrameworkRelativeBase
)) {
367 $base = parse_url($config->userFrameworkBaseURL
);
368 $config->useFrameworkRelativeBase
= $base['path'];
370 $base = $absolute ?
$config->userFrameworkBaseURL
: $config->useFrameworkRelativeBase
;
372 if (!empty($query)) {
373 $url = "{$base}{$script}?option=com_civicrm{$separator}task={$path}{$Itemid}{$separator}{$query}{$fragment}";
376 $url = "{$base}{$script}?option=com_civicrm{$separator}task={$path}{$Itemid}{$fragment}";
379 // gross hack for joomla, we are in the backend and want to send a frontend url
380 if ($frontend && $config->userFramework
== 'Joomla') {
381 // handle both joomla v1.5 and v1.6, CRM-7939
382 $url = str_replace('/administrator/index2.php', '/index.php', $url);
383 $url = str_replace('/administrator/index.php', '/index.php', $url);
386 $url = str_replace('/administrator/', '/index.php', $url);
388 elseif ($forceBackend) {
389 if (defined('JVERSION')) {
390 $joomlaVersion = JVERSION
;
392 $jversion = new JVersion
;
393 $joomlaVersion = $jversion->getShortVersion();
396 if (version_compare($joomlaVersion, '1.6') >= 0) {
397 $url = str_replace('/index.php', '/administrator/index.php', $url);
404 * Rewrite various system urls to https
409 public function mapConfigToSSL() {
410 // dont need to do anything, let CMS handle their own switch to SSL
415 * Figure out the post url for the form
417 * @param $action the default action if one is pre-specified
419 * @return string the url to post the form
421 public function postURL($action) {
422 if (!empty($action)) {
426 return $this->url(CRM_Utils_Array
::value('task', $_GET),
427 NULL, TRUE, NULL, FALSE
432 * Set the email address of the user
434 * @param object $user handle to the user object
438 public function setEmail(&$user) {
440 $query = "SELECT email FROM #__users WHERE id='$user->id'";
441 $database->setQuery($query);
442 $user->email
= $database->loadResult();
446 * Authenticate the user against the joomla db
448 * @param string $name the user name
449 * @param string $password the password for the above user name
450 * @param $loadCMSBootstrap boolean load cms bootstrap?
452 * @return mixed false if no auth
454 contactID, ufID, unique string ) if success
456 public function authenticate($name, $password, $loadCMSBootstrap = FALSE) {
457 require_once 'DB.php';
459 $config = CRM_Core_Config
::singleton();
462 if ($loadCMSBootstrap) {
463 $bootStrapParams = array();
464 if ($name && $password) {
465 $bootStrapParams = array(
470 CRM_Utils_System
::loadBootStrap($bootStrapParams, TRUE, TRUE, FALSE);
473 jimport('joomla.application.component.helper');
474 jimport('joomla.database.table');
475 jimport('joomla.user.helper');
477 $JUserTable = JTable
::getInstance('User', 'JTable');
479 $db = $JUserTable->getDbo();
480 $query = $db->getQuery(TRUE);
481 $query->select('id, name, username, email, password');
482 $query->from($JUserTable->getTableName());
483 $query->where('(LOWER(username) = LOWER(\'' . $name . '\')) AND (block = 0)');
484 $db->setQuery($query, 0, 0);
485 $users = $db->loadObjectList();
492 $joomlaBase = dirname(dirname(dirname(dirname(dirname(dirname(dirname(dirname(__FILE__
))))))));
493 if ( !defined('JVERSION') ) {
494 require $joomlaBase . '/libraries/cms/version/version.php';
495 $jversion = new JVersion
;
496 define('JVERSION', $jversion->getShortVersion());
500 $dbPassword = $row->password
;
502 $dbEmail = $row->email
;
504 if ( version_compare(JVERSION
, '2.5.18', 'lt') ||
505 ( version_compare(JVERSION
, '3.0', 'ge') && version_compare(JVERSION
, '3.2.1', 'lt') )
507 // now check password
508 if (strpos($dbPassword, ':') === FALSE) {
509 if ($dbPassword != md5($password)) {
514 list($hash, $salt) = explode(':', $dbPassword);
515 $cryptpass = md5($password . $salt);
516 if ($hash != $cryptpass) {
522 if (!JUserHelper
::verifyPassword($password, $dbPassword, $dbId)) return FALSE;
524 //include additional files required by Joomla 3.2.1+
525 if ( version_compare(JVERSION
, '3.2.1', 'ge') ) {
526 require_once $joomlaBase . '/libraries/cms/application/helper.php';
527 require_once $joomlaBase . '/libraries/cms/application/cms.php';
528 require_once $joomlaBase . '/libraries/cms/application/administrator.php';
532 CRM_Core_BAO_UFMatch
::synchronizeUFMatch($row, $dbId, $dbEmail, 'Joomla');
533 $contactID = CRM_Core_BAO_UFMatch
::getContactId($dbId);
537 return array($contactID, $dbId, mt_rand());
544 * Set a init session with user object
546 * @param array $data array with user specific data
549 public function setUserSession($data) {
550 list($userID, $ufID) = $data;
551 $user = new JUser( $ufID );
552 $session = JFactory
::getSession();
553 $session->set('user', $user);
555 parent
::setUserSession($data);
559 * Set a message in the UF to display to a user
561 * @param string $message the message to set
564 public function setMessage($message) {
573 public function loadUser($user) {
577 public function permissionDenied() {
578 CRM_Core_Error
::fatal(ts('You do not have permission to access this page.'));
581 public function logout() {
583 header("Location:index.php");
587 * Get the locale set in the hosting CMS
589 * @return string the used locale or null for none
591 public function getUFLocale() {
592 if (defined('_JEXEC')) {
593 $conf = JFactory
::getConfig();
594 $locale = $conf->get('language');
595 return str_replace('-', '_', $locale);
603 public function getVersion() {
604 if (class_exists('JVersion')) {
605 $version = new JVersion
;
606 return $version->getShortVersion();
614 * Load joomla bootstrap
616 * @param $params array with uid or name and password
617 * @param $loadUser boolean load cms user?
618 * @param bool|\throw $throwError throw error on failure?
619 * @param null $realPath
620 * @param bool $loadDefines
624 public function loadBootStrap($params = array(), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL, $loadDefines = TRUE) {
625 // Setup the base path related constant.
626 $joomlaBase = dirname(dirname(dirname(dirname(dirname(dirname(dirname(dirname(__FILE__
))))))));
628 // load BootStrap here if needed
629 // We are a valid Joomla entry point.
630 if ( ! defined( '_JEXEC' ) && $loadDefines ) {
632 define('DS', DIRECTORY_SEPARATOR
);
633 define('JPATH_BASE', $joomlaBase . '/administrator');
634 require $joomlaBase . '/administrator/includes/defines.php';
637 // Get the framework.
638 if (file_exists($joomlaBase . '/libraries/import.legacy.php')) {
639 require $joomlaBase . '/libraries/import.legacy.php';
641 require $joomlaBase . '/libraries/import.php';
642 require $joomlaBase . '/libraries/joomla/event/dispatcher.php';
643 require $joomlaBase . '/configuration.php';
645 // Files may be in different places depending on Joomla version
646 if ( !defined('JVERSION') ) {
647 require $joomlaBase . '/libraries/cms/version/version.php';
648 $jversion = new JVersion
;
649 define('JVERSION', $jversion->getShortVersion());
652 if( version_compare(JVERSION
, '3.0', 'lt') ) {
653 require $joomlaBase . '/libraries/joomla/environment/uri.php';
654 require $joomlaBase . '/libraries/joomla/application/component/helper.php';
657 require $joomlaBase . '/libraries/cms.php';
658 require $joomlaBase . '/libraries/joomla/uri/uri.php';
661 jimport('joomla.application.cli');
663 // CRM-14281 Joomla wasn't available during bootstrap, so hook_civicrm_config never executes.
664 $config = CRM_Core_Config
::singleton();
665 CRM_Utils_Hook
::config($config);
671 * Check is user logged in.
673 * @return boolean true/false.
675 public function isUserLoggedIn() {
676 $user = JFactory
::getUser();
677 return ($user->guest
) ?
FALSE : TRUE;
681 * Get currently logged in user uf id.
683 * @return int logged in user uf id.
685 public function getLoggedInUfID() {
686 $user = JFactory
::getUser();
687 return ($user->guest
) ?
NULL : $user->id
;
691 * Get currently logged in user unique identifier - this tends to be the email address or user name.
693 * @return string $userID logged in user unique identifier
695 public function getLoggedInUniqueIdentifier() {
696 $user = JFactory
::getUser();
697 return $this->getUniqueIdentifierFromUserObject($user);
700 * Get User ID from UserFramework system (Joomla)
701 * @param object $user object as described by the CMS
702 * @return mixed <NULL, number>
704 public function getUserIDFromUserObject($user) {
705 return !empty($user->id
) ?
$user->id
: NULL;
709 * Get Unique Identifier from UserFramework system (CMS)
710 * @param object $user object as described by the User Framework
711 * @return mixed $uniqueIdentifer Unique identifier from the user Framework system
714 public function getUniqueIdentifierFromUserObject($user) {
715 return ($user->guest
) ?
NULL : $user->email
;
719 * Get a list of all installed modules, including enabled and disabled ones
721 * @return array CRM_Core_Module
723 public function getModules() {
726 $db = JFactory
::getDbo();
727 $query = $db->getQuery(true);
728 $query->select('type, folder, element, enabled')
729 ->from('#__extensions')
730 ->where('type =' . $db->Quote('plugin'));
731 $plugins = $db->setQuery($query)->loadAssocList();
732 foreach ($plugins as $plugin) {
733 // question: is the folder really a critical part of the plugin's name?
734 $name = implode('.', array('joomla', $plugin['type'], $plugin['folder'], $plugin['element']));
735 $result[] = new CRM_Core_Module($name, $plugin['enabled'] ?
TRUE : FALSE);
742 * Get user login URL for hosting CMS (method declared in each CMS system class)
744 * @param string $destination - if present, add destination to querystring (works for Drupal only)
746 * @return string - loginURL for the current CMS
749 public function getLoginURL($destination = '') {
750 $config = CRM_Core_Config
::singleton();
751 $loginURL = $config->userFrameworkBaseURL
;
752 $loginURL = str_replace('administrator/', '', $loginURL);
753 $loginURL .= 'index.php?option=com_users&view=login';
755 //CRM-14872 append destination
756 if ( !empty($destination) ) {
757 $loginURL .= '&return='.urlencode(base64_encode($destination));
763 * @param CRM_Core_Form $form
765 public function getLoginDestination(&$form) {
768 $id = $form->get('id');
773 $gid = $form->get('gid');
775 $args .= "&gid=$gid";
778 // Setup Personal Campaign Page link uses pageId
779 $pageId = $form->get('pageId');
781 $component = $form->get('component');
782 $args .= "&pageId=$pageId&component=$component&action=add";
789 // append destination so user is returned to form they came from after login
790 $args = 'reset=1'.$args;
791 $destination = CRM_Utils_System
::url(CRM_Utils_System
::currentPath(), $args, TRUE, NULL, TRUE, TRUE);
798 * Return default Site Settings
802 * @return array array
803 * - $url, (Joomla - non admin url)
807 public function getDefaultSiteSettings($dir){
808 $config = CRM_Core_Config
::singleton();
812 $config->userFrameworkBaseURL
814 $siteRoot = preg_replace(
815 '|/media/civicrm/.*$|',
817 $config->imageUploadDir
819 return array($url, NULL, $siteRoot);
823 * Get Url to view user record
824 * @param integer $contactID Contact ID
828 public function getUserRecordUrl($contactID) {
829 $uid = CRM_Core_BAO_UFMatch
::getUFId($contactID);
830 $userRecordUrl = NULL;
831 // if logged in user is super user, then he can view other users joomla profile
832 if (JFactory
::getUser()->authorise('core.admin')) {
833 return CRM_Core_Config
::singleton()->userFrameworkBaseURL
. "index.php?option=com_users&view=user&task=user.edit&id=" . $uid;
835 elseif (CRM_Core_Session
::singleton()->get('userID') == $contactID) {
836 return CRM_Core_Config
::singleton()->userFrameworkBaseURL
. "index.php?option=com_admin&view=profile&layout=edit&id=" . $uid;
841 * Is the current user permitted to add a user
844 public function checkPermissionAddUser() {
845 if (JFactory
::getUser()->authorise('core.create', 'com_users')) {
851 * Output code from error function
852 * @param string $content
854 public function outputError($content) {
855 if (class_exists('JErrorPage')) {
856 $error = new Exception($content);
857 JErrorPage
::render($error);
859 else if (class_exists('JError')) {
860 JError
::raiseError('CiviCRM-001', $content);
863 parent
::outputError($content);
868 * Append to coreResourcesList
870 public function appendCoreResources(&$list) {
871 $list[] = 'js/crm.joomla.js';