Skip to content

Commit 2a0d39f

Browse files
authored
Merge pull request #4103 from MGatner/cache-permissions
2 parents 2020c2d + 06b9225 commit 2a0d39f

File tree

9 files changed

+106
-32
lines changed

9 files changed

+106
-32
lines changed

app/Config/Cache.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class Cache extends BaseConfig
4646
* system.
4747
*
4848
* @var string
49+
*
50+
* @deprecated Use the driver-specific variant under $file
4951
*/
5052
public $storePath = WRITEPATH . 'cache/';
5153

@@ -80,6 +82,20 @@ class Cache extends BaseConfig
8082
*/
8183
public $prefix = '';
8284

85+
/**
86+
* --------------------------------------------------------------------------
87+
* File settings
88+
* --------------------------------------------------------------------------
89+
* Your file storage preferences can be specified below, if you are using
90+
* the File driver.
91+
*
92+
* @var array<string, string|int|null>
93+
*/
94+
public $file = [
95+
'storePath' => WRITEPATH . 'cache/',
96+
'mode' => 0640,
97+
];
98+
8399
/**
84100
* -------------------------------------------------------------------------
85101
* Memcached settings

system/Cache/Handlers/FileHandler.php

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ class FileHandler implements CacheInterface
3434
*/
3535
protected $path;
3636

37+
/**
38+
* Mode for the stored files.
39+
* Must be chmod-safe (octal).
40+
*
41+
* @var integer
42+
*
43+
* @see https://www.php.net/manual/en/function.chmod.php
44+
*/
45+
protected $mode;
46+
3747
//--------------------------------------------------------------------
3848

3949
/**
@@ -44,14 +54,24 @@ class FileHandler implements CacheInterface
4454
*/
4555
public function __construct(Cache $config)
4656
{
47-
$path = ! empty($config->storePath) ? $config->storePath : WRITEPATH . 'cache';
48-
if (! is_really_writable($path))
57+
if (! property_exists($config, 'file'))
58+
{
59+
$config->file = [
60+
'storePath' => $config->storePath ?? WRITEPATH . 'cache',
61+
'mode' => 0640,
62+
];
63+
}
64+
65+
$this->path = ! empty($config->file['storePath']) ? $config->file['storePath'] : WRITEPATH . 'cache';
66+
$this->path = rtrim($this->path, '/') . '/';
67+
68+
if (! is_really_writable($this->path))
4969
{
50-
throw CacheException::forUnableToWrite($path);
70+
throw CacheException::forUnableToWrite($this->path);
5171
}
5272

53-
$this->prefix = $config->prefix ?: '';
54-
$this->path = rtrim($path, '/') . '/';
73+
$this->mode = $config->file['mode'] ?? 0640;
74+
$this->prefix = (string) $config->prefix;
5575
}
5676

5777
//--------------------------------------------------------------------
@@ -105,7 +125,7 @@ public function save(string $key, $value, int $ttl = 60)
105125

106126
if ($this->writeFile($this->path . $key, serialize($contents)))
107127
{
108-
chmod($this->path . $key, 0640);
128+
chmod($this->path . $key, $this->mode);
109129

110130
return true;
111131
}

system/Cache/Handlers/MemcachedHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class MemcachedHandler implements CacheInterface
5858
*/
5959
public function __construct(Cache $config)
6060
{
61-
$this->prefix = $config->prefix ?: '';
61+
$this->prefix = (string) $config->prefix;
6262

6363
if (! empty($config))
6464
{

system/Cache/Handlers/PredisHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class PredisHandler implements CacheInterface
5858
*/
5959
public function __construct(Cache $config)
6060
{
61-
$this->prefix = $config->prefix ?: '';
61+
$this->prefix = (string) $config->prefix;
6262

6363
if (isset($config->redis))
6464
{

system/Cache/Handlers/RedisHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class RedisHandler implements CacheInterface
5858
*/
5959
public function __construct(Cache $config)
6060
{
61-
$this->prefix = $config->prefix ?: '';
61+
$this->prefix = (string) $config->prefix;
6262

6363
if (! empty($config))
6464
{

system/Cache/Handlers/WincacheHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class WincacheHandler implements CacheInterface
3737
*/
3838
public function __construct(Cache $config)
3939
{
40-
$this->prefix = $config->prefix ?: '';
40+
$this->prefix = (string) $config->prefix;
4141
}
4242

4343
//--------------------------------------------------------------------

tests/system/Cache/Handlers/FileHandlerTest.php

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,18 @@ protected function setUp(): void
2626
{
2727
parent::setUp();
2828

29-
//Initialize path
30-
$this->config = new \Config\Cache();
31-
$this->config->storePath .= self::$directory;
29+
if (! function_exists('octal_permissions'))
30+
{
31+
helper('filesystem');
32+
}
33+
34+
// Initialize path
35+
$this->config = new \Config\Cache();
36+
$this->config->file['storePath'] .= self::$directory;
3237

33-
if (! is_dir($this->config->storePath))
38+
if (! is_dir($this->config->file['storePath']))
3439
{
35-
mkdir($this->config->storePath, 0777, true);
40+
mkdir($this->config->file['storePath'], 0777, true);
3641
}
3742

3843
$this->fileHandler = new FileHandler($this->config);
@@ -41,20 +46,20 @@ protected function setUp(): void
4146

4247
public function tearDown(): void
4348
{
44-
if (is_dir($this->config->storePath))
49+
if (is_dir($this->config->file['storePath']))
4550
{
46-
chmod($this->config->storePath, 0777);
51+
chmod($this->config->file['storePath'], 0777);
4752

4853
foreach (self::getKeyArray() as $key)
4954
{
50-
if (is_file($this->config->storePath . DIRECTORY_SEPARATOR . $key))
55+
if (is_file($this->config->file['storePath'] . DIRECTORY_SEPARATOR . $key))
5156
{
52-
chmod($this->config->storePath . DIRECTORY_SEPARATOR . $key, 0777);
53-
unlink($this->config->storePath . DIRECTORY_SEPARATOR . $key);
57+
chmod($this->config->file['storePath'] . DIRECTORY_SEPARATOR . $key, 0777);
58+
unlink($this->config->file['storePath'] . DIRECTORY_SEPARATOR . $key);
5459
}
5560
}
5661

57-
rmdir($this->config->storePath);
62+
rmdir($this->config->file['storePath']);
5863
}
5964
}
6065

@@ -67,15 +72,15 @@ public function testNewWithNonWritablePath()
6772
{
6873
$this->expectException('CodeIgniter\Cache\Exceptions\CacheException');
6974

70-
chmod($this->config->storePath, 0444);
75+
chmod($this->config->file['storePath'], 0444);
7176
new FileHandler($this->config);
7277
}
7378

7479
public function testSetDefaultPath()
7580
{
76-
//Initialize path
77-
$config = new \Config\Cache();
78-
$config->storePath = null;
81+
// Initialize path
82+
$config = new \Config\Cache();
83+
$config->file['storePath'] = null;
7984

8085
$this->fileHandler = new FileHandler($config);
8186
$this->fileHandler->initialize();
@@ -98,7 +103,7 @@ public function testSave()
98103
{
99104
$this->assertTrue($this->fileHandler->save(self::$key1, 'value'));
100105

101-
chmod($this->config->storePath, 0444);
106+
chmod($this->config->file['storePath'], 0444);
102107
$this->assertFalse($this->fileHandler->save(self::$key2, 'value'));
103108
}
104109

@@ -173,6 +178,36 @@ public function testIsSupported()
173178
$this->assertTrue($this->fileHandler->isSupported());
174179
}
175180

181+
/**
182+
* @dataProvider modeProvider
183+
*/
184+
public function testSaveMode($int, $string)
185+
{
186+
// Initialize mode
187+
$config = new \Config\Cache();
188+
$config->file['mode'] = $int;
189+
190+
$this->fileHandler = new FileHandler($config);
191+
$this->fileHandler->initialize();
192+
193+
$this->fileHandler->save(self::$key1, 'value');
194+
195+
$file = $config->file['storePath'] . DIRECTORY_SEPARATOR . self::$key1;
196+
$mode = octal_permissions(fileperms($file));
197+
198+
$this->assertEquals($string, $mode);
199+
}
200+
201+
public function modeProvider()
202+
{
203+
return [
204+
[0640, '640'],
205+
[0600, '600'],
206+
[0660, '660'],
207+
[0777, '777'],
208+
];
209+
}
210+
176211
//--------------------------------------------------------------------
177212

178213
public function testFileHandler()
@@ -200,8 +235,8 @@ final class BaseTestFileHandler extends FileHandler
200235

201236
public function __construct()
202237
{
203-
$this->config = new \Config\Cache();
204-
$this->config->storePath .= self::$directory;
238+
$this->config = new \Config\Cache();
239+
$this->config->file['storePath'] .= self::$directory;
205240

206241
parent::__construct($this->config);
207242
}

user_guide_src/source/changelogs/v4.0.5.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Enhancements:
1414
- Support for setting SameSite attribute on Session and CSRF cookies has been added. For security and compatibility with latest browser versions, the default setting is ``Lax``.
1515
- Guessing file extensions from mime type in ``Config\Mimes::guessExtensionFromType`` now only reverse searches the ``$mimes`` array if no extension is proposed (i.e., usually not for uploaded files).
1616
- The getter functions for file extensions of uploaded files now have different fallback values (``$this->getClientExtension()`` for ``UploadedFile->getExtension()`` and ``''`` for ``UploadedFile->guessExtension()``). This is a security fix and makes the process less dependent on the client.
17+
- The Cache ``FileHandler`` now allows setting the file permissions mode via ``Config\Cache``
1718

1819
Changes:
1920

@@ -44,3 +45,4 @@ Deprecations:
4445
- Deprecated ``CodeIgniter\Config\Config`` in favor of ``CodeIgniter\Config\Factories::config()``
4546
- Deprecated ``CodeIgniter\HTTP\Message::getHeader`` in favor of ``header()`` to prepare for PSR-7
4647
- Deprecated ``CodeIgniter\HTTP\Message::getHeaders`` in favor of ``headers()`` to prepare for PSR-7
48+
- Deprecated ``Config\Cache::$storePath`` in favor of ``Config\Cache::$file['storePath']``

user_guide_src/source/libraries/caching.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ more complex, multi-server setups.
5757
**$prefix**
5858

5959
If you have more than one application using the same cache storage, you can add a custom prefix
60-
here that is prepended to all key names.
60+
string here that is prepended to all key names.
6161

62-
**$path**
62+
**$file**
6363

64-
This is used by the ``file`` handler to show where it should save the cache files to.
64+
This is an array of settings specific to the ``File`` handler to determine how it should save the cache files.
6565

6666
**$memcached**
6767

@@ -212,7 +212,8 @@ File-based Caching
212212
Unlike caching from the Output Class, the driver file-based caching
213213
allows for pieces of view files to be cached. Use this with care, and
214214
make sure to benchmark your application, as a point can come where disk
215-
I/O will negate positive gains by caching. This requires a writable cache directory to be really writable (0777).
215+
I/O will negate positive gains by caching. This requires a cache
216+
directory to be really writable by the application.
216217

217218
=================
218219
Memcached Caching

0 commit comments

Comments
 (0)