Uploader   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 130
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 11
eloc 40
c 4
b 0
f 0
dl 0
loc 130
ccs 44
cts 44
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A getHttpClient() 0 3 1
A findBinFile() 0 10 3
A update() 0 4 1
A uploadUrl() 0 27 2
A extractBinFile() 0 12 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace slavkluev\Ip2Location;
6
7
use GuzzleHttp\Client;
8
use GuzzleHttp\Exception\GuzzleException;
9
use GuzzleHttp\RequestOptions;
10
use ZipArchive;
11
12
class Uploader
13
{
14
    const BASE_URI = 'https://www.ip2location.com/download/';
15
16
    /**
17
     * Stores the HTTP Client.
18
     * @var Client
19
     */
20
    private $httpClient;
21
22
    /**
23
     * Uploader constructor.
24
     * @param Client|null $client
25
     */
26 24
    public function __construct(?Client $client = null)
27
    {
28 24
        if ($client) {
29 24
            $this->httpClient = $client;
30
        } else {
31 3
            $this->httpClient = new Client([
32 3
                'base_uri' => self::BASE_URI,
33
            ]);
34
        }
35 24
    }
36
37
    /**
38
     * @return Client
39
     */
40 3
    public function getHttpClient(): Client
41
    {
42 3
        return $this->httpClient;
43
    }
44
45
    /**
46
     * Updates the database.
47
     *
48
     * @param string $token
49
     * @param string $code
50
     * @param string $filePath
51
     *
52
     * @throws GuzzleException
53
     * @throws \Exception
54
     */
55 21
    public function update(string $token, string $code, string $filePath)
56
    {
57 21
        $tmpFile = $this->uploadUrl($token, $code);
58 15
        $this->extractBinFile((string)$tmpFile, $filePath);
59 6
    }
60
61
    /**
62
     * Extracts bin file from the zip archive to filepath.
63
     *
64
     * @param string $filename
65
     * @param string $filepath
66
     *
67
     * @throws \Exception
68
     */
69 15
    protected function extractBinFile(string $filename, string $filepath)
70
    {
71 15
        $zip = new ZipArchive();
72 15
        $zip->open($filename);
73 15
        $binFilename = $this->findBinFile($zip);
74 12
        $file = $zip->getFromName($binFilename);
75
76 12
        if (false === @file_put_contents($filepath, $file)) {
77 6
            throw new \Exception('Failure while storing: ' . error_get_last()['message']);
78
        }
79
80 6
        $zip->close();
81 6
    }
82
83
    /**
84
     * Finds bin file in the zip archive.
85
     *
86
     * @param ZipArchive $archive
87
     *
88
     * @return string
89
     *
90
     * @throws \Exception
91
     */
92 15
    protected function findBinFile(ZipArchive $archive): string
93
    {
94 15
        for ($i = 0; $i < $archive->numFiles; $i++) {
95 15
            $filename = $archive->getNameIndex($i);
96 15
            if (substr(strtolower($filename), -4, 4) == '.bin') {
97 12
                return $filename;
98
            }
99
        }
100
101 3
        throw new \Exception("bin file has not found");
102
    }
103
104
    /**
105
     * Uploads IP2Location database.
106
     *
107
     * @param string $token
108
     * @param string $code
109
     *
110
     * @return TmpFile
111
     *
112
     * @throws \GuzzleHttp\Exception\GuzzleException
113
     * @throws \Exception
114
     */
115 21
    protected function uploadUrl(string $token, string $code): TmpFile
116
    {
117 21
        $tmpFile = new TmpFile();
118 21
        $resource = fopen((string)$tmpFile, 'w+');
119 21
        $response = $this->httpClient->request(
120 21
            'GET',
121 21
            '',
122
            [
123
                'query' => [
124 21
                    'token' => $token,
125 21
                    'file' => $code,
126
                ],
127 21
                RequestOptions::SINK => $resource,
128
            ]
129
        );
130 21
        $contentType = $response->getHeaderLine('Content-Type');
131
132 21
        if ($contentType !== 'application/zip') {
133 6
            $response->getBody()->seek(0);
134 6
            $message = $response->getBody()->read(1024);
135 6
            throw new \Exception('Failure while uploading: ' . $message);
136
        }
137
138 15
        $response->getBody()->detach();
139 15
        fclose($resource);
0 ignored issues
show
Bug introduced by
It seems like $resource 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

139
        fclose(/** @scrutinizer ignore-type */ $resource);
Loading history...
140
141 15
        return $tmpFile;
142
    }
143
}
144