FilesystemStorage::truncate()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
namespace LaraGeoData\Storage;
4
5
use Exception;
6
use Illuminate\Filesystem\Filesystem;
7
use Illuminate\Support\Str;
8
use Symfony\Component\Process\Process;
9
use ZipArchive;
10
11
/**
12
 * Stores collected data into files
13
 */
14
class FilesystemStorage
15
{
16
17
    /**
18
     * Provider.
19
     *
20
     * @var Filesystem
21
     */
22
    protected Filesystem $files;
23
24
    /**
25
     * Directory name.
26
     *
27
     * @var string
28
     */
29
    protected string $dirname;
30
31
    /**
32
     * @param Filesystem $files
33
     * @param string $dirname
34
     */
35 20
    public function __construct(Filesystem $files, string $dirname)
36
    {
37 20
        $this->files   = $files;
38 20
        $this->dirname = rtrim($dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
39 20
    }
40
41
    /**
42
     * Create directory if not exists.
43
     *
44
     * @throws Exception
45
     */
46 13
    public function prepareDirectory(): void
47
    {
48 13
        if (!$this->files->isDirectory($this->dirname)) {
49 9
            if ($this->files->makeDirectory($this->dirname, 0777, true)) {
50 8
                $this->files->put($this->dirname . '.gitignore', "*\n!.gitignore\n");
51
            } else {
52
                throw new Exception("Cannot create directory '$this->dirname'.");
53
            }
54
        }
55 12
    }
56
57
    /**
58
     * Clear all stored files.
59
     *
60
     * @return bool
61
     * @throws Exception
62
     */
63 6
    public function truncate(): bool
64
    {
65 6
        $result = $this->files->deleteDirectory($this->dirname);
66 6
        $this->prepareDirectory();
67
68 6
        return $result;
69
    }
70
71
    /**
72
     * CheckIf File exists.
73
     *
74
     * @param string $filePath
75
     *
76
     * @return bool
77
     */
78 10
    public function exists(string $filePath): bool
79
    {
80 10
        return $this->files->exists($this->path($filePath));
81
    }
82
83
    /**
84
     * Get absolute file path.
85
     *
86
     * @param string $filePath
87
     *
88
     * @return string
89
     */
90 16
    public function path(string $filePath = ''): string
91
    {
92 16
        return $this->dirname . ltrim($filePath, DIRECTORY_SEPARATOR);
93
    }
94
95
    /**
96
     * Delete file.
97
     *
98
     * @param string $filePath
99
     *
100
     * @return bool
101
     */
102 1
    public function delete(string $filePath): bool
103
    {
104 1
        return $this->files->delete($this->path($filePath));
105
    }
106
107
    /**
108
     * Get valid file path.
109
     *
110
     * @param string|null $filePath
111
     * @param string $url
112
     *
113
     * @return string
114
     */
115 10
    protected function validFilePathFromUrl(?string $filePath,  string $url): string
116
    {
117 10
        if (!$filePath) {
118 2
            $filePath = Str::afterLast($url, DIRECTORY_SEPARATOR);
119
        }
120
121 10
        return (string) $filePath;
122
    }
123
124
    /**
125
     * @param string $url
126
     * @param string|null $filePath
127
     * @param \Closure|null $progressCallback
128
     * @param bool $force
129
     *
130
     * @return bool
131
     * @throws Exception
132
     */
133 10
    public function createFromUrl(string $url, ?string $filePath = null, ?\Closure $progressCallback = null, bool $force = false): bool
134
    {
135 10
        $this->prepareDirectory();
136
137 10
        $filePath = $this->validFilePathFromUrl($filePath, $url);
138
139 10
        if (($exists = $this->exists($filePath)) && !$force) {
140 2
            return false;
141
        }
142
143 9
        if ($exists) {
144 1
            $this->delete($filePath);
145
        }
146
147 9
        $path = $this->path($filePath);
148
149 9
        $this->files->ensureDirectoryExists(Str::beforeLast($path, DIRECTORY_SEPARATOR), 0777, true);
150
151 9
        return match (config('geonames.storage.download_provider')) {
152 1
            'curl_php' => $this->downloadViaCurlPhp($url, $path, $progressCallback),
153 7
            'wget'     => $this->downloadViaWget($url, $path),
154 9
            default    => throw new Exception('Current download provider not supported'),
155
        };
156
    }
157
158
    /**
159
     * Extract zip file.
160
     *
161
     * @param string $file
162
     *
163
     * @return bool
164
     * @throws Exception
165
     */
166 6
    public function extractZipFile(string $file): bool
167
    {
168 6
        $zipArchive = new ZipArchive();
169 6
        $filePath   = $this->path($file);
170 6
        if (true === ($openResult = $zipArchive->open($filePath, ZipArchive::RDONLY))) {
171 5
            $extractTo     = Str::beforeLast($filePath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
172 5
            $extractResult = $zipArchive->extractTo($extractTo);
173 5
            $zipArchive->close();
174 5
            if ($extractResult === true) {
175 5
                return true;
176
            }
177
        }
178
179 1
        if (is_numeric($openResult)) {
180 1
            throw new Exception("Zip open [{$filePath}] error: {$openResult}. See: https://php.net/manual/en/zip.constants.php");
181
        }
182
183
        return false;
184
    }
185
186
    /**
187
     * Download File using wget util.
188
     *
189
     * @param string $url
190
     * @param string $path
191
     *
192
     * @return bool
193
     */
194 7
    protected function downloadViaWget(string $url, string $path): bool
195
    {
196 7
        $process = new Process([
197 7
            'wget',
198
            //'-c',
199 7
            '-N',
200 7
            '-O',
201 7
            $path,
202 7
            $url,
203
        ]);
204 7
        $process->run();
205
206 7
        return $process->isSuccessful();
207
    }
208
209
    /**
210
     * Download File using wget util.
211
     *
212
     * @param string $url
213
     * @param string $path
214
     *
215
     * @return bool
216
     * @throws Exception
217
     */
218 1
    protected function downloadViaCurlPhp(string $url, string $path, ?\Closure $progressCallback = null): bool
219
    {
220 1
        $fp = fopen($path, 'w');
221 1
        $ch = curl_init($url);
222 1
        if ($progressCallback) {
223 1
            curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, $progressCallback);
224 1
            curl_setopt($ch, CURLOPT_NOPROGRESS, false);
225
        }
226 1
        curl_setopt($ch, CURLOPT_FILE, $fp);
227
228 1
        $result = curl_exec($ch);
229
230 1
        if ($errorNumber = curl_errno($ch)) {
231 1
            throw new Exception("Error [{$errorNumber}]. See https://php.net/manual/en/function.curl-errno.php");
232
        }
233
234 1
        curl_close($ch);
235 1
        fclose($fp);
236
237 1
        return (bool) $result;
238
    }
239
}
240