3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
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 * @var string Page title
50 * Compose a new URL string from the current URL string.
52 * Used by all the framework components, specifically,
55 * @param string $urlVar
56 * The url variable being considered (i.e. crmPageID, crmSortID etc).
57 * @param bool $includeReset
58 * (optional) Whether to include the reset GET string (if present).
59 * @param bool $includeForce
60 * (optional) Whether to include the force GET string (if present).
62 * (optional) The path to use for the new url.
63 * @param string $absolute
64 * (optional) Whether to return an absolute URL.
70 static function makeURL($urlVar, $includeReset = FALSE, $includeForce = TRUE, $path = NULL, $absolute = FALSE) {
72 $config = CRM_Core_Config
::singleton();
73 $path = CRM_Utils_Array
::value($config->userFrameworkURLVar
, $_GET);
82 CRM_Utils_System
::getLinksUrl($urlVar, $includeReset, $includeForce),
88 * Get the query string and clean it up.
90 * Strips some variables that should not be propagated, specifically variables
91 * like 'reset'. Also strips any side-affect actions (e.g. export).
93 * This function is copied mostly verbatim from Pager.php (_getLinksUrl)
95 * @param string $urlVar
96 * The URL variable being considered (e.g. crmPageID, crmSortID etc).
97 * @param bool $includeReset
98 * (optional) By default this is FALSE, meaning that the reset parameter
99 * is skipped. Set to TRUE to leave the reset parameter as-is.
100 * @param bool $includeForce
102 * @param bool $skipUFVar
108 static function getLinksUrl($urlVar, $includeReset = FALSE, $includeForce = TRUE, $skipUFVar = TRUE) {
109 // Sort out query string to prevent messy urls
110 $querystring = array();
114 if (!empty($_SERVER['QUERY_STRING'])) {
115 $qs = explode('&', str_replace('&', '&', $_SERVER['QUERY_STRING']));
116 for ($i = 0, $cnt = count($qs); $i < $cnt; $i++
) {
117 // check first if exist a pair
118 if (strstr($qs[$i], '=') !== FALSE) {
119 list($name, $value) = explode('=', $qs[$i]);
120 if ($name != $urlVar) {
121 $name = rawurldecode($name);
122 //check for arrays in parameters: site.php?foo[]=1&foo[]=2&foo[]=3
123 if ((strpos($name, '[') !== FALSE) &&
124 (strpos($name, ']') !== FALSE)
144 // Ok this is a big assumption but usually works
145 // If we are in snippet mode, retain the 'section' param, if not, get rid
147 if (!empty($qs['snippet'])) {
148 unset($qs['snippet']);
151 unset($qs['section']);
155 $config = CRM_Core_Config
::singleton();
156 unset($qs[$config->userFrameworkURLVar
]);
159 foreach ($qs as $name => $value) {
160 if ($name != 'reset' ||
$includeReset) {
161 $querystring[] = $name . '=' . $value;
165 $querystring = array_merge($querystring, array_unique($arrays));
167 $url = implode('&', $querystring);
169 $url .= (!empty($querystring) ?
'&' : '') . $urlVar . '=';
176 * If we are using a theming system, invoke theme, else just print the
179 * @param string $content
180 * The content that will be themed.
182 * (optional) Are we displaying to the screen or bypassing theming?
183 * @param bool $maintenance
184 * (optional) For maintenance mode.
188 static function theme(
193 $config = &CRM_Core_Config
::singleton();
194 return $config->userSystem
->theme($content, $print, $maintenance);
198 * Generate a query string if input is an array.
200 * @param array|string $query
203 static function makeQueryString($query) {
204 if (is_array($query)) {
206 foreach ($query as $key => $value) {
207 $buf .= ($buf ?
'&' : '') . urlencode($key) . '=' . urlencode($value);
215 * Generate an internal CiviCRM URL.
217 * @param string $path
218 * The path being linked to, such as "civicrm/add".
219 * @param array|string $query
220 * A query string to append to the link, or an array of key-value pairs.
221 * @param bool $absolute
222 * Whether to force the output to be an absolute link (beginning with a
223 * URI-scheme such as 'http:'). Useful for links that will be displayed
224 * outside the site, such as in an RSS feed.
225 * @param string $fragment
226 * A fragment identifier (named anchor) to append to the link.
228 * @param bool $htmlize
229 * @param bool $frontend
230 * @param bool $forceBackend
232 * An HTML string containing a link to the given path.
242 $forceBackend = FALSE
244 $query = self
::makeQueryString($query);
246 // we have a valid query and it has not yet been transformed
247 if ($htmlize && !empty($query) && strpos($query, '&') === FALSE) {
248 $query = htmlentities($query);
251 $config = CRM_Core_Config
::singleton();
252 return $config->userSystem
->url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
255 static function href($text, $path = NULL, $query = NULL, $absolute = TRUE,
256 $fragment = NULL, $htmlize = TRUE, $frontend = FALSE, $forceBackend = FALSE
258 $url = self
::url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
259 return "<a href=\"$url\">$text</a>";
262 static function permissionDenied() {
263 $config = CRM_Core_Config
::singleton();
264 return $config->userSystem
->permissionDenied();
267 static function logout() {
268 $config = CRM_Core_Config
::singleton();
269 return $config->userSystem
->logout();
272 // this is a very drupal specific function for now
273 static function updateCategories() {
274 $config = CRM_Core_Config
::singleton();
275 if ($config->userSystem
->is_drupal
) {
276 $config->userSystem
->updateCategories();
281 * What menu path are we currently on. Called for the primary tpl
283 * @return string the current menu path
286 static function currentPath() {
287 $config = CRM_Core_Config
::singleton();
288 return trim(CRM_Utils_Array
::value($config->userFrameworkURLVar
, $_GET), '/');
292 * This function is called from a template to compose a url.
294 * @param array $params
295 * List of parameters.
300 static function crmURL($params) {
301 $p = CRM_Utils_Array
::value('p', $params);
303 $p = self
::currentPath();
308 CRM_Utils_Array
::value('q', $params),
309 CRM_Utils_Array
::value('a', $params, FALSE),
310 CRM_Utils_Array
::value('f', $params),
311 CRM_Utils_Array
::value('h', $params, TRUE),
312 CRM_Utils_Array
::value('fe', $params, FALSE),
313 CRM_Utils_Array
::value('fb', $params, FALSE)
318 * Sets the title of the page.
320 * @param string $title
321 * @param string $pageTitle
325 static function setTitle($title, $pageTitle = NULL) {
326 self
::$title = $title;
327 $config = CRM_Core_Config
::singleton();
328 return $config->userSystem
->setTitle($title, $pageTitle);
332 * Figures and sets the userContext.
334 * Uses the referer if valid else uses the default.
336 * @param array $names
337 * Refererer should match any str in this array.
338 * @param string $default
339 * (optional) The default userContext if no match found.
343 static function setUserContext($names, $default = NULL) {
346 $session = CRM_Core_Session
::singleton();
347 $referer = CRM_Utils_Array
::value('HTTP_REFERER', $_SERVER);
349 if ($referer && !empty($names)) {
350 foreach ($names as $name) {
351 if (strstr($referer, $name)) {
359 $session->pushUserContext($url);
364 * Gets a class name for an object.
366 * @param object $object
367 * Object whose class name is needed.
370 * The class name of the object.
374 static function getClassName($object) {
375 return get_class($object);
379 * Redirect to another URL.
382 * The URL to provide to the browser via the Location header.
386 static function redirect($url = NULL) {
388 $url = self
::url('civicrm/dashboard', 'reset=1');
391 // replace the & characters with &
392 // this is kinda hackish but not sure how to do it right
393 $url = str_replace('&', '&', $url);
394 header('Location: ' . $url);
399 * Redirect to another URL using JavaScript.
401 * Use an html based file with javascript embedded to redirect to another url
402 * This prevent the too many redirect errors emitted by various browsers
405 * (optional) The destination URL.
406 * @param string $title
407 * (optional) The page title to use for the redirect page.
408 * @param string $message
409 * (optional) The message to provide in the body of the redirect page.
413 static function jsRedirect(
419 $url = self
::url('civicrm/dashboard', 'reset=1');
423 $title = ts('CiviCRM task in progress');
427 $message = ts('A long running CiviCRM task is currently in progress. This message will be refreshed till the task is completed');
430 // replace the & characters with &
431 // this is kinda hackish but not sure how to do it right
432 $url = str_replace('&', '&', $url);
434 $template = CRM_Core_Smarty
::singleton();
435 $template->assign('redirectURL', $url);
436 $template->assign('title', $title);
437 $template->assign('message', $message);
439 $html = $template->fetch('CRM/common/redirectJS.tpl');
447 * Append an additional breadcrumb tag to the existing breadcrumbs.
449 * @param $breadCrumbs
453 static function appendBreadCrumb($breadCrumbs) {
454 $config = CRM_Core_Config
::singleton();
455 return $config->userSystem
->appendBreadCrumb($breadCrumbs);
459 * Reset an additional breadcrumb tag to the existing breadcrumb.
463 static function resetBreadCrumb() {
464 $config = CRM_Core_Config
::singleton();
465 return $config->userSystem
->resetBreadCrumb();
469 * Append a string to the head of the HTML file.
475 static function addHTMLHead($bc) {
476 $config = CRM_Core_Config
::singleton();
477 return $config->userSystem
->addHTMLHead($bc);
481 * Determine the post URL for a form
484 * The default action if one is pre-specified.
487 * The URL to post the form.
490 static function postURL($action) {
491 $config = CRM_Core_Config
::singleton();
492 return $config->userSystem
->postURL($action);
496 * Rewrite various system URLs to https.
500 static function mapConfigToSSL() {
501 $config = CRM_Core_Config
::singleton();
502 $config->userFrameworkResourceURL
= str_replace('http://', 'https://', $config->userFrameworkResourceURL
);
503 $config->resourceBase
= $config->userFrameworkResourceURL
;
505 if (! empty($config->extensionsURL
)) {
506 $config->extensionsURL
= str_replace('http://', 'https://', $config->extensionsURL
);
509 return $config->userSystem
->mapConfigToSSL();
513 * Get the base URL of the system.
518 static function baseURL() {
519 $config = CRM_Core_Config
::singleton();
520 return $config->userFrameworkBaseURL
;
525 static function authenticateAbort($message, $abort) {
537 * (optional) Whether to exit; defaults to true.
539 static function authenticateKey($abort = TRUE) {
540 // also make sure the key is sent and is valid
541 $key = trim(CRM_Utils_Array
::value('key', $_REQUEST));
543 $docAdd = "More info at:" . CRM_Utils_System
::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
546 return self
::authenticateAbort(
547 "ERROR: You need to send a valid key to execute this file. " . $docAdd . "\n",
552 $siteKey = defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY
: NULL;
554 if (!$siteKey ||
empty($siteKey)) {
555 return self
::authenticateAbort(
556 "ERROR: You need to set a valid site key in civicrm.settings.php. " . $docAdd . "\n",
561 if (strlen($siteKey) < 8) {
562 return self
::authenticateAbort(
563 "ERROR: Site key needs to be greater than 7 characters in civicrm.settings.php. " . $docAdd . "\n",
568 if ($key !== $siteKey) {
569 return self
::authenticateAbort(
570 "ERROR: Invalid key value sent. " . $docAdd . "\n",
581 static function authenticateScript($abort = TRUE, $name = NULL, $pass = NULL, $storeInSession = TRUE, $loadCMSBootstrap = TRUE, $requireKey = TRUE) {
582 // auth to make sure the user has a login/password to do a shell operation
583 // later on we'll link this to acl's
585 $name = trim(CRM_Utils_Array
::value('name', $_REQUEST));
586 $pass = trim(CRM_Utils_Array
::value('pass', $_REQUEST));
589 // its ok to have an empty password
591 return self
::authenticateAbort(
592 "ERROR: You need to send a valid user name and password to execute this file\n",
597 if ($requireKey && !self
::authenticateKey($abort)) {
601 $result = CRM_Utils_System
::authenticate($name, $pass, $loadCMSBootstrap);
603 return self
::authenticateAbort(
604 "ERROR: Invalid username and/or password\n",
608 elseif ($storeInSession) {
609 // lets store contact id and user id in session
610 list($userID, $ufID, $randomNumber) = $result;
611 if ($userID && $ufID) {
612 $config = CRM_Core_Config
::singleton();
613 $config->userSystem
->setUserSession( array($userID, $ufID) );
616 return self
::authenticateAbort(
617 "ERROR: Unexpected error, could not match userID and contactID",
627 * Authenticate the user against the uf db.
629 * In case of succesful authentication, returns an array consisting of
630 * (contactID, ufID, unique string). Returns FALSE if authentication is
633 * @param string $name
635 * @param string $password
637 * @param bool $loadCMSBootstrap
640 * @return false|array
643 static function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realPath = NULL) {
644 $config = CRM_Core_Config
::singleton();
646 /* Before we do any loading, let's start the session and write to it.
647 * We typically call authenticate only when we need to bootstrap the CMS
648 * directly via Civi and hence bypass the normal CMS auth and bootstrap
649 * process typically done in CLI and cron scripts. See: CRM-12648
651 $session = CRM_Core_Session
::singleton();
652 $session->set( 'civicrmInitSession', TRUE );
654 $dbDrupal = DB
::connect($config->userFrameworkDSN
);
655 return $config->userSystem
->authenticate($name, $password, $loadCMSBootstrap, $realPath);
659 * Set a message in the UF to display to a user.
661 * @param string $message
662 * The message to set.
666 static function setUFMessage($message) {
667 $config = CRM_Core_Config
::singleton();
668 return $config->userSystem
->setMessage($message);
673 * Determine whether a value is null-ish.
676 * The value to check for null.
679 static function isNull($value) {
680 // FIXME: remove $value = 'null' string test when we upgrade our DAO code to handle passing null in a better way.
681 if (!isset($value) ||
$value === NULL ||
$value === '' ||
$value === 'null') {
684 if (is_array($value)) {
685 foreach ($value as $key => $value) {
686 if (!self
::isNull($value)) {
696 * Obscure all but the last few digits of a credit card number.
698 * @param string $number
699 * The credit card number to obscure.
701 * (optional) The number of digits to preserve unmodified.
703 * The obscured credit card number.
705 static function mungeCreditCard($number, $keep = 4) {
706 $number = trim($number);
707 if (empty($number)) {
710 $replace = str_repeat('*', strlen($number) - $keep);
711 return substr_replace($number, $replace, 0, -$keep);
715 * Determine which PHP modules are loaded.
719 public static function parsePHPModules() {
721 phpinfo(INFO_MODULES
);
722 $s = ob_get_contents();
725 $s = strip_tags($s, '<h2><th><td>');
726 $s = preg_replace('/<th[^>]*>([^<]+)<\/th>/', "<info>\\1</info>", $s);
727 $s = preg_replace('/<td[^>]*>([^<]+)<\/td>/', "<info>\\1</info>", $s);
728 $vTmp = preg_split('/(<h2>[^<]+<\/h2>)/', $s, -1, PREG_SPLIT_DELIM_CAPTURE
);
730 for ($i = 1; $i < count($vTmp); $i++
) {
731 if (preg_match('/<h2>([^<]+)<\/h2>/', $vTmp[$i], $vMat)) {
732 $vName = trim($vMat[1]);
733 $vTmp2 = explode("\n", $vTmp[$i +
1]);
734 foreach ($vTmp2 AS $vOne) {
735 $vPat = '<info>([^<]+)<\/info>';
736 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
737 $vPat2 = "/$vPat\s*$vPat/";
739 if (preg_match($vPat3, $vOne, $vMat)) {
740 $vModules[$vName][trim($vMat[1])] = array(trim($vMat[2]), trim($vMat[3]));
743 elseif (preg_match($vPat2, $vOne, $vMat)) {
744 $vModules[$vName][trim($vMat[1])] = trim($vMat[2]);
753 * Get a setting from a loaded PHP module.
755 public static function getModuleSetting($pModuleName, $pSetting) {
756 $vModules = self
::parsePHPModules();
757 return $vModules[$pModuleName][$pSetting];
764 static function memory($title = NULL) {
767 $pid = posix_getpid();
770 $memory = str_replace("\n", '', shell_exec("ps -p" . $pid . " -o rss="));
771 $memory .= ", " . time();
773 CRM_Core_Error
::debug_var($title, $memory);
779 * @param string $name
780 * @param string $mimeType
783 * @param bool $output
785 static function download($name, $mimeType, &$buffer,
789 $now = gmdate('D, d M Y H:i:s') . ' GMT';
791 header('Content-Type: ' . $mimeType);
792 header('Expires: ' . $now);
794 // lem9 & loic1: IE need specific headers
795 $isIE = strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE');
797 $fileString = "filename=\"{$name}.{$ext}\"";
800 $fileString = "filename=\"{$name}\"";
803 header("Content-Disposition: inline; $fileString");
804 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
805 header('Pragma: public');
808 header("Content-Disposition: attachment; $fileString");
809 header('Pragma: no-cache');
819 * Gather and print (and possibly log) amount of used memory.
821 * @param string $title
823 * (optional) Whether to log the memory usage information.
825 static function xMemory($title = NULL, $log = FALSE) {
826 $mem = (float ) xdebug_memory_usage() / (float )(1024);
827 $mem = number_format($mem, 5) . ", " . time();
829 echo "<p>$title: $mem<p>";
831 CRM_Core_Error
::debug_var($title, $mem);
834 echo "<p>$title: $mem<p>";
840 * Take a URL (or partial URL) and make it better.
842 * Currently, URLs pass straight through unchanged unless they are "seriously
843 * malformed" (see http://us2.php.net/parse_url).
846 * The URL to operate on.
850 static function fixURL($url) {
851 $components = parse_url($url);
857 // at some point we'll add code here to make sure the url is not
858 // something that will mess up up, so we need to clean it up here
863 * Make sure a callback is valid in the current context.
865 * @param string $callback
866 * Name of the function to check.
870 static function validCallback($callback) {
871 if (self
::$_callbacks === NULL) {
872 self
::$_callbacks = array();
875 if (!array_key_exists($callback, self
::$_callbacks)) {
876 if (strpos($callback, '::') !== FALSE) {
877 list($className, $methodName) = explode('::', $callback);
878 $fileName = str_replace('_', DIRECTORY_SEPARATOR
, $className) . '.php';
879 // ignore errors if any
880 @include_once
($fileName);
881 if (!class_exists($className)) {
882 self
::$_callbacks[$callback] = FALSE;
885 // instantiate the class
886 $object = new $className();
887 if (!method_exists($object, $methodName)) {
888 self
::$_callbacks[$callback] = FALSE;
891 self
::$_callbacks[$callback] = TRUE;
896 self
::$_callbacks[$callback] = function_exists($callback);
899 return self
::$_callbacks[$callback];
903 * Like PHP's built-in explode(), but always return an array of $limit items.
905 * This serves as a wrapper to the PHP explode() function. In the event that
906 * PHP's explode() returns an array with fewer than $limit elements, pad
907 * the end of the array with NULLs.
909 * @param string $separator
910 * @param string $string
914 static function explode($separator, $string, $limit) {
915 $result = explode($separator, $string, $limit);
916 for ($i = count($result); $i < $limit; $i++
) {
925 * @param bool $addCookie
928 static function checkURL($url, $addCookie = FALSE) {
929 // make a GET request to $url
930 $ch = curl_init($url);
932 curl_setopt($ch, CURLOPT_COOKIE
, http_build_query($_COOKIE));
934 // it's quite alright to use a self-signed cert
935 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER
, 0);
937 // lets capture the return stuff rather than echo
938 curl_setopt($ch, CURLOPT_RETURNTRANSFER
, true );
940 return curl_exec($ch);
944 * Assert that we are running on a particular PHP version.
947 * The major version of PHP that is required.
949 * (optional) Whether to fatally abort if the version requirement is not
950 * met. Defaults to TRUE.
952 * Returns TRUE if the requirement is met, FALSE if the requirement is not
953 * met and we're not aborting due to the failed requirement. If $abort is
954 * TRUE and the requirement fails, this function does not return.
956 static function checkPHPVersion($ver = 5, $abort = TRUE) {
957 $phpVersion = substr(PHP_VERSION
, 0, 1);
958 if ($phpVersion >= $ver) {
963 CRM_Core_Error
::fatal(ts('This feature requires PHP Version %1 or greater',
973 static function formatWikiURL($string, $encode = FALSE) {
974 $items = explode(' ', trim($string), 2);
975 if (count($items) == 2) {
983 $url = $encode ? self
::urlEncode($items[0]) : $items[0];
984 return "<a href=\"$url\">$title</a>";
990 static function urlEncode($url) {
991 $items = parse_url($url);
992 if ($items === FALSE) {
996 if (empty($items['query'])) {
1000 $items['query'] = urlencode($items['query']);
1002 $url = $items['scheme'] . '://';
1003 if (!empty($items['user'])) {
1004 $url .= "{$items['user']}:{$items['pass']}@";
1007 $url .= $items['host'];
1008 if (!empty($items['port'])) {
1009 $url .= ":{$items['port']}";
1012 $url .= "{$items['path']}?{$items['query']}";
1013 if (!empty($items['fragment'])) {
1014 $url .= "#{$items['fragment']}";
1021 * Return the running civicrm version.
1027 static function version() {
1031 $verFile = implode(DIRECTORY_SEPARATOR
,
1032 array(dirname(__FILE__
), '..', '..', 'civicrm-version.php')
1034 if (file_exists($verFile)) {
1035 require_once ($verFile);
1036 if (function_exists('civicrmVersion')) {
1037 $info = civicrmVersion();
1038 $version = $info['version'];
1042 // svn installs don't have version.txt by default. In that case version.xml should help -
1043 $verFile = implode(DIRECTORY_SEPARATOR
,
1044 array(dirname(__FILE__
), '..', '..', 'xml', 'version.xml')
1046 if (file_exists($verFile)) {
1047 $str = file_get_contents($verFile);
1048 $xmlObj = simplexml_load_string($str);
1049 $version = (string) $xmlObj->version_no
;
1054 if (!CRM_Utils_System
::isVersionFormatValid($version)) {
1055 CRM_Core_Error
::fatal('Unknown codebase version.');
1063 * Determines whether a string is a valid CiviCRM version string.
1065 * @param string $version
1066 * Version string to be checked.
1069 static function isVersionFormatValid($version) {
1070 return preg_match("/^(\d{1,2}\.){2,3}(\d{1,2}|(alpha|beta)\d{1,2})(\.upgrade)?$/", $version);
1074 * Wraps or emulates PHP's getallheaders() function.
1076 static function getAllHeaders() {
1077 if (function_exists('getallheaders')) {
1078 return getallheaders();
1081 // emulate get all headers
1082 // http://www.php.net/manual/en/function.getallheaders.php#66335
1084 foreach ($_SERVER as $name => $value) {
1085 if (substr($name, 0, 5) == 'HTTP_') {
1086 $headers[str_replace(' ',
1088 ucwords(strtolower(str_replace('_',
1101 static function getRequestHeaders() {
1102 if (function_exists('apache_request_headers')) {
1103 return apache_request_headers();
1111 * Determine whether this is an SSL request.
1113 * Note that we inline this function in install/civicrm.php, so if you change
1114 * this function, please go and change the code in the install script as well.
1116 static function isSSL( ) {
1118 (isset($_SERVER['HTTPS']) &&
1119 !empty($_SERVER['HTTPS']) &&
1120 strtolower($_SERVER['HTTPS']) != 'off') ?
true : false;
1125 static function redirectToSSL($abort = FALSE) {
1126 $config = CRM_Core_Config
::singleton();
1127 $req_headers = self
::getRequestHeaders();
1128 if (CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'enableSSL') &&
1130 strtolower(CRM_Utils_Array
::value('X_FORWARDED_PROTO', $req_headers)) != 'https'
1132 // ensure that SSL is enabled on a civicrm url (for cookie reasons etc)
1133 $url = "https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
1134 if (!self
::checkURL($url, TRUE)) {
1136 CRM_Core_Error
::fatal('HTTPS is not set up on this machine');
1139 CRM_Core_Session
::setStatus(ts('HTTPS is not set up on this machine'), ts('Warning'), 'alert');
1140 // admin should be the only one following this
1141 // since we dont want the user stuck in a bad place
1145 CRM_Utils_System
::redirect($url);
1150 * Get logged in user's IP address.
1152 * Get IP address from HTTP REMOTE_ADDR header. If the CMS is Drupal then use
1153 * the Drupal function as this also handles reverse proxies (based on proper
1154 * configuration in settings.php)
1156 * @param bool $strictIPV4
1157 * (optional) Whether to return only IPv4 addresses.
1160 * IP address of logged in user.
1162 static function ipAddress($strictIPV4 = TRUE) {
1163 $address = CRM_Utils_Array
::value('REMOTE_ADDR', $_SERVER);
1165 $config = CRM_Core_Config
::singleton();
1166 if ($config->userSystem
->is_drupal
) {
1167 //drupal function handles the server being behind a proxy securely
1168 $address = ip_address();
1172 if ($address == '::1') {
1173 $address = '127.0.0.1';
1176 // when we need to have strictly IPV4 ip address
1177 // convert ipV6 to ipV4
1179 // this converts 'IPV4 mapped IPV6 address' to IPV4
1180 if (filter_var($address, FILTER_VALIDATE_IP
, FILTER_FLAG_IPV6
) && strstr($address, '::ffff:')) {
1181 $address = ltrim($address, '::ffff:');
1189 * Get the referring / previous page URL.
1192 * The previous page URL
1195 static function refererPath() {
1196 return CRM_Utils_Array
::value('HTTP_REFERER', $_SERVER);
1200 * Get the documentation base URL.
1203 * Base URL of the CRM documentation.
1206 static function getDocBaseURL() {
1207 // FIXME: move this to configuration at some stage
1208 return 'http://book.civicrm.org/';
1212 * Returns wiki (alternate) documentation URL base.
1214 * @return string documentation url
1217 static function getWikiBaseURL() {
1218 // FIXME: move this to configuration at some stage
1219 return 'http://wiki.civicrm.org/confluence/display/CRMDOC/';
1223 * Returns URL or link to documentation page, based on provided parameters.
1225 * For use in PHP code.
1226 * WARNING: Always returns URL, if ts function is not defined ($URLonly has
1229 * @param string $page
1230 * Title of documentation wiki page.
1231 * @param boolean $URLonly
1232 * (optional) Whether to return URL only or full HTML link (default).
1233 * @param string $text
1234 * (optional) Text of HTML link (no effect if $URLonly = false).
1235 * @param string $title
1236 * (optional) Tooltip text for HTML link (no effect if $URLonly = false)
1237 * @param string $style
1238 * (optional) Style attribute value for HTML link (no effect if $URLonly = false)
1241 * URL or link to documentation page, based on provided parameters.
1244 static function docURL2($page, $URLonly = FALSE, $text = NULL, $title = NULL, $style = NULL, $resource = NULL) {
1245 // if ts function doesn't exist, it means that CiviCRM hasn't been fully initialised yet -
1246 // return just the URL, no matter what other parameters are defined
1247 if (!function_exists('ts')) {
1248 if ($resource == 'wiki') {
1249 $docBaseURL = self
::getWikiBaseURL();
1251 $docBaseURL = self
::getDocBaseURL();
1253 return $docBaseURL . str_replace(' ', '+', $page);
1258 'URLonly' => $URLonly,
1262 'resource' => $resource,
1264 return self
::docURL($params);
1269 * Returns URL or link to documentation page, based on provided parameters.
1271 * For use in templates code.
1273 * @param array $params
1274 * An array of parameters (see CRM_Utils_System::docURL2 method for names)
1277 * URL or link to documentation page, based on provided parameters.
1280 static function docURL($params) {
1282 if (!isset($params['page'])) {
1286 if (CRM_Utils_Array
::value('resource', $params) == 'wiki') {
1287 $docBaseURL = self
::getWikiBaseURL();
1289 $docBaseURL = self
::getDocBaseURL();
1292 if (!isset($params['title']) or $params['title'] === NULL) {
1293 $params['title'] = ts('Opens documentation in a new window.');
1296 if (!isset($params['text']) or $params['text'] === NULL) {
1297 $params['text'] = ts('(learn more...)');
1300 if (!isset($params['style']) ||
$params['style'] === NULL) {
1304 $style = "style=\"{$params['style']}\"";
1307 $link = $docBaseURL . str_replace(' ', '+', $params['page']);
1309 if (isset($params['URLonly']) && $params['URLonly'] == TRUE) {
1313 return "<a href=\"{$link}\" $style target=\"_blank\" title=\"{$params['title']}\">{$params['text']}</a>";
1318 * Get the locale set in the hosting CMS
1321 * The used locale or null for none.
1323 static function getUFLocale() {
1324 $config = CRM_Core_Config
::singleton();
1325 return $config->userSystem
->getUFLocale();
1329 * Execute external or internal URLs and return server response.
1331 * @param string $url
1333 * @param bool $addCookie
1334 * Whether to provide a cookie. Should be true to access internal URLs.
1337 * Response from URL.
1339 static function getServerResponse($url, $addCookie = TRUE) {
1340 CRM_Core_Error
::ignoreException();
1341 require_once 'HTTP/Request.php';
1342 $request = new HTTP_Request($url);
1345 foreach ($_COOKIE as $name => $value) {
1346 $request->addCookie($name, $value);
1350 if (isset($_SERVER['AUTH_TYPE'])) {
1351 $request->setBasicAuth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
1354 $config = CRM_Core_Config
::singleton();
1355 if ($config->userFramework
== 'WordPress') {
1356 session_write_close();
1359 $request->sendRequest();
1360 $response = $request->getResponseBody();
1362 CRM_Core_Error
::setCallback();
1368 static function isDBVersionValid(&$errorMessage) {
1369 $dbVersion = CRM_Core_BAO_Domain
::version();
1372 // if db.ver missing
1373 $errorMessage = ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.');
1376 elseif (!CRM_Utils_System
::isVersionFormatValid($dbVersion)) {
1377 $errorMessage = ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.');
1380 elseif (stripos($dbVersion, 'upgrade')) {
1381 // if db.ver indicates a partially upgraded db
1382 $upgradeUrl = CRM_Utils_System
::url("civicrm/upgrade", "reset=1");
1383 $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));
1387 $codeVersion = CRM_Utils_System
::version();
1389 // if db.ver < code.ver, time to upgrade
1390 if (version_compare($dbVersion, $codeVersion) < 0) {
1391 $upgradeUrl = CRM_Utils_System
::url("civicrm/upgrade", "reset=1");
1392 $errorMessage = ts('New codebase version detected. You might want to visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl));
1396 // if db.ver > code.ver, sth really wrong
1397 if (version_compare($dbVersion, $codeVersion) > 0) {
1398 $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.',
1399 array(1 => $dbVersion, 2 => $codeVersion)
1401 $errorMessage .= "<p>" . ts('OR if this is a manual install from git, you might want to fix civicrm-version.php file.') . "</p>";
1405 // FIXME: there should be another check to make sure version is in valid format - X.Y.alpha_num
1411 * Exit with provided exit code.
1413 * @param int $status
1414 * (optional) Code with which to exit.
1416 static function civiExit($status = 0) {
1417 // move things to CiviCRM cache as needed
1418 CRM_Core_Session
::storeSessionObjects();
1424 * Reset the various system caches and some important static variables.
1426 static function flushCache( ) {
1427 // flush out all cache entries so we can reload new data
1428 // a bit aggressive, but livable for now
1429 $cache = CRM_Utils_Cache
::singleton();
1432 // also reset the various static memory caches
1434 // reset the memory or array cache
1435 CRM_Core_BAO_Cache
::deleteGroup('contact fields', NULL, FALSE);
1438 CRM_ACL_BAO_Cache
::resetCache();
1440 // reset various static arrays used here
1441 CRM_Contact_BAO_Contact
::$_importableFields =
1442 CRM_Contact_BAO_Contact
::$_exportableFields =
1443 CRM_Contribute_BAO_Contribution
::$_importableFields =
1444 CRM_Contribute_BAO_Contribution
::$_exportableFields =
1445 CRM_Pledge_BAO_Pledge
::$_exportableFields =
1446 CRM_Contribute_BAO_Query
::$_contributionFields =
1447 CRM_Core_BAO_CustomField
::$_importFields =
1448 CRM_Core_BAO_Cache
::$_cache =
1449 CRM_Core_DAO
::$_dbColumnValueCache = NULL;
1451 CRM_Core_OptionGroup
::flushAll();
1452 CRM_Utils_PseudoConstant
::flushAll();
1456 * Load CMS bootstrap.
1458 * @param array $params
1459 * Array with uid name and pass
1460 * @param bool $loadUser
1461 * Boolean load user or not.
1462 * @param bool $throwError
1465 static function loadBootStrap($params = array(
1466 ), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) {
1467 if (!is_array($params)) {
1470 $config = CRM_Core_Config
::singleton();
1471 return $config->userSystem
->loadBootStrap($params, $loadUser, $throwError, $realPath);
1475 * Check if user is logged in.
1479 public static function isUserLoggedIn() {
1480 $config = CRM_Core_Config
::singleton();
1481 return $config->userSystem
->isUserLoggedIn();
1485 * Get current logged in user id.
1488 * ufId, currently logged in user uf id.
1490 public static function getLoggedInUfID() {
1491 $config = CRM_Core_Config
::singleton();
1492 return $config->userSystem
->getLoggedInUfID();
1497 static function baseCMSURL() {
1498 static $_baseURL = NULL;
1500 $config = CRM_Core_Config
::singleton();
1501 $_baseURL = $userFrameworkBaseURL = $config->userFrameworkBaseURL
;
1503 if ($config->userFramework
== 'Joomla') {
1505 // we need to remove the administrator/ from the end
1506 $_baseURL = str_replace("/administrator/", "/", $userFrameworkBaseURL);
1510 global $civicrm_root;
1511 if (strpos($civicrm_root,
1512 DIRECTORY_SEPARATOR
. 'sites' .
1513 DIRECTORY_SEPARATOR
. 'all' .
1514 DIRECTORY_SEPARATOR
. 'modules'
1516 $startPos = strpos($civicrm_root,
1517 DIRECTORY_SEPARATOR
. 'sites' . DIRECTORY_SEPARATOR
1519 $endPos = strpos($civicrm_root,
1520 DIRECTORY_SEPARATOR
. 'modules' . DIRECTORY_SEPARATOR
1522 if ($startPos && $endPos) {
1523 // if component is in sites/SITENAME/modules
1524 $siteName = substr($civicrm_root,
1526 $endPos - $startPos - 7
1529 $_baseURL = $userFrameworkBaseURL . "sites/$siteName/";
1538 * Given a URL, return a relative URL if possible.
1540 * @param string $url
1543 static function relativeURL($url) {
1544 // check if url is relative, if so return immediately
1545 if (substr($url, 0, 4) != 'http') {
1549 // make everything relative from the baseFilePath
1550 $baseURL = self
::baseCMSURL();
1552 // check if baseURL is a substr of $url, if so
1553 // return rest of string
1554 if (substr($url, 0, strlen($baseURL)) == $baseURL) {
1555 return substr($url, strlen($baseURL));
1558 // return the original value
1563 * Produce an absolute URL from a possibly-relative URL.
1565 * @param string $url
1566 * @param bool $remoteLanguagePart
1569 static function absoluteURL($url, $removeLanguagePart = FALSE) {
1570 // check if url is already absolute, if so return immediately
1571 if (substr($url, 0, 4) == 'http') {
1575 // make everything absolute from the baseFileURL
1576 $baseURL = self
::baseCMSURL();
1578 //CRM-7622: drop the language from the URL if requested (and it’s there)
1579 $config = CRM_Core_Config
::singleton();
1580 if ($removeLanguagePart) {
1581 $baseURL = self
::languageNegotiationURL($baseURL, FALSE, TRUE);
1584 return $baseURL . $url;
1588 * Function to clean url, replaces first '&' with '?'
1590 * @param string $url
1592 * @return string $url, clean url
1594 static function cleanUrl($url) {
1599 if ($pos = strpos($url, '&')) {
1600 $url = substr_replace($url, '?', $pos, 1);
1607 * Format the url as per language Negotiation.
1609 * @param string $url
1611 * @return string $url, formatted url.
1613 static function languageNegotiationURL($url,
1614 $addLanguagePart = TRUE,
1615 $removeLanguagePart = FALSE
1617 $config = &CRM_Core_Config
::singleton();
1618 return $config->userSystem
->languageNegotiationURL($url, $addLanguagePart, $removeLanguagePart);
1622 * Append the contents of an 'extra' smarty template file if it is present in
1623 * the custom template directory. This does not work if there are
1624 * multiple custom template directories
1626 * @param string $fileName
1627 * The name of the tpl file that we are processing.
1628 * @param string $content
1629 * The current content string. May be modified by this function.
1630 * @param string $overideFileName
1631 * (optional) Sent by contribution/event reg/profile pages which uses a id
1632 * specific extra file name if present.
1634 static function appendTPLFile($fileName,
1636 $overideFileName = NULL
1638 $template = CRM_Core_Smarty
::singleton();
1639 if ($overideFileName) {
1640 $additionalTPLFile = $overideFileName;
1643 $additionalTPLFile = str_replace('.tpl', '.extra.tpl', $fileName);
1646 if ($template->template_exists($additionalTPLFile)) {
1647 $content .= $template->fetch($additionalTPLFile);
1652 * Get a list of all files that are found within the directories
1653 * that are the result of appending the provided relative path to
1654 * each component of the PHP include path.
1656 * @author Ken Zalewski
1658 * @param string $relpath
1659 * A relative path, typically pointing to a directory with multiple class
1663 * An array of files that exist in one or more of the directories that are
1664 * referenced by the relative path when appended to each element of the PHP
1668 static function listIncludeFiles($relpath) {
1669 $file_list = array();
1670 $inc_dirs = explode(PATH_SEPARATOR
, get_include_path());
1671 foreach ($inc_dirs as $inc_dir) {
1672 $target_dir = $inc_dir . DIRECTORY_SEPARATOR
. $relpath;
1673 if (is_dir($target_dir)) {
1674 $cur_list = scandir($target_dir);
1675 foreach ($cur_list as $fname) {
1676 if ($fname != '.' && $fname != '..') {
1677 $file_list[$fname] = $fname;
1684 // listIncludeFiles()
1687 * Get a list of all "plugins" (PHP classes that implement a piece of
1688 * functionality using a well-defined interface) that are found in a
1689 * particular CiviCRM directory (both custom and core are searched).
1691 * @author Ken Zalewski
1693 * @param string $relpath
1694 * A relative path referencing a directory that contains one or more
1696 * @param string $fext
1697 * (optional) Only files with this extension will be considered to be
1699 * @param array $skipList
1700 * (optional) List of files to skip.
1703 * List of plugins, where the plugin name is both the key and the value of
1707 static function getPluginList($relpath, $fext = '.php', $skipList = array(
1709 $fext_len = strlen($fext);
1711 $inc_files = CRM_Utils_System
::listIncludeFiles($relpath);
1712 foreach ($inc_files as $inc_file) {
1713 if (substr($inc_file, 0 - $fext_len) == $fext) {
1714 $plugin_name = substr($inc_file, 0, 0 - $fext_len);
1715 if (!in_array($plugin_name, $skipList)) {
1716 $plugins[$plugin_name] = $plugin_name;
1727 static function executeScheduledJobs() {
1728 $facility = new CRM_Core_JobManager();
1729 $facility->execute(FALSE);
1731 $redirectUrl = self
::url('civicrm/admin/job', 'reset=1');
1733 CRM_Core_Session
::setStatus(
1734 ts('Scheduled jobs have been executed according to individual timing settings. Please check log for messages.'),
1735 ts('Complete'), 'success');
1737 CRM_Utils_System
::redirect($redirectUrl);
1741 * Evaluate any tokens in a URL.
1743 * @param string|FALSE $url
1744 * @return string|FALSE
1746 public static function evalUrl($url) {
1747 if ($url === FALSE) {
1751 $config = CRM_Core_Config
::singleton();
1753 '{ver}' => CRM_Utils_System
::version(),
1754 '{uf}' => $config->userFramework
,
1755 '{php}' => phpversion(),
1756 '{sid}' => md5('sid_' . (defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY
: '') . '_' . $config->userFrameworkBaseURL
),
1757 '{baseUrl}' => $config->userFrameworkBaseURL
,
1758 '{lang}' => $config->lcMessages
,
1759 '{co}' => $config->defaultContactCountry
,
1761 foreach (array_keys($vars) as $k) {
1762 $vars[$k] = urlencode($vars[$k]);
1764 return strtr($url, $vars);
1770 * Determine whether this is a developmental system.
1774 static function isDevelopment() {
1775 static $cache = NULL;
1776 if ($cache === NULL) {
1777 global $civicrm_root;
1778 $cache = file_exists("{$civicrm_root}/.svn") ||
file_exists("{$civicrm_root}/.git");