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 * 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)
50 * @param boolean $includeReset - should we include or ignore the reset GET string (if present)
51 * @param boolean $includeForce - should we include or ignore the force GET string (if present)
52 * @param string $path - the path to use for the new url
53 * @param string $absolute - do we need a absolute or relative URL?
55 * @return string the url fragment
58 static function makeURL($urlVar, $includeReset = FALSE, $includeForce = TRUE, $path = NULL, $absolute = FALSE) {
60 $config = CRM_Core_Config
::singleton();
61 $path = CRM_Utils_Array
::value($config->userFrameworkURLVar
, $_GET);
70 CRM_Utils_System
::getLinksUrl($urlVar, $includeReset, $includeForce),
76 * get the query string and clean it up. Strip some variables that should not
77 * be propagated, specically variable like 'reset'. Also strip any side-affect
78 * actions (i.e. export)
80 * This function is copied mostly verbatim from Pager.php (_getLinksUrl)
82 * @param string $urlVar the url variable being considered (i.e. crmPageID, crmSortID etc)
83 * @param boolean $includeReset should we include the reset var (generally this variable should be skipped)
88 static function getLinksUrl($urlVar, $includeReset = FALSE, $includeForce = TRUE, $skipUFVar = TRUE) {
89 // Sort out query string to prevent messy urls
90 $querystring = array();
94 if (!empty($_SERVER['QUERY_STRING'])) {
95 $qs = explode('&', str_replace('&', '&', $_SERVER['QUERY_STRING']));
96 for ($i = 0, $cnt = count($qs); $i < $cnt; $i++
) {
97 // check first if exist a pair
98 if (strstr($qs[$i], '=') !== FALSE) {
99 list($name, $value) = explode('=', $qs[$i]);
100 if ($name != $urlVar) {
101 $name = rawurldecode($name);
102 //check for arrays in parameters: site.php?foo[]=1&foo[]=2&foo[]=3
103 if ((strpos($name, '[') !== FALSE) &&
104 (strpos($name, ']') !== FALSE)
124 unset($qs['snippet']);
125 unset($qs['section']);
128 $config = CRM_Core_Config
::singleton();
129 unset($qs[$config->userFrameworkURLVar
]);
132 foreach ($qs as $name => $value) {
133 if ($name != 'reset' ||
$includeReset) {
134 $querystring[] = $name . '=' . $value;
138 $querystring = array_merge($querystring, array_unique($arrays));
139 $querystring = array_map('htmlentities', $querystring);
141 $url = implode('&', $querystring);
143 $url .= (!empty($querystring) ?
'&' : '') . $urlVar . '=';
150 * if we are using a theming system, invoke theme, else just print the
153 * @param string $content the content that will be themed
154 * @param boolean $print are we displaying to the screen or bypassing theming?
155 * @param boolean $maintenance for maintenance mode
157 * @return void prints content on stdout
161 static function theme(
166 $config = &CRM_Core_Config
::singleton();
167 return $config->userSystem
->theme($content, $print, $maintenance);
171 * Generate a query string if input is an array
173 * @param mixed $query: array or string
178 static function makeQueryString($query) {
179 if (is_array($query)) {
181 foreach ($query as $key => $value) {
182 $buf .= ($buf ?
'&' : '') . urlencode($key) . '=' . urlencode($value);
190 * Generate an internal CiviCRM URL
192 * @param $path string The path being linked to, such as "civicrm/add"
193 * @param $query mixed A query string to append to the link, or an array of key-value pairs
194 * @param $absolute boolean Whether to force the output to be an absolute link (beginning with http:).
195 * Useful for links that will be displayed outside the site, such as in an
197 * @param $fragment string A fragment identifier (named anchor) to append to the link.
199 * @return string an HTML string containing a link to the given path.
210 $forceBackend = FALSE
212 $query = self
::makeQueryString($query);
214 // we have a valid query and it has not yet been transformed
215 if ($htmlize && !empty($query) && strpos($query, '&') === FALSE) {
216 $query = htmlentities($query);
219 $config = CRM_Core_Config
::singleton();
220 return $config->userSystem
->url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
223 static function href($text, $path = NULL, $query = NULL, $absolute = TRUE,
224 $fragment = NULL, $htmlize = TRUE, $frontend = FALSE, $forceBackend = FALSE
226 $url = self
::url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
227 return "<a href=\"$url\">$text</a>";
230 static function permissionDenied() {
231 $config = CRM_Core_Config
::singleton();
232 return $config->userSystem
->permissionDenied();
235 static function logout() {
236 $config = CRM_Core_Config
::singleton();
237 return $config->userSystem
->logout();
240 // this is a very drupal specific function for now
241 static function updateCategories() {
242 $config = CRM_Core_Config
::singleton();
243 if ($config->userSystem
->is_drupal
) {
244 $config->userSystem
->updateCategories();
249 * What menu path are we currently on. Called for the primary tpl
251 * @return string the current menu path
254 static function currentPath() {
255 $config = CRM_Core_Config
::singleton();
256 return trim(CRM_Utils_Array
::value($config->userFrameworkURLVar
, $_GET), '/');
260 * this function is called from a template to compose a url
262 * @param array $params list of parameters
268 static function crmURL($params) {
269 $p = CRM_Utils_Array
::value('p', $params);
271 $p = self
::currentPath();
276 CRM_Utils_Array
::value('q', $params),
277 CRM_Utils_Array
::value('a', $params, FALSE),
278 CRM_Utils_Array
::value('f', $params),
279 CRM_Utils_Array
::value('h', $params, TRUE),
280 CRM_Utils_Array
::value('fe', $params, FALSE),
281 CRM_Utils_Array
::value('fb', $params, FALSE)
286 * sets the title of the page
288 * @param string $title
289 * @param string $pageTitle
295 static function setTitle($title, $pageTitle = NULL) {
296 $config = CRM_Core_Config
::singleton();
297 return $config->userSystem
->setTitle($title, $pageTitle);
301 * figures and sets the userContext. Uses the referer if valid
302 * else uses the default
304 * @param array $names refererer should match any str in this array
305 * @param string $default the default userContext if no match found
310 static function setUserContext($names, $default = NULL) {
313 $session = CRM_Core_Session
::singleton();
314 $referer = CRM_Utils_Array
::value('HTTP_REFERER', $_SERVER);
316 if ($referer && !empty($names)) {
317 foreach ($names as $name) {
318 if (strstr($referer, $name)) {
326 $session->pushUserContext($url);
331 * gets a class name for an object
333 * @param object $object - object whose class name is needed
335 * @return string $className - class name
340 static function getClassName($object) {
341 return get_class($object);
345 * redirect to another url
347 * @param string $url the url to goto
353 static function redirect($url = NULL) {
355 $url = self
::url('civicrm/dashboard', 'reset=1');
358 // replace the & characters with &
359 // this is kinda hackish but not sure how to do it right
360 $url = str_replace('&', '&', $url);
361 header('Location: ' . $url);
366 * use a html based file with javascript embedded to redirect to another url
367 * This prevent the too many redirect errors emitted by various browsers
369 * @param string $url the url to goto
375 static function jsRedirect(
381 $url = self
::url('civicrm/dashboard', 'reset=1');
385 $title = ts('CiviCRM task in progress');
389 $message = ts('A long running CiviCRM task is currently in progress. This message will be refreshed till the task is completed');
392 // replace the & characters with &
393 // this is kinda hackish but not sure how to do it right
394 $url = str_replace('&', '&', $url);
396 $template = CRM_Core_Smarty
::singleton();
397 $template->assign('redirectURL', $url);
398 $template->assign('title', $title);
399 $template->assign('message', $message);
401 $html = $template->fetch('CRM/common/redirectJS.tpl');
409 * Append an additional breadcrumb tag to the existing breadcrumb
411 * @param string $title
418 static function appendBreadCrumb($breadCrumbs) {
419 $config = CRM_Core_Config
::singleton();
420 return $config->userSystem
->appendBreadCrumb($breadCrumbs);
424 * Reset an additional breadcrumb tag to the existing breadcrumb
430 static function resetBreadCrumb() {
431 $config = CRM_Core_Config
::singleton();
432 return $config->userSystem
->resetBreadCrumb();
436 * Append a string to the head of the html file
438 * @param string $head the new string to be appended
444 static function addHTMLHead($bc) {
445 $config = CRM_Core_Config
::singleton();
446 return $config->userSystem
->addHTMLHead($bc);
450 * figure out the post url for the form
452 * @param the default action if one is pre-specified
454 * @return string the url to post the form
458 static function postURL($action) {
459 $config = CRM_Core_Config
::singleton();
460 return $config->userSystem
->postURL($action);
464 * rewrite various system urls to https
470 static function mapConfigToSSL() {
471 $config = CRM_Core_Config
::singleton();
472 $config->userFrameworkResourceURL
= str_replace('http://', 'https://', $config->userFrameworkResourceURL
);
473 $config->resourceBase
= $config->userFrameworkResourceURL
;
475 if (! empty($config->extensionsURL
)) {
476 $config->extensionsURL
= str_replace('http://', 'https://', $config->extensionsURL
);
479 return $config->userSystem
->mapConfigToSSL();
483 * Get the base URL from the system
491 static function baseURL() {
492 $config = CRM_Core_Config
::singleton();
493 return $config->userFrameworkBaseURL
;
496 static function authenticateAbort($message, $abort) {
506 static function authenticateKey($abort = TRUE) {
507 // also make sure the key is sent and is valid
508 $key = trim(CRM_Utils_Array
::value('key', $_REQUEST));
510 $docAdd = "More info at:" . CRM_Utils_System
::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
513 return self
::authenticateAbort(
514 "ERROR: You need to send a valid key to execute this file. " . $docAdd . "\n",
519 $siteKey = defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY
: NULL;
521 if (!$siteKey ||
empty($siteKey)) {
522 return self
::authenticateAbort(
523 "ERROR: You need to set a valid site key in civicrm.settings.php. " . $docAdd . "\n",
528 if (strlen($siteKey) < 8) {
529 return self
::authenticateAbort(
530 "ERROR: Site key needs to be greater than 7 characters in civicrm.settings.php. " . $docAdd . "\n",
535 if ($key !== $siteKey) {
536 return self
::authenticateAbort(
537 "ERROR: Invalid key value sent. " . $docAdd . "\n",
545 static function authenticateScript($abort = TRUE, $name = NULL, $pass = NULL, $storeInSession = TRUE, $loadCMSBootstrap = TRUE, $requireKey = TRUE) {
546 // auth to make sure the user has a login/password to do a shell
548 // later on we'll link this to acl's
550 $name = trim(CRM_Utils_Array
::value('name', $_REQUEST));
551 $pass = trim(CRM_Utils_Array
::value('pass', $_REQUEST));
554 // its ok to have an empty password
556 return self
::authenticateAbort(
557 "ERROR: You need to send a valid user name and password to execute this file\n",
562 if ($requireKey && !self
::authenticateKey($abort)) {
566 $result = CRM_Utils_System
::authenticate($name, $pass, $loadCMSBootstrap);
568 return self
::authenticateAbort(
569 "ERROR: Invalid username and/or password\n",
573 elseif ($storeInSession) {
574 // lets store contact id and user id in session
575 list($userID, $ufID, $randomNumber) = $result;
576 if ($userID && $ufID) {
577 $config = CRM_Core_Config
::singleton();
578 $config->userSystem
->setUserSession( array($userID, $ufID) );
581 return self
::authenticateAbort(
582 "ERROR: Unexpected error, could not match userID and contactID",
592 * Authenticate the user against the uf db
594 * @param string $name the user name
595 * @param string $password the password for the above user name
597 * @return mixed false if no auth
599 contactID, ufID, unique string ) if success
603 static function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realPath = NULL) {
604 $config = CRM_Core_Config
::singleton();
606 // before we do any loading, lets start the session and write to it
607 // we typically call authenticate only when we need to bootstrap the CMS directly via Civi
608 // and hence bypass the normal CMS auth and bootstrap process
609 // typically done in cli and cron scripts
611 $session = CRM_Core_Session
::singleton();
612 $session->set( 'civicrmInitSession', TRUE );
614 $dbDrupal = DB
::connect($config->userFrameworkDSN
);
615 return $config->userSystem
->authenticate($name, $password, $loadCMSBootstrap, $realPath);
619 * Set a message in the UF to display to a user
621 * @param string $name the message to set
626 static function setUFMessage($message) {
627 $config = CRM_Core_Config
::singleton();
628 return $config->userSystem
->setMessage($message);
633 static function isNull($value) {
634 // FIXME: remove $value = 'null' string test when we upgrade our DAO code to handle passing null in a better way.
635 if (!isset($value) ||
$value === NULL ||
$value === '' ||
$value === 'null') {
638 if (is_array($value)) {
639 foreach ($value as $key => $value) {
640 if (!self
::isNull($value)) {
649 static function mungeCreditCard($number, $keep = 4) {
650 $number = trim($number);
651 if (empty($number)) {
654 $replace = str_repeat('*', strlen($number) - $keep);
655 return substr_replace($number, $replace, 0, -$keep);
658 /** parse php modules from phpinfo */
659 public static function parsePHPModules() {
661 phpinfo(INFO_MODULES
);
662 $s = ob_get_contents();
665 $s = strip_tags($s, '<h2><th><td>');
666 $s = preg_replace('/<th[^>]*>([^<]+)<\/th>/', "<info>\\1</info>", $s);
667 $s = preg_replace('/<td[^>]*>([^<]+)<\/td>/', "<info>\\1</info>", $s);
668 $vTmp = preg_split('/(<h2>[^<]+<\/h2>)/', $s, -1, PREG_SPLIT_DELIM_CAPTURE
);
670 for ($i = 1; $i < count($vTmp); $i++
) {
671 if (preg_match('/<h2>([^<]+)<\/h2>/', $vTmp[$i], $vMat)) {
672 $vName = trim($vMat[1]);
673 $vTmp2 = explode("\n", $vTmp[$i +
1]);
674 foreach ($vTmp2 AS $vOne) {
675 $vPat = '<info>([^<]+)<\/info>';
676 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
677 $vPat2 = "/$vPat\s*$vPat/";
679 if (preg_match($vPat3, $vOne, $vMat)) {
680 $vModules[$vName][trim($vMat[1])] = array(trim($vMat[2]), trim($vMat[3]));
683 elseif (preg_match($vPat2, $vOne, $vMat)) {
684 $vModules[$vName][trim($vMat[1])] = trim($vMat[2]);
692 /** get a module setting */
693 public static function getModuleSetting($pModuleName, $pSetting) {
694 $vModules = self
::parsePHPModules();
695 return $vModules[$pModuleName][$pSetting];
698 static function memory($title = NULL) {
701 $pid = posix_getpid();
704 $memory = str_replace("\n", '', shell_exec("ps -p" . $pid . " -o rss="));
705 $memory .= ", " . time();
707 CRM_Core_Error
::debug_var($title, $memory);
712 static function download($name, $mimeType, &$buffer,
716 $now = gmdate('D, d M Y H:i:s') . ' GMT';
718 header('Content-Type: ' . $mimeType);
719 header('Expires: ' . $now);
721 // lem9 & loic1: IE need specific headers
722 $isIE = strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE');
724 $fileString = "filename=\"{$name}.{$ext}\"";
727 $fileString = "filename=\"{$name}\"";
730 header("Content-Disposition: inline; $fileString");
731 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
732 header('Pragma: public');
735 header("Content-Disposition: attachment; $fileString");
736 header('Pragma: no-cache');
745 static function xMemory($title = NULL, $log = FALSE) {
746 $mem = (float ) xdebug_memory_usage() / (float )(1024);
747 $mem = number_format($mem, 5) . ", " . time();
749 echo "<p>$title: $mem<p>";
751 CRM_Core_Error
::debug_var($title, $mem);
754 echo "<p>$title: $mem<p>";
759 static function fixURL($url) {
760 $components = parse_url($url);
766 // at some point we'll add code here to make sure the url is not
767 // something that will mess up up, so we need to clean it up here
772 * make sure the callback is valid in the current context
774 * @param string $callback the name of the function
779 static function validCallback($callback) {
780 if (self
::$_callbacks === NULL) {
781 self
::$_callbacks = array();
784 if (!array_key_exists($callback, self
::$_callbacks)) {
785 if (strpos($callback, '::') !== FALSE) {
786 list($className, $methodName) = explode('::', $callback);
787 $fileName = str_replace('_', DIRECTORY_SEPARATOR
, $className) . '.php';
788 // ignore errors if any
789 @include_once
($fileName);
790 if (!class_exists($className)) {
791 self
::$_callbacks[$callback] = FALSE;
794 // instantiate the class
795 $object = new $className();
796 if (!method_exists($object, $methodName)) {
797 self
::$_callbacks[$callback] = FALSE;
800 self
::$_callbacks[$callback] = TRUE;
805 self
::$_callbacks[$callback] = function_exists($callback);
808 return self
::$_callbacks[$callback];
812 * This serves as a wrapper to the php explode function
813 * we expect exactly $limit arguments in return, and if we dont
814 * get them, we pad it with null
816 static function explode($separator, $string, $limit) {
817 $result = explode($separator, $string, $limit);
818 for ($i = count($result); $i < $limit; $i++
) {
824 static function checkURL($url, $addCookie = FALSE) {
825 // make a GET request to $url
826 $ch = curl_init($url);
828 curl_setopt($ch, CURLOPT_COOKIE
, http_build_query($_COOKIE));
830 // it's quite alright to use a self-signed cert
831 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER
, 0);
833 // lets capture the return stuff rather than echo
834 curl_setopt($ch, CURLOPT_RETURNTRANSFER
, true );
836 return curl_exec($ch);
839 static function checkPHPVersion($ver = 5, $abort = TRUE) {
840 $phpVersion = substr(PHP_VERSION
, 0, 1);
841 if ($phpVersion >= $ver) {
846 CRM_Core_Error
::fatal(ts('This feature requires PHP Version %1 or greater',
853 static function formatWikiURL($string, $encode = FALSE) {
854 $items = explode(' ', trim($string), 2);
855 if (count($items) == 2) {
863 $url = $encode ? self
::urlEncode($items[0]) : $items[0];
864 return "<a href=\"$url\">$title</a>";
867 static function urlEncode($url) {
868 $items = parse_url($url);
869 if ($items === FALSE) {
873 if (!CRM_Utils_Array
::value('query', $items)) {
877 $items['query'] = urlencode($items['query']);
879 $url = $items['scheme'] . '://';
880 if (CRM_Utils_Array
::value('user', $items)) {
881 $url .= "{$items['user']}:{$items['pass']}@";
884 $url .= $items['host'];
885 if (CRM_Utils_Array
::value('port', $items)) {
886 $url .= ":{$items['port']}";
889 $url .= "{$items['path']}?{$items['query']}";
890 if (CRM_Utils_Array
::value('fragment', $items)) {
891 $url .= "#{$items['fragment']}";
898 * Function to return the latest civicrm version.
900 * @return string civicrm version
903 static function version() {
907 $verFile = implode(DIRECTORY_SEPARATOR
,
908 array(dirname(__FILE__
), '..', '..', 'civicrm-version.php')
910 if (file_exists($verFile)) {
911 require_once ($verFile);
912 if (function_exists('civicrmVersion')) {
913 $info = civicrmVersion();
914 $version = $info['version'];
918 // svn installs don't have version.txt by default. In that case version.xml should help -
919 $verFile = implode(DIRECTORY_SEPARATOR
,
920 array(dirname(__FILE__
), '..', '..', 'xml', 'version.xml')
922 if (file_exists($verFile)) {
923 $str = file_get_contents($verFile);
924 $xmlObj = simplexml_load_string($str);
925 $version = (string) $xmlObj->version_no
;
930 if (!CRM_Utils_System
::isVersionFormatValid($version)) {
931 CRM_Core_Error
::fatal('Unknown codebase version.');
938 static function isVersionFormatValid($version) {
939 return preg_match("/^(\d{1,2}\.){2,3}(\d{1,2}|(alpha|beta)\d{1,2})(\.upgrade)?$/", $version);
942 static function getAllHeaders() {
943 if (function_exists('getallheaders')) {
944 return getallheaders();
947 // emulate get all headers
948 // http://www.php.net/manual/en/function.getallheaders.php#66335
950 foreach ($_SERVER as $name => $value) {
951 if (substr($name, 0, 5) == 'HTTP_') {
952 $headers[str_replace(' ',
954 ucwords(strtolower(str_replace('_',
965 static function getRequestHeaders() {
966 if (function_exists('apache_request_headers')) {
967 return apache_request_headers();
975 * Check and determine is this is an SSL request
976 * Note that we inline this function in install/civicrm.php, so if
977 * you change this function, please go and change the code in the install script
979 static function isSSL( ) {
981 (isset($_SERVER['HTTPS']) &&
982 !empty($_SERVER['HTTPS']) &&
983 strtolower($_SERVER['HTTPS']) != 'off') ?
true : false;
986 static function redirectToSSL($abort = FALSE) {
987 $config = CRM_Core_Config
::singleton();
988 $req_headers = self
::getRequestHeaders();
989 if (CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'enableSSL') &&
991 strtolower(CRM_Utils_Array
::value('X_FORWARDED_PROTO', $req_headers)) != 'https'
993 // ensure that SSL is enabled on a civicrm url (for cookie reasons etc)
994 $url = "https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
995 if (!self
::checkURL($url, TRUE)) {
997 CRM_Core_Error
::fatal('HTTPS is not set up on this machine');
1000 CRM_Core_Session
::setStatus(ts('HTTPS is not set up on this machine'), ts('Warning'), 'alert');
1001 // admin should be the only one following this
1002 // since we dont want the user stuck in a bad place
1006 CRM_Utils_System
::redirect($url);
1011 * Get logged in user's IP address.
1013 * Get IP address from HTTP Header. If the CMS is Drupal then use the Drupal function
1014 * as this also handles reverse proxies (based on proper configuration in settings.php)
1016 * @return string ip address of logged in user
1018 static function ipAddress($strictIPV4 = TRUE) {
1019 $address = CRM_Utils_Array
::value('REMOTE_ADDR', $_SERVER);
1021 $config = CRM_Core_Config
::singleton();
1022 if ($config->userSystem
->is_drupal
) {
1023 //drupal function handles the server being behind a proxy securely
1024 $address = ip_address();
1028 if ($address == '::1') {
1029 $address = '127.0.0.1';
1032 // when we need to have strictly IPV4 ip address
1033 // convert ipV6 to ipV4
1035 // this converts 'IPV4 mapped IPV6 address' to IPV4
1036 if (filter_var($address, FILTER_VALIDATE_IP
, FILTER_FLAG_IPV6
) && strstr($address, '::ffff:')) {
1037 $address = ltrim($address, '::ffff:');
1045 * Returns you the referring / previous page url
1047 * @return string the previous page url
1050 static function refererPath() {
1051 return CRM_Utils_Array
::value('HTTP_REFERER', $_SERVER);
1055 * Returns default documentation URL base
1057 * @return string documentation url
1060 static function getDocBaseURL() {
1061 // FIXME: move this to configuration at some stage
1062 return 'http://book.civicrm.org/';
1066 * Returns wiki (alternate) documentation URL base
1068 * @return string documentation url
1071 static function getWikiBaseURL() {
1072 // FIXME: move this to configuration at some stage
1073 return 'http://wiki.civicrm.org/confluence/display/CRMDOC/';
1077 * Returns URL or link to documentation page, based on provided parameters.
1078 * For use in PHP code.
1079 * WARNING: Always returns URL, if ts function is not defined ($URLonly has no effect).
1081 * @param string $page Title of documentation wiki page
1082 * @param boolean $URLonly Whether function should return URL only or whole link (default)
1083 * @param string $text Text of HTML link (no effect if $URLonly = false)
1084 * @param string $title Tooltip text for HTML link (no effect if $URLonly = false)
1085 * @param string $style Style attribute value for HTML link (no effect if $URLonly = false)
1087 * @return string URL or link to documentation page, based on provided parameters
1090 static function docURL2($page, $URLonly = FALSE, $text = NULL, $title = NULL, $style = NULL, $resource = NULL) {
1091 // if ts function doesn't exist, it means that CiviCRM hasn't been fully initialised yet -
1092 // return just the URL, no matter what other parameters are defined
1093 if (!function_exists('ts')) {
1094 if ($resource == 'wiki') {
1095 $docBaseURL = self
::getWikiBaseURL();
1097 $docBaseURL = self
::getDocBaseURL();
1099 return $docBaseURL . str_replace(' ', '+', $page);
1104 'URLonly' => $URLonly,
1108 'resource' => $resource,
1110 return self
::docURL($params);
1115 * Returns URL or link to documentation page, based on provided parameters.
1116 * For use in templates code.
1118 * @param array $params An array of parameters (see CRM_Utils_System::docURL2 method for names)
1120 * @return string URL or link to documentation page, based on provided parameters
1123 static function docURL($params) {
1125 if (!isset($params['page'])) {
1129 if (CRM_Utils_Array
::value('resource', $params) == 'wiki') {
1130 $docBaseURL = self
::getWikiBaseURL();
1132 $docBaseURL = self
::getDocBaseURL();
1135 if (!isset($params['title']) or $params['title'] === NULL) {
1136 $params['title'] = ts('Opens documentation in a new window.');
1139 if (!isset($params['text']) or $params['text'] === NULL) {
1140 $params['text'] = ts('(learn more...)');
1143 if (!isset($params['style']) ||
$params['style'] === NULL) {
1147 $style = "style=\"{$params['style']}\"";
1150 $link = $docBaseURL . str_replace(' ', '+', $params['page']);
1152 if (isset($params['URLonly']) && $params['URLonly'] == TRUE) {
1156 return "<a href=\"{$link}\" $style target=\"_blank\" title=\"{$params['title']}\">{$params['text']}</a>";
1161 * Get the locale set in the hosting CMS
1163 * @return string the used locale or null for none
1165 static function getUFLocale() {
1166 $config = CRM_Core_Config
::singleton();
1167 return $config->userSystem
->getUFLocale();
1171 * Execute external or internal urls and return server response
1173 * @param string $url request url
1174 * @param boolean $addCookie should be true to access internal urls
1176 * @return string $response response from url
1179 static function getServerResponse($url, $addCookie = TRUE) {
1180 CRM_Core_Error
::ignoreException();
1181 require_once 'HTTP/Request.php';
1182 $request = new HTTP_Request($url);
1185 foreach ($_COOKIE as $name => $value) {
1186 $request->addCookie($name, $value);
1190 if (isset($_SERVER['AUTH_TYPE'])) {
1191 $request->setBasicAuth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
1194 $config = CRM_Core_Config
::singleton();
1195 if ($config->userFramework
== 'WordPress') {
1196 session_write_close();
1199 $request->sendRequest();
1200 $response = $request->getResponseBody();
1202 CRM_Core_Error
::setCallback();
1206 static function isDBVersionValid(&$errorMessage) {
1207 $dbVersion = CRM_Core_BAO_Domain
::version();
1210 // if db.ver missing
1211 $errorMessage = ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.');
1214 elseif (!CRM_Utils_System
::isVersionFormatValid($dbVersion)) {
1215 $errorMessage = ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.');
1218 elseif (stripos($dbVersion, 'upgrade')) {
1219 // if db.ver indicates a partially upgraded db
1220 $upgradeUrl = CRM_Utils_System
::url("civicrm/upgrade", "reset=1");
1221 $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));
1225 $codeVersion = CRM_Utils_System
::version();
1227 // if db.ver < code.ver, time to upgrade
1228 if (version_compare($dbVersion, $codeVersion) < 0) {
1229 $upgradeUrl = CRM_Utils_System
::url("civicrm/upgrade", "reset=1");
1230 $errorMessage = ts('New codebase version detected. You might want to visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl));
1234 // if db.ver > code.ver, sth really wrong
1235 if (version_compare($dbVersion, $codeVersion) > 0) {
1236 $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.',
1237 array(1 => $dbVersion, 2 => $codeVersion)
1239 $errorMessage .= "<p>" . ts('OR if this is a manual install from git, you might want to fix civicrm-version.php file.') . "</p>";
1243 // FIXME: there should be another check to make sure version is in valid format - X.Y.alpha_num
1248 static function civiExit($status = 0) {
1249 // move things to CiviCRM cache as needed
1250 CRM_Core_Session
::storeSessionObjects();
1256 * Reset the various system caches and some important
1259 static function flushCache( ) {
1260 // flush out all cache entries so we can reload new data
1261 // a bit aggressive, but livable for now
1262 $cache = CRM_Utils_Cache
::singleton();
1265 // also reset the various static memory caches
1267 // reset the memory or array cache
1268 CRM_Core_BAO_Cache
::deleteGroup('contact fields', NULL, FALSE);
1271 CRM_ACL_BAO_Cache
::resetCache();
1273 // reset various static arrays used here
1274 CRM_Contact_BAO_Contact
::$_importableFields =
1275 CRM_Contact_BAO_Contact
::$_exportableFields =
1276 CRM_Contribute_BAO_Contribution
::$_importableFields =
1277 CRM_Contribute_BAO_Contribution
::$_exportableFields =
1278 CRM_Pledge_BAO_Pledge
::$_exportableFields =
1279 CRM_Contribute_BAO_Query
::$_contributionFields =
1280 CRM_Core_BAO_CustomField
::$_importFields =
1281 CRM_Core_BAO_Cache
::$_cache =
1282 CRM_Core_DAO
::$_dbColumnValueCache = NULL;
1284 CRM_Core_OptionGroup
::flushAll();
1285 CRM_Utils_PseudoConstant
::flushAll();
1289 * load cms bootstrap
1291 * @param $params array with uid name and pass
1292 * @param $loadUser boolean load user or not
1294 static function loadBootStrap($params = array(
1295 ), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) {
1296 if (!is_array($params)) {
1299 $config = CRM_Core_Config
::singleton();
1300 return $config->userSystem
->loadBootStrap($params, $loadUser, $throwError, $realPath);
1304 * check is user logged in.
1308 public static function isUserLoggedIn() {
1309 $config = CRM_Core_Config
::singleton();
1310 return $config->userSystem
->isUserLoggedIn();
1314 * Get current logged in user id.
1316 * @return int ufId, currently logged in user uf id.
1318 public static function getLoggedInUfID() {
1319 $config = CRM_Core_Config
::singleton();
1320 return $config->userSystem
->getLoggedInUfID();
1323 static function baseCMSURL() {
1324 static $_baseURL = NULL;
1326 $config = CRM_Core_Config
::singleton();
1327 $_baseURL = $userFrameworkBaseURL = $config->userFrameworkBaseURL
;
1329 if ($config->userFramework
== 'Joomla') {
1331 // we need to remove the administrator/ from the end
1332 $_baseURL = str_replace("/administrator/", "/", $userFrameworkBaseURL);
1336 global $civicrm_root;
1337 if (strpos($civicrm_root,
1338 DIRECTORY_SEPARATOR
. 'sites' .
1339 DIRECTORY_SEPARATOR
. 'all' .
1340 DIRECTORY_SEPARATOR
. 'modules'
1342 $startPos = strpos($civicrm_root,
1343 DIRECTORY_SEPARATOR
. 'sites' . DIRECTORY_SEPARATOR
1345 $endPos = strpos($civicrm_root,
1346 DIRECTORY_SEPARATOR
. 'modules' . DIRECTORY_SEPARATOR
1348 if ($startPos && $endPos) {
1349 // if component is in sites/SITENAME/modules
1350 $siteName = substr($civicrm_root,
1352 $endPos - $startPos - 7
1355 $_baseURL = $userFrameworkBaseURL . "sites/$siteName/";
1363 static function relativeURL($url) {
1364 // check if url is relative, if so return immediately
1365 if (substr($url, 0, 4) != 'http') {
1369 // make everything relative from the baseFilePath
1370 $baseURL = self
::baseCMSURL();
1372 // check if baseURL is a substr of $url, if so
1373 // return rest of string
1374 if (substr($url, 0, strlen($baseURL)) == $baseURL) {
1375 return substr($url, strlen($baseURL));
1378 // return the original value
1382 static function absoluteURL($url, $removeLanguagePart = FALSE) {
1383 // check if url is already absolute, if so return immediately
1384 if (substr($url, 0, 4) == 'http') {
1388 // make everything absolute from the baseFileURL
1389 $baseURL = self
::baseCMSURL();
1391 //CRM-7622: drop the language from the URL if requested (and it’s there)
1392 $config = CRM_Core_Config
::singleton();
1393 if ($removeLanguagePart) {
1394 $baseURL = self
::languageNegotiationURL($baseURL, FALSE, TRUE);
1397 return $baseURL . $url;
1401 * Function to clean url, replaces first '&' with '?'
1403 * @param string $url
1405 * @return string $url, clean url
1408 static function cleanUrl($url) {
1413 if ($pos = strpos($url, '&')) {
1414 $url = substr_replace($url, '?', $pos, 1);
1421 * Format the url as per language Negotiation.
1423 * @param string $url
1425 * @return string $url, formatted url.
1428 static function languageNegotiationURL($url,
1429 $addLanguagePart = TRUE,
1430 $removeLanguagePart = FALSE
1432 $config = &CRM_Core_Config
::singleton();
1433 return $config->userSystem
->languageNegotiationURL($url, $addLanguagePart, $removeLanguagePart);
1437 * Append the contents of an 'extra' smarty template file if it is present in
1438 * the custom template directory. This does not work if there are
1439 * multiple custom template directories
1441 * @param string $fileName - the name of the tpl file that we are processing
1442 * @param string $content (by reference) - the current content string
1443 * @param string $overideFileName - an optional parameter which is sent by contribution/event reg/profile pages
1444 * which uses a id specific extra file name if present
1446 * @return void - the content string is modified if needed
1449 static function appendTPLFile($fileName,
1451 $overideFileName = NULL
1453 $template = CRM_Core_Smarty
::singleton();
1454 if ($overideFileName) {
1455 $additionalTPLFile = $overideFileName;
1458 $additionalTPLFile = str_replace('.tpl', '.extra.tpl', $fileName);
1461 if ($template->template_exists($additionalTPLFile)) {
1462 $content .= $template->fetch($additionalTPLFile);
1467 * Get a list of all files that are found within the directories
1468 * that are the result of appending the provided relative path to
1469 * each component of the PHP include path.
1471 * @author Ken Zalewski
1473 * @param string $relpath a relative path, typically pointing to
1474 * a directory with multiple class files
1476 * @return array An array of files that exist in one or more of the
1477 * directories that are referenced by the relative path
1478 * when appended to each element of the PHP include path
1481 static function listIncludeFiles($relpath) {
1482 $file_list = array();
1483 $inc_dirs = explode(PATH_SEPARATOR
, get_include_path());
1484 foreach ($inc_dirs as $inc_dir) {
1485 $target_dir = $inc_dir . DIRECTORY_SEPARATOR
. $relpath;
1486 if (is_dir($target_dir)) {
1487 $cur_list = scandir($target_dir);
1488 foreach ($cur_list as $fname) {
1489 if ($fname != '.' && $fname != '..') {
1490 $file_list[$fname] = $fname;
1497 // listIncludeFiles()
1500 * Get a list of all "plugins" (PHP classes that implement a piece of
1501 * functionality using a well-defined interface) that are found in a
1502 * particular CiviCRM directory (both custom and core are searched).
1504 * @author Ken Zalewski
1506 * @param string $relpath a relative path referencing a directory that
1507 * contains one or more plugins
1508 * @param string $fext only files with this extension will be considered
1510 * @param array $skipList list of files to skip
1512 * @return array List of plugins, where the plugin name is both the
1513 * key and the value of each element.
1516 static function getPluginList($relpath, $fext = '.php', $skipList = array(
1518 $fext_len = strlen($fext);
1520 $inc_files = CRM_Utils_System
::listIncludeFiles($relpath);
1521 foreach ($inc_files as $inc_file) {
1522 if (substr($inc_file, 0 - $fext_len) == $fext) {
1523 $plugin_name = substr($inc_file, 0, 0 - $fext_len);
1524 if (!in_array($plugin_name, $skipList)) {
1525 $plugins[$plugin_name] = $plugin_name;
1535 * @param string $fileName - the name of the tpl file that we are processing
1536 * @param string $content (by reference) - the current content string
1538 * @return void - the content string is modified if needed
1541 static function executeScheduledJobs() {
1542 $facility = new CRM_Core_JobManager();
1543 $facility->execute(FALSE);
1545 $redirectUrl = self
::url('civicrm/admin/job', 'reset=1');
1547 CRM_Core_Session
::setStatus(
1548 ts('Scheduled jobs have been executed according to individual timing settings. Please check log for messages.'),
1549 ts('Complete'), 'success');
1551 CRM_Utils_System
::redirect($redirectUrl);
1555 * Evaluate any tokens in a URL
1557 * @param string|FALSE $url
1558 * @return string|FALSE
1560 public static function evalUrl($url) {
1561 if ($url === FALSE) {
1565 $config = CRM_Core_Config
::singleton();
1567 '{ver}' => CRM_Utils_System
::version(),
1568 '{uf}' => $config->userFramework
,
1569 '{php}' => phpversion(),
1570 '{sid}' => md5('sid_' . (defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY
: '') . '_' . $config->userFrameworkBaseURL
),
1571 '{baseUrl}' => $config->userFrameworkBaseURL
,
1572 '{lang}' => $config->lcMessages
,
1573 '{co}' => $config->defaultContactCountry
,
1575 foreach (array_keys($vars) as $k) {
1576 $vars[$k] = urlencode($vars[$k]);
1578 return strtr($url, $vars);
1584 * Determine whether this is a developmental system.
1588 static function isDevelopment() {
1589 static $cache = NULL;
1590 if ($cache === NULL) {
1591 global $civicrm_root;
1592 $cache = file_exists("{$civicrm_root}/.svn") ||
file_exists("{$civicrm_root}/.git");