This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace libraries; |
||
4 | |||
5 | /** |
||
6 | * Creating DB backups |
||
7 | * getting backup files |
||
8 | * deleting old backup-files |
||
9 | * |
||
10 | * @author kolia |
||
11 | */ |
||
12 | class Backup |
||
13 | { |
||
14 | |||
15 | /** |
||
16 | * |
||
17 | * @var Backup |
||
18 | */ |
||
19 | protected static $instance; |
||
20 | |||
21 | /** |
||
22 | * Backup directory |
||
23 | * @var string |
||
24 | */ |
||
25 | protected $directory = BACKUPFOLDER; |
||
26 | |||
27 | /** |
||
28 | * Aviable extentions |
||
29 | * @var array |
||
30 | */ |
||
31 | protected $ext = [ |
||
32 | 'sql', |
||
33 | 'zip', |
||
34 | 'gzip', |
||
35 | ]; |
||
36 | |||
37 | /** |
||
38 | * Patterns for backup file names |
||
39 | * key - regex pattern, value - boolean (allow delete) |
||
40 | * @var array |
||
41 | */ |
||
42 | protected $filePatterns = [ |
||
43 | // для файлів із авт. підбором імені. |
||
44 | '/^[a-zA-Z]{1,10}_[0-9]{2}-[0-9]{2}-[0-9]{4}_[0-9]{2}.[0-9]{2}.[0-9]{2}.(zip|gzip|sql|txt)$/' => [ |
||
45 | 'allowDelete' => TRUE, |
||
46 | 'type' => 'default', |
||
47 | ], |
||
48 | // для старіших бекапів із обновлення |
||
49 | '/^[0-9]{10}.(zip|gzip|sql|txt)$/' => [ |
||
50 | 'allowDelete' => TRUE, |
||
51 | 'type' => 'update', |
||
52 | ], |
||
53 | // для новіших бекапів із обновлення |
||
54 | '/^backup.(zip|gzip|sql|txt)$/' => [ |
||
55 | 'allowDelete' => FALSE, |
||
56 | 'type' => 'update', |
||
57 | ], |
||
58 | ]; |
||
59 | |||
60 | /** |
||
61 | * |
||
62 | * @var CodeIgniter |
||
63 | */ |
||
64 | protected $ci; |
||
65 | |||
66 | /** |
||
67 | * |
||
68 | * @var string |
||
69 | */ |
||
70 | public $error; |
||
71 | |||
72 | public function __construct() { |
||
73 | $this->ci = &get_instance(); |
||
74 | $this->ci->load->dbutil(); |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * |
||
79 | * @return Backup |
||
80 | */ |
||
81 | public static function create() { |
||
82 | (null !== self::$instance) OR self::$instance = new self(); |
||
83 | return self::$instance; |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * Setting the backup value into the DB |
||
88 | * @param string $key |
||
89 | * @param string|int $value |
||
90 | */ |
||
91 | public function setSetting($key, $value) { |
||
92 | $settings = $this->getSetting(); |
||
93 | if (!is_array($settings)) { //no settings yet |
||
94 | $settings = []; |
||
95 | } |
||
96 | $settings[$key] = $value; |
||
97 | return $this->ci->db->update('settings', ['backup' => serialize($settings)]); |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * Getting the backup value from the DB |
||
102 | * @param string |
||
103 | * @param string $key |
||
104 | * @return mixed settings array or specified value |
||
105 | */ |
||
106 | public function getSetting($key = NULL) { |
||
107 | $result = $this->ci->db->select('backup')->get('settings'); |
||
108 | if ($result) { |
||
109 | $row = $result->result_array(); |
||
110 | } else { |
||
111 | $row = []; |
||
112 | } |
||
113 | |||
114 | $backupSettings = unserialize($row[0]['backup']); |
||
115 | if (!is_array($backupSettings)) { // no settings yet |
||
116 | return NULL; |
||
117 | } |
||
118 | if ($key != null) { |
||
119 | if (!array_key_exists($key, $backupSettings)) { |
||
120 | return NULL; |
||
121 | } |
||
122 | return $backupSettings[$key]; |
||
123 | } |
||
124 | return $backupSettings; |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * Creating the backup file |
||
129 | * @param string $ext extention (txt|zip|gzip) |
||
130 | * @param string $prefix |
||
131 | * @param bool|string $fullName (optional) filename |
||
132 | * @param array $params |
||
133 | * @return false|string filename|FALSE |
||
134 | */ |
||
135 | public function createBackup($ext, $prefix = NULL, $fullName = FALSE, $params = []) { |
||
136 | if (is_really_writable($this->directory)) { |
||
137 | if ($prefix == null) { |
||
138 | $prefix = 'sql'; |
||
139 | } |
||
140 | if ($fullName === TRUE) { |
||
141 | $fileName = $prefix; |
||
142 | } else { |
||
143 | $fileName = $prefix . '_' . date('d-m-Y_H.i.s'); |
||
144 | } |
||
145 | |||
146 | $params = [ |
||
147 | 'format' => $ext == 'sql' ? 'txt' : $ext, |
||
148 | ]; |
||
149 | |||
150 | $currentDbInstance = $this->ci->db; |
||
151 | |||
152 | $this->initBackupDB(); |
||
153 | |||
154 | $backup = & $this->ci->dbutil->backup($params); |
||
155 | |||
156 | $this->ci->db = $currentDbInstance; |
||
157 | |||
158 | if (write_file($this->directory . '/' . $fileName . '.' . $ext, $backup)) { |
||
159 | return $this->directory . '/' . $fileName . '.' . $ext; |
||
160 | } |
||
161 | $this->error = 'Невозможно создать файл, проверте папку ' . BACKUPFOLDER . ' на возможность записи'; |
||
162 | return FALSE; |
||
163 | } else { |
||
164 | $this->error = 'Невозможно создать снимок базы, проверте папку ' . BACKUPFOLDER . ' на возможность записи'; |
||
165 | return FALSE; |
||
166 | } |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Init DB for backup with msql driver |
||
171 | */ |
||
172 | private function initBackupDB() { |
||
173 | // this is just all config keys |
||
174 | $configNames = [ |
||
175 | 'hostname', |
||
176 | 'username', |
||
177 | 'password', |
||
178 | 'database', |
||
179 | 'dbdriver', |
||
180 | 'dbprefix', |
||
181 | 'pconnect', |
||
182 | 'db_debug', |
||
183 | 'cache_on', |
||
184 | 'cachedir', |
||
185 | 'char_set', |
||
186 | 'dbcollat', |
||
187 | 'swap_pre', |
||
188 | 'autoinit', |
||
189 | 'stricton', |
||
190 | ]; |
||
191 | |||
192 | $config = []; |
||
193 | foreach ($configNames as $key) { |
||
194 | $config[$key] = $key == 'dbdriver' ? 'mysql' : $this->ci->db->$key; |
||
195 | } |
||
196 | |||
197 | $this->ci->db = $this->ci->load->database($config, TRUE); |
||
198 | $this->ci->load->dbutil(); |
||
199 | } |
||
200 | |||
201 | /** |
||
202 | * |
||
203 | * @return boolean |
||
204 | */ |
||
205 | public function deleteOldFiles() { |
||
206 | $term = $this->getSetting('backup_term'); |
||
207 | $maxSize = ($this->getSetting('backup_maxsize') * 1024 * 1024); |
||
208 | |||
209 | $maxSize = 5 * 1024 * 1024; |
||
210 | // if time of file will be lower then delete |
||
211 | $time = time() - (60 * 60 * 24 * 30.5 * $term); |
||
212 | |||
213 | $files = $this->backupFiles(); |
||
214 | // get summary backup size |
||
215 | $size = 0; |
||
216 | foreach ($files as $file) { |
||
217 | $size += $file['size']; |
||
218 | } |
||
219 | |||
220 | // start deleting if overload more then max size |
||
221 | if ($size > $maxSize) { |
||
222 | $deleteSize = $size - $maxSize; |
||
223 | $deleteEdOnSize = 0; |
||
224 | $filesCount = 0; |
||
225 | do { |
||
226 | $fileToDelete = $this->getOldestFileToDelete(); |
||
227 | if ($fileToDelete == FALSE) { // if FALSE then no more files to delete |
||
228 | break; |
||
229 | } |
||
230 | if ($fileToDelete['timeUpdate'] > $time) { // check if not overrun max date |
||
231 | break; |
||
232 | } |
||
233 | $filesCount++; |
||
234 | $deleteEdOnSize += $fileToDelete['size']; |
||
235 | unlink($this->directory . '/' . $fileToDelete['filename']); |
||
236 | } while ($deleteEdOnSize < $deleteSize); |
||
237 | |||
238 | return [ |
||
239 | 'count' => $filesCount, |
||
240 | 'size' => $deleteEdOnSize, |
||
241 | ]; |
||
242 | } |
||
243 | return FALSE; |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * |
||
248 | * @return boolean |
||
249 | */ |
||
250 | public function getOldestFileToDelete() { |
||
251 | $files_ = $this->backupFiles(); |
||
252 | // getting only files that allow to delete by pattern |
||
253 | $files = []; |
||
254 | foreach ($files_ as $file) { |
||
255 | if ($this->checkFileName($file['filename'], 'allowDelete') && $file['locked'] != 1) { |
||
256 | $files[] = $file; |
||
257 | } |
||
258 | } |
||
259 | |||
260 | if (!count($files) > 0) { |
||
261 | return FALSE; |
||
262 | } |
||
263 | |||
264 | $minKey = 0; |
||
265 | $minTime = $files[0]['timeUpdate']; |
||
266 | |||
267 | $countFiles = count($files); |
||
268 | for ($i = 1; $i < $countFiles; $i++) { |
||
269 | if ($minTime > $files[$i]['timeUpdate']) { |
||
270 | $minTime = $files[$i]['timeUpdate']; |
||
271 | $minKey = $i; |
||
272 | } |
||
273 | } |
||
274 | return $files[$minKey]; |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Getting list of backup files |
||
279 | * @return array |
||
280 | */ |
||
281 | public function backupFiles() { |
||
282 | $lockedFiles = $this->getSetting('lockedFiles'); |
||
283 | if (!is_array($lockedFiles)) { |
||
284 | $lockedFiles = []; |
||
285 | } |
||
286 | $files = []; |
||
287 | if ($dir = opendir($this->directory)) { |
||
288 | while (FALSE !== ($fileName = readdir($dir))) { |
||
289 | if ($fileName != '.' & $fileName !== '..') { |
||
290 | if (TRUE === $this->checkFileName($fileName)) { |
||
291 | $file = [ |
||
292 | 'filename' => $fileName, |
||
293 | 'allowDelete' => $this->checkFileName($fileName, 'allowDelete') == TRUE ? 1 : 0, |
||
294 | 'type' => $this->checkFileName($fileName, 'type'), |
||
295 | 'ext' => pathinfo($fileName, PATHINFO_EXTENSION), |
||
296 | 'size' => filesize($this->directory . '/' . $fileName), |
||
297 | 'timeUpdate' => filemtime($this->directory . '/' . $fileName), |
||
298 | ]; |
||
299 | if ($file['type'] == 'default') { |
||
300 | $prefIndex = strpos($fileName, '_'); |
||
301 | $file['prefix'] = substr($fileName, 0, $prefIndex); |
||
302 | } else { |
||
303 | $file['prefix'] = 'update'; |
||
304 | } |
||
305 | if (in_array($fileName, $lockedFiles)) { |
||
306 | $file['locked'] = 1; |
||
307 | } else { |
||
308 | $file['locked'] = 0; |
||
309 | } |
||
310 | $files[] = $file; |
||
311 | } |
||
312 | } |
||
313 | } |
||
314 | closedir($dir); |
||
315 | } |
||
316 | |||
317 | foreach ($files as $key => $row) { |
||
318 | $backaps[$key] = $row['timeUpdate']; |
||
0 ignored issues
–
show
|
|||
319 | } |
||
320 | |||
321 | array_multisort($backaps, SORT_DESC, $files); |
||
322 | |||
323 | return $files; |
||
324 | } |
||
325 | |||
326 | /** |
||
327 | * Checking file name by pattern |
||
328 | * @param string $fileName |
||
329 | * @param boolean|string $returnValue |
||
330 | * @return boolean|string |
||
331 | */ |
||
332 | protected function checkFileName($fileName, $returnValue = FALSE) { |
||
333 | foreach ($this->filePatterns as $pattern => $params) { |
||
334 | if (preg_match($pattern, $fileName)) { |
||
335 | return $returnValue !== FALSE ? $params[$returnValue] : TRUE; |
||
336 | } |
||
337 | } |
||
338 | return FALSE; |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Deleting backup file |
||
343 | * @param string $file |
||
344 | * @return boolean true on success, false on error |
||
345 | */ |
||
346 | public function deleteFile($file) { |
||
347 | if (FALSE === $this->checkFileName($file, 'allowDelete')) { |
||
348 | return FALSE; |
||
349 | } |
||
350 | if (file_exists($this->directory . '/' . $file)) { |
||
351 | return unlink($this->directory . '/' . $file); |
||
352 | } |
||
353 | return FALSE; |
||
354 | } |
||
355 | |||
356 | } |
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArray
is initialized the first time when the foreach loop is entered. You can also see that the value of thebar
key is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.