Passed
Push — develop ( 208565...e8eb5b )
by Портнов
05:11
created

WorkerDownloader::getHeaders()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 1
c 2
b 0
f 0
dl 0
loc 2
rs 10
cc 1
nc 1
nop 1
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright (C) 2017-2020 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\PBXCoreREST\Workers;
21
require_once 'Globals.php';
22
use MikoPBX\Core\Workers\WorkerBase;
23
use MikoPBX\Core\System\Util;
24
use GuzzleHttp;
25
use Psr\Http\Message\ResponseInterface;
26
27
class WorkerDownloader extends WorkerBase
28
{
29
    private string $old_memory_limit;
30
    private int $progress = 0;
31
    private array $settings;
32
    private string $progress_file = '';
33
    private string $error_file = '';
34
    private int $file_size = 0;
35
    private int $lastUpdate = 0;
36
    private int $httpCode = 0;
37
38
    /**
39
     * WorkerDownloader entry point.
40
     *
41
     * @param $params
42
     */
43
    public function start($params): void
44
    {
45
        $this->lastUpdate=time();
46
        $this->old_memory_limit = ini_get('memory_limit');
47
        $filename = $params[2]??'';
48
        if (file_exists($filename)) {
49
            $this->settings = json_decode(file_get_contents($filename), true);
50
        } else {
51
            Util::sysLogMsg(__CLASS__, 'Wrong download settings', LOG_ERR);
52
            return;
53
        }
54
        ini_set('memory_limit', '300M');
55
        $temp_dir            = dirname($this->settings['res_file']);
56
        $this->progress_file = $temp_dir . '/progress';
57
        $this->error_file    = $temp_dir . '/error';
58
59
        $result = $this->getFile();
60
        $result = $result && $this->checkFile();
61
        if ( ! $result) {
62
            Util::sysLogMsg(__CLASS__, 'Download error...', LOG_ERR);
63
        }
64
    }
65
66
    /**
67
     * Downloads file from remote resource by link
68
     */
69
    public function getFile(): bool
70
    {
71
        if (empty($this->settings)) {
72
            return false;
73
        }
74
        if (file_exists($this->settings['res_file'])) {
75
            unlink($this->settings['res_file']);
76
        }
77
78
        file_put_contents($this->progress_file, 0);
79
        $curl = new GuzzleHttp\Handler\CurlMultiHandler();
80
        $handler = GuzzleHttp\HandlerStack::create($curl);
81
        $client = new GuzzleHttp\Client();
82
        $promise = $client->getAsync($this->settings['url'], [
83
            'handler' => $handler,
84
            'sink'     => $this->settings['res_file'],
85
            'progress' =>  [$this, 'progress'],
86
            'connect_timeout' => 5,
87
            'on_headers' => [$this, 'getHeaders']
88
        ]);
89
        $promise->then(
90
            function (ResponseInterface $res) {
91
                $this->httpCode = $res->getStatusCode();
92
            },
93
            function (GuzzleHttp\Exception\RequestException $e) {
94
                file_put_contents($this->error_file, $e->getMessage(), FILE_APPEND);
95
                $this->httpCode = -1;
96
            }
97
        );
98
        while ($promise->getState() === 'pending'){
99
            $curl->tick();
100
            if(time() - $this->lastUpdate > 30){
101
                $this->httpCode = -1;
102
                $error = 'Fail download file... No progress for more than 30 seconds.';
103
                Util::sysLogMsg(__CLASS__, $error, LOG_ERR);
104
                file_put_contents($this->error_file, $error, FILE_APPEND);
105
                break;
106
            }
107
        }
108
        if ($this->httpCode !== 200) {
109
            file_put_contents($this->error_file, "Curl return code $this->httpCode. ", FILE_APPEND);
110
        }
111
        return $this->httpCode === 200;
112
    }
113
114
    /**
115
     * Получение заголовков ответа сервера.
116
     * @param ResponseInterface $response
117
     * @return void
118
     */
119
    public function getHeaders(ResponseInterface $response):void {
120
        $this->file_size = $response->getHeaderLine('Content-Length');
121
    }
122
123
    /**
124
     * Обработка сведений о прогрессе.
125
     * @param $downloadTotal
126
     * @param $downloadedBytes
127
     * @param $uploadTotal
128
     * @param $uploadedBytes
129
     * @return void
130
     */
131
    public function progress( $downloadTotal, $downloadedBytes, $uploadTotal, $uploadedBytes) :void
0 ignored issues
show
Unused Code introduced by
The parameter $uploadedBytes 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

131
    public function progress( $downloadTotal, $downloadedBytes, $uploadTotal, /** @scrutinizer ignore-unused */ $uploadedBytes) :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 $uploadTotal 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

131
    public function progress( $downloadTotal, $downloadedBytes, /** @scrutinizer ignore-unused */ $uploadTotal, $uploadedBytes) :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...
132
    {
133
        if ($downloadedBytes === 0) {
134
            return;
135
        }
136
        $this->lastUpdate = time();
137
        $new_progress = $downloadedBytes / $downloadTotal * 100;
138
        $delta = $new_progress - $this->progress;
139
        if ($delta > 1) {
140
            // Лимит на работу скрипта. Чтобы исключить "Зависание".
141
            // Если нет прогресса, то завершать работу.
142
            $this->progress = round($new_progress);
143
            $this->progress = min($this->progress, 99);
144
            file_put_contents($this->progress_file, $this->progress);
145
        }
146
    }
147
148
    /**
149
     * Checks file md5 sum and size
150
     */
151
    public function checkFile(): bool
152
    {
153
        $result = true;
154
        if ( ! file_exists($this->settings['res_file'])) {
155
            file_put_contents($this->error_file, 'File did not upload', FILE_APPEND);
156
            return false;
157
        }
158
        if (md5_file($this->settings['res_file']) !== $this->settings['md5']) {
159
            unlink($this->settings['res_file']);
160
            file_put_contents($this->error_file, 'Error on comparing MD5 sum', FILE_APPEND);
161
162
            $result = false;
163
        }elseif($this->file_size !== filesize($this->settings['res_file'])) {
164
            unlink($this->settings['res_file']);
165
            file_put_contents($this->error_file, 'Error on comparing file size', FILE_APPEND);
166
            $result = false;
167
        }
168
        file_put_contents($this->progress_file, 100);
169
        return $result;
170
    }
171
172
    /**
173
     * Returns memory_limit to default value.
174
     */
175
    public function __destruct()
176
    {
177
        parent::__destruct();
178
        ini_set('memory_limit', $this->old_memory_limit);
179
    }
180
}
181
182
// Start worker process
183
WorkerDownloader::startWorker($argv??null, false);
184