Completed
Push — master ( 69dd33...0cd5d9 )
by Pierre
01:46
created

Downloader   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 17
eloc 62
dl 0
loc 171
rs 10
c 1
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getProgress() 0 3 1
A downloadProgress() 0 7 3
A download() 0 11 3
A contentsDownload() 0 14 3
A displayProgress() 0 4 1
A setAdapter() 0 7 2
A curlDownload() 0 30 3
1
<?php
2
3
namespace PierInfor\GeoLite;
4
5
/**
6
 * Downloader class let download files
7
 */
8
class Downloader implements Interfaces\DownloaderInterface
9
{
10
11
    /**
12
     * factory adapter
13
     *
14
     * @var String
15
     */
16
    private $adapter;
17
18
    /**
19
     * Download progress percent
20
     *
21
     * @var Integer
22
     */
23
    private $progress;
24
25
    /**
26
     * Download progress percent
27
     *
28
     * @var Boolean
29
     */
30
    private $showProgress;
31
32
    /**
33
     * Instanciate
34
     */
35
    public function __construct()
36
    {
37
        $this->showProgress = false;
38
        $this->setAdapter();
39
    }
40
41
    /**
42
     * set adapter for download factory
43
     *
44
     * @param string $adapter
45
     * @return Downloader
46
     */
47
    public function setAdapter(string $adapter = self::ADAPTER_CURL): Downloader
48
    {
49
        if (!in_array($adapter, self::ADAPTERS)) {
50
            throw new \Exception('Downloader - bad adapter');
51
        }
52
        $this->adapter = $adapter;
53
        return $this;
54
    }
55
56
    /**
57
     * download factory
58
     *
59
     * @param string $url
60
     * @param string $toFilename
61
     * @return Downloader
62
     */
63
    public function download(string $url, string $toFilename): Downloader
64
    {
65
        switch ($this->adapter) {
66
            case self::ADAPTER_CONTENTS:
67
                $this->contentsDownload($url, $toFilename);
68
                break;
69
            case self::ADAPTER_CURL:
70
                $this->curlDownload($url, $toFilename);
71
                break;
72
        }
73
        return $this;
74
    }
75
76
    /**
77
     * download a file using file_get_content
78
     *
79
     * @param string $url
80
     * @param string $toFilename
81
     * @return Downloader
82
     */
83
    public function contentsDownload(string $url, string $toFilename): Downloader
84
    {
85
        $headers = get_headers($url);
86
        $statusCode = 0;
87
        if (isset($headers[0])) {
88
            $header = $headers[0];
89
            preg_match("/^HTTP.+\s(\d\d\d)\s/", $header, $m);
90
            $statusCode = $m[1];
91
        }
92
        if ($statusCode != 200) {
93
            throw new \Exception('Bad http code : ' . $statusCode);
94
        }
95
        file_put_contents($toFilename, file_get_contents($url));
96
        return $this;
97
    }
98
99
    /**
100
     * enable progress output when using curlDownload
101
     *
102
     * @param boolean $show
103
     * @return Downloader
104
     */
105
    public function displayProgress(bool $show = false): Downloader
106
    {
107
        $this->showProgress = $show;
108
        return $this;
109
    }
110
111
    /**
112
     * download a file using curl
113
     *
114
     * @param string $url
115
     * @param string $toFilename
116
     * @return Downloader
117
     */
118
    public function curlDownload(string $url, string $toFilename): Downloader
119
    {
120
        touch($toFilename, 0777);
121
        $fp = fopen($toFilename, 'wba+');
122
        $ch = curl_init();
123
        curl_setopt($ch, CURLOPT_VERBOSE, false);
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

123
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_VERBOSE, false);
Loading history...
124
        curl_setopt($ch, CURLOPT_URL, $url);
125
        curl_setopt($ch, CURLOPT_POST, 0);
126
        curl_setopt($ch, CURLOPT_TIMEOUT, 300);
127
        curl_setopt($ch, CURLOPT_HEADER, false);
128
        curl_setopt($ch, CURLOPT_USERAGENT, self::USER_AGENT);
129
        curl_setopt($ch, CURLOPT_BUFFERSIZE, self::BUFFER_SIZE);
130
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
131
        curl_setopt($ch, CURLOPT_FILE, $fp);
132
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
133
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
134
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
135
        curl_setopt($ch, CURLOPT_NOPROGRESS, false);
136
        curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, [$this, self::DOWNLOAD_CALLBACK]);
137
        curl_setopt($ch, CURLOPT_AUTOREFERER, true);
138
        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

138
        curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
139
        if (!curl_errno($ch)) {
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_errno() 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

139
        if (!curl_errno(/** @scrutinizer ignore-type */ $ch)) {
Loading history...
140
            $statusCode = 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

140
            $statusCode = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
141
            if ($statusCode != 200) {
142
                throw new \Exception('Bad http code : ' . $statusCode);
143
            }
144
        }
145
        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

145
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
146
        fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() 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

146
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
147
        return $this;
148
    }
149
150
    /**
151
     * download progress callback
152
     *
153
     * @param mixed $resource
154
     * @param integer $download_size
155
     * @param integer $downloaded
156
     * @param integer $upload_size
157
     * @param integer $uploaded
158
     * @return void
159
     */
160
    protected function downloadProgress($resource, int $download_size, int $downloaded, int $upload_size, int $uploaded)
161
    {
162
        if ($download_size > 0) {
163
            $this->progress = ($downloaded / $download_size) * 100;
164
            if ($this->showProgress === true) {
165
                echo self::WHEELS[$this->progress % 4]
166
                    . ' ' . $this->getProgress() . "%\r";
167
            }
168
        }
169
    }
170
171
    /**
172
     * returns progress value
173
     *
174
     * @return integer
175
     */
176
    protected function getProgress(): int
177
    {
178
        return $this->progress;
179
    }
180
}
181