CRM-16499 - Fix relative Angular paths in Windows
[civicrm-core.git] / CRM / Utils / File.php
index a9a5d63844bed8398466c51d44b484be78e658bb..a8ca3b77c3c17fb6955fd9a0bf4374cebd8a6197 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 4.6                                                |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2014                                |
+ | Copyright CiviCRM LLC (c) 2004-2015                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
  | GNU Affero General Public License or the licensing of CiviCRM,     |
  | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
  +--------------------------------------------------------------------+
-*/
+ */
 
 /**
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2014
+ * @copyright CiviCRM LLC (c) 2004-2015
  * $Id: $
  *
  */
@@ -44,7 +44,8 @@ class CRM_Utils_File {
    * @param string $name
    *   Name of file.
    *
-   * @return boolean     true if file is ascii
+   * @return bool
+   *   true if file is ascii
    */
   public static function isAscii($name) {
     $fd = fopen($name, "r");
@@ -71,7 +72,8 @@ class CRM_Utils_File {
    * @param string $name
    *   Name of file.
    *
-   * @return boolean     true if file is html
+   * @return bool
+   *   true if file is html
    */
   public static function isHtml($name) {
     $fd = fopen($name, "r");
@@ -104,7 +106,6 @@ class CRM_Utils_File {
    *   Should we abort or just return an invalid code.
    *
    * @return void
-   * @static
    */
   public static function createDir($path, $abort = TRUE) {
     if (is_dir($path) || empty($path)) {
@@ -137,7 +138,6 @@ class CRM_Utils_File {
    *
    * @throws Exception
    * @return void
-   * @static
    */
   public static function cleanDir($target, $rmdir = TRUE, $verbose = TRUE) {
     static $exceptions = array('.', '..');
@@ -145,8 +145,8 @@ class CRM_Utils_File {
       throw new Exception("Overly broad deletion");
     }
 
-    if ($sourcedir = opendir($target)) {
-      while (FALSE !== ($sibling = readdir($sourcedir))) {
+    if ($dh = @opendir($target)) {
+      while (FALSE !== ($sibling = readdir($dh))) {
         if (!in_array($sibling, $exceptions)) {
           $object = $target . DIRECTORY_SEPARATOR . $sibling;
 
@@ -160,7 +160,7 @@ class CRM_Utils_File {
           }
         }
       }
-      closedir($sourcedir);
+      closedir($dh);
 
       if ($rmdir) {
         if (rmdir($target)) {
@@ -177,13 +177,35 @@ class CRM_Utils_File {
   }
 
   /**
-   * @param $source
-   * @param $destination
+   * Concatenate several files.
+   *
+   * @param array $files
+   *   List of file names.
+   * @param string $delim
+   *   An optional delimiter to put between files.
+   * @return string
    */
-  static function copyDir($source, $destination) {
-    if ($dir = opendir($source)) {
+  public static function concat($files, $delim = '') {
+    $buf = '';
+    $first = TRUE;
+    foreach ($files as $file) {
+      if (!$first) {
+        $buf .= $delim;
+      }
+      $buf .= file_get_contents($file);
+      $first = FALSE;
+    }
+    return $buf;
+  }
+
+  /**
+   * @param string $source
+   * @param string $destination
+   */
+  public static function copyDir($source, $destination) {
+    if ($dh = opendir($source)) {
       @mkdir($destination);
-      while (FALSE !== ($file = readdir($dir))) {
+      while (FALSE !== ($file = readdir($dh))) {
         if (($file != '.') && ($file != '..')) {
           if (is_dir($source . DIRECTORY_SEPARATOR . $file)) {
             CRM_Utils_File::copyDir($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file);
@@ -193,7 +215,7 @@ class CRM_Utils_File {
           }
         }
       }
-      closedir($dir);
+      closedir($dh);
     }
   }
 
@@ -203,7 +225,8 @@ class CRM_Utils_File {
    * @param string $name
    *   Name of file.
    *
-   * @return boolean  whether the file was recoded properly
+   * @return bool
+   *   whether the file was recoded properly
    */
   public static function toUtf8($name) {
     static $config = NULL;
@@ -250,7 +273,6 @@ class CRM_Utils_File {
    * @param string $slash
    *
    * @return string
-   * @static
    */
   public static function addTrailingSlash($path, $slash = NULL) {
     if (!$slash) {
@@ -328,11 +350,12 @@ class CRM_Utils_File {
       // allow html/htm extension ONLY if the user is admin
       // and/or has access CiviMail
       if (!(CRM_Core_Permission::check('access CiviMail') ||
-          CRM_Core_Permission::check('administer CiviCRM') ||
-          (CRM_Mailing_Info::workflowEnabled() &&
-            CRM_Core_Permission::check('create mailings')
-          )
-        )) {
+        CRM_Core_Permission::check('administer CiviCRM') ||
+        (CRM_Mailing_Info::workflowEnabled() &&
+          CRM_Core_Permission::check('create mailings')
+        )
+      )
+      ) {
         unset($extensions['html']);
         unset($extensions['htm']);
       }
@@ -342,12 +365,13 @@ class CRM_Utils_File {
   }
 
   /**
-   * Determine whether a given file is listed in the PHP include path
+   * Determine whether a given file is listed in the PHP include path.
    *
    * @param string $name
    *   Name of file.
    *
-   * @return boolean  whether the file can be include()d or require()d
+   * @return bool
+   *   whether the file can be include()d or require()d
    */
   public static function isIncludable($name) {
     $x = @fopen($name, 'r', TRUE);
@@ -376,8 +400,8 @@ class CRM_Utils_File {
    * @return string
    */
   public static function makeFileName($name) {
-    $uniqID   = md5(uniqid(rand(), TRUE));
-    $info     = pathinfo($name);
+    $uniqID = md5(uniqid(rand(), TRUE));
+    $info = pathinfo($name);
     $basename = substr($info['basename'],
       0, -(strlen(CRM_Utils_Array::value('extension', $info)) + (CRM_Utils_Array::value('extension', $info) == '' ? 0 : 1))
     );
@@ -399,17 +423,17 @@ class CRM_Utils_File {
    * @return array
    */
   public static function getFilesByExtension($path, $ext) {
-    $path  = self::addTrailingSlash($path);
+    $path = self::addTrailingSlash($path);
+    $files = array();
     if ($dh = opendir($path)) {
-      $files = array();
       while (FALSE !== ($elem = readdir($dh))) {
         if (substr($elem, -(strlen($ext) + 1)) == '.' . $ext) {
           $files[] .= $path . $elem;
         }
       }
       closedir($dh);
-      return $files;
     }
+    return $files;
   }
 
   /**
@@ -496,6 +520,24 @@ HTACCESS;
     return $_path;
   }
 
+  /**
+   * Determine if a path is absolute.
+   *
+   * @return bool
+   *   TRUE if absolute. FALSE if relative.
+   */
+  public static function isAbsolute($path) {
+    if (substr($path, 0, 1) === DIRECTORY_SEPARATOR) {
+      return TRUE;
+    }
+    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+      if (preg_match('!^[a-zA-Z]:[/\\\\]!', $path)) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
   /**
    * @param $directory
    *
@@ -508,7 +550,7 @@ HTACCESS;
     }
 
     // check if directory is relative, if so return immediately
-    if (substr($directory, 0, 1) != DIRECTORY_SEPARATOR) {
+    if (!self::isAbsolute($directory)) {
       return $directory;
     }
 
@@ -548,7 +590,7 @@ HTACCESS;
   }
 
   /**
-   * Make a file path relative to some base dir
+   * Make a file path relative to some base dir.
    *
    * @param $directory
    * @param $basePath
@@ -556,6 +598,10 @@ HTACCESS;
    * @return string
    */
   public static function relativize($directory, $basePath) {
+    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+      $directory = strtr($directory, '\\', '/');
+      $basePath = strtr($basePath, '\\', '/');
+    }
     if (substr($directory, 0, strlen($basePath)) == $basePath) {
       return substr($directory, strlen($basePath));
     }
@@ -565,7 +611,7 @@ HTACCESS;
   }
 
   /**
-   * Create a path to a temporary file which can endure for multiple requests
+   * Create a path to a temporary file which can endure for multiple requests.
    *
    * TODO: Automatic file cleanup using, eg, TTL policy
    *
@@ -583,7 +629,7 @@ HTACCESS;
   }
 
   /**
-   * Create a path to a temporary directory which can endure for multiple requests
+   * Create a path to a temporary directory which can endure for multiple requests.
    *
    * TODO: Automatic file cleanup using, eg, TTL policy
    *
@@ -608,9 +654,12 @@ HTACCESS;
    *   base dir.
    * @param string $pattern
    *   glob pattern, eg "*.txt".
+   * @param bool $relative
+   *   TRUE if paths should be made relative to $dir
    * @return array(string)
    */
-  public static function findFiles($dir, $pattern) {
+  public static function findFiles($dir, $pattern, $relative = FALSE) {
+    $dir = rtrim($dir, '/');
     $todos = array($dir);
     $result = array();
     while (!empty($todos)) {
@@ -619,7 +668,7 @@ HTACCESS;
       if (is_array($matches)) {
         foreach ($matches as $match) {
           if (!is_dir($match)) {
-            $result[] = $match;
+            $result[] = $relative ? CRM_Utils_File::relativize($match, "$dir/") : $match;
           }
         }
       }
@@ -679,7 +728,8 @@ HTACCESS;
    *   The new location of the directory.
    * @param bool $verbose
    *
-   * @return bool TRUE on success
+   * @return bool
+   *   TRUE on success
    */
   public static function replaceDir($fromDir, $toDir, $verbose = FALSE) {
     if (is_dir($toDir)) {
@@ -697,4 +747,5 @@ HTACCESS;
     }
     return TRUE;
   }
+
 }