Completed
Branch release-2.1 (e49a83)
by Mert
04:10
created

smf_cache::cleanCache()   C

Complexity

Conditions 9
Paths 4

Size

Total Lines 22
Code Lines 11

Duplication

Lines 5
Ratio 22.73 %

Importance

Changes 0
Metric Value
cc 9
eloc 11
nc 4
nop 1
dl 5
loc 22
rs 6.412
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Simple Machines Forum (SMF)
5
 *
6
 * @package SMF
7
 * @author Simple Machines http://www.simplemachines.org
8
 * @copyright 2016 Simple Machines and individual contributors
9
 * @license http://www.simplemachines.org/about/smf/license.php BSD
10
 *
11
 * @version 2.1 Beta 3
12
 */
13
14
if (!defined('SMF'))
15
	die('Hacking attempt...');
16
17
/**
18
 * Our Cache API class
19
 * @package cacheAPI
20
 */
21
class smf_cache extends cache_api
22
{
23
	/**
24
	 * @var string The path to the current $cachedir directory.
25
	 */
26
	private $cachedir = null;
27
28
	/**
29
	 * {@inheritDoc}
30
	 */
31
	public function __construct()
32
	{
33
		parent::__construct();
34
35
		// Set our default cachedir.
36
		$this->setCachedir();		
37
	}
38
39
	/**
40
	 * {@inheritDoc}
41
	 */
42
	public function isSupported($test = false)
43
	{
44
		$supported = is_writable($this->cachedir);
45
46
		if ($test)
47
			return $supported;
48
		return parent::isSupported() && $supported;
49
	}
50
51
	/**
52
	 * {@inheritDoc}
53
	 */
54
	public function getData($key, $ttl = null)
55
	{
56
		$key = $this->prefix . strtr($key, ':/', '-_');
57
		$cachedir = $this->cachedir;
58
59
		// SMF Data returns $value and $expired.  $expired has a unix timestamp of when this expires.
60
		if (file_exists($cachedir . '/data_' . $key . '.php') && filesize($cachedir . '/data_' . $key . '.php') > 10)
61
		{
62
			// Work around Zend's opcode caching (PHP 5.5+), they would cache older files for a couple of seconds
63
			// causing newer files to take effect a while later.
64
			if (function_exists('opcache_invalidate'))
65
				opcache_invalidate($cachedir . '/data_' . $key . '.php', true);
66
67
			if (function_exists('apc_delete_file'))
68
				@apc_delete_file($cachedir . '/data_' . $key . '.php');
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...
69
70
			// php will cache file_exists et all, we can't 100% depend on its results so proceed with caution
71
			@include($cachedir . '/data_' . $key . '.php');
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...
72
			if (!empty($expired) && isset($value))
0 ignored issues
show
Bug introduced by
The variable $expired 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...
Bug introduced by
The variable $value seems to never exist, and therefore isset should always return false. 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...
73
			{
74
				@unlink($cachedir . '/data_' . $key . '.php');
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...
75
				unset($value);
76
			}
77
		}
78
79
		return !empty($value) ? $value : null;
80
	}
81
82
	/**
83
	 * {@inheritDoc}
84
	 */
85
	public function putData($key, $value, $ttl = null)
86
	{
87
		$key = $this->prefix . strtr($key, ':/', '-_');
88
		$cachedir = $this->cachedir;
89
90
		// Work around Zend's opcode caching (PHP 5.5+), they would cache older files for a couple of seconds
91
		// causing newer files to take effect a while later.
92
		if (function_exists('opcache_invalidate'))
93
			opcache_invalidate($cachedir . '/data_' . $key . '.php', true);
94
95
		if (function_exists('apc_delete_file'))
96
			@apc_delete_file($cachedir . '/data_' . $key . '.php');
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...
97
98
		// Otherwise custom cache?
99
		if ($value === null)
100
			@unlink($cachedir . '/data_' . $key . '.php');
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...
101
		else
102
		{
103
			$cache_data = '<' . '?' . 'php if (!defined(\'SMF\')) die; if (' . (time() + $ttl) . ' < time()) $expired = true; else{$expired = false; $value = \'' . addcslashes($value, '\\\'') . '\';}' . '?' . '>';
104
105
			// Write out the cache file, check that the cache write was successful; all the data must be written
106
			// If it fails due to low diskspace, or other, remove the cache file
107
			$fileSize = file_put_contents($cachedir . '/data_' . $key . '.php', $cache_data, LOCK_EX);
108
			if ($fileSize !== strlen($cache_data))
109
			{
110
				@unlink($cachedir . '/data_' . $key . '.php');
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...
111
				return false;
112
			}
113
			else
114
				return true;
115
		}
116
	}
117
118
	/**
119
	 * {@inheritDoc}
120
	 */
121
	public function cleanCache($type = '')
122
	{
123
		$cachedir = $this->cachedir;
124
125
		// No directory = no game.
126
		if (!is_dir($cachedir))
127
			return;
128
129
		// Remove the files in SMF's own disk cache, if any
130
		$dh = opendir($cachedir);
131 View Code Duplication
		while ($file = readdir($dh))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
		{
133
			if ($file != '.' && $file != '..' && $file != 'index.php' && $file != '.htaccess' && (!$type || substr($file, 0, strlen($type)) == $type))
134
				@unlink($cachedir . '/' . $file);
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...
135
		}
136
		closedir($dh);
137
138
		// Make this invalid.
139
		$this->invalidateCache();
140
141
		return true;
142
	}
143
144
	/**
145
	 * {@inheritDoc}
146
	 */
147
	public function invalidateCache()
148
	{
149
		// We don't worry about $cachedir here, since the key is based on the real $cachedir.
150
		parent::invalidateCache();
151
152
		// Since SMF is file based, be sure to clear the statcache.
153
		clearstatcache();
154
155
		return true;
156
	}
157
158
	/**
159
	 * {@inheritDoc}
160
	 */
161
	public function cacheSettings(array &$config_vars)
162
	{
163
		global $context, $txt;
164
165
		$config_vars[] = $txt['cache_smf_settings'];
166
		$config_vars[] = array('cachedir', $txt['cachedir'], 'file', 'text', 36, 'cache_cachedir');
167
168
		if (!isset($context['settings_post_javascript']))
169
			$context['settings_post_javascript'] = '';
170
171
		$context['settings_post_javascript'] .= '
172
			$("#cache_accelerator").change(function (e) {
173
				var cache_type = e.currentTarget.value;
174
				$("#cachedir").prop("disabled", cache_type != "smf");
175
			});';
176
	}
177
178
	/**
179
	 * Sets the $cachedir or uses the SMF default $cachedir..
180
	 *
181
	 * @access public
182
	 * @param string $dir A valid path
183
	 * @return boolean If this was successful or not.
184
	 */
185
	public function setCachedir($dir = null)
186
	{
187
		global $cachedir;
188
189
		// If its invalid, use SMF's.
190
		if (is_null($dir) || !is_writable($dir))
191
			$this->cachedir = $cachedir;
192
		else
193
			$this->cachedir = $dir;
194
	}
195
196
	/**
197
	 * Gets the current $cachedir.
198
	 *
199
	 * @access public
200
	 * @return string the value of $ttl.
201
	 */
202
	public function getCachedir()
203
	{
204
		return $this->cachedir;
205
	}
206
}