Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
31 / 31 |
|
100.00% |
4 / 4 |
CRAP | |
100.00% |
1 / 1 |
file_downloader | |
100.00% |
31 / 31 |
|
100.00% |
4 / 4 |
12 | |
100.00% |
1 / 1 |
create_client | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
get | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
7 | |||
get_error_string | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
get_error_number | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb; |
15 | |
16 | use GuzzleHttp\Client; |
17 | use GuzzleHttp\Exception\RequestException; |
18 | use phpbb\exception\runtime_exception; |
19 | |
20 | class file_downloader |
21 | { |
22 | const OK = 200; |
23 | const NOT_FOUND = 404; |
24 | const REQUEST_TIMEOUT = 408; |
25 | |
26 | /** @var string Error string */ |
27 | protected string $error_string = ''; |
28 | |
29 | /** @var int Error number */ |
30 | protected int $error_number = 0; |
31 | |
32 | /** |
33 | * Create new guzzle client |
34 | * |
35 | * @param string $host |
36 | * @param int $port |
37 | * @param int $timeout |
38 | * |
39 | * @return Client |
40 | */ |
41 | protected function create_client(string $host, int $port = 443, int $timeout = 6): Client |
42 | { |
43 | // Only set URL scheme if not specified in URL |
44 | $url_parts = parse_url($host); |
45 | if (!isset($url_parts['scheme'])) |
46 | { |
47 | $host = (($port === 443) ? 'https://' : 'http://') . $host; |
48 | } |
49 | |
50 | // Initialize Guzzle client |
51 | return new Client([ |
52 | 'base_uri' => $host, |
53 | 'timeout' => $timeout, |
54 | ]); |
55 | } |
56 | |
57 | /** |
58 | * Retrieve contents from remotely stored file |
59 | * |
60 | * @param string $host File host |
61 | * @param string $directory Directory file is in |
62 | * @param string $filename Filename of file to retrieve |
63 | * @param int $port Port to connect to; default: 443 |
64 | * @param int $timeout Connection timeout in seconds; default: 6 |
65 | * |
66 | * @return false|string File data as string if file can be read and there is no |
67 | * timeout, false if there were errors or the connection timed out |
68 | * |
69 | * @throws runtime_exception If data can't be retrieved and no error |
70 | * message is returned |
71 | */ |
72 | public function get(string $host, string $directory, string $filename, int $port = 443, int $timeout = 6): bool|string |
73 | { |
74 | // Initialize Guzzle client |
75 | $client = $this->create_client($host, $port, $timeout); |
76 | |
77 | // Set default values for error variables |
78 | $this->error_number = 0; |
79 | $this->error_string = ''; |
80 | |
81 | try |
82 | { |
83 | $response = $client->request('GET', "$directory/$filename"); |
84 | |
85 | // Check if the response status code is 200 (OK) |
86 | if ($response->getStatusCode() == self::OK) |
87 | { |
88 | return $response->getBody()->getContents(); |
89 | } |
90 | else |
91 | { |
92 | $this->error_number = $response->getStatusCode(); |
93 | throw new runtime_exception('FILE_NOT_FOUND', [$filename]); |
94 | } |
95 | } |
96 | catch (RequestException $exception) |
97 | { |
98 | if ($exception->hasResponse()) |
99 | { |
100 | $this->error_number = $exception->getResponse()->getStatusCode(); |
101 | |
102 | if ($this->error_number == self::NOT_FOUND) |
103 | { |
104 | throw new runtime_exception('FILE_NOT_FOUND', [$filename]); |
105 | } |
106 | } |
107 | else |
108 | { |
109 | $this->error_number = self::REQUEST_TIMEOUT; |
110 | throw new runtime_exception('FSOCK_TIMEOUT'); |
111 | } |
112 | |
113 | $this->error_string = utf8_convert_message($exception->getMessage()); |
114 | return false; |
115 | } |
116 | catch (runtime_exception $exception) |
117 | { |
118 | // Rethrow runtime_exceptions, only handle unknown cases below |
119 | throw $exception; |
120 | } |
121 | catch (\Throwable $exception) |
122 | { |
123 | $this->error_string = utf8_convert_message($exception->getMessage()); |
124 | throw new runtime_exception('FSOCK_DISABLED'); |
125 | } |
126 | } |
127 | |
128 | /** |
129 | * Get error string |
130 | * |
131 | * @return string Error string |
132 | */ |
133 | public function get_error_string(): string |
134 | { |
135 | return $this->error_string; |
136 | } |
137 | |
138 | /** |
139 | * Get error number |
140 | * |
141 | * @return int Error number |
142 | */ |
143 | public function get_error_number(): int |
144 | { |
145 | return $this->error_number; |
146 | } |
147 | } |