Completed
Push — V6 ( e1be50...8533dc )
by Georges
02:33
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\EventManager;
21
use phpFastCache\Exceptions\phpFastCacheIOException;
22
use phpFastCache\Util\Directory;
23
24
/**
25
 * Trait IOHelperTrait
26
 * @package phpFastCache\Core\Pool\IO
27
 * @property array $config The configuration array passed via DriverBaseTrait
28
 * @property ExtendedCacheItemInterface[] $itemInstances The item instance passed via CacheItemPoolTrait
29
 * @property EventManager $eventManager The event manager passed via CacheItemPoolTrait
30
 */
31
trait IOHelperTrait
32
{
33
    /**
34
     * @var array
35
     */
36
    public $tmp = [];
37
38
    /**
39
     * @param bool $readonly
40
     * @return string
41
     * @throws phpFastCacheIOException
42
     */
43
    public function getPath($readonly = false)
44
    {
45
        /**
46
         * Get the base system temporary directory
47
         */
48
        $tmp_dir = rtrim(ini_get('upload_tmp_dir') ?: sys_get_temp_dir(), '\\/') . DIRECTORY_SEPARATOR . 'phpfastcache';
49
50
        /**
51
         * Calculate the security key
52
         */
53
        {
54
            $securityKey = array_key_exists('securityKey', $this->config) ? $this->config[ 'securityKey' ] : '';
55
            if (!$securityKey || $securityKey === 'auto') {
56
                if (isset($_SERVER[ 'HTTP_HOST' ])) {
57
                    $securityKey = preg_replace('/^www./', '', strtolower(str_replace(':', '_', $_SERVER[ 'HTTP_HOST' ])));
58
                } else {
59
                    $securityKey = ($this->isPHPModule() ? 'web' : 'cli');
60
                }
61
            }
62
63
            if ($securityKey !== '') {
64
                $securityKey .= '/';
65
            }
66
67
            $securityKey = static::cleanFileName($securityKey);
68
        }
69
70
        /**
71
         * Extends the temporary directory
72
         * with the security key and the driver name
73
         */
74
        $tmp_dir = rtrim($tmp_dir, '/') . DIRECTORY_SEPARATOR;
75
76
        if (empty($this->config[ 'path' ]) || !is_string($this->config[ 'path' ])) {
77
            $path = $tmp_dir;
78
        } else {
79
            $path = rtrim($this->config[ 'path' ], '/') . DIRECTORY_SEPARATOR;
80
        }
81
82
        $path_suffix = $securityKey . DIRECTORY_SEPARATOR . $this->getDriverName();
83
        $full_path = Directory::getAbsolutePath($path . $path_suffix);
84
        $full_path_tmp = Directory::getAbsolutePath($tmp_dir . $path_suffix);
85
        $full_path_hash = md5($full_path);
86
87
        /**
88
         * In readonly mode we only attempt
89
         * to verify if the directory exists
90
         * or not, if it does not then we
91
         * return the temp dir
92
         */
93
        if ($readonly === true) {
94
            if($this->config[ 'autoTmpFallback' ] && (!@file_exists($full_path) || !@is_writable($full_path))){
95
                return $full_path_tmp;
96
            }
97
            return $full_path;
98
        }else{
99
            if (!isset($this->tmp[ $full_path_hash ]) || (!@file_exists($full_path) || !@is_writable($full_path))) {
100
                if (!@file_exists($full_path)) {
101
                    @mkdir($full_path, $this->getDefaultChmod(), true);
102
                }else if (!@is_writable($full_path)) {
103
                    if (!@chmod($full_path, $this->getDefaultChmod()) && $this->config[ 'autoTmpFallback' ])
104
                    {
105
                        /**
106
                         * Switch back to tmp dir
107
                         * again if the path is not writable
108
                         */
109
                        $full_path = $full_path_tmp;
110
                        if (!@file_exists($full_path)) {
111
                            @mkdir($full_path, $this->getDefaultChmod(), true);
112
                        }
113
                    }
114
                }
115
116
                /**
117
                 * In case there is no directory
118
                 * writable including tye temporary
119
                 * one, we must throw an exception
120
                 */
121
                if (!@file_exists($full_path) || !@is_writable($full_path)) {
122
                    throw new phpFastCacheIOException('PLEASE CREATE OR CHMOD ' . $full_path . ' - 0777 OR ANY WRITABLE PERMISSION!');
123
                }
124
125
                $this->tmp[ $full_path_hash ] = $full_path;
126
                $this->htaccessGen($full_path, array_key_exists('htaccess', $this->config) ? $this->config[ 'htaccess' ] : false);
127
            }
128
        }
129
130
        return realpath($full_path);
131
    }
132
133
134
    /**
135
     * @param $keyword
136
     * @param bool $skip
137
     * @return string
138
     * @throws phpFastCacheIOException
139
     */
140
    protected function getFilePath($keyword, $skip = false)
141
    {
142
        $path = $this->getPath();
143
144
        if ($keyword === false) {
145
            return $path;
146
        }
147
148
        $filename = $this->encodeFilename($keyword);
149
        $folder = substr($filename, 0, 2) . DIRECTORY_SEPARATOR . substr($filename, 2, 2);
150
        $path = rtrim($path, '/\\') . DIRECTORY_SEPARATOR . $folder;
151
152
        /**
153
         * Skip Create Sub Folders;
154
         */
155
        if (!$skip) {
156
            if (!file_exists($path)) {
157
                if (@!mkdir($path, $this->getDefaultChmod(), true)) {
158
                    throw new phpFastCacheIOException('PLEASE CHMOD ' . $path . ' - ' . $this->getDefaultChmod() . ' OR ANY WRITABLE PERMISSION!');
159
                }
160
            }
161
        }
162
163
        return $path . '/' . $filename . '.txt';
164
    }
165
166
167
168
    /**
169
     * @param $keyword
170
     * @return string
171
     */
172
    protected function encodeFilename($keyword)
173
    {
174
        return md5($keyword);
175
    }
176
177
    /**
178
     * @param $this ->config
179
     * @return int
180
     */
181
    protected function getDefaultChmod()
182
    {
183
        if (!isset($this->config[ 'default_chmod' ]) || $this->config[ 'default_chmod' ] == '' || is_null($this->config[ 'default_chmod' ])) {
184
            return 0777;
185
        } else {
186
            return $this->config[ 'default_chmod' ];
187
        }
188
    }
189
190
    /**
191
     * @param $filename
192
     * @return mixed
193
     */
194
    protected static function cleanFileName($filename)
195
    {
196
        $regex = [
197
          '/[\?\[\]\/\\\=\<\>\:\;\,\'\"\&\$\#\*\(\)\|\~\`\!\{\}]/',
198
          '/\.$/',
199
          '/^\./',
200
        ];
201
        $replace = ['-', '', ''];
202
203
        return trim(preg_replace($regex, $replace, trim($filename)), '-');
204
    }
205
206
    /**
207
     * @param $path
208
     * @param bool $create
209
     * @throws phpFastCacheIOException
210
     */
211
    protected function htaccessGen($path, $create = true)
212
    {
213
        if ($create === true) {
214
            if (!is_writable($path)) {
215
                try {
216
                    if(!chmod($path, 0777)){
217
                        throw new phpFastCacheIOException('Chmod failed on : ' . $path);
218
                    }
219
                } catch (phpFastCacheIOException $e) {
220
                    throw new phpFastCacheIOException('PLEASE CHMOD ' . $path . ' - 0777 OR ANY WRITABLE PERMISSION!', 0, $e);
221
                }
222
            }
223
224
            if (!file_exists($path . "/.htaccess")) {
225
                $content = <<<HTACCESS
226
### This .htaccess is auto-generated by PhpFastCache ###
227
order deny, allow
228
deny from all
229
allow from 127.0.0.1
230
HTACCESS;
231
232
                $file = @fopen($path . '/.htaccess', 'w+');
233
                if (!$file) {
234
                    throw new phpFastCacheIOException('PLEASE CHMOD ' . $path . ' - 0777 OR ANY WRITABLE PERMISSION!');
235
                }
236
                fwrite($file, $content);
237
                fclose($file);
238
            }
239
        }
240
    }
241
242
243
    /**
244
     * @param $file
245
     * @return string
246
     * @throws phpFastCacheIOException
247
     */
248
    protected function readfile($file)
249
    {
250
        if (function_exists('file_get_contents')) {
251
            return file_get_contents($file);
252
        } else {
253
            $string = '';
254
255
            $file_handle = @fopen($file, 'r');
256
            if (!$file_handle) {
257
                throw new phpFastCacheIOException("Cannot read file located at: {$file}");
258
            }
259
            while (!feof($file_handle)) {
260
                $line = fgets($file_handle);
261
                $string .= $line;
262
            }
263
            fclose($file_handle);
264
265
            return $string;
266
        }
267
    }
268
269
    /**
270
     * @param string $file
271
     * @param string $data
272
     * @param bool $secureFileManipulation
273
     * @return bool
274
     * @throws phpFastCacheIOException
275
     */
276
    protected function writefile($file, $data, $secureFileManipulation = false)
277
    {
278
        /**
279
         * @eventName CacheWriteFileOnDisk
280
         * @param ExtendedCacheItemPoolInterface $this
281
         * @param string $file
282
         * @param bool $secureFileManipulation
283
         *
284
         */
285
        $this->eventManager->dispatch('CacheWriteFileOnDisk', $this, $file, $secureFileManipulation);
286
287
        if($secureFileManipulation){
288
            $tmpFilename = Directory::getAbsolutePath(dirname($file) . '/tmp_' . md5(
289
                str_shuffle(uniqid($this->getDriverName(), false))
290
                . str_shuffle(uniqid($this->getDriverName(), false))
291
              ));
292
293
            $f = fopen($tmpFilename, 'w+');
294
            flock($f, LOCK_EX);
295
            $octetWritten = fwrite($f, $data);
296
            flock($f, LOCK_UN);
297
            fclose($f);
298
299
            if(!rename($tmpFilename, $file)){
300
                throw new phpFastCacheIOException(sprintf('Failed to rename %s to %s', $tmpFilename, $file));
301
            }
302
        }else{
303
            $f = fopen($file, 'w+');
304
            $octetWritten = fwrite($f, $data);
305
            fclose($f);
306
        }
307
308
        return $octetWritten !== false;
309
    }
310
311
    /********************
312
     *
313
     * PSR-6 Extended Methods
314
     *
315
     *******************/
316
317
    /**
318
     * Provide a generic getStats() method
319
     * for files-based drivers
320
     * @return driverStatistic
321
     * @throws \phpFastCache\Exceptions\phpFastCacheIOException
322
     */
323
    public function getStats()
324
    {
325
        $stat = new driverStatistic();
326
        $path = $this->getFilePath(false);
327
328
        if (!is_dir($path)) {
329
            throw new phpFastCacheIOException("Can't read PATH:" . $path);
330
        }
331
332
        $stat->setData(implode(', ', array_keys($this->itemInstances)))
333
          ->setRawData([
334
            'tmp' => $this->tmp
335
          ])
336
          ->setSize(Directory::dirSize($path))
337
          ->setInfo('Number of files used to build the cache: ' . Directory::getFileCount($path));
338
339
        return $stat;
340
    }
341
}