comment block fixes
[civicrm-core.git] / CRM / Utils / System.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
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. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2014
32 * $Id$
33 *
34 */
35
36 /**
37 * System wide utilities.
38 *
39 */
40 class CRM_Utils_System {
41
42 static $_callbacks = NULL;
43
44 /**
45 * @var string Page title
46 */
47 static $title = '';
48
49 /**
50 * Compose a new URL string from the current URL string.
51 *
52 * Used by all the framework components, specifically,
53 * pager, sort and qfc
54 *
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).
61 * @param string $path
62 * (optional) The path to use for the new url.
63 * @param string $absolute
64 * (optional) Whether to return an absolute URL.
65 *
66 * @return string
67 * The URL fragment.
68 * @access public
69 */
70 static function makeURL($urlVar, $includeReset = FALSE, $includeForce = TRUE, $path = NULL, $absolute = FALSE) {
71 if (empty($path)) {
72 $config = CRM_Core_Config::singleton();
73 $path = CRM_Utils_Array::value($config->userFrameworkURLVar, $_GET);
74 if (empty($path)) {
75 return '';
76 }
77 }
78
79 return
80 self::url(
81 $path,
82 CRM_Utils_System::getLinksUrl($urlVar, $includeReset, $includeForce),
83 $absolute
84 );
85 }
86
87 /**
88 * Get the query string and clean it up.
89 *
90 * Strips some variables that should not be propagated, specifically variables
91 * like 'reset'. Also strips any side-affect actions (e.g. export).
92 *
93 * This function is copied mostly verbatim from Pager.php (_getLinksUrl)
94 *
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
101 * (optional)
102 * @param bool $skipUFVar
103 * (optional)
104 *
105 * @return string
106 * @access public
107 */
108 static function getLinksUrl($urlVar, $includeReset = FALSE, $includeForce = TRUE, $skipUFVar = TRUE) {
109 // Sort out query string to prevent messy urls
110 $querystring = array();
111 $qs = array();
112 $arrays = array();
113
114 if (!empty($_SERVER['QUERY_STRING'])) {
115 $qs = explode('&', str_replace('&amp;', '&', $_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)
125 ) {
126 $arrays[] = $qs[$i];
127 }
128 else {
129 $qs[$name] = $value;
130 }
131 }
132 }
133 else {
134 $qs[$qs[$i]] = '';
135 }
136 unset($qs[$i]);
137 }
138 }
139
140 if ($includeForce) {
141 $qs['force'] = 1;
142 }
143
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
146 // of it.
147 if (!empty($qs['snippet'])) {
148 unset($qs['snippet']);
149 }
150 else {
151 unset($qs['section']);
152 }
153
154 if ($skipUFVar) {
155 $config = CRM_Core_Config::singleton();
156 unset($qs[$config->userFrameworkURLVar]);
157 }
158
159 foreach ($qs as $name => $value) {
160 if ($name != 'reset' || $includeReset) {
161 $querystring[] = $name . '=' . $value;
162 }
163 }
164
165 $querystring = array_merge($querystring, array_unique($arrays));
166
167 $url = implode('&', $querystring);
168 if ($urlVar) {
169 $url .= (!empty($querystring) ? '&' : '') . $urlVar . '=';
170 }
171
172 return $url;
173 }
174
175 /**
176 * If we are using a theming system, invoke theme, else just print the
177 * content.
178 *
179 * @param string $content
180 * The content that will be themed.
181 * @param bool $print
182 * (optional) Are we displaying to the screen or bypassing theming?
183 * @param bool $maintenance
184 * (optional) For maintenance mode.
185 *
186 * @access public
187 */
188 static function theme(
189 &$content,
190 $print = FALSE,
191 $maintenance = FALSE
192 ) {
193 $config = &CRM_Core_Config::singleton();
194 return $config->userSystem->theme($content, $print, $maintenance);
195 }
196
197 /**
198 * Generate a query string if input is an array.
199 *
200 * @param array|string $query
201 * @return string
202 */
203 static function makeQueryString($query) {
204 if (is_array($query)) {
205 $buf = '';
206 foreach ($query as $key => $value) {
207 $buf .= ($buf ? '&' : '') . urlencode($key) . '=' . urlencode($value);
208 }
209 $query = $buf;
210 }
211 return $query;
212 }
213
214 /**
215 * Generate an internal CiviCRM URL.
216 *
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.
227 *
228 * @param bool $htmlize
229 * @param bool $frontend
230 * @param bool $forceBackend
231 * @return string
232 * An HTML string containing a link to the given path.
233 * @access public
234 */
235 static function url(
236 $path = NULL,
237 $query = NULL,
238 $absolute = FALSE,
239 $fragment = NULL,
240 $htmlize = TRUE,
241 $frontend = FALSE,
242 $forceBackend = FALSE
243 ) {
244 $query = self::makeQueryString($query);
245
246 // we have a valid query and it has not yet been transformed
247 if ($htmlize && !empty($query) && strpos($query, '&amp;') === FALSE) {
248 $query = htmlentities($query);
249 }
250
251 $config = CRM_Core_Config::singleton();
252 return $config->userSystem->url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
253 }
254
255 static function href($text, $path = NULL, $query = NULL, $absolute = TRUE,
256 $fragment = NULL, $htmlize = TRUE, $frontend = FALSE, $forceBackend = FALSE
257 ) {
258 $url = self::url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
259 return "<a href=\"$url\">$text</a>";
260 }
261
262 static function permissionDenied() {
263 $config = CRM_Core_Config::singleton();
264 return $config->userSystem->permissionDenied();
265 }
266
267 static function logout() {
268 $config = CRM_Core_Config::singleton();
269 return $config->userSystem->logout();
270 }
271
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();
277 }
278 }
279
280 /**
281 * What menu path are we currently on. Called for the primary tpl
282 *
283 * @return string the current menu path
284 * @access public
285 */
286 static function currentPath() {
287 $config = CRM_Core_Config::singleton();
288 return trim(CRM_Utils_Array::value($config->userFrameworkURLVar, $_GET), '/');
289 }
290
291 /**
292 * This function is called from a template to compose a url.
293 *
294 * @param array $params
295 * List of parameters.
296 *
297 * @return string url
298 * @access public
299 */
300 static function crmURL($params) {
301 $p = CRM_Utils_Array::value('p', $params);
302 if (!isset($p)) {
303 $p = self::currentPath();
304 }
305
306 return self::url(
307 $p,
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)
314 );
315 }
316
317 /**
318 * Sets the title of the page.
319 *
320 * @param string $title
321 * @param string $pageTitle
322 *
323 * @access public
324 */
325 static function setTitle($title, $pageTitle = NULL) {
326 self::$title = $title;
327 $config = CRM_Core_Config::singleton();
328 return $config->userSystem->setTitle($title, $pageTitle);
329 }
330
331 /**
332 * Figures and sets the userContext.
333 *
334 * Uses the referer if valid else uses the default.
335 *
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.
340 *
341 * @access public
342 */
343 static function setUserContext($names, $default = NULL) {
344 $url = $default;
345
346 $session = CRM_Core_Session::singleton();
347 $referer = CRM_Utils_Array::value('HTTP_REFERER', $_SERVER);
348
349 if ($referer && !empty($names)) {
350 foreach ($names as $name) {
351 if (strstr($referer, $name)) {
352 $url = $referer;
353 break;
354 }
355 }
356 }
357
358 if ($url) {
359 $session->pushUserContext($url);
360 }
361 }
362
363 /**
364 * Gets a class name for an object.
365 *
366 * @param object $object
367 * Object whose class name is needed.
368 *
369 * @return string
370 * The class name of the object.
371 *
372 * @access public
373 */
374 static function getClassName($object) {
375 return get_class($object);
376 }
377
378 /**
379 * Redirect to another URL.
380 *
381 * @param string $url
382 * The URL to provide to the browser via the Location header.
383 *
384 * @access public
385 */
386 static function redirect($url = NULL) {
387 if (!$url) {
388 $url = self::url('civicrm/dashboard', 'reset=1');
389 }
390
391 // replace the &amp; characters with &
392 // this is kinda hackish but not sure how to do it right
393 $url = str_replace('&amp;', '&', $url);
394 header('Location: ' . $url);
395 self::civiExit();
396 }
397
398 /**
399 * Redirect to another URL using JavaScript.
400 *
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
403 *
404 * @param string $url
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.
410 *
411 * @access public
412 */
413 static function jsRedirect(
414 $url = NULL,
415 $title = NULL,
416 $message = NULL
417 ) {
418 if (!$url) {
419 $url = self::url('civicrm/dashboard', 'reset=1');
420 }
421
422 if (!$title) {
423 $title = ts('CiviCRM task in progress');
424 }
425
426 if (!$message) {
427 $message = ts('A long running CiviCRM task is currently in progress. This message will be refreshed till the task is completed');
428 }
429
430 // replace the &amp; characters with &
431 // this is kinda hackish but not sure how to do it right
432 $url = str_replace('&amp;', '&', $url);
433
434 $template = CRM_Core_Smarty::singleton();
435 $template->assign('redirectURL', $url);
436 $template->assign('title', $title);
437 $template->assign('message', $message);
438
439 $html = $template->fetch('CRM/common/redirectJS.tpl');
440
441 echo $html;
442
443 self::civiExit();
444 }
445
446 /**
447 * Append an additional breadcrumb tag to the existing breadcrumbs.
448 *
449 * @param $breadCrumbs
450 *
451 * @access public
452 */
453 static function appendBreadCrumb($breadCrumbs) {
454 $config = CRM_Core_Config::singleton();
455 return $config->userSystem->appendBreadCrumb($breadCrumbs);
456 }
457
458 /**
459 * Reset an additional breadcrumb tag to the existing breadcrumb.
460 *
461 * @access public
462 */
463 static function resetBreadCrumb() {
464 $config = CRM_Core_Config::singleton();
465 return $config->userSystem->resetBreadCrumb();
466 }
467
468 /**
469 * Append a string to the head of the HTML file.
470 *
471 * @param string $bc
472 *
473 * @access public
474 */
475 static function addHTMLHead($bc) {
476 $config = CRM_Core_Config::singleton();
477 return $config->userSystem->addHTMLHead($bc);
478 }
479
480 /**
481 * Determine the post URL for a form
482 *
483 * @param $action
484 * The default action if one is pre-specified.
485 *
486 * @return string
487 * The URL to post the form.
488 * @access public
489 */
490 static function postURL($action) {
491 $config = CRM_Core_Config::singleton();
492 return $config->userSystem->postURL($action);
493 }
494
495 /**
496 * Rewrite various system URLs to https.
497 *
498 * @access public
499 */
500 static function mapConfigToSSL() {
501 $config = CRM_Core_Config::singleton();
502 $config->userFrameworkResourceURL = str_replace('http://', 'https://', $config->userFrameworkResourceURL);
503 $config->resourceBase = $config->userFrameworkResourceURL;
504
505 if (! empty($config->extensionsURL)) {
506 $config->extensionsURL = str_replace('http://', 'https://', $config->extensionsURL);
507 }
508
509 return $config->userSystem->mapConfigToSSL();
510 }
511
512 /**
513 * Get the base URL of the system.
514 *
515 * @return string
516 * @access public
517 */
518 static function baseURL() {
519 $config = CRM_Core_Config::singleton();
520 return $config->userFrameworkBaseURL;
521 }
522
523 /**
524 */
525 static function authenticateAbort($message, $abort) {
526 if ($abort) {
527 echo $message;
528 self::civiExit(0);
529 }
530 else {
531 return FALSE;
532 }
533 }
534
535 /**
536 * @param bool $abort
537 * (optional) Whether to exit; defaults to true.
538 */
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));
542
543 $docAdd = "More info at:" . CRM_Utils_System::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
544
545 if (!$key) {
546 return self::authenticateAbort(
547 "ERROR: You need to send a valid key to execute this file. " . $docAdd . "\n",
548 $abort
549 );
550 }
551
552 $siteKey = defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY : NULL;
553
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",
557 $abort
558 );
559 }
560
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",
564 $abort
565 );
566 }
567
568 if ($key !== $siteKey) {
569 return self::authenticateAbort(
570 "ERROR: Invalid key value sent. " . $docAdd . "\n",
571 $abort
572 );
573 }
574
575 return TRUE;
576 }
577
578 /**
579 * @return bool
580 */
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
584 if (!$name) {
585 $name = trim(CRM_Utils_Array::value('name', $_REQUEST));
586 $pass = trim(CRM_Utils_Array::value('pass', $_REQUEST));
587 }
588
589 // its ok to have an empty password
590 if (!$name) {
591 return self::authenticateAbort(
592 "ERROR: You need to send a valid user name and password to execute this file\n",
593 $abort
594 );
595 }
596
597 if ($requireKey && !self::authenticateKey($abort)) {
598 return FALSE;
599 }
600
601 $result = CRM_Utils_System::authenticate($name, $pass, $loadCMSBootstrap);
602 if (!$result) {
603 return self::authenticateAbort(
604 "ERROR: Invalid username and/or password\n",
605 $abort
606 );
607 }
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) );
614 }
615 else {
616 return self::authenticateAbort(
617 "ERROR: Unexpected error, could not match userID and contactID",
618 $abort
619 );
620 }
621 }
622
623 return $result;
624 }
625
626 /**
627 * Authenticate the user against the uf db.
628 *
629 * In case of succesful authentication, returns an array consisting of
630 * (contactID, ufID, unique string). Returns FALSE if authentication is
631 * unsuccessful.
632 *
633 * @param string $name
634 * The username.
635 * @param string $password
636 * The password.
637 * @param bool $loadCMSBootstrap
638 * @param $realPath
639 *
640 * @return false|array
641 * @access public
642 */
643 static function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realPath = NULL) {
644 $config = CRM_Core_Config::singleton();
645
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
650 */
651 $session = CRM_Core_Session::singleton();
652 $session->set( 'civicrmInitSession', TRUE );
653
654 $dbDrupal = DB::connect($config->userFrameworkDSN);
655 return $config->userSystem->authenticate($name, $password, $loadCMSBootstrap, $realPath);
656 }
657
658 /**
659 * Set a message in the UF to display to a user.
660 *
661 * @param string $message
662 * The message to set.
663 *
664 * @access public
665 */
666 static function setUFMessage($message) {
667 $config = CRM_Core_Config::singleton();
668 return $config->userSystem->setMessage($message);
669 }
670
671
672 /**
673 * Determine whether a value is null-ish.
674 *
675 * @param $value
676 * The value to check for null.
677 * @return bool
678 */
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') {
682 return TRUE;
683 }
684 if (is_array($value)) {
685 foreach ($value as $key => $value) {
686 if (!self::isNull($value)) {
687 return FALSE;
688 }
689 }
690 return TRUE;
691 }
692 return FALSE;
693 }
694
695 /**
696 * Obscure all but the last few digits of a credit card number.
697 *
698 * @param string $number
699 * The credit card number to obscure.
700 * @param int $keep
701 * (optional) The number of digits to preserve unmodified.
702 * @return string
703 * The obscured credit card number.
704 */
705 static function mungeCreditCard($number, $keep = 4) {
706 $number = trim($number);
707 if (empty($number)) {
708 return NULL;
709 }
710 $replace = str_repeat('*', strlen($number) - $keep);
711 return substr_replace($number, $replace, 0, -$keep);
712 }
713
714 /**
715 * Determine which PHP modules are loaded.
716 *
717 * @return array
718 */
719 public static function parsePHPModules() {
720 ob_start();
721 phpinfo(INFO_MODULES);
722 $s = ob_get_contents();
723 ob_end_clean();
724
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);
729 $vModules = array();
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/";
738 // 3cols
739 if (preg_match($vPat3, $vOne, $vMat)) {
740 $vModules[$vName][trim($vMat[1])] = array(trim($vMat[2]), trim($vMat[3]));
741 // 2cols
742 }
743 elseif (preg_match($vPat2, $vOne, $vMat)) {
744 $vModules[$vName][trim($vMat[1])] = trim($vMat[2]);
745 }
746 }
747 }
748 }
749 return $vModules;
750 }
751
752 /**
753 * Get a setting from a loaded PHP module.
754 */
755 public static function getModuleSetting($pModuleName, $pSetting) {
756 $vModules = self::parsePHPModules();
757 return $vModules[$pModuleName][$pSetting];
758 }
759
760 /**
761 * @param $title
762 * (optional)
763 */
764 static function memory($title = NULL) {
765 static $pid = NULL;
766 if (!$pid) {
767 $pid = posix_getpid();
768 }
769
770 $memory = str_replace("\n", '', shell_exec("ps -p" . $pid . " -o rss="));
771 $memory .= ", " . time();
772 if ($title) {
773 CRM_Core_Error::debug_var($title, $memory);
774 }
775 return $memory;
776 }
777
778 /**
779 * @param string $name
780 * @param string $mimeType
781 * @param $buffer
782 * @param string $ext
783 * @param bool $output
784 */
785 static function download($name, $mimeType, &$buffer,
786 $ext = NULL,
787 $output = TRUE
788 ) {
789 $now = gmdate('D, d M Y H:i:s') . ' GMT';
790
791 header('Content-Type: ' . $mimeType);
792 header('Expires: ' . $now);
793
794 // lem9 & loic1: IE need specific headers
795 $isIE = strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE');
796 if ($ext) {
797 $fileString = "filename=\"{$name}.{$ext}\"";
798 }
799 else {
800 $fileString = "filename=\"{$name}\"";
801 }
802 if ($isIE) {
803 header("Content-Disposition: inline; $fileString");
804 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
805 header('Pragma: public');
806 }
807 else {
808 header("Content-Disposition: attachment; $fileString");
809 header('Pragma: no-cache');
810 }
811
812 if ($output) {
813 print $buffer;
814 self::civiExit();
815 }
816 }
817
818 /**
819 * Gather and print (and possibly log) amount of used memory.
820 *
821 * @param string $title
822 * @param bool $log
823 * (optional) Whether to log the memory usage information.
824 */
825 static function xMemory($title = NULL, $log = FALSE) {
826 $mem = (float ) xdebug_memory_usage() / (float )(1024);
827 $mem = number_format($mem, 5) . ", " . time();
828 if ($log) {
829 echo "<p>$title: $mem<p>";
830 flush();
831 CRM_Core_Error::debug_var($title, $mem);
832 }
833 else {
834 echo "<p>$title: $mem<p>";
835 flush();
836 }
837 }
838
839 /**
840 * Take a URL (or partial URL) and make it better.
841 *
842 * Currently, URLs pass straight through unchanged unless they are "seriously
843 * malformed" (see http://us2.php.net/parse_url).
844 *
845 * @param string $url
846 * The URL to operate on.
847 * @return string
848 * The fixed URL.
849 */
850 static function fixURL($url) {
851 $components = parse_url($url);
852
853 if (!$components) {
854 return NULL;
855 }
856
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
859 return $url;
860 }
861
862 /**
863 * Make sure a callback is valid in the current context.
864 *
865 * @param string $callback
866 * Name of the function to check.
867 *
868 * @return bool
869 */
870 static function validCallback($callback) {
871 if (self::$_callbacks === NULL) {
872 self::$_callbacks = array();
873 }
874
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;
883 }
884 else {
885 // instantiate the class
886 $object = new $className();
887 if (!method_exists($object, $methodName)) {
888 self::$_callbacks[$callback] = FALSE;
889 }
890 else {
891 self::$_callbacks[$callback] = TRUE;
892 }
893 }
894 }
895 else {
896 self::$_callbacks[$callback] = function_exists($callback);
897 }
898 }
899 return self::$_callbacks[$callback];
900 }
901
902 /**
903 * Like PHP's built-in explode(), but always return an array of $limit items.
904 *
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.
908 *
909 * @param string $separator
910 * @param string $string
911 * @param int $limit
912 * @return string[]
913 */
914 static function explode($separator, $string, $limit) {
915 $result = explode($separator, $string, $limit);
916 for ($i = count($result); $i < $limit; $i++) {
917 $result[$i] = NULL;
918 }
919 return $result;
920 }
921
922 /**
923 * @param string $url
924 * The URL to check.
925 * @param bool $addCookie
926 * (optional)
927 */
928 static function checkURL($url, $addCookie = FALSE) {
929 // make a GET request to $url
930 $ch = curl_init($url);
931 if ($addCookie) {
932 curl_setopt($ch, CURLOPT_COOKIE, http_build_query($_COOKIE));
933 }
934 // it's quite alright to use a self-signed cert
935 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
936
937 // lets capture the return stuff rather than echo
938 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
939
940 return curl_exec($ch);
941 }
942
943 /**
944 * Assert that we are running on a particular PHP version.
945 *
946 * @param int $ver
947 * The major version of PHP that is required.
948 * @param bool $abort
949 * (optional) Whether to fatally abort if the version requirement is not
950 * met. Defaults to TRUE.
951 * @return bool
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.
955 */
956 static function checkPHPVersion($ver = 5, $abort = TRUE) {
957 $phpVersion = substr(PHP_VERSION, 0, 1);
958 if ($phpVersion >= $ver) {
959 return TRUE;
960 }
961
962 if ($abort) {
963 CRM_Core_Error::fatal(ts('This feature requires PHP Version %1 or greater',
964 array(1 => $ver)
965 ));
966 }
967 return FALSE;
968 }
969
970 /**
971 * @return string
972 */
973 static function formatWikiURL($string, $encode = FALSE) {
974 $items = explode(' ', trim($string), 2);
975 if (count($items) == 2) {
976 $title = $items[1];
977 }
978 else {
979 $title = $items[0];
980 }
981
982 // fix for CRM-4044
983 $url = $encode ? self::urlEncode($items[0]) : $items[0];
984 return "<a href=\"$url\">$title</a>";
985 }
986
987 /**
988 * @param string $url
989 */
990 static function urlEncode($url) {
991 $items = parse_url($url);
992 if ($items === FALSE) {
993 return NULL;
994 }
995
996 if (empty($items['query'])) {
997 return $url;
998 }
999
1000 $items['query'] = urlencode($items['query']);
1001
1002 $url = $items['scheme'] . '://';
1003 if (!empty($items['user'])) {
1004 $url .= "{$items['user']}:{$items['pass']}@";
1005 }
1006
1007 $url .= $items['host'];
1008 if (!empty($items['port'])) {
1009 $url .= ":{$items['port']}";
1010 }
1011
1012 $url .= "{$items['path']}?{$items['query']}";
1013 if (!empty($items['fragment'])) {
1014 $url .= "#{$items['fragment']}";
1015 }
1016
1017 return $url;
1018 }
1019
1020 /**
1021 * Return the running civicrm version.
1022 *
1023 * @return string
1024 * civicrm version
1025 * @access public
1026 */
1027 static function version() {
1028 static $version;
1029
1030 if (!$version) {
1031 $verFile = implode(DIRECTORY_SEPARATOR,
1032 array(dirname(__FILE__), '..', '..', 'civicrm-version.php')
1033 );
1034 if (file_exists($verFile)) {
1035 require_once ($verFile);
1036 if (function_exists('civicrmVersion')) {
1037 $info = civicrmVersion();
1038 $version = $info['version'];
1039 }
1040 }
1041 else {
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')
1045 );
1046 if (file_exists($verFile)) {
1047 $str = file_get_contents($verFile);
1048 $xmlObj = simplexml_load_string($str);
1049 $version = (string) $xmlObj->version_no;
1050 }
1051 }
1052
1053 // pattern check
1054 if (!CRM_Utils_System::isVersionFormatValid($version)) {
1055 CRM_Core_Error::fatal('Unknown codebase version.');
1056 }
1057 }
1058
1059 return $version;
1060 }
1061
1062 /**
1063 * Determines whether a string is a valid CiviCRM version string.
1064 *
1065 * @param string $version
1066 * Version string to be checked.
1067 * @return bool
1068 */
1069 static function isVersionFormatValid($version) {
1070 return preg_match("/^(\d{1,2}\.){2,3}(\d{1,2}|(alpha|beta)\d{1,2})(\.upgrade)?$/", $version);
1071 }
1072
1073 /**
1074 * Wraps or emulates PHP's getallheaders() function.
1075 */
1076 static function getAllHeaders() {
1077 if (function_exists('getallheaders')) {
1078 return getallheaders();
1079 }
1080
1081 // emulate get all headers
1082 // http://www.php.net/manual/en/function.getallheaders.php#66335
1083 $headers = array();
1084 foreach ($_SERVER as $name => $value) {
1085 if (substr($name, 0, 5) == 'HTTP_') {
1086 $headers[str_replace(' ',
1087 '-',
1088 ucwords(strtolower(str_replace('_',
1089 ' ',
1090 substr($name, 5)
1091 )
1092 ))
1093 )] = $value;
1094 }
1095 }
1096 return $headers;
1097 }
1098
1099 /**
1100 */
1101 static function getRequestHeaders() {
1102 if (function_exists('apache_request_headers')) {
1103 return apache_request_headers();
1104 }
1105 else {
1106 return $_SERVER;
1107 }
1108 }
1109
1110 /**
1111 * Determine whether this is an SSL request.
1112 *
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.
1115 */
1116 static function isSSL( ) {
1117 return
1118 (isset($_SERVER['HTTPS']) &&
1119 !empty($_SERVER['HTTPS']) &&
1120 strtolower($_SERVER['HTTPS']) != 'off') ? true : false;
1121 }
1122
1123 /**
1124 */
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') &&
1129 !self::isSSL() &&
1130 strtolower(CRM_Utils_Array::value('X_FORWARDED_PROTO', $req_headers)) != 'https'
1131 ) {
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)) {
1135 if ($abort) {
1136 CRM_Core_Error::fatal('HTTPS is not set up on this machine');
1137 }
1138 else {
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
1142 return;
1143 }
1144 }
1145 CRM_Utils_System::redirect($url);
1146 }
1147 }
1148
1149 /*
1150 * Get logged in user's IP address.
1151 *
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)
1155 *
1156 * @param bool $strictIPV4
1157 * (optional) Whether to return only IPv4 addresses.
1158 *
1159 * @return string
1160 * IP address of logged in user.
1161 */
1162 static function ipAddress($strictIPV4 = TRUE) {
1163 $address = CRM_Utils_Array::value('REMOTE_ADDR', $_SERVER);
1164
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();
1169 }
1170
1171 // hack for safari
1172 if ($address == '::1') {
1173 $address = '127.0.0.1';
1174 }
1175
1176 // when we need to have strictly IPV4 ip address
1177 // convert ipV6 to ipV4
1178 if ($strictIPV4) {
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:');
1182 }
1183 }
1184
1185 return $address;
1186 }
1187
1188 /**
1189 * Get the referring / previous page URL.
1190 *
1191 * @return string
1192 * The previous page URL
1193 * @access public
1194 */
1195 static function refererPath() {
1196 return CRM_Utils_Array::value('HTTP_REFERER', $_SERVER);
1197 }
1198
1199 /**
1200 * Get the documentation base URL.
1201 *
1202 * @return string
1203 * Base URL of the CRM documentation.
1204 * @access public
1205 */
1206 static function getDocBaseURL() {
1207 // FIXME: move this to configuration at some stage
1208 return 'http://book.civicrm.org/';
1209 }
1210
1211 /**
1212 * Returns wiki (alternate) documentation URL base.
1213 *
1214 * @return string documentation url
1215 * @access public
1216 */
1217 static function getWikiBaseURL() {
1218 // FIXME: move this to configuration at some stage
1219 return 'http://wiki.civicrm.org/confluence/display/CRMDOC/';
1220 }
1221
1222 /**
1223 * Returns URL or link to documentation page, based on provided parameters.
1224 *
1225 * For use in PHP code.
1226 * WARNING: Always returns URL, if ts function is not defined ($URLonly has
1227 * no effect).
1228 *
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)
1239 *
1240 * @return string
1241 * URL or link to documentation page, based on provided parameters.
1242 * @access public
1243 */
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();
1250 } else {
1251 $docBaseURL = self::getDocBaseURL();
1252 }
1253 return $docBaseURL . str_replace(' ', '+', $page);
1254 }
1255 else {
1256 $params = array(
1257 'page' => $page,
1258 'URLonly' => $URLonly,
1259 'text' => $text,
1260 'title' => $title,
1261 'style' => $style,
1262 'resource' => $resource,
1263 );
1264 return self::docURL($params);
1265 }
1266 }
1267
1268 /**
1269 * Returns URL or link to documentation page, based on provided parameters.
1270 *
1271 * For use in templates code.
1272 *
1273 * @param array $params
1274 * An array of parameters (see CRM_Utils_System::docURL2 method for names)
1275 *
1276 * @return string
1277 * URL or link to documentation page, based on provided parameters.
1278 * @access public
1279 */
1280 static function docURL($params) {
1281
1282 if (!isset($params['page'])) {
1283 return;
1284 }
1285
1286 if (CRM_Utils_Array::value('resource', $params) == 'wiki') {
1287 $docBaseURL = self::getWikiBaseURL();
1288 } else {
1289 $docBaseURL = self::getDocBaseURL();
1290 }
1291
1292 if (!isset($params['title']) or $params['title'] === NULL) {
1293 $params['title'] = ts('Opens documentation in a new window.');
1294 }
1295
1296 if (!isset($params['text']) or $params['text'] === NULL) {
1297 $params['text'] = ts('(learn more...)');
1298 }
1299
1300 if (!isset($params['style']) || $params['style'] === NULL) {
1301 $style = '';
1302 }
1303 else {
1304 $style = "style=\"{$params['style']}\"";
1305 }
1306
1307 $link = $docBaseURL . str_replace(' ', '+', $params['page']);
1308
1309 if (isset($params['URLonly']) && $params['URLonly'] == TRUE) {
1310 return $link;
1311 }
1312 else {
1313 return "<a href=\"{$link}\" $style target=\"_blank\" class=\"crm-doc-link no-popup\" title=\"{$params['title']}\">{$params['text']}</a>";
1314 }
1315 }
1316
1317 /**
1318 * Get the locale set in the hosting CMS
1319 *
1320 * @return string
1321 * The used locale or null for none.
1322 */
1323 static function getUFLocale() {
1324 $config = CRM_Core_Config::singleton();
1325 return $config->userSystem->getUFLocale();
1326 }
1327
1328 /**
1329 * Execute external or internal URLs and return server response.
1330 *
1331 * @param string $url
1332 * Request URL.
1333 * @param bool $addCookie
1334 * Whether to provide a cookie. Should be true to access internal URLs.
1335 *
1336 * @return string
1337 * Response from URL.
1338 */
1339 static function getServerResponse($url, $addCookie = TRUE) {
1340 $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
1341 require_once 'HTTP/Request.php';
1342 $request = new HTTP_Request($url);
1343
1344 if ($addCookie) {
1345 foreach ($_COOKIE as $name => $value) {
1346 $request->addCookie($name, $value);
1347 }
1348 }
1349
1350 if (isset($_SERVER['AUTH_TYPE'])) {
1351 $request->setBasicAuth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
1352 }
1353
1354 $config = CRM_Core_Config::singleton();
1355 if ($config->userFramework == 'WordPress') {
1356 session_write_close();
1357 }
1358
1359 $request->sendRequest();
1360 $response = $request->getResponseBody();
1361
1362 return $response;
1363 }
1364
1365 /**
1366 */
1367 static function isDBVersionValid(&$errorMessage) {
1368 $dbVersion = CRM_Core_BAO_Domain::version();
1369
1370 if (!$dbVersion) {
1371 // if db.ver missing
1372 $errorMessage = ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.');
1373 return FALSE;
1374 }
1375 elseif (!CRM_Utils_System::isVersionFormatValid($dbVersion)) {
1376 $errorMessage = ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.');
1377 return FALSE;
1378 }
1379 elseif (stripos($dbVersion, 'upgrade')) {
1380 // if db.ver indicates a partially upgraded db
1381 $upgradeUrl = CRM_Utils_System::url("civicrm/upgrade", "reset=1");
1382 $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));
1383 return FALSE;
1384 }
1385 else {
1386 $codeVersion = CRM_Utils_System::version();
1387
1388 // if db.ver < code.ver, time to upgrade
1389 if (version_compare($dbVersion, $codeVersion) < 0) {
1390 $upgradeUrl = CRM_Utils_System::url("civicrm/upgrade", "reset=1");
1391 $errorMessage = ts('New codebase version detected. You might want to visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl));
1392 return FALSE;
1393 }
1394
1395 // if db.ver > code.ver, sth really wrong
1396 if (version_compare($dbVersion, $codeVersion) > 0) {
1397 $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.',
1398 array(1 => $dbVersion, 2 => $codeVersion)
1399 ) . '</p>';
1400 $errorMessage .= "<p>" . ts('OR if this is a manual install from git, you might want to fix civicrm-version.php file.') . "</p>";
1401 return FALSE;
1402 }
1403 }
1404 // FIXME: there should be another check to make sure version is in valid format - X.Y.alpha_num
1405
1406 return TRUE;
1407 }
1408
1409 /**
1410 * Exit with provided exit code.
1411 *
1412 * @param int $status
1413 * (optional) Code with which to exit.
1414 */
1415 static function civiExit($status = 0) {
1416 // move things to CiviCRM cache as needed
1417 CRM_Core_Session::storeSessionObjects();
1418
1419 exit($status);
1420 }
1421
1422 /**
1423 * Reset the various system caches and some important static variables.
1424 */
1425 static function flushCache( ) {
1426 // flush out all cache entries so we can reload new data
1427 // a bit aggressive, but livable for now
1428 $cache = CRM_Utils_Cache::singleton();
1429 $cache->flush();
1430
1431 // also reset the various static memory caches
1432
1433 // reset the memory or array cache
1434 CRM_Core_BAO_Cache::deleteGroup('contact fields', NULL, FALSE);
1435
1436 // reset ACL cache
1437 CRM_ACL_BAO_Cache::resetCache();
1438
1439 // reset various static arrays used here
1440 CRM_Contact_BAO_Contact::$_importableFields =
1441 CRM_Contact_BAO_Contact::$_exportableFields =
1442 CRM_Contribute_BAO_Contribution::$_importableFields =
1443 CRM_Contribute_BAO_Contribution::$_exportableFields =
1444 CRM_Pledge_BAO_Pledge::$_exportableFields =
1445 CRM_Contribute_BAO_Query::$_contributionFields =
1446 CRM_Core_BAO_CustomField::$_importFields =
1447 CRM_Core_BAO_Cache::$_cache =
1448 CRM_Core_DAO::$_dbColumnValueCache = NULL;
1449
1450 CRM_Core_OptionGroup::flushAll();
1451 CRM_Utils_PseudoConstant::flushAll();
1452 }
1453
1454 /**
1455 * Load CMS bootstrap.
1456 *
1457 * @param array $params
1458 * Array with uid name and pass
1459 * @param bool $loadUser
1460 * Boolean load user or not.
1461 * @param bool $throwError
1462 * @param $realPath
1463 */
1464 static function loadBootStrap($params = array(
1465 ), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) {
1466 if (!is_array($params)) {
1467 $params = array();
1468 }
1469 $config = CRM_Core_Config::singleton();
1470 return $config->userSystem->loadBootStrap($params, $loadUser, $throwError, $realPath);
1471 }
1472
1473 /**
1474 * Check if user is logged in.
1475 *
1476 * @return bool
1477 */
1478 public static function isUserLoggedIn() {
1479 $config = CRM_Core_Config::singleton();
1480 return $config->userSystem->isUserLoggedIn();
1481 }
1482
1483 /**
1484 * Get current logged in user id.
1485 *
1486 * @return int
1487 * ufId, currently logged in user uf id.
1488 */
1489 public static function getLoggedInUfID() {
1490 $config = CRM_Core_Config::singleton();
1491 return $config->userSystem->getLoggedInUfID();
1492 }
1493
1494 /**
1495 */
1496 static function baseCMSURL() {
1497 static $_baseURL = NULL;
1498 if (!$_baseURL) {
1499 $config = CRM_Core_Config::singleton();
1500 $_baseURL = $userFrameworkBaseURL = $config->userFrameworkBaseURL;
1501
1502 if ($config->userFramework == 'Joomla') {
1503 // gross hack
1504 // we need to remove the administrator/ from the end
1505 $_baseURL = str_replace("/administrator/", "/", $userFrameworkBaseURL);
1506 }
1507 else {
1508 // Drupal setting
1509 global $civicrm_root;
1510 if (strpos($civicrm_root,
1511 DIRECTORY_SEPARATOR . 'sites' .
1512 DIRECTORY_SEPARATOR . 'all' .
1513 DIRECTORY_SEPARATOR . 'modules'
1514 ) === FALSE) {
1515 $startPos = strpos($civicrm_root,
1516 DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR
1517 );
1518 $endPos = strpos($civicrm_root,
1519 DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR
1520 );
1521 if ($startPos && $endPos) {
1522 // if component is in sites/SITENAME/modules
1523 $siteName = substr($civicrm_root,
1524 $startPos + 7,
1525 $endPos - $startPos - 7
1526 );
1527
1528 $_baseURL = $userFrameworkBaseURL . "sites/$siteName/";
1529 }
1530 }
1531 }
1532 }
1533 return $_baseURL;
1534 }
1535
1536 /**
1537 * Given a URL, return a relative URL if possible.
1538 *
1539 * @param string $url
1540 * @return string
1541 */
1542 static function relativeURL($url) {
1543 // check if url is relative, if so return immediately
1544 if (substr($url, 0, 4) != 'http') {
1545 return $url;
1546 }
1547
1548 // make everything relative from the baseFilePath
1549 $baseURL = self::baseCMSURL();
1550
1551 // check if baseURL is a substr of $url, if so
1552 // return rest of string
1553 if (substr($url, 0, strlen($baseURL)) == $baseURL) {
1554 return substr($url, strlen($baseURL));
1555 }
1556
1557 // return the original value
1558 return $url;
1559 }
1560
1561 /**
1562 * Produce an absolute URL from a possibly-relative URL.
1563 *
1564 * @param string $url
1565 * @param bool $remoteLanguagePart
1566 * @return string
1567 */
1568 static function absoluteURL($url, $removeLanguagePart = FALSE) {
1569 // check if url is already absolute, if so return immediately
1570 if (substr($url, 0, 4) == 'http') {
1571 return $url;
1572 }
1573
1574 // make everything absolute from the baseFileURL
1575 $baseURL = self::baseCMSURL();
1576
1577 //CRM-7622: drop the language from the URL if requested (and it’s there)
1578 $config = CRM_Core_Config::singleton();
1579 if ($removeLanguagePart) {
1580 $baseURL = self::languageNegotiationURL($baseURL, FALSE, TRUE);
1581 }
1582
1583 return $baseURL . $url;
1584 }
1585
1586 /**
1587 * Function to clean url, replaces first '&' with '?'
1588 *
1589 * @param string $url
1590 *
1591 * @return string $url, clean url
1592 */
1593 static function cleanUrl($url) {
1594 if (!$url) {
1595 return NULL;
1596 }
1597
1598 if ($pos = strpos($url, '&')) {
1599 $url = substr_replace($url, '?', $pos, 1);
1600 }
1601
1602 return $url;
1603 }
1604
1605 /**
1606 * Format the url as per language Negotiation.
1607 *
1608 * @param string $url
1609 *
1610 * @return string $url, formatted url.
1611 */
1612 static function languageNegotiationURL($url,
1613 $addLanguagePart = TRUE,
1614 $removeLanguagePart = FALSE
1615 ) {
1616 $config = &CRM_Core_Config::singleton();
1617 return $config->userSystem->languageNegotiationURL($url, $addLanguagePart, $removeLanguagePart);
1618 }
1619
1620 /**
1621 * Append the contents of an 'extra' smarty template file if it is present in
1622 * the custom template directory. This does not work if there are
1623 * multiple custom template directories
1624 *
1625 * @param string $fileName
1626 * The name of the tpl file that we are processing.
1627 * @param string $content
1628 * The current content string. May be modified by this function.
1629 * @param string $overideFileName
1630 * (optional) Sent by contribution/event reg/profile pages which uses a id
1631 * specific extra file name if present.
1632 */
1633 static function appendTPLFile($fileName,
1634 &$content,
1635 $overideFileName = NULL
1636 ) {
1637 $template = CRM_Core_Smarty::singleton();
1638 if ($overideFileName) {
1639 $additionalTPLFile = $overideFileName;
1640 }
1641 else {
1642 $additionalTPLFile = str_replace('.tpl', '.extra.tpl', $fileName);
1643 }
1644
1645 if ($template->template_exists($additionalTPLFile)) {
1646 $content .= $template->fetch($additionalTPLFile);
1647 }
1648 }
1649
1650 /**
1651 * Get a list of all files that are found within the directories
1652 * that are the result of appending the provided relative path to
1653 * each component of the PHP include path.
1654 *
1655 * @author Ken Zalewski
1656 *
1657 * @param string $relpath
1658 * A relative path, typically pointing to a directory with multiple class
1659 * files.
1660 *
1661 * @return array
1662 * An array of files that exist in one or more of the directories that are
1663 * referenced by the relative path when appended to each element of the PHP
1664 * include path.
1665 * @access public
1666 */
1667 static function listIncludeFiles($relpath) {
1668 $file_list = array();
1669 $inc_dirs = explode(PATH_SEPARATOR, get_include_path());
1670 foreach ($inc_dirs as $inc_dir) {
1671 $target_dir = $inc_dir . DIRECTORY_SEPARATOR . $relpath;
1672 if (is_dir($target_dir)) {
1673 $cur_list = scandir($target_dir);
1674 foreach ($cur_list as $fname) {
1675 if ($fname != '.' && $fname != '..') {
1676 $file_list[$fname] = $fname;
1677 }
1678 }
1679 }
1680 }
1681 return $file_list;
1682 }
1683 // listIncludeFiles()
1684
1685 /**
1686 * Get a list of all "plugins" (PHP classes that implement a piece of
1687 * functionality using a well-defined interface) that are found in a
1688 * particular CiviCRM directory (both custom and core are searched).
1689 *
1690 * @author Ken Zalewski
1691 *
1692 * @param string $relpath
1693 * A relative path referencing a directory that contains one or more
1694 * plugins.
1695 * @param string $fext
1696 * (optional) Only files with this extension will be considered to be
1697 * plugins.
1698 * @param array $skipList
1699 * (optional) List of files to skip.
1700 *
1701 * @return array
1702 * List of plugins, where the plugin name is both the key and the value of
1703 * each element.
1704 * @access public
1705 */
1706 static function getPluginList($relpath, $fext = '.php', $skipList = array(
1707 )) {
1708 $fext_len = strlen($fext);
1709 $plugins = array();
1710 $inc_files = CRM_Utils_System::listIncludeFiles($relpath);
1711 foreach ($inc_files as $inc_file) {
1712 if (substr($inc_file, 0 - $fext_len) == $fext) {
1713 $plugin_name = substr($inc_file, 0, 0 - $fext_len);
1714 if (!in_array($plugin_name, $skipList)) {
1715 $plugins[$plugin_name] = $plugin_name;
1716 }
1717 }
1718 }
1719 return $plugins;
1720 }
1721 // getPluginList()
1722
1723 /**
1724 *
1725 */
1726 static function executeScheduledJobs() {
1727 $facility = new CRM_Core_JobManager();
1728 $facility->execute(FALSE);
1729
1730 $redirectUrl = self::url('civicrm/admin/job', 'reset=1');
1731
1732 CRM_Core_Session::setStatus(
1733 ts('Scheduled jobs have been executed according to individual timing settings. Please check log for messages.'),
1734 ts('Complete'), 'success');
1735
1736 CRM_Utils_System::redirect($redirectUrl);
1737 }
1738
1739 /**
1740 * Evaluate any tokens in a URL.
1741 *
1742 * @param string|FALSE $url
1743 * @return string|FALSE
1744 */
1745 public static function evalUrl($url) {
1746 if ($url === FALSE) {
1747 return FALSE;
1748 }
1749 else {
1750 $config = CRM_Core_Config::singleton();
1751 $vars = array(
1752 '{ver}' => CRM_Utils_System::version(),
1753 '{uf}' => $config->userFramework,
1754 '{php}' => phpversion(),
1755 '{sid}' => md5('sid_' . (defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY : '') . '_' . $config->userFrameworkBaseURL),
1756 '{baseUrl}' => $config->userFrameworkBaseURL,
1757 '{lang}' => $config->lcMessages,
1758 '{co}' => $config->defaultContactCountry,
1759 );
1760 foreach (array_keys($vars) as $k) {
1761 $vars[$k] = urlencode($vars[$k]);
1762 }
1763 return strtr($url, $vars);
1764 }
1765 }
1766
1767
1768 /**
1769 * Determine whether this is a developmental system.
1770 *
1771 * @return bool
1772 */
1773 static function isDevelopment() {
1774 static $cache = NULL;
1775 if ($cache === NULL) {
1776 global $civicrm_root;
1777 $cache = file_exists("{$civicrm_root}/.svn") || file_exists("{$civicrm_root}/.git");
1778 }
1779 return $cache;
1780 }
1781 }
1782