Passed
Push — develop ( bbba6b...68db6a )
by Nikolay
05:49 queued 11s
created

WorkerDownloader::start()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 21
rs 9.7333
c 0
b 0
f 0
cc 3
nc 3
nop 1
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\Core\Workers;
10
11
require_once 'Globals.php';
12
13
use MikoPBX\Core\Workers\Cron\WorkerSafeScriptsCore;
14
use MikoPBX\Core\System\{MikoPBXConfig, 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
            echo 'Download error... Settings file does not exist';
38
            return;
39
        }
40
        $this->old_memory_limit = ini_get('memory_limit');
41
        register_shutdown_function([$this, 'shutdownHandler']);
42
        ini_set('memory_limit', '300M');
43
44
        $temp_dir             = dirname($this->settings['res_file']);
45
        $this->progress_file  = $temp_dir . '/progress';
46
        $this->error_file     = $temp_dir . '/error';
47
        Util::mwMkdir($temp_dir);
48
49
        if ($this->getFile()) {
50
            $this->action();
51
        } else {
52
            echo 'Download error... ';
53
        }
54
    }
55
56
    /**
57
     * Скачивание файла с удаленного ресурса.
58
     */
59
    public function getFile(): bool
60
    {
61
        if (empty($this->settings)) {
62
            return false;
63
        }
64
        if (file_exists($this->settings['res_file'])) {
65
            unlink($this->settings['res_file']);
66
        }
67
        $this->file_size = $this->remoteFileSize($this->settings['url']);
68
69
        file_put_contents($this->progress_file, 0);
70
71
        $fp = fopen($this->settings['res_file'], 'w');
72
        $ch = curl_init();
73
74
        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

74
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_FILE, $fp);
Loading history...
75
        curl_setopt($ch, CURLOPT_URL, $this->settings['url']);
76
        curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, [$this, 'progress']);
77
        curl_setopt($ch, CURLOPT_NOPROGRESS, false); // needed to make progress function work
78
        curl_setopt($ch, CURLOPT_HEADER, 0);
79
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
80
81
        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

81
        curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
82
        $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

82
        $http_code = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
83
        if ($http_code !== 200) {
84
            file_put_contents($this->error_file, "Curl return code $http_code", FILE_APPEND);
85
        }
86
        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

86
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
87
88
        return $http_code === 200;
89
    }
90
91
    /**
92
     * Remote File Size Using cURL
93
     *
94
     * @param string $url
95
     *
96
     * @return int || void
0 ignored issues
show
Documentation Bug introduced by
The doc comment int || void at position 2 could not be parsed: Unknown type name '|' at position 2 in int || void.
Loading history...
97
     */
98
    private function remoteFileSize($url): int
99
    {
100
        $ch       = curl_init($url);
101
        $fileSize = 0;
102
        if ($ch !== false) {
103
            curl_setopt($ch, CURLOPT_NOBODY, 1);
104
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
105
            curl_setopt($ch, CURLOPT_HEADER, 0);
106
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
107
            curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
108
            curl_exec($ch);
109
            $fileSize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
110
            curl_close($ch);
111
        }
112
113
        return $fileSize;
114
    }
115
116
    /**
117
     * Выполнение действия с загруженным файлом.
118
     */
119
    public function action(): void
120
    {
121
        if (empty($this->settings) || ! isset($this->settings['action'])) {
122
            return;
123
        }
124
        if ( ! file_exists($this->settings['res_file'])) {
125
            file_put_contents($this->error_file, 'File does not uploaded', FILE_APPEND);
126
127
            return;
128
        }
129
        if ( ! file_exists($this->settings['res_file']) || md5_file(
130
                $this->settings['res_file']
131
            ) !== $this->settings['md5']) {
132
            if (file_exists($this->settings['res_file'])) {
133
                unlink($this->settings['res_file']);
134
            }
135
            file_put_contents($this->error_file, 'Error check sum.', FILE_APPEND);
136
137
            return;
138
        }
139
        file_put_contents($this->progress_file, 100);
140
    }
141
142
    /**
143
     * Возвращаем memory_limit в исходную.
144
     */
145
    public function __destruct()
146
    {
147
        ini_set('memory_limit', $this->old_memory_limit);
148
    }
149
150
    /**
151
     * Обработка фатальных ошибок скрипта.
152
     */
153
    public function shutdownHandler(): void
154
    {
155
        if (@is_array($e = @error_get_last())) {
156
            if (file_exists($this->error_file)) {
157
                file_put_contents(
158
                    $this->error_file,
159
                    json_encode(error_get_last(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
160
                );
161
            } else {
162
                Util::sysLogMsg('FileWorkerDownloader', json_encode(error_get_last()));
163
            }
164
        }
165
    }
166
167
    /**
168
     * Обработка прогресса скачивания файла.
169
     *
170
     * @param $resource
171
     * @param $download_size
172
     * @param $downloaded
173
     * @param $upload_size
174
     * @param $uploaded
175
     */
176
    public function progress($resource, $download_size, $downloaded, $upload_size, $uploaded): void
0 ignored issues
show
Unused Code introduced by
The parameter $uploaded is not used and could be removed. ( Ignorable by Annotation )

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

176
    public function progress($resource, $download_size, $downloaded, $upload_size, /** @scrutinizer ignore-unused */ $uploaded): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $upload_size is not used and could be removed. ( Ignorable by Annotation )

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

176
    public function progress($resource, $download_size, $downloaded, /** @scrutinizer ignore-unused */ $upload_size, $uploaded): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
177
    {
178
        if ($download_size === 0) {
179
            return;
180
        }
181
        if ($this->file_size < 0) {
182
            $new_progress = $downloaded / $download_size * 100;
183
        } else {
184
            $new_progress = $downloaded / $this->file_size * 100;
185
        }
186
        $delta = $new_progress - $this->progress;
187
        if ($delta > 1) {
188
            $this->progress = round($new_progress, 0);
189
            file_put_contents($this->progress_file, $this->progress);
190
        }
191
        if ($this->file_size === $downloaded) {
192
            file_put_contents($this->progress_file, 100);
193
        }
194
    }
195
196
}
197
198
// Start worker process
199
$workerClassname = WorkerDownloader::class;
200
if (isset($argv) && count($argv) > 1) {
201
    cli_set_process_title($workerClassname);
202
    try {
203
        $worker = new $workerClassname();
204
        $worker->start($argv);
205
    } catch (\Exception $e) {
206
        global $errorLogger;
207
        $errorLogger->captureException($e);
208
        Util::sysLogMsg("{$workerClassname}_EXCEPTION", $e->getMessage());
209
    }
210
}
211
212
// php -dxdebug.remote_autostart=On -f {$workersPath}/WorkerDownloader.php /storage/usbdisk1/mikopbx/tmp/ModuleCTIClient/download_settings.json