From 73359771530730c6252b39133e2d110e6f68fcb9 Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Thu, 20 Sep 2012 15:29:59 -0400
Subject: [PATCH] Allow default cache settings to be set through config.ini;
 thanks to Tod Olson for the patch.

---
 config/vufind/config.ini                   | 18 +++++-
 module/VuFind/src/VuFind/Cache/Manager.php | 67 +++++++++++++++++++---
 2 files changed, 77 insertions(+), 8 deletions(-)

diff --git a/config/vufind/config.ini b/config/vufind/config.ini
index a33e8a530f2..051a44dd400 100644
--- a/config/vufind/config.ini
+++ b/config/vufind/config.ini
@@ -756,4 +756,20 @@ HMACkey = mySuperSecretValue
 ; The userWhitelist[] setting can be repeated as many times as necessary.  If it is
 ; commented out, login will not be required to access the Admin module.
 ;userWhitelist[] = username1
-;userWhitelist[] = username2
\ No newline at end of file
+;userWhitelist[] = username2
+
+; This section sets global defaults for caches; file caching is used by default.
+;[Cache]
+; Set time to live value for Zend caches (in seconds), 0 means maximum possible.
+;ttl = 0
+; This setting can be used to force caching in a specific location other than the
+; default location inside the local settings directory. This directory must exist
+; and be writable by the web server.
+;cache_dir = "local/cache/"
+; Override umask for cache directories and files.
+;umask = 022
+; Permissions for Zend-created cache directories and files, subject to umask
+; Default dir_permission seems to be 0700.
+;dir_permission = 0700
+; Default file_permission seems to be 0600.
+;file_permission = 0600
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Cache/Manager.php b/module/VuFind/src/VuFind/Cache/Manager.php
index b785301a434..605fa700a23 100644
--- a/module/VuFind/src/VuFind/Cache/Manager.php
+++ b/module/VuFind/src/VuFind/Cache/Manager.php
@@ -41,6 +41,13 @@ use VuFind\Config\Reader as ConfigReader, Zend\Cache\StorageFactory;
  */
 class Manager
 {
+    /**
+     * Default configuration settings.
+     *
+     * @var array
+     */
+    protected $defaults;
+
     /**
      * Was there a problem building cache directories?
      *
@@ -67,6 +74,17 @@ class Manager
      */
     public function __construct()
     {
+        // Get global cache options
+        $config = ConfigReader::getConfig('config');
+
+        // $config and $config->Cache are Zend\Config\Config objects
+        // $cache is created immutable, so get the array, it will be modified
+        // downstream.
+        // Zend\Config\Config can be created mutable or cloned and merged, useful
+        // for future cache-specific overrides.
+        $cacheConfig = isset($config->Cache) ? $config->Cache : false;
+        $this->defaults = $cacheConfig ? $cacheConfig->toArray() : false;
+
         // Get base cache directory.
         $cacheBase = $this->getCacheDir();
 
@@ -78,8 +96,9 @@ class Manager
 
         // Set up search specs cache based on config settings:
         $config = ConfigReader::getConfig('searches');
-        $cacheSetting = isset($config->Cache->type) ? $config->Cache->type : false;
-        switch ($cacheSetting) {
+        $searchCacheType = isset($config->Cache->type)
+            ? $config->Cache->type : false;
+        switch ($searchCacheType) {
         case 'APC':
             $this->createAPCCache('searchspecs');
             break;
@@ -118,6 +137,14 @@ class Manager
      */
     public function getCacheDir()
     {
+        if ($this->defaults && isset($this->defaults['cache_dir'])) {
+            $dir = $this->defaults['cache_dir'];
+            // ensure trailing slash:
+            if (substr($dir, -1) != '/') {
+                $dir .= '/';
+            }
+            return $dir;
+        }
         if (strlen(LOCAL_OVERRIDE_DIR) > 0) {
             return LOCAL_OVERRIDE_DIR . '/cache/';
         }
@@ -144,16 +171,42 @@ class Manager
      */
     protected function createFileCache($cacheName, $dirName)
     {
+        $opts = $this->defaults;    // copy defaults -- we'll modify them below
         if (!is_dir($dirName)) {
-            if (!@mkdir($dirName)) {
+            if (isset($opts['umask'])) {
+                // convert umask from string
+                $umask = octdec($opts['umask']);
+                // validate
+                if ($umask & 0700) {
+                    throw new \Exception(
+                        'Invalid umask: ' . $opts['umask']
+                        . '; need permission to execute, read and write by owner'
+                    );
+                }
+                umask($umask);
+            }
+            if (isset($opts['dir_permission'])) {
+                $dir_perm = octdec($opts['dir_permission']);
+            } else {
+                // 0777 is chmod default, use if dir_permission is not explicitly set
+                $dir_perm = 0777;
+            }
+            if (!@mkdir($dirName, $dir_perm)) {
                 $this->directoryCreationError = true;
             }
         }
+        if (empty($opts)) {
+            $opts = array('cache_dir' => $dirName);
+        } elseif (is_array($opts)) {
+            // If cache_dir was set in config.ini, the cache-specific name should
+            // have been appended to the path to create the value $dirName.
+            $opts['cache_dir'] = $dirName;
+        } else {
+            // Dryrot
+            throw new \Exception('$opts is neither array nor false');
+        }
         $this->cacheSettings[$cacheName] = array(
-            'adapter' => array(
-                'name' => 'filesystem',
-                'options' => array('cache_dir' => $dirName)
-            ),
+            'adapter' => array('name' => 'filesystem', 'options' => $opts),
             'plugins' => array('serializer')
         );
     }
-- 
GitLab