Passed
Push — develop ( 94894c...636f36 )
by Nikolay
06:22
created

WorkerDownloader::shutdownHandler()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 10
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
/**
3
 * Copyright © MIKO LLC - All Rights Reserved
4
 * Unauthorized copying of this file, via any medium is strictly prohibited
5
 * Proprietary and confidential
6
 * Written by Alexey Portnov, 2 2020
7
 */
8
9
namespace MikoPBX\PBXCoreREST\Workers;
10
11
require_once 'Globals.php';
12
13
use MikoPBX\Core\Workers\WorkerBase;
14
use MikoPBX\Core\System\Util;
15
16
17
class WorkerDownloader extends WorkerBase
18
{
19
    private string $old_memory_limit;
20
    private int $progress = 0;
21
    private array $settings;
22
    private string $progress_file = '';
23
    private string $error_file = '';
24
    private int $file_size = 0;
25
26
    /**
27
     * WorkerDownloader entry point.
28
     *
29
     * @param $argv
30
     */
31
32
    public function start($argv): void
33
    {
34
        if (file_exists($argv[1])) {
35
            $this->settings = json_decode(file_get_contents($argv[1]), true);
36
        } else {
37
            Util::sysLogMsg("WorkerDownloader", 'Wrong settings');
38
            return;
39
        }
40
        $this->old_memory_limit = ini_get('memory_limit');
41
        ini_set('memory_limit', '300M');
42
43
        $temp_dir            = dirname($this->settings['res_file']);
44
        $this->progress_file = $temp_dir . '/progress';
45
        $this->error_file    = $temp_dir . '/error';
46
        Util::mwMkdir($temp_dir);
47
48
        if ($this->getFile()) {
49
            $this->action();
50
        } else {
51
            Util::sysLogMsg("WorkerDownloader", 'Download error...');
52
        }
53
    }
54
55
    /**
56
     * Скачивание файла с удаленного ресурса.
57
     */
58
    public function getFile(): bool
59
    {
60
        if (empty($this->settings)) {
61
            return false;
62
        }
63
        if (file_exists($this->settings['res_file'])) {
64
            unlink($this->settings['res_file']);
65
        }
66
        $this->file_size = $this->remoteFileSize($this->settings['url']);
67
68
        file_put_contents($this->progress_file, 0);
69
70
        $fp = fopen($this->settings['res_file'], 'w');
71
        $ch = curl_init();
72
        if ($ch !== false) {
73
            return false;
74
        }
75
        curl_setopt($ch, CURLOPT_FILE, $fp);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

75
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_FILE, $fp);
Loading history...
76
        curl_setopt($ch, CURLOPT_URL, $this->settings['url']);
77
        curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, [$this, 'progress']);
78
        curl_setopt($ch, CURLOPT_NOPROGRESS, false); // needed to make progress function work
79
        curl_setopt($ch, CURLOPT_HEADER, 0);
80
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
81
82
        curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

82
        curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
83
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_getinfo() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

83
        $http_code = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
84
        if ($http_code !== 200) {
85
            file_put_contents($this->error_file, "Curl return code $http_code", FILE_APPEND);
86
        }
87
        curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

87
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
88
89
        return $http_code === 200;
90
    }
91
92
    /**
93
     * Remote File Size Using cURL
94
     *
95
     * @param string $url
96
     *
97
     * @return int
98
     */
99
    private function remoteFileSize(string $url): int
100
    {
101
        $ch       = curl_init($url);
102
        $fileSize = 0;
103
        if ($ch !== false) {
104
            curl_setopt($ch, CURLOPT_NOBODY, 1);
105
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
106
            curl_setopt($ch, CURLOPT_HEADER, 0);
107
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
108
            curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
109
            curl_exec($ch);
110
            $fileSize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
111
            curl_close($ch);
112
        }
113
114
        return $fileSize;
115
    }
116
117
    /**
118
     * Выполнение действия с загруженным файлом.
119
     */
120
    public function action(): void
121
    {
122
        if (empty($this->settings) || ! isset($this->settings['action'])) {
123
            return;
124
        }
125
        if ( ! file_exists($this->settings['res_file'])) {
126
            file_put_contents($this->error_file, 'File does not uploaded', FILE_APPEND);
127
128
            return;
129
        }
130
        if ( ! file_exists($this->settings['res_file']) || md5_file(
131
                $this->settings['res_file']
132
            ) !== $this->settings['md5']) {
133
            if (file_exists($this->settings['res_file'])) {
134
                unlink($this->settings['res_file']);
135
            }
136
            file_put_contents($this->error_file, 'Error check sum.', FILE_APPEND);
137
138
            return;
139
        }
140
        file_put_contents($this->progress_file, 100);
141
    }
142
143
    /**
144
     * Возвращаем memory_limit в исходную.
145
     */
146
    public function __destruct()
147
    {
148
        ini_set('memory_limit', $this->old_memory_limit);
149
    }
150
151
    /**
152
     * Обработка прогресса скачивания файла.
153
     *
154
     * @param $resource
155
     * @param $download_size
156
     * @param $downloaded
157
     */
158
    public function progress($resource, $download_size, $downloaded): void
159
    {
160
        if ($download_size === 0) {
161
            return;
162
        }
163
        if ($this->file_size < 0) {
164
            $new_progress = $downloaded / $download_size * 100;
165
        } else {
166
            $new_progress = $downloaded / $this->file_size * 100;
167
        }
168
        $delta = $new_progress - $this->progress;
169
        if ($delta > 1) {
170
            $this->progress = round($new_progress, 0);
171
            file_put_contents($this->progress_file, $this->progress);
172
        }
173
        if ($this->file_size === $downloaded) {
174
            file_put_contents($this->progress_file, 100);
175
        }
176
    }
177
178
}
179
180
// Start worker process
181
$workerClassname = WorkerDownloader::class;
182
if (isset($argv) && count($argv) > 1) {
183
    cli_set_process_title($workerClassname);
184
    try {
185
        $worker = new $workerClassname();
186
        $worker->start($argv);
187
    } catch (\Error $e) {
188
        global $errorLogger;
189
        $errorLogger->captureException($e);
190
        Util::sysLogMsg("{$workerClassname}_EXCEPTION", $e->getMessage());
191
    }
192
}