~ubuntu-branches/ubuntu/wily/php-horde-cache/wily

« back to all changes in this revision

Viewing changes to Horde_Cache-2.4.1/lib/Horde/Cache/Storage/File.php

  • Committer: Package Import Robot
  • Author(s): Mathieu Parent
  • Date: 2014-04-13 09:11:33 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20140413091133-um8xxmlwuawkhbi5
Tags: 2.4.2-1
New upstream version 2.4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
/**
3
 
 * Copyright 1999-2014 Horde LLC (http://www.horde.org/)
4
 
 *
5
 
 * See the enclosed file COPYING for license information (LGPL). If you
6
 
 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
7
 
 *
8
 
 * @category  Horde
9
 
 * @copyright 1999-2014 Horde LLC
10
 
 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
11
 
 * @package   Cache
12
 
 */
13
 
 
14
 
/**
15
 
 * Cache storage in the filesystem.
16
 
 *
17
 
 * @author    Anil Madhavapeddy <anil@recoil.org>
18
 
 * @author    Chuck Hagenbuch <chuck@horde.org>
19
 
 * @author    Michael Slusarz <slusarz@horde.org>
20
 
 * @category  Horde
21
 
 * @copyright 1999-2014 Horde LLC
22
 
 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
23
 
 * @package   Cache
24
 
 */
25
 
class Horde_Cache_Storage_File extends Horde_Cache_Storage_Base
26
 
{
27
 
    /* Location of the garbage collection data file. */
28
 
    const GC_FILE = 'horde_cache_gc';
29
 
 
30
 
    /**
31
 
     * List of key to filename mappings.
32
 
     *
33
 
     * @var array
34
 
     */
35
 
    protected $_file = array();
36
 
 
37
 
    /**
38
 
     * Constructor.
39
 
     *
40
 
     * @param array $params  Optional parameters:
41
 
     * <pre>
42
 
     *   - dir: (string) The base directory to store the cache files in.
43
 
     *          DEFAULT: System default
44
 
     *   - no_gc: (boolean) If true, don't perform garbage collection.
45
 
     *            DEFAULT: false
46
 
     *   - prefix: (string) The filename prefix to use for the cache files.
47
 
     *             DEFAULT: 'cache_'
48
 
     *   - sub: (integer) If non-zero, the number of subdirectories to create
49
 
     *          to store the file (i.e. PHP's session.save_path).
50
 
     *          DEFAULT: 0
51
 
     * </pre>
52
 
     */
53
 
    public function __construct(array $params = array())
54
 
    {
55
 
        $params = array_merge(array(
56
 
            'prefix' => 'cache_',
57
 
            'sub' => 0
58
 
        ), $params);
59
 
 
60
 
        if (!isset($params['dir']) || !@is_dir($params['dir'])) {
61
 
            $params['dir'] = sys_get_temp_dir();
62
 
        }
63
 
 
64
 
        parent::__construct($params);
65
 
    }
66
 
 
67
 
    /**
68
 
     * Destructor.
69
 
     */
70
 
    public function __destruct()
71
 
    {
72
 
        $c_time = time();
73
 
 
74
 
        /* Only do garbage collection 0.1% of the time we create an object. */
75
 
        if (!empty($this->_params['no_gc']) ||
76
 
            (intval(substr($c_time, -3)) !== 0)) {
77
 
            return;
78
 
        }
79
 
 
80
 
        $filename = $this->_params['dir'] . '/' . self::GC_FILE;
81
 
        $excepts = array();
82
 
 
83
 
        if (is_readable($filename)) {
84
 
            $gc_file = file($filename, FILE_IGNORE_NEW_LINES);
85
 
            reset($gc_file);
86
 
            next($gc_file);
87
 
            while (list(,$data) = each($gc_file)) {
88
 
                $parts = explode("\t", $data, 2);
89
 
                $excepts[$parts[0]] = $parts[1];
90
 
            }
91
 
        }
92
 
 
93
 
        foreach ($this->_getCacheFiles() as $fname => $pname) {
94
 
            if (!empty($excepts[$fname]) &&
95
 
                (($c_time - $excepts[$fname]) > filemtime($pname))) {
96
 
                @unlink($pname);
97
 
                unset($excepts[$fname]);
98
 
            }
99
 
        }
100
 
 
101
 
        if ($fp = @fopen($filename, 'w')) {
102
 
            foreach ($excepts as $key => $val) {
103
 
                fwrite($fp, $key . "\t" . $val . "\n");
104
 
            }
105
 
            fclose($fp);
106
 
        }
107
 
    }
108
 
 
109
 
    /**
110
 
     */
111
 
    public function get($key, $lifetime = 0)
112
 
    {
113
 
        if (!$this->exists($key, $lifetime)) {
114
 
            /* Nothing cached, return failure. */
115
 
            return false;
116
 
        }
117
 
 
118
 
        $filename = $this->_keyToFile($key);
119
 
        $size = filesize($filename);
120
 
 
121
 
        return $size
122
 
            ? @file_get_contents($filename)
123
 
            : '';
124
 
    }
125
 
 
126
 
    /**
127
 
     */
128
 
    public function set($key, $data, $lifetime = 0)
129
 
    {
130
 
        $filename = $this->_keyToFile($key, true);
131
 
        $tmp_file = Horde_Util::getTempFile('HordeCache', true, $this->_params['dir']);
132
 
        if (isset($this->_params['umask'])) {
133
 
            chmod($tmp_file, 0666 & ~$this->_params['umask']);
134
 
        }
135
 
 
136
 
        if (file_put_contents($tmp_file, $data) === false) {
137
 
            throw new Horde_Cache_Exception('Cannot write to cache directory ' . $this->_params['dir']);
138
 
        }
139
 
 
140
 
        @rename($tmp_file, $filename);
141
 
 
142
 
        if ($lifetime &&
143
 
            ($fp = @fopen($this->_params['dir'] . '/' . self::GC_FILE, 'a'))) {
144
 
            // This may result in duplicate entries in GC_FILE, but we
145
 
            // will take care of these whenever we do GC and this is quicker
146
 
            // than having to check every time we access the file.
147
 
            fwrite($fp, $filename . "\t" . (time() + $lifetime) . "\n");
148
 
            fclose($fp);
149
 
        }
150
 
    }
151
 
 
152
 
    /**
153
 
     */
154
 
    public function exists($key, $lifetime = 0)
155
 
    {
156
 
        $filename = $this->_keyToFile($key);
157
 
 
158
 
        /* Key exists in the cache */
159
 
        if (file_exists($filename)) {
160
 
            /* 0 means no expire.
161
 
             * Also, If the file was been created after the supplied value,
162
 
             * the data is valid (fresh). */
163
 
            if (($lifetime == 0) ||
164
 
                (time() - $lifetime <= filemtime($filename))) {
165
 
                return true;
166
 
            }
167
 
 
168
 
            @unlink($filename);
169
 
        }
170
 
 
171
 
        return false;
172
 
    }
173
 
 
174
 
    /**
175
 
     */
176
 
    public function expire($key)
177
 
    {
178
 
        return @unlink($this->_keyToFile($key));
179
 
    }
180
 
 
181
 
    /**
182
 
     */
183
 
    public function clear()
184
 
    {
185
 
        foreach ($this->_getCacheFiles() as $val) {
186
 
            @unlink($val);
187
 
        }
188
 
        @unlink($this->_params['dir'] . '/' . self::GC_FILE);
189
 
    }
190
 
 
191
 
    /**
192
 
     * Return a list of cache files.
193
 
     *
194
 
     * @return array  Pathnames to cache files.
195
 
     */
196
 
    protected function _getCacheFiles()
197
 
    {
198
 
        $paths = array();
199
 
 
200
 
        try {
201
 
            $it = empty($this->_params['sub'])
202
 
                ? new DirectoryIterator($this->_params['dir'])
203
 
                : new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->_params['dir']), RecursiveIteratorIterator::CHILD_FIRST);
204
 
        } catch (UnexpectedValueException $e) {
205
 
            return $paths;
206
 
        }
207
 
 
208
 
        foreach ($it as $val) {
209
 
            if (!$val->isDir() &&
210
 
                ($fname = $val->getFilename()) &&
211
 
                (strpos($fname, $this->_params['prefix']) === 0)) {
212
 
                $paths[$fname] = $val->getPathname();
213
 
            }
214
 
        }
215
 
 
216
 
        return $paths;
217
 
    }
218
 
 
219
 
    /**
220
 
     * Map a cache key to a unique filename.
221
 
     *
222
 
     * @param string $key     Cache key.
223
 
     * @param string $create  Create path if it doesn't exist?
224
 
     *
225
 
     * @return string  Fully qualified filename.
226
 
     */
227
 
    protected function _keyToFile($key, $create = false)
228
 
    {
229
 
        if ($create || !isset($this->_file[$key])) {
230
 
            $dir = $this->_params['dir'] . '/';
231
 
            $md5 = hash('md5', $key);
232
 
            $sub = '';
233
 
 
234
 
            if (!empty($this->_params['sub'])) {
235
 
                $max = min($this->_params['sub'], strlen($md5));
236
 
                for ($i = 0; $i < $max; $i++) {
237
 
                    $sub .= $md5[$i];
238
 
                    if ($create && !is_dir($dir . $sub)) {
239
 
                        if (!mkdir($dir . $sub)) {
240
 
                            $sub = '';
241
 
                            break;
242
 
                        }
243
 
                    }
244
 
                    $sub .= '/';
245
 
                }
246
 
            }
247
 
 
248
 
            $this->_file[$key] = $dir . $sub . $this->_params['prefix'] . $md5;
249
 
        }
250
 
 
251
 
        return $this->_file[$key];
252
 
    }
253
 
 
254
 
}