Merge pull request #4621 from atif-shaikh/CRM-15589
[civicrm-core.git] / CRM / Utils / System.php
index f2cbf2c7b4d35e36ec599287390469b248caf6f5..91fc83dd25e7078316edb8e0160eb4b5d93480ab 100644 (file)
@@ -1,9 +1,9 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.4                                                |
+ | CiviCRM version 4.5                                                |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2013                                |
+ | Copyright CiviCRM LLC (c) 2004-2014                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
@@ -28,7 +28,7 @@
 /**
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2013
+ * @copyright CiviCRM LLC (c) 2004-2014
  * $Id$
  *
  */
@@ -47,17 +47,24 @@ class CRM_Utils_System {
   static $title = '';
 
   /**
-   * Compose a new url string from the current url string
+   * Compose a new URL string from the current URL string.
+   *
    * Used by all the framework components, specifically,
    * pager, sort and qfc
    *
-   * @param string $urlVar the url variable being considered (i.e. crmPageID, crmSortID etc)
-   * @param boolean $includeReset - should we include or ignore the reset GET string (if present)
-   * @param boolean $includeForce - should we include or ignore the force GET string (if present)
-   * @param string  $path - the path to use for the new url
-   * @param string  $absolute - do we need a absolute or relative URL?
+   * @param string $urlVar
+   *   The url variable being considered (i.e. crmPageID, crmSortID etc).
+   * @param bool $includeReset
+   *   (optional) Whether to include the reset GET string (if present).
+   * @param bool $includeForce
+   *   (optional) Whether to include the force GET string (if present).
+   * @param string $path
+   *   (optional) The path to use for the new url.
+   * @param bool|string $absolute
+   *   (optional) Whether to return an absolute URL.
    *
-   * @return string the url fragment
+   * @return string
+   *   The URL fragment.
    * @access public
    */
   static function makeURL($urlVar, $includeReset = FALSE, $includeForce = TRUE, $path = NULL, $absolute = FALSE) {
@@ -78,14 +85,22 @@ class CRM_Utils_System {
   }
 
   /**
-   * get the query string and clean it up. Strip some variables that should not
-   * be propagated, specically variable like 'reset'. Also strip any side-affect
-   * actions (i.e. export)
+   * Get the query string and clean it up.
+   *
+   * Strips some variables that should not be propagated, specifically variables
+   * like 'reset'. Also strips any side-affect actions (e.g. export).
    *
    * This function is copied mostly verbatim from Pager.php (_getLinksUrl)
    *
-   * @param string  $urlVar       the url variable being considered (i.e. crmPageID, crmSortID etc)
-   * @param boolean $includeReset should we include the reset var (generally this variable should be skipped)
+   * @param string $urlVar
+   *   The URL variable being considered (e.g. crmPageID, crmSortID etc).
+   * @param bool $includeReset
+   *   (optional) By default this is FALSE, meaning that the reset parameter
+   *   is skipped. Set to TRUE to leave the reset parameter as-is.
+   * @param bool $includeForce
+   *   (optional)
+   * @param bool $skipUFVar
+   *   (optional)
    *
    * @return string
    * @access public
@@ -127,7 +142,8 @@ class CRM_Utils_System {
     }
 
     // Ok this is a big assumption but usually works
-    // If we are in snippet mode, retain the 'section' param, if not, get rid of it.
+    // If we are in snippet mode, retain the 'section' param, if not, get rid
+    // of it.
     if (!empty($qs['snippet'])) {
       unset($qs['snippet']);
     }
@@ -157,16 +173,19 @@ class CRM_Utils_System {
   }
 
   /**
-   * if we are using a theming system, invoke theme, else just print the
-   * content
+   * If we are using a theming system, invoke theme, else just print the
+   * content.
    *
-   * @param string  $content the content that will be themed
-   * @param boolean $print   are we displaying to the screen or bypassing theming?
-   * @param boolean $maintenance  for maintenance mode
+   * @param string $content
+   *   The content that will be themed.
+   * @param bool $print
+   *   (optional) Are we displaying to the screen or bypassing theming?
+   * @param bool $maintenance
+   *   (optional) For maintenance mode.
+   *
+   * @return string
    *
-   * @return void           prints content on stdout
    * @access public
-   * @static
    */
   static function theme(
     &$content,
@@ -178,12 +197,10 @@ class CRM_Utils_System {
   }
 
   /**
-   * Generate a query string if input is an array
-   *
-   * @param mixed $query: array or string
-   * @return str
+   * Generate a query string if input is an array.
    *
-   * @static
+   * @param array|string $query
+   * @return string
    */
   static function makeQueryString($query) {
     if (is_array($query)) {
@@ -197,21 +214,25 @@ class CRM_Utils_System {
   }
 
   /**
-   * Generate an internal CiviCRM URL
-   *
-   * @param $path     string   The path being linked to, such as "civicrm/add"
-   * @param $query    mixed    A query string to append to the link, or an array of key-value pairs
-   * @param $absolute boolean  Whether to force the output to be an absolute link (beginning with http:).
-   *                           Useful for links that will be displayed outside the site, such as in an
-   *                           RSS feed.
-   * @param $fragment string   A fragment identifier (named anchor) to append to the link.
+   * Generate an internal CiviCRM URL.
+   *
+   * @param string $path
+   *   The path being linked to, such as "civicrm/add".
+   * @param array|string $query
+   *   A query string to append to the link, or an array of key-value pairs.
+   * @param bool $absolute
+   *   Whether to force the output to be an absolute link (beginning with a
+   *   URI-scheme such as 'http:'). Useful for links that will be displayed
+   *   outside the site, such as in an RSS feed.
+   * @param string $fragment
+   *   A fragment identifier (named anchor) to append to the link.
    *
    * @param bool $htmlize
    * @param bool $frontend
    * @param bool $forceBackend
-   * @return string            an HTML string containing a link to the given path.
+   * @return string
+   *   An HTML string containing a link to the given path.
    * @access public
-   * @static
    */
   static function url(
     $path = NULL,
@@ -233,6 +254,18 @@ class CRM_Utils_System {
     return $config->userSystem->url($path, $query, $absolute, $fragment, $htmlize, $frontend, $forceBackend);
   }
 
+  /**
+   * @param $text
+   * @param null $path
+   * @param null $query
+   * @param bool $absolute
+   * @param null $fragment
+   * @param bool $htmlize
+   * @param bool $frontend
+   * @param bool $forceBackend
+   *
+   * @return string
+   */
   static function href($text, $path = NULL, $query = NULL, $absolute = TRUE,
     $fragment = NULL, $htmlize = TRUE, $frontend = FALSE, $forceBackend = FALSE
   ) {
@@ -240,11 +273,17 @@ class CRM_Utils_System {
     return "<a href=\"$url\">$text</a>";
   }
 
+  /**
+   * @return mixed
+   */
   static function permissionDenied() {
     $config = CRM_Core_Config::singleton();
     return $config->userSystem->permissionDenied();
   }
 
+  /**
+   * @return mixed
+   */
   static function logout() {
     $config = CRM_Core_Config::singleton();
     return $config->userSystem->logout();
@@ -270,13 +309,13 @@ class CRM_Utils_System {
   }
 
   /**
-   * this function is called from a template to compose a url
+   * This function is called from a template to compose a url.
    *
-   * @param array $params list of parameters
+   * @param array $params
+   *   List of parameters.
    *
    * @return string url
    * @access public
-   * @static
    */
   static function crmURL($params) {
     $p = CRM_Utils_Array::value('p', $params);
@@ -296,14 +335,12 @@ class CRM_Utils_System {
   }
 
   /**
-   * sets the title of the page
+   * Sets the title of the page.
    *
    * @param string $title
    * @param string $pageTitle
    *
-   * @return void
    * @access public
-   * @static
    */
   static function setTitle($title, $pageTitle = NULL) {
     self::$title = $title;
@@ -312,13 +349,15 @@ class CRM_Utils_System {
   }
 
   /**
-   * figures and sets the userContext. Uses the referer if valid
-   * else uses the default
+   * Figures and sets the userContext.
    *
-   * @param array  $names   refererer should match any str in this array
-   * @param string $default the default userContext if no match found
+   * Uses the referer if valid else uses the default.
+   *
+   * @param array $names
+   *   Refererer should match any str in this array.
+   * @param string $default
+   *   (optional) The default userContext if no match found.
    *
-   * @return void
    * @access public
    */
   static function setUserContext($names, $default = NULL) {
@@ -342,27 +381,27 @@ class CRM_Utils_System {
   }
 
   /**
-   * gets a class name for an object
+   * Gets a class name for an object.
    *
-   * @param  object $object      - object whose class name is needed
+   * @param object $object
+   *   Object whose class name is needed.
    *
-   * @return string $className   - class name
+   * @return string
+   *   The class name of the object.
    *
    * @access public
-   * @static
    */
   static function getClassName($object) {
     return get_class($object);
   }
 
   /**
-   * redirect to another url
+   * Redirect to another URL.
    *
-   * @param string $url the url to goto
+   * @param string $url
+   *   The URL to provide to the browser via the Location header.
    *
-   * @return void
    * @access public
-   * @static
    */
   static function redirect($url = NULL) {
     if (!$url) {
@@ -372,19 +411,33 @@ class CRM_Utils_System {
     // replace the &amp; characters with &
     // this is kinda hackish but not sure how to do it right
     $url = str_replace('&amp;', '&', $url);
+
+    // If we are in a json context, respond appropriately
+    if (CRM_Utils_Array::value('snippet', $_GET) === 'json') {
+      CRM_Core_Page_AJAX::returnJsonResponse(array(
+        'status' => 'redirect',
+        'userContext' => $url,
+      ));
+    }
+
     header('Location: ' . $url);
     self::civiExit();
   }
 
   /**
-   * use a html based file with javascript embedded to redirect to another url
+   * Redirect to another URL using JavaScript.
+   *
+   * Use an html based file with javascript embedded to redirect to another url
    * This prevent the too many redirect errors emitted by various browsers
    *
-   * @param string $url the url to goto
+   * @param string $url
+   *   (optional) The destination URL.
+   * @param string $title
+   *   (optional) The page title to use for the redirect page.
+   * @param string $message
+   *   (optional) The message to provide in the body of the redirect page.
    *
-   * @return void
    * @access public
-   * @static
    */
   static function jsRedirect(
     $url     = NULL,
@@ -420,14 +473,11 @@ class CRM_Utils_System {
   }
 
   /**
-   * Append an additional breadcrumb tag to the existing breadcrumb
+   * Append an additional breadcrumb tag to the existing breadcrumbs.
    *
-   * @param string $title
-   * @param string $url
+   * @param $breadCrumbs
    *
-   * @return void
    * @access public
-   * @static
    */
   static function appendBreadCrumb($breadCrumbs) {
     $config = CRM_Core_Config::singleton();
@@ -435,11 +485,9 @@ class CRM_Utils_System {
   }
 
   /**
-   * Reset an additional breadcrumb tag to the existing breadcrumb
+   * Reset an additional breadcrumb tag to the existing breadcrumb.
    *
-   * @return void
    * @access public
-   * @static
    */
   static function resetBreadCrumb() {
     $config = CRM_Core_Config::singleton();
@@ -447,13 +495,11 @@ class CRM_Utils_System {
   }
 
   /**
-   * Append a string to the head of the html file
+   * Append a string to the head of the HTML file.
    *
-   * @param string $head the new string to be appended
+   * @param string $bc
    *
-   * @return void
    * @access public
-   * @static
    */
   static function addHTMLHead($bc) {
     $config = CRM_Core_Config::singleton();
@@ -461,13 +507,14 @@ class CRM_Utils_System {
   }
 
   /**
-   * figure out the post url for the form
+   * Determine the post URL for a form
    *
-   * @param the default action if one is pre-specified
+   * @param $action
+   *   The default action if one is pre-specified.
    *
-   * @return string the url to post the form
+   * @return string
+   *   The URL to post the form.
    * @access public
-   * @static
    */
   static function postURL($action) {
     $config = CRM_Core_Config::singleton();
@@ -475,11 +522,9 @@ class CRM_Utils_System {
   }
 
   /**
-   * rewrite various system urls to https
+   * Rewrite various system URLs to https.
    *
-   * @return void
-   * access public
-   * @static
+   * @access public
    */
   static function mapConfigToSSL() {
     $config = CRM_Core_Config::singleton();
@@ -494,19 +539,18 @@ class CRM_Utils_System {
   }
 
   /**
-   * Get the base URL from the system
-   *
-   * @param
+   * Get the base URL of the system.
    *
    * @return string
    * @access public
-   * @static
    */
   static function baseURL() {
     $config = CRM_Core_Config::singleton();
     return $config->userFrameworkBaseURL;
   }
 
+  /**
+   */
   static function authenticateAbort($message, $abort) {
     if ($abort) {
       echo $message;
@@ -517,6 +561,12 @@ class CRM_Utils_System {
     }
   }
 
+  /**
+   * @param bool $abort
+   *   (optional) Whether to exit; defaults to true.
+   *
+   * @return bool
+   */
   static function authenticateKey($abort = TRUE) {
     // also make sure the key is sent and is valid
     $key = trim(CRM_Utils_Array::value('key', $_REQUEST));
@@ -556,9 +606,18 @@ class CRM_Utils_System {
     return TRUE;
   }
 
+  /**
+   * @param bool $abort
+   * @param null $name
+   * @param null $pass
+   * @param bool $storeInSession
+   * @param bool $loadCMSBootstrap
+   * @param bool $requireKey
+   *
+   * @return bool
+   */
   static function authenticateScript($abort = TRUE, $name = NULL, $pass = NULL, $storeInSession = TRUE, $loadCMSBootstrap = TRUE, $requireKey = TRUE) {
-    // auth to make sure the user has a login/password to do a shell
-    // operation
+    // auth to make sure the user has a login/password to do a shell operation
     // later on we'll link this to acl's
     if (!$name) {
       $name = trim(CRM_Utils_Array::value('name', $_REQUEST));
@@ -603,25 +662,30 @@ class CRM_Utils_System {
   }
 
   /**
-   * Authenticate the user against the uf db
+   * Authenticate the user against the uf db.
    *
-   * @param string $name     the user name
-   * @param string $password the password for the above user name
+   * In case of succesful authentication, returns an array consisting of
+   * (contactID, ufID, unique string). Returns FALSE if authentication is
+   * unsuccessful.
    *
-   * @return mixed false if no auth
-   *               array(
-      contactID, ufID, unique string ) if success
+   * @param string $name
+   *   The username.
+   * @param string $password
+   *   The password.
+   * @param bool $loadCMSBootstrap
+   * @param $realPath
+   *
+   * @return false|array
    * @access public
-   * @static
    */
   static function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realPath = NULL) {
     $config = CRM_Core_Config::singleton();
 
-    // before we do any loading, lets start the session and write to it
-    // we typically call authenticate only when we need to bootstrap the CMS directly via Civi
-    // and hence bypass the normal CMS auth and bootstrap process
-    // typically done in cli and cron scripts
-    // CRM-12648
+    /* Before we do any loading, let's start the session and write to it.
+     * We typically call authenticate only when we need to bootstrap the CMS
+     * directly via Civi and hence bypass the normal CMS auth and bootstrap
+     * process typically done in CLI and cron scripts. See: CRM-12648
+     */
     $session = CRM_Core_Session::singleton();
     $session->set( 'civicrmInitSession', TRUE );
 
@@ -630,12 +694,12 @@ class CRM_Utils_System {
   }
 
   /**
-   * Set a message in the UF to display to a user
+   * Set a message in the UF to display to a user.
    *
-   * @param string $name     the message to set
+   * @param string $message
+   *   The message to set.
    *
    * @access public
-   * @static
    */
   static function setUFMessage($message) {
     $config = CRM_Core_Config::singleton();
@@ -643,7 +707,13 @@ class CRM_Utils_System {
   }
 
 
-
+  /**
+   * Determine whether a value is null-ish.
+   *
+   * @param $value
+   *   The value to check for null.
+   * @return bool
+   */
   static function isNull($value) {
     // FIXME: remove $value = 'null' string test when we upgrade our DAO code to handle passing null in a better way.
     if (!isset($value) || $value === NULL || $value === '' || $value === 'null') {
@@ -660,6 +730,16 @@ class CRM_Utils_System {
     return FALSE;
   }
 
+  /**
+   * Obscure all but the last few digits of a credit card number.
+   *
+   * @param string $number
+   *   The credit card number to obscure.
+   * @param int $keep
+   *   (optional) The number of digits to preserve unmodified.
+   * @return string
+   *   The obscured credit card number.
+   */
   static function mungeCreditCard($number, $keep = 4) {
     $number = trim($number);
     if (empty($number)) {
@@ -669,7 +749,11 @@ class CRM_Utils_System {
     return substr_replace($number, $replace, 0, -$keep);
   }
 
-  /** parse php modules from phpinfo */
+  /**
+   * Determine which PHP modules are loaded.
+   *
+   * @return array
+   */
   public static function parsePHPModules() {
     ob_start();
     phpinfo(INFO_MODULES);
@@ -703,12 +787,20 @@ class CRM_Utils_System {
     return $vModules;
   }
 
-  /** get a module setting */
+  /**
+   * Get a setting from a loaded PHP module.
+   */
   public static function getModuleSetting($pModuleName, $pSetting) {
     $vModules = self::parsePHPModules();
     return $vModules[$pModuleName][$pSetting];
   }
 
+  /**
+   * @param $title
+   *   (optional)
+   *
+   * @return mixed|string
+   */
   static function memory($title = NULL) {
     static $pid = NULL;
     if (!$pid) {
@@ -723,9 +815,18 @@ class CRM_Utils_System {
     return $memory;
   }
 
+  /**
+   * @param string $name
+   * @param string $mimeType
+   * @param $buffer
+   * @param string $ext
+   * @param bool $output
+   * @param string $disposition
+   */
   static function download($name, $mimeType, &$buffer,
     $ext = NULL,
-    $output = TRUE
+    $output = TRUE,
+    $disposition = 'attachment'
   ) {
     $now = gmdate('D, d M Y H:i:s') . ' GMT';
 
@@ -746,7 +847,7 @@ class CRM_Utils_System {
       header('Pragma: public');
     }
     else {
-      header("Content-Disposition: attachment; $fileString");
+      header("Content-Disposition: $disposition; $fileString");
       header('Pragma: no-cache');
     }
 
@@ -756,6 +857,13 @@ class CRM_Utils_System {
     }
   }
 
+  /**
+   * Gather and print (and possibly log) amount of used memory.
+   *
+   * @param string $title
+   * @param bool $log
+   *   (optional) Whether to log the memory usage information.
+   */
   static function xMemory($title = NULL, $log = FALSE) {
     $mem = (float ) xdebug_memory_usage() / (float )(1024);
     $mem = number_format($mem, 5) . ", " . time();
@@ -770,6 +878,17 @@ class CRM_Utils_System {
     }
   }
 
+  /**
+   * Take a URL (or partial URL) and make it better.
+   *
+   * Currently, URLs pass straight through unchanged unless they are "seriously
+   * malformed" (see http://us2.php.net/parse_url).
+   *
+   * @param string $url
+   *   The URL to operate on.
+   * @return string
+   *   The fixed URL.
+   */
   static function fixURL($url) {
     $components = parse_url($url);
 
@@ -783,12 +902,12 @@ class CRM_Utils_System {
   }
 
   /**
-   * make sure the callback is valid in the current context
+   * Make sure a callback is valid in the current context.
    *
-   * @param string $callback the name of the function
+   * @param string $callback
+   *   Name of the function to check.
    *
-   * @return boolean
-   * @static
+   * @return bool
    */
   static function validCallback($callback) {
     if (self::$_callbacks === NULL) {
@@ -823,9 +942,16 @@ class CRM_Utils_System {
   }
 
   /**
-   * This serves as a wrapper to the php explode function
-   * we expect exactly $limit arguments in return, and if we dont
-   * get them, we pad it with null
+   * Like PHP's built-in explode(), but always return an array of $limit items.
+   *
+   * This serves as a wrapper to the PHP explode() function. In the event that
+   * PHP's explode() returns an array with fewer than $limit elements, pad
+   * the end of the array with NULLs.
+   *
+   * @param string $separator
+   * @param string $string
+   * @param int $limit
+   * @return string[]
    */
   static function explode($separator, $string, $limit) {
     $result = explode($separator, $string, $limit);
@@ -835,6 +961,14 @@ class CRM_Utils_System {
     return $result;
   }
 
+  /**
+   * @param string $url
+   *   The URL to check.
+   * @param bool $addCookie
+   *   (optional)
+   *
+   * @return mixed
+   */
   static function checkURL($url, $addCookie = FALSE) {
     // make a GET request to $url
     $ch = curl_init($url);
@@ -845,11 +979,25 @@ class CRM_Utils_System {
     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
 
     // lets capture the return stuff rather than echo
-    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE );
 
-    return curl_exec($ch);
+    // CRM-13227, CRM-14744: only return the SSL error status
+    return (curl_exec($ch) !== FALSE);
   }
 
+  /**
+   * Assert that we are running on a particular PHP version.
+   *
+   * @param int $ver
+   *   The major version of PHP that is required.
+   * @param bool $abort
+   *   (optional) Whether to fatally abort if the version requirement is not
+   *   met. Defaults to TRUE.
+   * @return bool
+   *   Returns TRUE if the requirement is met, FALSE if the requirement is not
+   *   met and we're not aborting due to the failed requirement. If $abort is
+   *   TRUE and the requirement fails, this function does not return.
+   */
   static function checkPHPVersion($ver = 5, $abort = TRUE) {
     $phpVersion = substr(PHP_VERSION, 0, 1);
     if ($phpVersion >= $ver) {
@@ -864,6 +1012,12 @@ class CRM_Utils_System {
     return FALSE;
   }
 
+  /**
+   * @param $string
+   * @param bool $encode
+   *
+   * @return string
+   */
   static function formatWikiURL($string, $encode = FALSE) {
     $items = explode(' ', trim($string), 2);
     if (count($items) == 2) {
@@ -878,30 +1032,35 @@ class CRM_Utils_System {
     return "<a href=\"$url\">$title</a>";
   }
 
+  /**
+   * @param string $url
+   *
+   * @return null|string
+   */
   static function urlEncode($url) {
     $items = parse_url($url);
     if ($items === FALSE) {
       return NULL;
     }
 
-    if (!CRM_Utils_Array::value('query', $items)) {
+    if (empty($items['query'])) {
       return $url;
     }
 
     $items['query'] = urlencode($items['query']);
 
     $url = $items['scheme'] . '://';
-    if (CRM_Utils_Array::value('user', $items)) {
+    if (!empty($items['user'])) {
       $url .= "{$items['user']}:{$items['pass']}@";
     }
 
     $url .= $items['host'];
-    if (CRM_Utils_Array::value('port', $items)) {
+    if (!empty($items['port'])) {
       $url .= ":{$items['port']}";
     }
 
     $url .= "{$items['path']}?{$items['query']}";
-    if (CRM_Utils_Array::value('fragment', $items)) {
+    if (!empty($items['fragment'])) {
       $url .= "#{$items['fragment']}";
     }
 
@@ -909,9 +1068,10 @@ class CRM_Utils_System {
   }
 
   /**
-   * Function to return the latest civicrm version.
+   * Return the running civicrm version.
    *
-   * @return string civicrm version
+   * @return string
+   *   civicrm version
    * @access public
    */
   static function version() {
@@ -949,10 +1109,20 @@ class CRM_Utils_System {
     return $version;
   }
 
+  /**
+   * Determines whether a string is a valid CiviCRM version string.
+   *
+   * @param string $version
+   *   Version string to be checked.
+   * @return bool
+   */
   static function isVersionFormatValid($version) {
     return preg_match("/^(\d{1,2}\.){2,3}(\d{1,2}|(alpha|beta)\d{1,2})(\.upgrade)?$/", $version);
   }
 
+  /**
+   * Wraps or emulates PHP's getallheaders() function.
+   */
   static function getAllHeaders() {
     if (function_exists('getallheaders')) {
       return getallheaders();
@@ -976,6 +1146,8 @@ class CRM_Utils_System {
     return $headers;
   }
 
+  /**
+   */
   static function getRequestHeaders() {
     if (function_exists('apache_request_headers')) {
       return apache_request_headers();
@@ -986,17 +1158,20 @@ class CRM_Utils_System {
   }
 
   /**
-   * Check and determine is this is an SSL request
-   * Note that we inline this function in install/civicrm.php, so if
-   * you change this function, please go and change the code in the install script
+   * Determine whether this is an SSL request.
+   *
+   * Note that we inline this function in install/civicrm.php, so if you change
+   * this function, please go and change the code in the install script as well.
    */
   static function isSSL( ) {
     return
       (isset($_SERVER['HTTPS']) &&
         !empty($_SERVER['HTTPS']) &&
-        strtolower($_SERVER['HTTPS']) != 'off') ? true : false;
+        strtolower($_SERVER['HTTPS']) != 'off') ? TRUE : FALSE;
   }
 
+  /**
+   */
   static function redirectToSSL($abort = FALSE) {
     $config = CRM_Core_Config::singleton();
     $req_headers = self::getRequestHeaders();
@@ -1024,18 +1199,29 @@ class CRM_Utils_System {
   /*
    * Get logged in user's IP address.
    *
-   * Get IP address from HTTP Header. If the CMS is Drupal then use the Drupal function
-   * as this also handles reverse proxies (based on proper configuration in settings.php)
+   * Get IP address from HTTP REMOTE_ADDR header. If the CMS is Drupal then use
+   * the Drupal function as this also handles reverse proxies (based on proper
+   * configuration in settings.php)
+   *
+   * @param bool $strictIPV4
+   *   (optional) Whether to return only IPv4 addresses.
+   *
+   * @return string
+   *   IP address of logged in user.
+   */
+  /**
+   * @param bool $strictIPV4
    *
-   * @return string ip address of logged in user
+   * @return mixed|string
    */
   static function ipAddress($strictIPV4 = TRUE) {
     $address = CRM_Utils_Array::value('REMOTE_ADDR', $_SERVER);
 
     $config = CRM_Core_Config::singleton();
-    if ($config->userSystem->is_drupal) {
-      //drupal function handles the server being behind a proxy securely
-      $address = ip_address();
+    if ($config->userSystem->is_drupal && function_exists('ip_address')) {
+      //drupal function handles the server being behind a proxy securely. We still have legacy ipn methods
+      // that reach this point without bootstrapping hence the check that the fn exists
+        $address = ip_address();
     }
 
     // hack for safari
@@ -1056,9 +1242,10 @@ class CRM_Utils_System {
   }
 
   /**
-   * Returns you the referring / previous page url
+   * Get the referring / previous page URL.
    *
-   * @return string the previous page url
+   * @return string
+   *   The previous page URL
    * @access public
    */
   static function refererPath() {
@@ -1066,9 +1253,10 @@ class CRM_Utils_System {
   }
 
   /**
-   * Returns default documentation URL base
+   * Get the documentation base URL.
    *
-   * @return string documentation url
+   * @return string
+   *   Base URL of the CRM documentation.
    * @access public
    */
   static function getDocBaseURL() {
@@ -1077,7 +1265,7 @@ class CRM_Utils_System {
   }
 
   /**
-   * Returns wiki (alternate) documentation URL base
+   * Returns wiki (alternate) documentation URL base.
    *
    * @return string documentation url
    * @access public
@@ -1089,16 +1277,26 @@ class CRM_Utils_System {
 
   /**
    * Returns URL or link to documentation page, based on provided parameters.
+   *
    * For use in PHP code.
-   * WARNING: Always returns URL, if ts function is not defined ($URLonly has no effect).
+   * WARNING: Always returns URL, if ts function is not defined ($URLonly has
+   * no effect).
+   *
+   * @param string $page
+   *   Title of documentation wiki page.
+   * @param boolean $URLonly
+   *   (optional) Whether to return URL only or full HTML link (default).
+   * @param string $text
+   *   (optional) Text of HTML link (no effect if $URLonly = false).
+   * @param string $title
+   *   (optional) Tooltip text for HTML link (no effect if $URLonly = false)
+   * @param string $style
+   *   (optional) Style attribute value for HTML link (no effect if $URLonly = false)
    *
-   * @param string  $page    Title of documentation wiki page
-   * @param boolean $URLonly Whether function should return URL only or whole link (default)
-   * @param string  $text    Text of HTML link (no effect if $URLonly = false)
-   * @param string  $title   Tooltip text for HTML link (no effect if $URLonly = false)
-   * @param string  $style   Style attribute value for HTML link (no effect if $URLonly = false)
+   * @param null $resource
    *
-   * @return string URL or link to documentation page, based on provided parameters
+   * @return string
+   *   URL or link to documentation page, based on provided parameters.
    * @access public
    */
   static function docURL2($page, $URLonly = FALSE, $text = NULL, $title = NULL, $style = NULL, $resource = NULL) {
@@ -1127,11 +1325,14 @@ class CRM_Utils_System {
 
   /**
    * Returns URL or link to documentation page, based on provided parameters.
+   *
    * For use in templates code.
    *
-   * @param array $params An array of parameters (see CRM_Utils_System::docURL2 method for names)
+   * @param array $params
+   *   An array of parameters (see CRM_Utils_System::docURL2 method for names)
    *
-   * @return string URL or link to documentation page, based on provided parameters
+   * @return string
+   *   URL or link to documentation page, based on provided parameters.
    * @access public
    */
   static function docURL($params) {
@@ -1167,14 +1368,15 @@ class CRM_Utils_System {
       return $link;
     }
     else {
-      return "<a href=\"{$link}\" $style target=\"_blank\" title=\"{$params['title']}\">{$params['text']}</a>";
+      return "<a href=\"{$link}\" $style target=\"_blank\" class=\"crm-doc-link no-popup\" title=\"{$params['title']}\">{$params['text']}</a>";
     }
   }
 
   /**
    * Get the locale set in the hosting CMS
    *
-   * @return string  the used locale or null for none
+   * @return string
+   *   The used locale or null for none.
    */
   static function getUFLocale() {
     $config = CRM_Core_Config::singleton();
@@ -1182,16 +1384,18 @@ class CRM_Utils_System {
   }
 
   /**
-   * Execute external or internal urls and return server response
+   * Execute external or internal URLs and return server response.
    *
-   *  @param string   $url request url
-   *  @param boolean  $addCookie  should be true to access internal urls
+   * @param string $url
+   *   Request URL.
+   * @param bool $addCookie
+   *   Whether to provide a cookie. Should be true to access internal URLs.
    *
-   *  @return string  $response response from url
-   *  @static
+   * @return string
+   *   Response from URL.
    */
   static function getServerResponse($url, $addCookie = TRUE) {
-    CRM_Core_Error::ignoreException();
+    CRM_Core_TemporaryErrorScope::ignoreException();
     require_once 'HTTP/Request.php';
     $request = new HTTP_Request($url);
 
@@ -1213,10 +1417,11 @@ class CRM_Utils_System {
     $request->sendRequest();
     $response = $request->getResponseBody();
 
-    CRM_Core_Error::setCallback();
     return $response;
   }
 
+  /**
+   */
   static function isDBVersionValid(&$errorMessage) {
     $dbVersion = CRM_Core_BAO_Domain::version();
 
@@ -1259,6 +1464,12 @@ class CRM_Utils_System {
     return TRUE;
   }
 
+  /**
+   * Exit with provided exit code.
+   *
+   * @param int $status
+   *   (optional) Code with which to exit.
+   */
   static function civiExit($status = 0) {
     // move things to CiviCRM cache as needed
     CRM_Core_Session::storeSessionObjects();
@@ -1267,8 +1478,7 @@ class CRM_Utils_System {
   }
 
   /**
-   * Reset the various system caches and some important
-   * static variables
+   * Reset the various system caches and some important static variables.
    */
   static function flushCache( ) {
     // flush out all cache entries so we can reload new data
@@ -1300,13 +1510,16 @@ class CRM_Utils_System {
   }
 
   /**
-   * load cms bootstrap
-   *
-   * @param $params   array with uid name and pass
-   * @param $loadUser boolean load user or not
+   * Load CMS bootstrap.
+   *
+   * @param array $params
+   *   Array with uid name and pass
+   * @param bool $loadUser
+   *   Boolean load user or not.
+   * @param bool $throwError
+   * @param $realPath
    */
-  static function loadBootStrap($params = array(
-    ), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) {
+  static function loadBootStrap($params = array(), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) {
     if (!is_array($params)) {
       $params = array();
     }
@@ -1315,9 +1528,9 @@ class CRM_Utils_System {
   }
 
   /**
-   * check is user logged in.
+   * Check if user is logged in.
    *
-   * @return boolean.
+   * @return bool
    */
   public static function isUserLoggedIn() {
     $config = CRM_Core_Config::singleton();
@@ -1327,13 +1540,16 @@ class CRM_Utils_System {
   /**
    * Get current logged in user id.
    *
-   * @return int ufId, currently logged in user uf id.
+   * @return int
+   *   ufId, currently logged in user uf id.
    */
   public static function getLoggedInUfID() {
     $config = CRM_Core_Config::singleton();
     return $config->userSystem->getLoggedInUfID();
   }
 
+  /**
+   */
   static function baseCMSURL() {
     static $_baseURL = NULL;
     if (!$_baseURL) {
@@ -1374,6 +1590,12 @@ class CRM_Utils_System {
     return $_baseURL;
   }
 
+  /**
+   * Given a URL, return a relative URL if possible.
+   *
+   * @param string $url
+   * @return string
+   */
   static function relativeURL($url) {
     // check if url is relative, if so return immediately
     if (substr($url, 0, 4) != 'http') {
@@ -1393,6 +1615,14 @@ class CRM_Utils_System {
     return $url;
   }
 
+  /**
+   * Produce an absolute URL from a possibly-relative URL.
+   *
+   * @param string $url
+   * @param bool $removeLanguagePart
+   *
+   * @return string
+   */
   static function absoluteURL($url, $removeLanguagePart = FALSE) {
     // check if url is already absolute, if so return immediately
     if (substr($url, 0, 4) == 'http') {
@@ -1412,12 +1642,11 @@ class CRM_Utils_System {
   }
 
   /**
-   * Function to clean url, replaces first '&' with '?'
+   * clean url, replaces first '&' with '?'
    *
    * @param string $url
    *
    * @return string $url, clean url
-   * @static
    */
   static function cleanUrl($url) {
     if (!$url) {
@@ -1436,8 +1665,10 @@ class CRM_Utils_System {
    *
    * @param string $url
    *
+   * @param bool $addLanguagePart
+   * @param bool $removeLanguagePart
+   *
    * @return string $url, formatted url.
-   * @static
    */
   static function languageNegotiationURL($url,
     $addLanguagePart = TRUE,
@@ -1452,13 +1683,13 @@ class CRM_Utils_System {
    * the custom template directory. This does not work if there are
    * multiple custom template directories
    *
-   * @param string $fileName - the name of the tpl file that we are processing
-   * @param string $content (by reference) - the current content string
-   * @param string $overideFileName - an optional parameter which is sent by contribution/event reg/profile pages
-   *               which uses a id specific extra file name if present
-   *
-   * @return void - the content string is modified if needed
-   * @static
+   * @param string $fileName
+   *   The name of the tpl file that we are processing.
+   * @param string $content
+   *   The current content string. May be modified by this function.
+   * @param string $overideFileName
+   *   (optional) Sent by contribution/event reg/profile pages which uses a id
+   *   specific extra file name if present.
    */
   static function appendTPLFile($fileName,
     &$content,
@@ -1484,12 +1715,14 @@ class CRM_Utils_System {
    *
    * @author Ken Zalewski
    *
-   * @param string $relpath a relative path, typically pointing to
-   *               a directory with multiple class files
+   * @param string $relpath
+   *   A relative path, typically pointing to a directory with multiple class
+   *   files.
    *
-   * @return array An array of files that exist in one or more of the
-   *               directories that are referenced by the relative path
-   *               when appended to each element of the PHP include path
+   * @return array
+   *   An array of files that exist in one or more of the directories that are
+   *   referenced by the relative path when appended to each element of the PHP
+   *   include path.
    * @access public
    */
   static function listIncludeFiles($relpath) {
@@ -1517,20 +1750,23 @@ class CRM_Utils_System {
    *
    * @author Ken Zalewski
    *
-   * @param string $relpath a relative path referencing a directory that
-   *               contains one or more plugins
-   * @param string $fext only files with this extension will be considered
-   *               to be plugins
-   * @param array  $skipList list of files to skip
-   *
-   * @return array List of plugins, where the plugin name is both the
-   *               key and the value of each element.
+   * @param string $relpath
+   *   A relative path referencing a directory that contains one or more
+   *   plugins.
+   * @param string $fext
+   *   (optional) Only files with this extension will be considered to be
+   *   plugins.
+   * @param array $skipList
+   *   (optional) List of files to skip.
+   *
+   * @return array
+   *   List of plugins, where the plugin name is both the key and the value of
+   *   each element.
    * @access public
    */
-  static function getPluginList($relpath, $fext = '.php', $skipList = array(
-    )) {
-    $fext_len  = strlen($fext);
-    $plugins   = array();
+  static function getPluginList($relpath, $fext = '.php', $skipList = array()) {
+    $fext_len = strlen($fext);
+    $plugins = array();
     $inc_files = CRM_Utils_System::listIncludeFiles($relpath);
     foreach ($inc_files as $inc_file) {
       if (substr($inc_file, 0 - $fext_len) == $fext) {
@@ -1546,11 +1782,6 @@ class CRM_Utils_System {
 
   /**
    *
-   * @param string $fileName - the name of the tpl file that we are processing
-   * @param string $content (by reference) - the current content string
-   *
-   * @return void - the content string is modified if needed
-   * @static
    */
   static function executeScheduledJobs() {
     $facility = new CRM_Core_JobManager();
@@ -1566,7 +1797,7 @@ class CRM_Utils_System {
   }
 
   /**
-   * Evaluate any tokens in a URL
+   * Evaluate any tokens in a URL.
    *
    * @param string|FALSE $url
    * @return string|FALSE
@@ -1607,5 +1838,68 @@ class CRM_Utils_System {
     }
     return $cache;
   }
-}
 
+  /**
+   * @return bool
+   */
+  static function isInUpgradeMode() {
+    $args = explode('/', $_GET['q']);
+    $upgradeInProcess = CRM_Core_Session::singleton()->get('isUpgradePending');
+    if ((isset($args[1]) && $args[1] == 'upgrade') || $upgradeInProcess) {
+      return TRUE;
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Determine the standard URL for viewing or editing the specified link
+   *
+   * This function delegates the decision-making to (a) the hook system and
+   * (b) the BAO system.
+   *
+   * @param array $crudLinkSpec with keys:
+   *  - action: int, CRM_Core_Action::UPDATE or CRM_Core_Action::VIEW [default: VIEW]
+   *  - entity_table: string, eg "civicrm_contact"
+   *  - entity_id: int
+   * @return array|NULL NULL if unavailable, or an array. array has keys:
+   *  - path: string
+   *  - query: array
+   *  - title: string
+   *  - url: string
+   */
+  static function createDefaultCrudLink($crudLinkSpec) {
+    $crudLinkSpec['action'] = CRM_Utils_Array::value('action', $crudLinkSpec, CRM_Core_Action::VIEW);
+    $daoClass = CRM_Core_DAO_AllCoreTables::getClassForTable($crudLinkSpec['entity_table']);
+    if (!$daoClass) {
+      return NULL;
+    }
+
+    $baoClass = str_replace('_DAO_', '_BAO_', $daoClass);
+    if (!class_exists($baoClass)) {
+      return NULL;
+    }
+
+    $bao = new $baoClass();
+    $bao->id = $crudLinkSpec['entity_id'];
+    if (!$bao->find(TRUE)) {
+      return NULL;
+    }
+
+    $link = array();
+    CRM_Utils_Hook::crudLink($crudLinkSpec, $bao, $link);
+    if (empty($link) && is_callable(array($bao, 'createDefaultCrudLink'))) {
+      $link = $bao->createDefaultCrudLink($crudLinkSpec);
+    }
+
+    if (!empty($link)) {
+      if (!isset($link['url'])) {
+        $link['url'] = self::url($link['path'], $link['query'], TRUE, NULL, FALSE);
+      }
+      return $link;
+    }
+
+    return NULL;
+  }
+}