3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
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-2013
37 * System wide utilities.
40 class CRM_Utils_System
{
42 static $_callbacks = NULL;
45 * Compose a new url string from the current url string
46 * Used by all the framework components, specifically,
49 * @param string $urlVar the url variable being considered (i.e. crmPageID, crmSortID etc)
51 * @return string the url fragment
54 static function makeURL($urlVar, $includeReset = FALSE, $includeForce = TRUE, $path = NULL) {
56 $config = CRM_Core_Config
::singleton();
57 $path = CRM_Utils_Array
::value($config->userFrameworkURLVar
, $_GET);
63 return self
::url($path,
64 CRM_Utils_System
::getLinksUrl($urlVar, $includeReset, $includeForce)
69 * get the query string and clean it up. Strip some variables that should not
70 * be propagated, specically variable like 'reset'. Also strip any side-affect
71 * actions (i.e. export)
73 * This function is copied mostly verbatim from Pager.php (_getLinksUrl)
75 * @param string $urlVar the url variable being considered (i.e. crmPageID, crmSortID etc)
76 * @param boolean $includeReset should we include the reset var (generally this variable should be skipped)
81 static function getLinksUrl($urlVar, $includeReset = FALSE, $includeForce = TRUE, $skipUFVar = TRUE) {
82 // Sort out query string to prevent messy urls
83 $querystring = array();
87 if (!empty($_SERVER['QUERY_STRING'])) {
88 $qs = explode('&', str_replace('&', '&', $_SERVER['QUERY_STRING']));
89 for ($i = 0, $cnt = count($qs); $i < $cnt; $i++
) {
90 // check first if exist a pair
91 if (strstr($qs[$i], '=') !== FALSE) {
92 list($name, $value) = explode('=', $qs[$i]);
93 if ($name != $urlVar) {
94 $name = rawurldecode($name);
95 //check for arrays in parameters: site.php?foo[]=1&foo[]=2&foo[]=3
96 if ((strpos($name, '[') !== FALSE) &&
97 (strpos($name, ']') !== FALSE)
117 unset($qs['snippet']);
118 unset($qs['section']);
121 $config = CRM_Core_Config
::singleton();
122 unset($qs[$config->userFrameworkURLVar
]);
125 foreach ($qs as $name => $value) {
126 if ($name != 'reset' ||
$includeReset) {
127 $querystring[] = $name . '=' . $value;
131 $querystring = array_merge($querystring, array_unique($arrays));
132 $querystring = array_map('htmlentities', $querystring);
134 return implode('&', $querystring) . (!empty($querystring) ?
'&' : '') . $urlVar . '=';
138 * if we are using a theming system, invoke theme, else just print the
141 * @param string $content the content that will be themed
142 * @param boolean $print are we displaying to the screen or bypassing theming?
143 * @param boolean $maintenance for maintenance mode
145 * @return void prints content on stdout
149 static function theme(
154 $config = &CRM_Core_Config
::singleton();
155 return $config->userSystem
->theme($content, $print, $maintenance);
159 * Generate a query string if input is an array
161 * @param mixed $query: array or string
166 static function makeQueryString($query) {
167 if (is_array($query)) {
169 foreach ($query as $key => $value) {
170 $buf .= ($buf ?
'&' : '') . urlencode($key) . '=' . urlencode($value);
178 * Generate an internal CiviCRM URL
180 * @param $path string The path being linked to, such as "civicrm/add"
181 * @param $query mixed A query string to append to the link, or an array of key-value pairs
182 * @param $absolute boolean Whether to force the output to be an absolute link (beginning with http:).
183 * Useful for links that will be displayed outside the site, such as in an
185 * @param $fragment string A fragment identifier (named anchor) to append to the link.
187 * @return string an HTML string containing a link to the given path.
198 $forceBackend = FALSE
200 $query = self
::makeQueryString($query);
202 // we have a valid query and it has not yet been transformed
203 if ($htmlize && !empty($query) && strpos($query, '&') === FALSE) {
204 $query = htmlentities($query);
207 $config = CRM_Core_Config
::singleton();
208 return $config->userSystem
->url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
211 static function href($text, $path = NULL, $query = NULL, $absolute = TRUE,
212 $fragment = NULL, $htmlize = TRUE, $frontend = FALSE, $forceBackend = FALSE
214 $url = self
::url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
215 return "<a href=\"$url\">$text</a>";
218 static function permissionDenied() {
219 $config = CRM_Core_Config
::singleton();
220 return $config->userSystem
->permissionDenied();
223 static function logout() {
224 $config = CRM_Core_Config
::singleton();
225 return $config->userSystem
->logout();
228 // this is a very drupal specific function for now
229 static function updateCategories() {
230 $config = CRM_Core_Config
::singleton();
231 if ($config->userSystem
->is_drupal
) {
232 $config->userSystem
->updateCategories();
237 * What menu path are we currently on. Called for the primary tpl
239 * @return string the current menu path
242 static function currentPath() {
243 $config = CRM_Core_Config
::singleton();
244 return trim(CRM_Utils_Array
::value($config->userFrameworkURLVar
, $_GET), '/');
248 * this function is called from a template to compose a url
250 * @param array $params list of parameters
256 static function crmURL($params) {
257 $p = CRM_Utils_Array
::value('p', $params);
259 $p = self
::currentPath();
264 CRM_Utils_Array
::value('q', $params),
265 CRM_Utils_Array
::value('a', $params, FALSE),
266 CRM_Utils_Array
::value('f', $params),
267 CRM_Utils_Array
::value('h', $params, TRUE),
268 CRM_Utils_Array
::value('fe', $params, FALSE),
269 CRM_Utils_Array
::value('fb', $params, FALSE)
274 * sets the title of the page
276 * @param string $title
277 * @param string $pageTitle
283 static function setTitle($title, $pageTitle = NULL) {
284 $config = CRM_Core_Config
::singleton();
285 return $config->userSystem
->setTitle($title, $pageTitle);
289 * figures and sets the userContext. Uses the referer if valid
290 * else uses the default
292 * @param array $names refererer should match any str in this array
293 * @param string $default the default userContext if no match found
298 static function setUserContext($names, $default = NULL) {
301 $session = CRM_Core_Session
::singleton();
302 $referer = CRM_Utils_Array
::value('HTTP_REFERER', $_SERVER);
304 if ($referer && !empty($names)) {
305 foreach ($names as $name) {
306 if (strstr($referer, $name)) {
314 $session->pushUserContext($url);
319 * gets a class name for an object
321 * @param object $object - object whose class name is needed
323 * @return string $className - class name
328 static function getClassName($object) {
329 return get_class($object);
333 * redirect to another url
335 * @param string $url the url to goto
341 static function redirect($url = NULL) {
343 $url = self
::url('civicrm/dashboard', 'reset=1');
346 // replace the & characters with &
347 // this is kinda hackish but not sure how to do it right
348 $url = str_replace('&', '&', $url);
349 header('Location: ' . $url);
354 * use a html based file with javascript embedded to redirect to another url
355 * This prevent the too many redirect errors emitted by various browsers
357 * @param string $url the url to goto
363 static function jsRedirect(
369 $url = self
::url('civicrm/dashboard', 'reset=1');
373 $title = ts('CiviCRM task in progress');
377 $message = ts('A long running CiviCRM task is currently in progress. This message will be refreshed till the task is completed');
380 // replace the & characters with &
381 // this is kinda hackish but not sure how to do it right
382 $url = str_replace('&', '&', $url);
384 $template = CRM_Core_Smarty
::singleton();
385 $template->assign('redirectURL', $url);
386 $template->assign('title', $title);
387 $template->assign('message', $message);
389 $html = $template->fetch('CRM/common/redirectJS.tpl');
397 * Append an additional breadcrumb tag to the existing breadcrumb
399 * @param string $title
406 static function appendBreadCrumb($breadCrumbs) {
407 $config = CRM_Core_Config
::singleton();
408 return $config->userSystem
->appendBreadCrumb($breadCrumbs);
412 * Reset an additional breadcrumb tag to the existing breadcrumb
418 static function resetBreadCrumb() {
419 $config = CRM_Core_Config
::singleton();
420 return $config->userSystem
->resetBreadCrumb();
424 * Append a string to the head of the html file
426 * @param string $head the new string to be appended
432 static function addHTMLHead($bc) {
433 $config = CRM_Core_Config
::singleton();
434 return $config->userSystem
->addHTMLHead($bc);
438 * figure out the post url for the form
440 * @param the default action if one is pre-specified
442 * @return string the url to post the form
446 static function postURL($action) {
447 $config = CRM_Core_Config
::singleton();
448 return $config->userSystem
->postURL($action);
452 * rewrite various system urls to https
458 static function mapConfigToSSL() {
459 $config = CRM_Core_Config
::singleton();
460 $config->userFrameworkResourceURL
= str_replace('http://', 'https://',
461 $config->userFrameworkResourceURL
463 $config->resourceBase
= $config->userFrameworkResourceURL
;
464 return $config->userSystem
->mapConfigToSSL();
468 * Get the base URL from the system
476 static function baseURL() {
477 $config = CRM_Core_Config
::singleton();
478 return $config->userFrameworkBaseURL
;
481 static function authenticateAbort($message, $abort) {
491 static function authenticateKey($abort = TRUE) {
492 // also make sure the key is sent and is valid
493 $key = trim(CRM_Utils_Array
::value('key', $_REQUEST));
495 $docAdd = "More info at:" . CRM_Utils_System
::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
498 return self
::authenticateAbort(
499 "ERROR: You need to send a valid key to execute this file. " . $docAdd . "\n",
504 $siteKey = defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY
: NULL;
506 if (!$siteKey ||
empty($siteKey)) {
507 return self
::authenticateAbort(
508 "ERROR: You need to set a valid site key in civicrm.settings.php. " . $docAdd . "\n",
513 if (strlen($siteKey) < 8) {
514 return self
::authenticateAbort(
515 "ERROR: Site key needs to be greater than 7 characters in civicrm.settings.php. " . $docAdd . "\n",
520 if ($key !== $siteKey) {
521 return self
::authenticateAbort(
522 "ERROR: Invalid key value sent. " . $docAdd . "\n",
530 static function authenticateScript($abort = TRUE, $name = NULL, $pass = NULL, $storeInSession = TRUE, $loadCMSBootstrap = TRUE, $requireKey = TRUE) {
531 // auth to make sure the user has a login/password to do a shell
533 // later on we'll link this to acl's
535 $name = trim(CRM_Utils_Array
::value('name', $_REQUEST));
536 $pass = trim(CRM_Utils_Array
::value('pass', $_REQUEST));
539 // its ok to have an empty password
541 return self
::authenticateAbort(
542 "ERROR: You need to send a valid user name and password to execute this file\n",
547 if ($requireKey && !self
::authenticateKey($abort)) {
551 $result = CRM_Utils_System
::authenticate($name, $pass, $loadCMSBootstrap);
553 return self
::authenticateAbort(
554 "ERROR: Invalid username and/or password\n",
558 elseif ($storeInSession) {
559 // lets store contact id and user id in session
560 list($userID, $ufID, $randomNumber) = $result;
561 if ($userID && $ufID) {
562 $config = CRM_Core_Config
::singleton();
563 $config->userSystem
->setUserSession( array($userID, $ufID) );
566 return self
::authenticateAbort(
567 "ERROR: Unexpected error, could not match userID and contactID",
577 * Authenticate the user against the uf db
579 * @param string $name the user name
580 * @param string $password the password for the above user name
582 * @return mixed false if no auth
584 contactID, ufID, unique string ) if success
588 static function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realPath = NULL) {
589 $config = CRM_Core_Config
::singleton();
591 // before we do any loading, lets start the session and write to it
592 // we typically call authenticate only when we need to bootstrap the CMS directly via Civi
593 // and hence bypass the normal CMS auth and bootstrap process
594 // typically done in cli and cron scripts
596 $session = CRM_Core_Session
::singleton();
597 $session->set( 'civicrmInitSession', TRUE );
599 $dbDrupal = DB
::connect($config->userFrameworkDSN
);
600 return $config->userSystem
->authenticate($name, $password, $loadCMSBootstrap, $realPath);
604 * Set a message in the UF to display to a user
606 * @param string $name the message to set
611 static function setUFMessage($message) {
612 $config = CRM_Core_Config
::singleton();
613 return $config->userSystem
->setMessage($message);
618 static function isNull($value) {
619 // FIXME: remove $value = 'null' string test when we upgrade our DAO code to handle passing null in a better way.
620 if (!isset($value) ||
$value === NULL ||
$value === '' ||
$value === 'null') {
623 if (is_array($value)) {
624 foreach ($value as $key => $value) {
625 if (!self
::isNull($value)) {
634 static function mungeCreditCard($number, $keep = 4) {
635 $number = trim($number);
636 if (empty($number)) {
639 $replace = str_repeat('*', strlen($number) - $keep);
640 return substr_replace($number, $replace, 0, -$keep);
643 /** parse php modules from phpinfo */
644 public static function parsePHPModules() {
646 phpinfo(INFO_MODULES
);
647 $s = ob_get_contents();
650 $s = strip_tags($s, '<h2><th><td>');
651 $s = preg_replace('/<th[^>]*>([^<]+)<\/th>/', "<info>\\1</info>", $s);
652 $s = preg_replace('/<td[^>]*>([^<]+)<\/td>/', "<info>\\1</info>", $s);
653 $vTmp = preg_split('/(<h2>[^<]+<\/h2>)/', $s, -1, PREG_SPLIT_DELIM_CAPTURE
);
655 for ($i = 1; $i < count($vTmp); $i++
) {
656 if (preg_match('/<h2>([^<]+)<\/h2>/', $vTmp[$i], $vMat)) {
657 $vName = trim($vMat[1]);
658 $vTmp2 = explode("\n", $vTmp[$i +
1]);
659 foreach ($vTmp2 AS $vOne) {
660 $vPat = '<info>([^<]+)<\/info>';
661 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
662 $vPat2 = "/$vPat\s*$vPat/";
664 if (preg_match($vPat3, $vOne, $vMat)) {
665 $vModules[$vName][trim($vMat[1])] = array(trim($vMat[2]), trim($vMat[3]));
668 elseif (preg_match($vPat2, $vOne, $vMat)) {
669 $vModules[$vName][trim($vMat[1])] = trim($vMat[2]);
677 /** get a module setting */
678 public static function getModuleSetting($pModuleName, $pSetting) {
679 $vModules = self
::parsePHPModules();
680 return $vModules[$pModuleName][$pSetting];
683 static function memory($title = NULL) {
686 $pid = posix_getpid();
689 $memory = str_replace("\n", '', shell_exec("ps -p" . $pid . " -o rss="));
690 $memory .= ", " . time();
692 CRM_Core_Error
::debug_var($title, $memory);
697 static function download($name, $mimeType, &$buffer,
701 $now = gmdate('D, d M Y H:i:s') . ' GMT';
703 header('Content-Type: ' . $mimeType);
704 header('Expires: ' . $now);
706 // lem9 & loic1: IE need specific headers
707 $isIE = strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE');
709 $fileString = "filename=\"{$name}.{$ext}\"";
712 $fileString = "filename=\"{$name}\"";
715 header("Content-Disposition: inline; $fileString");
716 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
717 header('Pragma: public');
720 header("Content-Disposition: attachment; $fileString");
721 header('Pragma: no-cache');
730 static function xMemory($title = NULL, $log = FALSE) {
731 $mem = (float ) xdebug_memory_usage() / (float )(1024);
732 $mem = number_format($mem, 5) . ", " . time();
734 echo "<p>$title: $mem<p>";
736 CRM_Core_Error
::debug_var($title, $mem);
739 echo "<p>$title: $mem<p>";
744 static function fixURL($url) {
745 $components = parse_url($url);
751 // at some point we'll add code here to make sure the url is not
752 // something that will mess up up, so we need to clean it up here
757 * make sure the callback is valid in the current context
759 * @param string $callback the name of the function
764 static function validCallback($callback) {
765 if (self
::$_callbacks === NULL) {
766 self
::$_callbacks = array();
769 if (!array_key_exists($callback, self
::$_callbacks)) {
770 if (strpos($callback, '::') !== FALSE) {
771 list($className, $methodName) = explode('::', $callback);
772 $fileName = str_replace('_', DIRECTORY_SEPARATOR
, $className) . '.php';
773 // ignore errors if any
774 @include_once
($fileName);
775 if (!class_exists($className)) {
776 self
::$_callbacks[$callback] = FALSE;
779 // instantiate the class
780 $object = new $className();
781 if (!method_exists($object, $methodName)) {
782 self
::$_callbacks[$callback] = FALSE;
785 self
::$_callbacks[$callback] = TRUE;
790 self
::$_callbacks[$callback] = function_exists($callback);
793 return self
::$_callbacks[$callback];
797 * This serves as a wrapper to the php explode function
798 * we expect exactly $limit arguments in return, and if we dont
799 * get them, we pad it with null
801 static function explode($separator, $string, $limit) {
802 $result = explode($separator, $string, $limit);
803 for ($i = count($result); $i < $limit; $i++
) {
809 static function checkURL($url, $addCookie = FALSE) {
810 // make a GET request to $url
811 $ch = curl_init($url);
813 curl_setopt($ch, CURLOPT_COOKIE
, http_build_query($_COOKIE));
815 // it's quite alright to use a self-signed cert
816 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER
, 0);
818 // lets capture the return stuff rather than echo
819 curl_setopt($ch, CURLOPT_RETURNTRANSFER
, true );
821 return curl_exec($ch);
824 static function checkPHPVersion($ver = 5, $abort = TRUE) {
825 $phpVersion = substr(PHP_VERSION
, 0, 1);
826 if ($phpVersion >= $ver) {
831 CRM_Core_Error
::fatal(ts('This feature requires PHP Version %1 or greater',
838 static function formatWikiURL($string, $encode = FALSE) {
839 $items = explode(' ', trim($string), 2);
840 if (count($items) == 2) {
848 $url = $encode ? self
::urlEncode($items[0]) : $items[0];
849 return "<a href=\"$url\">$title</a>";
852 static function urlEncode($url) {
853 $items = parse_url($url);
854 if ($items === FALSE) {
858 if (!CRM_Utils_Array
::value('query', $items)) {
862 $items['query'] = urlencode($items['query']);
864 $url = $items['scheme'] . '://';
865 if (CRM_Utils_Array
::value('user', $items)) {
866 $url .= "{$items['user']}:{$items['pass']}@";
869 $url .= $items['host'];
870 if (CRM_Utils_Array
::value('port', $items)) {
871 $url .= ":{$items['port']}";
874 $url .= "{$items['path']}?{$items['query']}";
875 if (CRM_Utils_Array
::value('fragment', $items)) {
876 $url .= "#{$items['fragment']}";
883 * Function to return the latest civicrm version.
885 * @return string civicrm version
888 static function version() {
892 $verFile = implode(DIRECTORY_SEPARATOR
,
893 array(dirname(__FILE__
), '..', '..', 'civicrm-version.php')
895 if (file_exists($verFile)) {
896 require_once ($verFile);
897 if (function_exists('civicrmVersion')) {
898 $info = civicrmVersion();
899 $version = $info['version'];
903 // svn installs don't have version.txt by default. In that case version.xml should help -
904 $verFile = implode(DIRECTORY_SEPARATOR
,
905 array(dirname(__FILE__
), '..', '..', 'xml', 'version.xml')
907 if (file_exists($verFile)) {
908 $str = file_get_contents($verFile);
909 $xmlObj = simplexml_load_string($str);
910 $version = (string) $xmlObj->version_no
;
915 if (!CRM_Utils_System
::isVersionFormatValid($version)) {
916 CRM_Core_Error
::fatal('Unknown codebase version.');
923 static function isVersionFormatValid($version) {
924 return preg_match("/^(\d{1,2}\.){2,3}(\d{1,2}|(alpha|beta)\d{1,2})(\.upgrade)?$/", $version);
927 static function getAllHeaders() {
928 if (function_exists('getallheaders')) {
929 return getallheaders();
932 // emulate get all headers
933 // http://www.php.net/manual/en/function.getallheaders.php#66335
935 foreach ($_SERVER as $name => $value) {
936 if (substr($name, 0, 5) == 'HTTP_') {
937 $headers[str_replace(' ',
939 ucwords(strtolower(str_replace('_',
950 static function getRequestHeaders() {
951 if (function_exists('apache_request_headers')) {
952 return apache_request_headers();
960 * Check and determine is this is an SSL request
961 * Note that we inline this function in install/civicrm.php, so if
962 * you change this function, please go and change the code in the install script
964 static function isSSL( ) {
966 (isset($_SERVER['HTTPS']) &&
967 !empty($_SERVER['HTTPS']) &&
968 strtolower($_SERVER['HTTPS']) != 'off') ?
true : false;
971 static function redirectToSSL($abort = FALSE) {
972 $config = CRM_Core_Config
::singleton();
973 $req_headers = self
::getRequestHeaders();
974 if (CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'enableSSL') &&
976 strtolower(CRM_Utils_Array
::value('X_FORWARDED_PROTO', $req_headers)) != 'https'
978 // ensure that SSL is enabled on a civicrm url (for cookie reasons etc)
979 $url = "https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
980 if (!self
::checkURL($url, TRUE)) {
982 CRM_Core_Error
::fatal('HTTPS is not set up on this machine');
985 CRM_Core_Session
::setStatus(ts('HTTPS is not set up on this machine'), ts('Warning'), 'alert');
986 // admin should be the only one following this
987 // since we dont want the user stuck in a bad place
991 CRM_Utils_System
::redirect($url);
996 * Get logged in user's IP address.
998 * Get IP address from HTTP Header. If the CMS is Drupal then use the Drupal function
999 * as this also handles reverse proxies (based on proper configuration in settings.php)
1001 * @return string ip address of logged in user
1004 static function ipAddress() {
1005 $address = CRM_Utils_Array
::value('REMOTE_ADDR', $_SERVER);
1007 $config = CRM_Core_Config
::singleton();
1008 if ($config->userSystem
->is_drupal
) {
1009 //drupal function handles the server being behind a proxy securely
1010 return ip_address();
1014 if ($address == '::1') {
1015 $address = '127.0.0.1';
1022 * Returns you the referring / previous page url
1024 * @return string the previous page url
1027 static function refererPath() {
1028 return CRM_Utils_Array
::value('HTTP_REFERER', $_SERVER);
1032 * Returns default documentation URL base
1034 * @return string documentation url
1037 static function getDocBaseURL() {
1038 // FIXME: move this to configuration at some stage
1039 return 'http://book.civicrm.org/';
1043 * Returns wiki (alternate) documentation URL base
1045 * @return string documentation url
1048 static function getWikiBaseURL() {
1049 // FIXME: move this to configuration at some stage
1050 return 'http://wiki.civicrm.org/confluence/display/CRMDOC/';
1054 * Returns URL or link to documentation page, based on provided parameters.
1055 * For use in PHP code.
1056 * WARNING: Always returns URL, if ts function is not defined ($URLonly has no effect).
1058 * @param string $page Title of documentation wiki page
1059 * @param boolean $URLonly Whether function should return URL only or whole link (default)
1060 * @param string $text Text of HTML link (no effect if $URLonly = false)
1061 * @param string $title Tooltip text for HTML link (no effect if $URLonly = false)
1062 * @param string $style Style attribute value for HTML link (no effect if $URLonly = false)
1064 * @return string URL or link to documentation page, based on provided parameters
1067 static function docURL2($page, $URLonly = FALSE, $text = NULL, $title = NULL, $style = NULL, $resource = NULL) {
1068 // if ts function doesn't exist, it means that CiviCRM hasn't been fully initialised yet -
1069 // return just the URL, no matter what other parameters are defined
1070 if (!function_exists('ts')) {
1071 if ($resource == 'wiki') {
1072 $docBaseURL = self
::getWikiBaseURL();
1074 $docBaseURL = self
::getDocBaseURL();
1076 return $docBaseURL . str_replace(' ', '+', $page);
1081 'URLonly' => $URLonly,
1085 'resource' => $resource,
1087 return self
::docURL($params);
1092 * Returns URL or link to documentation page, based on provided parameters.
1093 * For use in templates code.
1095 * @param array $params An array of parameters (see CRM_Utils_System::docURL2 method for names)
1097 * @return string URL or link to documentation page, based on provided parameters
1100 static function docURL($params) {
1102 if (!isset($params['page'])) {
1106 if (CRM_Utils_Array
::value('resource', $params) == 'wiki') {
1107 $docBaseURL = self
::getWikiBaseURL();
1109 $docBaseURL = self
::getDocBaseURL();
1112 if (!isset($params['title']) or $params['title'] === NULL) {
1113 $params['title'] = ts('Opens documentation in a new window.');
1116 if (!isset($params['text']) or $params['text'] === NULL) {
1117 $params['text'] = ts('(learn more...)');
1120 if (!isset($params['style']) ||
$params['style'] === NULL) {
1124 $style = "style=\"{$params['style']}\"";
1127 $link = $docBaseURL . str_replace(' ', '+', $params['page']);
1129 if (isset($params['URLonly']) && $params['URLonly'] == TRUE) {
1133 return "<a href=\"{$link}\" $style target=\"_blank\" title=\"{$params['title']}\">{$params['text']}</a>";
1138 * Get the locale set in the hosting CMS
1140 * @return string the used locale or null for none
1142 static function getUFLocale() {
1143 $config = CRM_Core_Config
::singleton();
1144 return $config->userSystem
->getUFLocale();
1148 * Execute external or internal urls and return server response
1150 * @param string $url request url
1151 * @param boolean $addCookie should be true to access internal urls
1153 * @return string $response response from url
1156 static function getServerResponse($url, $addCookie = TRUE) {
1157 CRM_Core_Error
::ignoreException();
1158 require_once 'HTTP/Request.php';
1159 $request = new HTTP_Request($url);
1162 foreach ($_COOKIE as $name => $value) {
1163 $request->addCookie($name, $value);
1167 if (isset($_SERVER['AUTH_TYPE'])) {
1168 $request->setBasicAuth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
1171 $config = CRM_Core_Config
::singleton();
1172 if ($config->userFramework
== 'WordPress') {
1173 session_write_close();
1176 $request->sendRequest();
1177 $response = $request->getResponseBody();
1179 CRM_Core_Error
::setCallback();
1183 static function isDBVersionValid(&$errorMessage) {
1184 $dbVersion = CRM_Core_BAO_Domain
::version();
1187 // if db.ver missing
1188 $errorMessage = ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.');
1191 elseif (!CRM_Utils_System
::isVersionFormatValid($dbVersion)) {
1192 $errorMessage = ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.');
1195 elseif (stripos($dbVersion, 'upgrade')) {
1196 // if db.ver indicates a partially upgraded db
1197 $upgradeUrl = CRM_Utils_System
::url("civicrm/upgrade", "reset=1");
1198 $errorMessage = ts('Database check failed - the database looks to have been partially upgraded. You may want to reload the database with the backup and try the <a href=\'%1\'>upgrade process</a> again.', array(1 => $upgradeUrl));
1202 $codeVersion = CRM_Utils_System
::version();
1204 // if db.ver < code.ver, time to upgrade
1205 if (version_compare($dbVersion, $codeVersion) < 0) {
1206 $upgradeUrl = CRM_Utils_System
::url("civicrm/upgrade", "reset=1");
1207 $errorMessage = ts('New codebase version detected. You might want to visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl));
1211 // if db.ver > code.ver, sth really wrong
1212 if (version_compare($dbVersion, $codeVersion) > 0) {
1213 $errorMessage = '<p>' . ts('Your database is marked with an unexpected version number: %1. The v%2 codebase may not be compatible with your database state. You will need to determine the correct version corresponding to your current database state. You may want to revert to the codebase you were using until you resolve this problem.',
1214 array(1 => $dbVersion, 2 => $codeVersion)
1216 $errorMessage .= "<p>" . ts('OR if this is a manual install from git, you might want to fix civicrm-version.php file.') . "</p>";
1220 // FIXME: there should be another check to make sure version is in valid format - X.Y.alpha_num
1225 static function civiExit($status = 0) {
1226 // move things to CiviCRM cache as needed
1227 CRM_Core_Session
::storeSessionObjects();
1233 * Reset the various system caches and some important
1236 static function flushCache( ) {
1237 // flush out all cache entries so we can reload new data
1238 // a bit aggressive, but livable for now
1239 $cache = CRM_Utils_Cache
::singleton();
1242 // also reset the various static memory caches
1244 // reset the memory or array cache
1245 CRM_Core_BAO_Cache
::deleteGroup('contact fields', NULL, FALSE);
1248 CRM_ACL_BAO_Cache
::resetCache();
1250 // reset various static arrays used here
1251 CRM_Contact_BAO_Contact
::$_importableFields =
1252 CRM_Contact_BAO_Contact
::$_exportableFields =
1253 CRM_Contribute_BAO_Contribution
::$_importableFields =
1254 CRM_Contribute_BAO_Contribution
::$_exportableFields =
1255 CRM_Pledge_BAO_Pledge
::$_exportableFields =
1256 CRM_Contribute_BAO_Query
::$_contributionFields =
1257 CRM_Core_BAO_CustomField
::$_importFields =
1258 CRM_Core_BAO_Cache
::$_cache =
1259 CRM_Core_DAO
::$_dbColumnValueCache = NULL;
1261 CRM_Core_OptionGroup
::flushAll();
1262 CRM_Utils_PseudoConstant
::flushAll();
1266 * load cms bootstrap
1268 * @param $params array with uid name and pass
1269 * @param $loadUser boolean load user or not
1271 static function loadBootStrap($params = array(
1272 ), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) {
1273 if (!is_array($params)) {
1276 $config = CRM_Core_Config
::singleton();
1277 return $config->userSystem
->loadBootStrap($params, $loadUser, $throwError, $realPath);
1281 * check is user logged in.
1285 public static function isUserLoggedIn() {
1286 $config = CRM_Core_Config
::singleton();
1287 return $config->userSystem
->isUserLoggedIn();
1291 * Get current logged in user id.
1293 * @return int ufId, currently logged in user uf id.
1295 public static function getLoggedInUfID() {
1296 $config = CRM_Core_Config
::singleton();
1297 return $config->userSystem
->getLoggedInUfID();
1300 static function baseCMSURL() {
1301 static $_baseURL = NULL;
1303 $config = CRM_Core_Config
::singleton();
1304 $_baseURL = $userFrameworkBaseURL = $config->userFrameworkBaseURL
;
1306 if ($config->userFramework
== 'Joomla') {
1308 // we need to remove the administrator/ from the end
1309 $_baseURL = str_replace("/administrator/", "/", $userFrameworkBaseURL);
1313 global $civicrm_root;
1314 if (strpos($civicrm_root,
1315 DIRECTORY_SEPARATOR
. 'sites' .
1316 DIRECTORY_SEPARATOR
. 'all' .
1317 DIRECTORY_SEPARATOR
. 'modules'
1319 $startPos = strpos($civicrm_root,
1320 DIRECTORY_SEPARATOR
. 'sites' . DIRECTORY_SEPARATOR
1322 $endPos = strpos($civicrm_root,
1323 DIRECTORY_SEPARATOR
. 'modules' . DIRECTORY_SEPARATOR
1325 if ($startPos && $endPos) {
1326 // if component is in sites/SITENAME/modules
1327 $siteName = substr($civicrm_root,
1329 $endPos - $startPos - 7
1332 $_baseURL = $userFrameworkBaseURL . "sites/$siteName/";
1340 static function relativeURL($url) {
1341 // check if url is relative, if so return immediately
1342 if (substr($url, 0, 4) != 'http') {
1346 // make everything relative from the baseFilePath
1347 $baseURL = self
::baseCMSURL();
1349 // check if baseURL is a substr of $url, if so
1350 // return rest of string
1351 if (substr($url, 0, strlen($baseURL)) == $baseURL) {
1352 return substr($url, strlen($baseURL));
1355 // return the original value
1359 static function absoluteURL($url, $removeLanguagePart = FALSE) {
1360 // check if url is already absolute, if so return immediately
1361 if (substr($url, 0, 4) == 'http') {
1365 // make everything absolute from the baseFileURL
1366 $baseURL = self
::baseCMSURL();
1368 //CRM-7622: drop the language from the URL if requested (and it’s there)
1369 $config = CRM_Core_Config
::singleton();
1370 if ($removeLanguagePart) {
1371 $baseURL = self
::languageNegotiationURL($baseURL, FALSE, TRUE);
1374 return $baseURL . $url;
1378 * Function to clean url, replaces first '&' with '?'
1380 * @param string $url
1382 * @return string $url, clean url
1385 static function cleanUrl($url) {
1390 if ($pos = strpos($url, '&')) {
1391 $url = substr_replace($url, '?', $pos, 1);
1398 * Format the url as per language Negotiation.
1400 * @param string $url
1402 * @return string $url, formatted url.
1405 static function languageNegotiationURL($url,
1406 $addLanguagePart = TRUE,
1407 $removeLanguagePart = FALSE
1409 $config = &CRM_Core_Config
::singleton();
1410 return $config->userSystem
->languageNegotiationURL($url, $addLanguagePart, $removeLanguagePart);
1414 * Append the contents of an 'extra' smarty template file if it is present in
1415 * the custom template directory. This does not work if there are
1416 * multiple custom template directories
1418 * @param string $fileName - the name of the tpl file that we are processing
1419 * @param string $content (by reference) - the current content string
1420 * @param string $overideFileName - an optional parameter which is sent by contribution/event reg/profile pages
1421 * which uses a id specific extra file name if present
1423 * @return void - the content string is modified if needed
1426 static function appendTPLFile($fileName,
1428 $overideFileName = NULL
1430 $template = CRM_Core_Smarty
::singleton();
1431 if ($overideFileName) {
1432 $additionalTPLFile = $overideFileName;
1435 $additionalTPLFile = str_replace('.tpl', '.extra.tpl', $fileName);
1438 if ($template->template_exists($additionalTPLFile)) {
1439 $content .= $template->fetch($additionalTPLFile);
1444 * Get a list of all files that are found within the directories
1445 * that are the result of appending the provided relative path to
1446 * each component of the PHP include path.
1448 * @author Ken Zalewski
1450 * @param string $relpath a relative path, typically pointing to
1451 * a directory with multiple class files
1453 * @return array An array of files that exist in one or more of the
1454 * directories that are referenced by the relative path
1455 * when appended to each element of the PHP include path
1458 static function listIncludeFiles($relpath) {
1459 $file_list = array();
1460 $inc_dirs = explode(PATH_SEPARATOR
, get_include_path());
1461 foreach ($inc_dirs as $inc_dir) {
1462 $target_dir = $inc_dir . DIRECTORY_SEPARATOR
. $relpath;
1463 if (is_dir($target_dir)) {
1464 $cur_list = scandir($target_dir);
1465 foreach ($cur_list as $fname) {
1466 if ($fname != '.' && $fname != '..') {
1467 $file_list[$fname] = $fname;
1474 // listIncludeFiles()
1477 * Get a list of all "plugins" (PHP classes that implement a piece of
1478 * functionality using a well-defined interface) that are found in a
1479 * particular CiviCRM directory (both custom and core are searched).
1481 * @author Ken Zalewski
1483 * @param string $relpath a relative path referencing a directory that
1484 * contains one or more plugins
1485 * @param string $fext only files with this extension will be considered
1487 * @param array $skipList list of files to skip
1489 * @return array List of plugins, where the plugin name is both the
1490 * key and the value of each element.
1493 static function getPluginList($relpath, $fext = '.php', $skipList = array(
1495 $fext_len = strlen($fext);
1497 $inc_files = CRM_Utils_System
::listIncludeFiles($relpath);
1498 foreach ($inc_files as $inc_file) {
1499 if (substr($inc_file, 0 - $fext_len) == $fext) {
1500 $plugin_name = substr($inc_file, 0, 0 - $fext_len);
1501 if (!in_array($plugin_name, $skipList)) {
1502 $plugins[$plugin_name] = $plugin_name;
1512 * @param string $fileName - the name of the tpl file that we are processing
1513 * @param string $content (by reference) - the current content string
1515 * @return void - the content string is modified if needed
1518 static function executeScheduledJobs() {
1519 $facility = new CRM_Core_JobManager();
1520 $facility->execute(FALSE);
1522 $redirectUrl = self
::url('civicrm/admin/job', 'reset=1');
1524 CRM_Core_Session
::setStatus(
1525 ts('Scheduled jobs have been executed according to individual timing settings. Please check log for messages.'),
1526 ts('Complete'), 'success');
1528 CRM_Utils_System
::redirect($redirectUrl);
1532 * Evaluate any tokens in a URL
1534 * @param string|FALSE $url
1535 * @return string|FALSE
1537 public static function evalUrl($url) {
1538 if ($url === FALSE) {
1542 $config = CRM_Core_Config
::singleton();
1544 '{ver}' => CRM_Utils_System
::version(),
1545 '{uf}' => $config->userFramework
,
1546 '{php}' => phpversion(),
1547 '{sid}' => md5('sid_' . (defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY
: '') . '_' . $config->userFrameworkBaseURL
),
1548 '{baseUrl}' => $config->userFrameworkBaseURL
,
1549 '{lang}' => $config->lcMessages
,
1550 '{co}' => $config->defaultContactCountry
,
1552 foreach (array_keys($vars) as $k) {
1553 $vars[$k] = urlencode($vars[$k]);
1555 return strtr($url, $vars);
1561 * Determine whether this is a developmental system.
1565 static function isDevelopment() {
1566 static $cache = NULL;
1567 if ($cache === NULL) {
1568 global $civicrm_root;
1569 $cache = file_exists("{$civicrm_root}/.svn") ||
file_exists("{$civicrm_root}/.git");