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