Completed
Push — development ( eb9524...db4517 )
by Andrij
28:49 queued 02:09
created

Update::createBackUp()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
rs 8.9713
cc 2
eloc 16
nc 2
nop 0
1
<?php
2
3
use libraries\Backup;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Backup.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
4
5
/**
6
 * ImageCMS System Update Class
7
 * @copyright ImageCMS(c) 2013
8
 * @version 0.1 big start
9
 */
10
class Update
11
{
0 ignored issues
show
introduced by
Opening brace of a class must be on the same line as the definition
Loading history...
12
13
    private $arr_files;
14
15
    private $files_dates = [];
16
17
    private $restore_files = [];
18
19
    /**
20
     * update server
21
     * @var string
22
     */
23
    private $US = 'http://upd.imagecms.net/';
24
25
    /**
26
     * path to update server
27
     * @var string
28
     */
29
    private $pathUS;
30
31
    /**
32
     * папки, які не враховувати при обновлені
33
     * @var array
34
     */
35
    private $distinctDirs = [
36
        '.',
37
        '..',
38
        '.git',
39
        'uploads',
40
        'cache',
41
        'templates',
42
        'tests',
43
        'captcha',
44
        'nbproject',
45
        'uploads_site',
46
        'backups',
47
        'cmlTemp',
48
    ];
49
50
    /**
51
     * файли, які не враховувати при обновлені
52
     * @var array
53
     */
54
    private $distinctFiles = [
55
        'md5.txt',
56
        '.htaccess',
57
        'config.php'
58
    ];
59
60
    /**
61
     * instance of ci
62
     * @var MY_Controller
63
     */
64
    public $ci;
65
66
    /**
67
     * SoapClient
68
     * @var SoapClient
69
     */
70
    public $client;
71
72
    /**
73
     *
74
     * @var array
75
     */
76
    public $settings;
77
78
    public function __construct() {
79
80
        $this->ci = &get_instance();
81
        $this->pathUS = $this->US . 'application/modules/update/UpdateService.wsdl';
82
        $this->client = new SoapClient($this->pathUS);
83
        $this->settings = $this->getSettings();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getSettings() of type string is incompatible with the declared type array of property $settings.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
84
    }
85
86
    /**
87
     * check new Version
88
     * @return mixed
89
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
90
     */
91
    public function getStatus() {
92
93
        $domen = $this->ci->input->server('SERVER_NAME');
94
95
        $result = $this->client->getStatus($domen, BUILD_ID, IMAGECMS_NUMBER);
96
97
        if (mb_strlen($result) < 5 and $result == !0) {
98
            throw new Exception(lang('Cant get status', 'admin'));
99
        }
100
        $this->setSettings(['newVersion' => $result]);
101
        $this->setSettings(['checkTime' => time()]);
102
103
        return unserialize($result);
104
    }
105
106
    /**
107
     * getting hash from setting
108
     * @return array
109
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
110
     */
111
    public function getHashSum() {
112
113
        $domen = $this->ci->input->server('SERVER_NAME');
114
        $key = $this->getSettings('careKey');
115
116
        $result = $this->client->getHashSum($domen, IMAGECMS_NUMBER, BUILD_ID, $key);
117
118
        $error = (array) json_decode($result);
119
        if ($error['error']) {
120
            throw new Exception($error['error']);
121
        }
122
123
        write_file(BACKUPFOLDER . 'md5.txt', $result);
124
        $result = (array) json_decode($result);
125
126
        $this->setSettings(['checkTime' => time()]);
127
128
        return $result;
129
    }
130
131
    public function getUpdate() {
132
133
        ini_set('soap.wsdl_cache_enabled', '0');
134
        $domain = $this->ci->input->server('SERVER_NAME');
135
136
        $href = $this->client->getUpdate($domain, IMAGECMS_NUMBER, $this->settings['careKey']);
137
        if (!$href) {
138
            throw new Exception(lang('Wrong generate hash code', 'admin'));
139
        }
140
141
        $all_href = $this->US . 'update/takeUpdate/' . $href . '/' . $domain . '/' . IMAGECMS_NUMBER . '/' . BUILD_ID;
142
        file_put_contents(BACKUPFOLDER . 'updates.zip', file_get_contents($all_href));
143
    }
144
145
    /**
146
     *
147
     * @param string $file
148
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be array? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
149
     */
150
    public function getOldMD5File($file = 'md5.txt') {
151
152
        return (array) json_decode(read_file($file));
153
    }
154
155
    /**
156
     * zipping files
157
     * @param array $files
158
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
introduced by
@return doc comment specified, but function has no return statement
Loading history...
159
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
160
     */
161
    public function add_to_ZIP($files = []) {
162
163
        if (empty($files)) {
164
            throw new Exception(lang('Nothing to create', 'admin'));
165
        }
166
167
        $zip = new ZipArchive();
168
        $filename = BACKUPFOLDER . 'backup.zip';
169
170
        if (file_exists($filename)) {
171
172
            $nameFolder = filemtime($filename);
173
            rename($filename, BACKUPFOLDER . "$nameFolder.zip");
174
            touch($filename, $nameFolder);
175
176
        }
177
178
        if ($zip->open($filename, ZipArchive::CREATE) !== true) {
179
            throw new Exception(lang('Dont have permissions folder backup', 'admin'));
180
        }
181
182
        foreach (array_keys($files) as $key) {
183
            if (!is_readable('.' . $key)) {
184
                continue;
185
            }
186
            $zip->addFile('.' . $key, $key);
187
        }
188
        $zip->close();
189
    }
190
191
    /**
192
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
193
     */
194
    public function createBackUp() {
195
196
        $old = $this->getOldMD5File(BACKUPFOLDER . 'md5.txt');
197
        $array = $this->parse_md5();
198
        $diff = array_diff($array, $old);
199
        chmod(BACKUPFOLDER, 0755);
200
201
        if (!is_writable(BACKUPFOLDER)) {
202
            throw new Exception(lang('Dont have permissions folder backup', 'admin'));
203
        }
204
205
        $this->add_to_ZIP($diff);
206
207
        $filename = BACKUPFOLDER . 'backup.zip';
208
        $zip = new ZipArchive();
209
        $zip->open($filename);
210
211
        $db = $this->db_backup();
212
        $zip->addFile(BACKUPFOLDER . $db, $db);
213
        $zip->close();
214
215
        chmod(BACKUPFOLDER . $db, 0777);
216
        unlink(BACKUPFOLDER . $db);
217
    }
218
219
    /**
220
     * restore file to zip
221
     * @param string $file
222
     * @param mixed|string $destination
223
     * @return bool
224
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
225
     */
226
    public function restoreFromZIP($file, $destination = FCPATH) {
227
228
        if (!$file) {
229
            $file = BACKUPFOLDER . 'backup.zip';
230
        }
231
232
        if (!file_exists($file) || substr(decoct(fileperms($destination)), 2) != '777') {
233
            throw  new Exception(lang('Dont have permissions folder backup', 'admin'));
234
        }
235
236
        $zip = new ZipArchive();
237
        $zip->open($file);
238
        $rez = $zip->extractTo($destination);
239
        $zip->close();
240
241
        if ($rez) {
242
            $this->db_restore($destination . '/backup.sql');
243
        }
244
245
        return $rez;
246
    }
247
248
    /**
249
     * Бере контрольні суми файлів текущих файлів і файлів старої теперішньої версії
250
     * Записує іх у відповідні файли з настройок, як серіалізований масив ключ - шлях до файлу, значення - контрольна сума
251
     * запускати два рази переоприділивши $this->path_parse
252
     * $this->path_parse = realpath('') текущі.
253
     * $this->path_parse = rtrim($this->dir_old_upd, '\')
254
     * @param null|string $directory
255
     * @return array
256
     */
257
    public function parse_md5($directory = null) {
258
259
        $dir = null === $directory ? realpath('') : $directory;
260
261
        $handle = opendir($dir);
262
        if ($handle) {
263
            while (FALSE !== ($file = readdir($handle))) {
264
                if (!in_array($file, $this->distinctDirs)) {
265
                    if (is_file($dir . DIRECTORY_SEPARATOR . $file) && !in_array($file, $this->distinctFiles)) {
266
                        $this->arr_files[str_replace(realpath(''), '', $dir) . DIRECTORY_SEPARATOR . $file] = md5_file($dir . DIRECTORY_SEPARATOR . $file);
267
                        $this->files_dates[str_replace(realpath(''), '', $dir) . DIRECTORY_SEPARATOR . $file] = filemtime($dir . DIRECTORY_SEPARATOR . $file);
268
                    }
269
                    if (is_dir($dir . DIRECTORY_SEPARATOR . $file)) {
270
                        $this->parse_md5($dir . DIRECTORY_SEPARATOR . $file);
271
                    }
272
                }
273
            }
274
        }
275
276
        return $this->arr_files;
277
    }
278
279
    /**
280
     * database backup
281
     * @return string
282
     */
283
    public function db_backup() {
284
285 View Code Duplication
        if (is_really_writable(BACKUPFOLDER)) {
286
            $this->ci->load->dbutil();
287
            $filePath = Backup::create()->createBackup('sql', 'backup', TRUE);
288
            return pathinfo($filePath, PATHINFO_BASENAME);
289
        } else {
290
            showMessage(langf('Can not create a database snapshot, Check the folder {0} on the ability to record', 'admin', [BACKUPFOLDER]));
291
        }
292
    }
293
294
    /**
295
     * database restore
296
     * @param string $file
297
     * @return boolean
298
     */
299
    public function db_restore($file) {
300
301
        if (empty($file)) {
302
            return FALSE;
303
        }
304
305
        if (is_readable($file)) {
306
            $restore = file_get_contents($file);
307
            return $this->query_from_file($restore);
308
        }
309
        return FALSE;
310
    }
311
312
    /**
313
     * Create restore files list
314
     * @return boolean|array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
315
     */
316
    public function restore_files_list() {
317
318
        if (is_readable(BACKUPFOLDER)) {
319
            $dh = opendir(BACKUPFOLDER);
320
            while ($filename = readdir($dh)) {
321
                if (filetype($filename) != 'dir') {
322
                    $file_type = '';
323
                    preg_match('/\.[a-z]{2,3}/', $filename, $file_type);
324
                    if ($file_type[0] == '.zip') {
325
                        $zip = new ZipArchive();
326
                        $zip->open(BACKUPFOLDER . $filename);
327
                        if ($zip->statName('backup.sql')) {
328
                            $this->restore_files[] = [
329
                                'name' => $filename,
330
                                'size' => round(filesize(BACKUPFOLDER . $filename) / 1024 / 1024, 2),
331
                                'create_date' => filemtime(BACKUPFOLDER . $filename)
332
                            ];
333
                        }
334
                        $zip->close();
335
                    }
336
                }
337
            }
338
            return $this->restore_files;
339
        } else {
340
            return FALSE;
341
        }
342
    }
343
344
    /**
345
     * remove dir recursive
346
     * @param string $dir - path to directory
347
     */
348
    public function removeDirRec($dir) {
349
350
        if ($objs = glob($dir . '/*')) {
351
            foreach ($objs as $obj) {
352
                is_dir($obj) ? $this->removeDirRec($obj) : unlink($obj);
353
            }
354
        }
355
        if (is_dir($dir)) {
356
            rmdir($dir);
357
        }
358
    }
359
360
    /**
361
     * db update
362
     * @param string $file_name
363
     * @return boolean
364
     */
365
    public function db_update($file_name = 'sql_19-08-2013_17.16.14.txt') {
366
367
        if (is_readable(BACKUPFOLDER . $file_name)) {
368
            $restore = file_get_contents(BACKUPFOLDER . $file_name);
369
            return $this->query_from_file($restore);
370
        } else {
371
            return FALSE;
372
        }
373
    }
374
375
    /**
376
     * ganerate sql query from file
377
     * @param string $file
378
     * @return boolean
379
     */
380
    public function query_from_file($file) {
381
382
        $string_query = rtrim($file, "\n;");
383
        $array_query = explode(";\n", $string_query);
384
385
        foreach ($array_query as $query) {
386
            if ($query) {
387
                if (!$this->ci->db->query($query)) {
388
                    echo 'Невозможно виполнить запрос: <br>';
389
                    return FALSE;
390
                }
391
            }
392
        }
393
        return TRUE;
394
    }
395
396
    public function get_files_dates() {
397
398
        if (!empty($this->files_dates)) {
399
            return $this->files_dates;
400
        } else {
401
            return FALSE;
402
        }
403
    }
404
405
    /**
406
     * @param bool|string $param
407
     * @return string
408
     */
409
    public function getSettings($param = false) {
410
411
        $settings = $this->ci->db
412
            ->get('settings')
413
            ->row_array();
414
        $settings = unserialize($settings['update']);
415
416
        if (!$param) {
417
            return $settings;
418
        } else {
419
            return $settings[$param];
420
        }
421
    }
422
423
    /**
424
     *
425
     * @param array $settings
426
     * @return bool
427
     */
428
    public function setSettings($settings) {
429
430
        if (!is_array($settings)) {
431
            return FALSE;
432
        }
433
        $s = (array) $this->getSettings();
434
435
        foreach ($settings as $key => $value) {
436
            $s[$key] = $value;
437
        }
438
439
        return $this->ci->db
440
            ->set('update', serialize($s))
441
            ->update('settings');
442
    }
443
444
}