Completed
Branch master (0dd1a0)
by Pierre-Henry
32:33
created

Cache   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 334
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 334
rs 9
c 0
b 0
f 0
wmc 35
lcom 1
cbo 4

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A enabled() 0 6 1
A setCacheDir() 0 10 2
A setPrefix() 0 5 1
A setExpire() 0 7 1
A start() 0 14 2
A stop() 0 17 3
A get() 0 10 2
A put() 0 10 2
A clear() 0 9 2
A getTimeOfCacheFile() 0 4 1
A getHeaderContents() 0 19 1
B _write() 0 28 4
A _read() 0 17 4
A _getFile() 0 4 1
B _check() 0 12 5
A _checkCacheDir() 0 6 2
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 22 and the first side effect is on line 15.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @title            Cache Class
4
 * @desc             Handler Cache.
5
 *
6
 * @author           Pierre-Henry Soria <[email protected]>
7
 * @copyright        (c) 2011-2017, Pierre-Henry Soria. All Rights Reserved.
8
 * @license          GNU General Public License; See PH7.LICENSE.txt and PH7.COPYRIGHT.txt in the root directory.
9
 * @package          PH7 / Framework / Cache
10
 * @version          1.3
11
 */
12
13
namespace PH7\Framework\Cache;
14
15
defined('PH7') or exit('Restricted access');
16
17
use PH7\Framework\Core\Kernel;
18
use PH7\Framework\Config\Config;
19
use PH7\Framework\File\File;
20
use PH7\Framework\Error\CException\PH7InvalidArgumentException;
21
22
class Cache
23
{
24
    const CACHE_DIR = 'pH7_cache/';
25
    const CACHE_FILE_EXT = '.cache.php';
26
27
    /** @var File */
28
    private $_oFile;
29
30
    /** @var string */
31
    private $_sCacheDir;
32
33
    /** @var string */
34
    private $_sGroup;
35
36
    /** @var string */
37
    private $_sId;
38
39
    /** @var integer */
40
    private $_iTtl;
41
42
    /** @var string */
43
    private $_sPrefix = 'pH7_';
44
45
    /** @var boolean */
46
    private $_bEnabled = true;
47
48
    public function __construct()
49
    {
50
        $this->_oFile = new File;
51
        $this->_bEnabled = (bool) Config::getInstance()->values['cache']['enable.general.cache'];
52
    }
53
54
    /**
55
     * Enabled/Disabled the cache.
56
     *
57
     * @param boolean $bIsEnable
58
     *
59
     * @return self
60
     */
61
    public function enabled($bIsEnable)
62
    {
63
        $this->_bEnabled = (bool) $bIsEnable;
64
65
        return $this;
66
    }
67
68
    /**
69
     * Sets cache directory.
70
     * If the directory is not correct, the method will cause an exception.
71
     * If you do not use this method, a default directory will be created.
72
     *
73
     * @param string $sCacheDir
74
     *
75
     * @return self
76
     *
77
     * @throws PH7InvalidArgumentException An explanatory message if the directory does not exist.
78
     */
79
    public function setCacheDir($sCacheDir)
80
    {
81
        if (is_dir($sCacheDir)) {
82
            $this->_sCacheDir = $sCacheDir;
83
        } else {
84
            throw new PH7InvalidArgumentException('"' . $sCacheDir . '" cache directory cannot be found!');
85
        }
86
87
        return $this;
88
    }
89
90
    /**
91
     * Sets the cache prefix.
92
     *
93
     * @param string $sPrefix
94
     *
95
     * @return self
96
     */
97
    public function setPrefix($sPrefix)
98
    {
99
        $this->_sPrefix = $sPrefix;
100
        return $this;
101
    }
102
103
    /**
104
     * Sets the time expire cache.
105
     *
106
     * @param integer $iExpire (the time with the 'touch' function).
107
     *
108
     * @return self
109
     */
110
    public function setExpire($iExpire)
0 ignored issues
show
Unused Code introduced by
The parameter $iExpire is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
111
    {
112
        // How long to cache for (in seconds, e.g. 3600*24 = 24 hour)
113
        @touch($this->_getFile(), time()+(int)$this->_iTtl);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
114
115
        return $this;
116
    }
117
118
    /**
119
     * Start the cache.
120
     *
121
     * @param string $sGroup The Group Cache (This creates a folder).
122
     * @param string $sId (The ID for the file).
123
     * @param integer $iTtl Cache lifetime in seconds. If NULL, the file never expires.
124
     *
125
     * @return self
126
     */
127
    public function start($sGroup, $sId, $iTtl)
128
    {
129
      $this->_checkCacheDir();
130
131
      if ($this->_bEnabled)
132
      {
133
          $this->_sGroup = $sGroup . PH7_DS;
134
          $this->_sId = $sId;
135
          $this->_iTtl = $iTtl;
136
          ob_start();
137
      }
138
139
      return $this;
140
    }
141
142
    /**
143
     * Stop the cache.
144
     *
145
     * @param boolean $bPrint TRUE = Display data with ECHO. FALSE = Return data. Default TRUE.
146
     *
147
     * @return string|null
148
     */
149
    public function stop($bPrint = true)
150
    {
151
        if (!$this->_bEnabled) {
152
            return null;
153
        }
154
155
        $sBuffer = ob_get_contents();
156
        ob_end_clean();
157
        $this->_write($sBuffer);
158
159
        if ($bPrint) {
160
            echo $sBuffer;
161
            return null;
162
        }
163
164
        return $sBuffer;
165
    }
166
167
    /**
168
     * Gets the data cache.
169
     *
170
     * @param boolean $bPrint Default FALSE
171
     * @return boolean|integer|float|string|array|object Returns the converted cache value if successful, FALSE otherwise.
172
     */
173
    public function get($bPrint = false)
174
    {
175
        $mData = $this->_read($bPrint);
176
177
        if ($mData !== false) {
178
            $mData = unserialize($mData);
179
        }
180
181
        return $mData;
182
    }
183
184
    /**
185
     * Puts the data in the cache.
186
     *
187
     * @param string $sData
188
     *
189
     * @return string|null|self If the cache is disabled, returns null, otherwise returns this class.
190
     */
191
    public function put($sData)
192
    {
193
        if (!$this->_bEnabled) {
194
            return null;
195
        }
196
197
        $this->_write(serialize($sData));
198
199
        return $this;
200
    }
201
202
    /**
203
     * Clear the cache.
204
     *
205
     * @return self this
206
     */
207
    public function clear()
208
    {
209
        if (!empty($this->_sId))
210
            $this->_oFile->deleteFile($this->_getFile());
211
         else
212
            $this->_oFile->deleteDir($this->_sCacheDir . $this->_sGroup);
213
214
         return $this;
215
    }
216
217
218
    /**
219
     * Get the creation/modification time of the current cache file.
220
     *
221
     * @return integer|boolean Time the file was last modified/created as a Unix timestamp, or FALSE on failure.
222
     */
223
    public function getTimeOfCacheFile()
224
    {
225
        return $this->_oFile->getModifTime($this->_getFile());
226
    }
227
228
    /**
229
     * Get the header content to put in the file.
230
     *
231
     * @return string
232
     */
233
    final protected function getHeaderContents()
234
    {
235
        return 'defined(\'PH7\') or exit(\'Restricted access\');
236
/*
237
Created on ' . gmdate('Y-m-d H:i:s') . '
238
File ID: ' . $this->_sId . '
239
*/
240
/***************************************************************************
241
 *     ' . Kernel::SOFTWARE_NAME . ' ' . Kernel::SOFTWARE_COMPANY . '
242
 *               --------------------
243
 * @since      Mon Oct 14 2011
244
 * @author     SORIA Pierre-Henry
245
 * @email      ' . Kernel::SOFTWARE_EMAIL . '
246
 * @link       ' . Kernel::SOFTWARE_WEBSITE . '
247
 * @copyright  ' . Kernel::SOFTWARE_COPYRIGHT . '
248
 * @license    ' . Kernel::SOFTWARE_LICENSE . '
249
 ***************************************************************************/
250
';
251
    }
252
253
    /**
254
     * Writes data in a cache file.
255
     *
256
     * @param string $sData
257
     *
258
     * @return boolean
259
     *
260
     * @throws Exception If the file cannot be written.
261
     */
262
    final private function _write($sData)
263
    {
264
      if (!$this->_bEnabled) {
265
          return null;
266
      }
267
268
      $sFile = $this->_getFile();
269
      $this->_oFile->createDir($this->_sCacheDir . $this->_sGroup);
270
271
      $sPhpHeader = $this->getHeaderContents();
272
273
        $sData = '<?php ' . $sPhpHeader . '$_mData = <<<\'EOF\'' . File::EOL . $sData . File::EOL . 'EOF;' . File::EOL . '?>';
274
275
        if ($rHandle = @fopen($sFile, 'wb')) {
276
            if (@flock($rHandle, LOCK_EX)) {
277
                fwrite($rHandle, $sData);
278
            }
279
280
            fclose($rHandle);
281
            $this->setExpire($this->_iTtl);
282
            $this->_oFile->chmod($sFile, 420);
283
            return true;
284
        }
285
286
        throw new Exception('Could not write cache file: \'' . $sFile . '\'');
287
288
        return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
289
    }
290
291
    /**
292
     * Reads the Cache.
293
     *
294
     * @param boolean $bPrint
295
     * @return boolean|string Returns TRUE or a string if successful, FALSE otherwise.
296
     */
297
    private function _read($bPrint)
298
    {
299
        if ($this->_check()) {
300
            require $this->_getFile();
301
302
            if (!empty($_mData)) {
0 ignored issues
show
Bug introduced by
The variable $_mData seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
303
                if ($bPrint) {
304
                    echo $_mData;
305
                    return true;
306
                } else {
307
                    return $_mData;
308
                }
309
            }
310
        }
311
312
        return false;
313
    }
314
315
    /**
316
     * Gets the file cache.
317
     *
318
     * @return string
319
     */
320
    private function _getFile()
321
    {
322
        return $this->_sCacheDir . $this->_sGroup . sha1($this->_sId) . static::CACHE_FILE_EXT;
323
    }
324
325
    /**
326
     * Checks the cache.
327
     *
328
     * @return boolean
329
     */
330
    private function _check()
331
    {
332
        $sFile = $this->_getFile();
333
334
        if (!$this->_bEnabled || !is_file($sFile) || (!empty($this->_iTtl) && $this->_oFile->getModifTime($sFile) < time())) {
335
            // If the cache has expired
336
            $this->_oFile->deleteFile($this->_getFile());
337
            return false;
338
        }
339
340
        return true;
341
    }
342
343
    /**
344
     * Checks if the cache directory has been defined otherwise we create a default directory.
345
     * If the folder cache does not exist, it creates a folder.
346
     *
347
     * @return self
348
     */
349
    private function _checkCacheDir()
350
    {
351
        $this->_sCacheDir = (empty($this->_sCacheDir)) ? PH7_PATH_CACHE . static::CACHE_DIR : $this->_sCacheDir;
352
353
        return $this;
354
    }
355
}
356