CRM-19533 System check: check for writable directories
authorAndrew Hunt <andrew@aghstrategies.com>
Tue, 18 Oct 2016 18:43:00 +0000 (14:43 -0400)
committerAndrew Hunt <andrew@aghstrategies.com>
Tue, 18 Oct 2016 19:01:01 +0000 (15:01 -0400)
CRM/Utils/Check/Component/Env.php
CRM/Utils/Check/Component/Security.php
CRM/Utils/File.php

index ee89958f5a4ab3d0a4ad2b90ca518ac251da58ce..75d6e5b208cc47251fca80fc5a5f0c8c1f0a5c89 100644 (file)
@@ -375,6 +375,56 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
     return $messages;
   }
 
+  /**
+   * Check that important directories are writable.
+   *
+   * @return array
+   *   Any CRM_Utils_Check_Message instances that need to be generated.
+   */
+  public function checkDirsWritable() {
+    $notWritable = array();
+
+    $config = CRM_Core_Config::singleton();
+    $directories = array(
+      'uploadDir' => ts('Temporary Files Directory'),
+      'imageUploadDir' => ts('Images Directory'),
+      'customFileUploadDir' => ts('Custom Files Directory'),
+      'extensionsDir' => ts('CiviCRM Extensions Directory'),
+    );
+
+    foreach ($directories as $directory => $label) {
+      $file = CRM_Utils_File::createFakeFile($config->$directory);
+
+      if ($file === FALSE) {
+        $notWritable[] = "$label ({$config->$directory})";
+      }
+      else {
+        $dirWithSlash = CRM_Utils_File::addTrailingSlash($config->$directory);
+        unlink($dirWithSlash . $file);
+      }
+    }
+
+    $messages = array();
+
+    if (!empty($notWritable)) {
+      $messages[] = new CRM_Utils_Check_Message(
+        __FUNCTION__,
+        ts('The %1 is not writable.  Please check your file permissions.', array(
+          1 => implode(', ', $notWritable),
+          'count' => count($notWritable),
+          'plural' => 'The following directories are not writable: %1.  Please check your file permissions.',
+        )),
+        ts('Directory not writable', array(
+          'count' => count($notWritable),
+          'plural' => 'Directories not writable',
+        )),
+        \Psr\Log\LogLevel::ERROR,
+        'fa-ban'
+      );
+    }
+
+    return $messages;
+  }
 
   /**
    * Checks if new versions are available
index 458dd5131c6033d34375c527de2b043c4ec816cb..db176db86afe42fec4c151b8dca55976f4110c24 100644 (file)
@@ -323,10 +323,15 @@ class CRM_Utils_Check_Component_Security extends CRM_Utils_Check_Component {
     }
 
     $result = FALSE;
-    $file = 'delete-this-' . CRM_Utils_String::createRandom(10, CRM_Utils_String::ALPHANUMERIC);
 
     // this could be a new system with no uploads (yet) -- so we'll make a file
-    file_put_contents("$dir/$file", "delete me");
+    $file = CRM_Utils_File::createFakeFile($dir);
+
+    if ($file === FALSE) {
+      // Couldn't write the file
+      return FALSE;
+    }
+
     $content = @file_get_contents("$url");
     if (stristr($content, $file)) {
       $result = TRUE;
@@ -347,17 +352,18 @@ class CRM_Utils_Check_Component_Security extends CRM_Utils_Check_Component {
    * @return bool
    */
   public function isDirAccessible($dir, $url) {
-    $dir = rtrim($dir, '/');
     $url = rtrim($url, '/');
     if (empty($dir) || empty($url) || !is_dir($dir)) {
       return FALSE;
     }
 
     $result = FALSE;
-    $file = 'delete-this-' . CRM_Utils_String::createRandom(10, CRM_Utils_String::ALPHANUMERIC);
+    $file = CRM_Utils_File::createFakeFile($dir, 'delete me');
 
-    // this could be a new system with no uploads (yet) -- so we'll make a file
-    file_put_contents("$dir/$file", "delete me");
+    if ($file === FALSE) {
+      // Couldn't write the file
+      return FALSE;
+    }
 
     $headers = @get_headers("$url/$file");
     if (stripos($headers[0], '200')) {
index 5d9d3a9a1c0bee8dbe8d344f35fae186589e258b..c2459104c1fa317d9240326938f268777826d1ff 100644 (file)
@@ -286,6 +286,25 @@ class CRM_Utils_File {
     return $path;
   }
 
+  /**
+   * Save a fake file somewhere
+   *
+   * @param string $dir
+   *   The directory where the file should be saved.
+   * @param string $contents
+   *   Optional: the contents of the file.
+   *
+   * @return string
+   *   The filename saved, or FALSE on failure.
+   */
+  public static function createFakeFile($dir, $contents = 'delete me') {
+    $dir = self::addTrailingSlash($dir);
+    $file = 'delete-this-' . CRM_Utils_String::createRandom(10, CRM_Utils_String::ALPHANUMERIC);
+    $success = file_put_contents($dir . $file, $contents);
+
+    return ($success === FALSE) ? FALSE : $file;
+  }
+
   /**
    * @param string|NULL $dsn
    *   Use NULL to load the default/active connection from CRM_Core_DAO.