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