Test Failed
Branch main (71ef7e)
by Rafael
10:37 queued 05:04
created

PhpFileCache::fileExpired()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright (C) 2022-2023  Rafael San José Tovar   <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace Alxarafe\Core\Singletons;
20
21
use Symfony\Component\Yaml\Yaml;
22
use function Alxarafe\Core\Helpers\debug_message;
0 ignored issues
show
introduced by
The function Alxarafe\Core\Helpers\debug_message was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
23
24
/**
25
 * Simple YAML file cache
26
 */
27
class PhpFileCache
28
{
29
    /**
30
     * Configuration
31
     *
32
     * @access private
33
     */
34
    private static $config;
35
36
    private static $yamlPath;
37
38
    /**
39
     * php_file_cache constructor.
40
     */
41
    public function __construct()
42
    {
43
        $tmpPath = constant('BASE_FOLDER') . '/tmp/';
44
        self::$config = [
45
            'cache_path' => $tmpPath . 'cache',
46
            'expires' => 60 * 24 * 365,
47
        ];
48
49
        self::$yamlPath = $tmpPath . 'yamlcache/';
50
        createDir(self::$yamlPath);
51
        createDir(self::$config['cache_path']);
52
    }
53
54
    /**
55
     * Get the data associated with a key
56
     *
57
     * @access public
58
     *
59
     * @param string $key
60
     *
61
     * @return mixed the content you put in, or null if expired or not found
62
     */
63
    public function get($key, $raw = false, $custom_time = null)
64
    {
65
        if (!$this->fileExpired($file = $this->getRoute($key), $custom_time)) {
66
            $content = file_get_contents($file);
67
            return $raw ? $content : unserialize($content);
68
        }
69
70
        return null;
71
    }
72
73
    /**
74
     * Check if a file has expired or not.
75
     *
76
     * @access public
77
     *
78
     * @param string $file the rout to the file
79
     * @param int    $time the number of minutes it was set to expire
80
     *
81
     * @return bool if the file has expired or not
82
     */
83
    public function fileExpired($file, $time = null)
84
    {
85
        if (file_exists($file)) {
86
            return (time() > (filemtime($file) + 60 * ($time ?? self::$config['expires'])));
87
        }
88
89
        return true;
90
    }
91
92
    /**
93
     * Get a route to the file associated to that key.
94
     *
95
     * @access public
96
     *
97
     * @param string $key
98
     *
99
     * @return string the filename of the php file
100
     */
101
    public function getRoute($key)
102
    {
103
        return self::$config['cache_path'] . '/' . md5($key) . '.php';
104
    }
105
106
    /**
107
     * Put content into the cache
108
     *
109
     * @access public
110
     *
111
     * @param string $key
112
     * @param mixed  $content the the content you want to store
113
     * @param bool   $raw     whether if you want to store raw data or not. If it is true, $content *must* be a string
114
     *
115
     * @return bool whether if the operation was successful or not
116
     */
117
    public function put($key, $content, $raw = false)
118
    {
119
        $dest_file_name = $this->getRoute($key);
120
        /** Use a unique temporary filename to make writes atomic with rewrite */
121
        $temp_file_name = str_replace(".php", uniqid("-", true) . ".php", $dest_file_name);
122
        $ret = @file_put_contents($temp_file_name, $raw ? $content : serialize($content));
123
        if ($ret !== false) {
124
            return @rename($temp_file_name, $dest_file_name);
125
        }
126
        @unlink($temp_file_name);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

126
        /** @scrutinizer ignore-unhandled */ @unlink($temp_file_name);

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...
127
        return false;
128
    }
129
130
    /**
131
     * Delete data from cache
132
     *
133
     * @access public
134
     *
135
     * @param string $key
136
     *
137
     * @return bool true if the data was removed successfully
138
     */
139
    public function delete($key)
140
    {
141
        $done = true;
142
        $ruta = $this->getRoute($key);
143
        if (file_exists($ruta)) {
144
            $done = @unlink($ruta);
145
        }
146
147
        return $done;
148
    }
149
150
    /**
151
     * Flush all cache
152
     *
153
     * @access public
154
     * @return bool always true
155
     */
156
    public function flush()
157
    {
158
        foreach (scandir(getcwd() . '/' . self::$config['cache_path']) as $file_name) {
159
            if (file_exists(self::$config['cache_path'] . '/' . $file_name) && substr($file_name, -4) == '.php') {
160
                @unlink(self::$config['cache_path'] . '/' . $file_name);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

160
                /** @scrutinizer ignore-unhandled */ @unlink(self::$config['cache_path'] . '/' . $file_name);

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...
161
            }
162
        }
163
164
        return true;
165
    }
166
167
    public static function clearYamlCache(): bool
168
    {
169
        return delTree(self::$yamlPath);
0 ignored issues
show
Bug introduced by
The function delTree was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

169
        return /** @scrutinizer ignore-call */ delTree(self::$yamlPath);
Loading history...
170
    }
171
172
    public static function getYamlFileName(string $folder, string $filename): string
173
    {
174
        $path = self::$yamlPath . $folder . '/';
175
        if (!file_exists($path)) {
176
            if (!createDir($path)) {
177
                debug_message('No se ha podido crear la carpeta ' . $path);
0 ignored issues
show
Bug introduced by
The function debug_message was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

177
                /** @scrutinizer ignore-call */ 
178
                debug_message('No se ha podido crear la carpeta ' . $path);
Loading history...
178
            }
179
        }
180
        return $path . $filename . '.yaml';;
181
    }
182
183
    public static function saveYamlFile(string $folder, string $filename, array $content, int $maxLevel = 3): bool
184
    {
185
        $path = self::getYamlFileName($folder, $filename);
186
        return file_put_contents($path, Yaml::dump($content, $maxLevel)) !== false;
187
    }
188
189
    public static function loadYamlFile(string $folder, string $filename): array
190
    {
191
        $path = self::getYamlFileName($folder, $filename);
192
        if (empty($path) || !file_exists($path) || !is_readable($path)) {
193
            return [];
194
        }
195
        if (!isset($path)) {
196
            dump($path);
197
        }
198
        return Yaml::parseFile($path);
199
    }
200
}
201