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