Completed
Push — V6 ( 86d7ee...00097a )
by Georges
02:12
created

IOHelperTrait::htaccessGen()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 9
nop 2
dl 0
loc 30
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * This file is part of phpFastCache.
5
 *
6
 * @license MIT License (MIT)
7
 *
8
 * For full copyright and license information, please see the docs/CREDITS.txt file.
9
 *
10
 * @author Khoa Bui (khoaofgod)  <[email protected]> http://www.phpfastcache.com
11
 * @author Georges.L (Geolim4)  <[email protected]>
12
 *
13
 */
14
15
namespace phpFastCache\Core\Pool\IO;
16
17
use phpFastCache\Core\Item\ExtendedCacheItemInterface;
18
use phpFastCache\Core\Pool\ExtendedCacheItemPoolInterface;
19
use phpFastCache\Entities\driverStatistic;
20
use phpFastCache\Exceptions\phpFastCacheIOException;
21
use phpFastCache\Util\Directory;
22
23
/**
24
 * Trait IOHelperTrait
25
 * @package phpFastCache\Core\Pool\IO
26
 * @property array $config The configuration array passed via DriverBaseTrait
27
 * @property ExtendedCacheItemInterface[] $itemInstances The item instance passed via CacheItemPoolTrait
28
 */
29
trait IOHelperTrait
30
{
31
    /**
32
     * @var array
33
     */
34
    public $tmp = [];
35
36
    /**
37
     * @param bool $readonly
38
     * @return string
39
     * @throws phpFastCacheIOException
40
     */
41
    public function getPath($readonly = false)
42
    {
43
        /**
44
         * Get the base system temporary directory
45
         */
46
        $tmp_dir = rtrim(ini_get('upload_tmp_dir') ?: sys_get_temp_dir(), '\\/') . DIRECTORY_SEPARATOR . 'phpfastcache';
47
48
        /**
49
         * Calculate the security key
50
         */
51
        {
52
            $securityKey = array_key_exists('securityKey', $this->config) ? $this->config[ 'securityKey' ] : '';
53
            if (!$securityKey || $securityKey === 'auto') {
54
                if (isset($_SERVER[ 'HTTP_HOST' ])) {
55
                    $securityKey = preg_replace('/^www./', '', strtolower(str_replace(':', '_', $_SERVER[ 'HTTP_HOST' ])));
56
                } else {
57
                    $securityKey = ($this->isPHPModule() ? 'web' : 'cli');
58
                }
59
            }
60
61
            if ($securityKey !== '') {
62
                $securityKey .= '/';
63
            }
64
65
            $securityKey = static::cleanFileName($securityKey);
66
        }
67
68
        /**
69
         * Extends the temporary directory
70
         * with the security key and the driver name
71
         */
72
        $tmp_dir = rtrim($tmp_dir, '/') . DIRECTORY_SEPARATOR;
73
74
        if (empty($this->config[ 'path' ]) || !is_string($this->config[ 'path' ])) {
75
            $path = $tmp_dir;
76
        } else {
77
            $path = rtrim($this->config[ 'path' ], '/') . DIRECTORY_SEPARATOR;
78
        }
79
80
        $path_suffix = $securityKey . DIRECTORY_SEPARATOR . $this->getDriverName();
81
        $full_path = Directory::getAbsolutePath($path . $path_suffix);
82
        $full_path_tmp = Directory::getAbsolutePath($tmp_dir . $path_suffix);
83
        $full_path_hash = md5($full_path);
84
85
        /**
86
         * In readonly mode we only attempt
87
         * to verify if the directory exists
88
         * or not, if it does not then we
89
         * return the temp dir
90
         */
91
        if ($readonly === true) {
92
            if($this->config[ 'autoTmpFallback' ] && (!@file_exists($full_path) || !@is_writable($full_path))){
93
                return $full_path_tmp;
94
            }
95
            return $full_path;
96
        }else{
97
            if (!isset($this->tmp[ $full_path_hash ]) || (!@file_exists($full_path) || !@is_writable($full_path))) {
98
                if (!@file_exists($full_path)) {
99
                    @mkdir($full_path, $this->setChmodAuto(), true);
100
                }else if (!@is_writable($full_path)) {
101
                    if (!@chmod($full_path, $this->setChmodAuto()) && $this->config[ 'autoTmpFallback' ])
102
                    {
103
                        /**
104
                         * Switch back to tmp dir
105
                         * again if the path is not writable
106
                         */
107
                        $full_path = $full_path_tmp;
108
                        if (!@file_exists($full_path)) {
109
                            @mkdir($full_path, $this->setChmodAuto(), true);
110
                        }
111
                    }
112
                }
113
114
                /**
115
                 * In case there is no directory
116
                 * writable including tye temporary
117
                 * one, we must throw an exception
118
                 */
119
                if (!@file_exists($full_path) || !@is_writable($full_path)) {
120
                    throw new phpFastCacheIOException('PLEASE CREATE OR CHMOD ' . $full_path . ' - 0777 OR ANY WRITABLE PERMISSION!');
121
                }
122
123
                $this->tmp[ $full_path_hash ] = $full_path;
124
                $this->htaccessGen($full_path, array_key_exists('htaccess', $this->config) ? $this->config[ 'htaccess' ] : false);
125
            }
126
        }
127
128
        return realpath($full_path);
129
    }
130
131
132
    /**
133
     * @param $keyword
134
     * @param bool $skip
135
     * @return string
136
     * @throws phpFastCacheIOException
137
     */
138
    private function getFilePath($keyword, $skip = false)
139
    {
140
        $path = $this->getPath();
141
142
        if ($keyword === false) {
143
            return $path;
144
        }
145
146
        $filename = $this->encodeFilename($keyword);
147
        $folder = substr($filename, 0, 2) . DIRECTORY_SEPARATOR . substr($filename, 2, 2);
148
        $path = rtrim($path, '/\\') . DIRECTORY_SEPARATOR . $folder;
149
150
        /**
151
         * Skip Create Sub Folders;
152
         */
153
        if ($skip == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
154
            if (!file_exists($path)) {
155
                if (@!mkdir($path, $this->setChmodAuto(), true)) {
156
                    throw new phpFastCacheIOException('PLEASE CHMOD ' . $path . ' - ' . $this->setChmodAuto() . ' OR ANY WRITABLE PERMISSION!');
157
                }
158
            }
159
        }
160
161
        return $path . '/' . $filename . '.txt';
162
    }
163
164
165
166
    /**
167
     * @param $keyword
168
     * @return string
169
     */
170
    protected function encodeFilename($keyword)
171
    {
172
        return md5($keyword);
173
    }
174
175
    /**
176
     * @return bool
177
     */
178
    public function isExpired()
179
    {
180
        trigger_error(__FUNCTION__ . '() is deprecated, use ExtendedCacheItemInterface::isExpired() instead.', E_USER_DEPRECATED);
181
182
        return true;
183
    }
184
185
    /**
186
     * @param $this ->config
187
     * @return int
188
     */
189
    public function setChmodAuto()
190
    {
191
        if (!isset($this->config[ 'default_chmod' ]) || $this->config[ 'default_chmod' ] == '' || is_null($this->config[ 'default_chmod' ])) {
192
            return 0777;
193
        } else {
194
            return $this->config[ 'default_chmod' ];
195
        }
196
    }
197
198
    /**
199
     * @param $filename
200
     * @return mixed
201
     */
202
    protected static function cleanFileName($filename)
203
    {
204
        $regex = [
205
          '/[\?\[\]\/\\\=\<\>\:\;\,\'\"\&\$\#\*\(\)\|\~\`\!\{\}]/',
206
          '/\.$/',
207
          '/^\./',
208
        ];
209
        $replace = ['-', '', ''];
210
211
        return trim(preg_replace($regex, $replace, trim($filename)), '-');
212
    }
213
214
    /**
215
     * @param $path
216
     * @param bool $create
217
     * @throws phpFastCacheIOException
218
     */
219
    protected function htaccessGen($path, $create = true)
220
    {
221
        if ($create === true) {
222
            if (!is_writable($path)) {
223
                try {
224
                    if(!chmod($path, 0777)){
225
                        throw new phpFastCacheIOException('Chmod failed on : ' . $path);
226
                    }
227
                } catch (phpFastCacheIOException $e) {
228
                    throw new phpFastCacheIOException('PLEASE CHMOD ' . $path . ' - 0777 OR ANY WRITABLE PERMISSION!', 0, $e);
229
                }
230
            }
231
232
            if (!file_exists($path . "/.htaccess")) {
233
                $content = <<<HTACCESS
234
### This .htaccess is auto-generated by PhpFastCache ###
235
order deny, allow
236
deny from all
237
allow from 127.0.0.1
238
HTACCESS;
239
240
                $file = @fopen($path . '/.htaccess', 'w+');
241
                if (!$file) {
242
                    throw new phpFastCacheIOException('PLEASE CHMOD ' . $path . ' - 0777 OR ANY WRITABLE PERMISSION!');
243
                }
244
                fwrite($file, $content);
245
                fclose($file);
246
            }
247
        }
248
    }
249
250
251
    /**
252
     * @param $file
253
     * @return string
254
     * @throws phpFastCacheIOException
255
     */
256
    protected function readfile($file)
257
    {
258
        if (function_exists('file_get_contents')) {
259
            return file_get_contents($file);
260
        } else {
261
            $string = '';
262
263
            $file_handle = @fopen($file, 'r');
264
            if (!$file_handle) {
265
                throw new phpFastCacheIOException("Cannot read file located at: {$file}");
266
            }
267
            while (!feof($file_handle)) {
268
                $line = fgets($file_handle);
269
                $string .= $line;
270
            }
271
            fclose($file_handle);
272
273
            return $string;
274
        }
275
    }
276
277
    /**
278
     * @param string $file
279
     * @param string $data
280
     * @param bool $secureFileManipulation
281
     * @return bool
282
     * @throws phpFastCacheIOException
283
     */
284
    protected function writefile($file, $data, $secureFileManipulation = false)
285
    {
286
        /**
287
         * @eventName CacheWriteFileOnDisk
288
         * @param ExtendedCacheItemPoolInterface $this
289
         * @param string $file
290
         * @param bool $secureFileManipulation
291
         *
292
         */
293
        $this->eventManager->dispatch('CacheWriteFileOnDisk', $this, $file, $secureFileManipulation);
0 ignored issues
show
Bug introduced by
The property eventManager does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
294
295
        if($secureFileManipulation){
296
            $tmpFilename = Directory::getAbsolutePath(dirname($file) . '/tmp_' . md5(
297
                str_shuffle(uniqid($this->getDriverName(), false))
298
                . str_shuffle(uniqid($this->getDriverName(), false))
299
              ));
300
301
            $f = fopen($tmpFilename, 'w+');
302
            flock($f, LOCK_EX);
303
            $octetWritten = fwrite($f, $data);
304
            flock($f, LOCK_UN);
305
            fclose($f);
306
307
            if(!rename($tmpFilename, $file)){
308
                throw new phpFastCacheIOException(sprintf('Failed to rename %s to %s', $tmpFilename, $file));
309
            }
310
        }else{
311
            $f = fopen($file, 'w+');
312
            $octetWritten = fwrite($f, $data);
313
            fclose($f);
314
        }
315
316
        return $octetWritten !== false;
317
    }
318
319
    /********************
320
     *
321
     * PSR-6 Extended Methods
322
     *
323
     *******************/
324
325
    /**
326
     * Provide a generic getStats() method
327
     * for files-based drivers
328
     * @return driverStatistic
329
     * @throws \phpFastCache\Exceptions\phpFastCacheIOException
330
     */
331
    public function getStats()
332
    {
333
        $stat = new driverStatistic();
334
        $path = $this->getFilePath(false);
335
336
        if (!is_dir($path)) {
337
            throw new phpFastCacheIOException("Can't read PATH:" . $path);
338
        }
339
340
        $stat->setData(implode(', ', array_keys($this->itemInstances)))
341
          ->setRawData([
342
            'tmp' => $this->tmp
343
          ])
344
          ->setSize(Directory::dirSize($path))
345
          ->setInfo('Number of files used to build the cache: ' . Directory::getFileCount($path));
346
347
        return $stat;
348
    }
349
}