1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Joomla! Statistics Server |
4
|
|
|
* |
5
|
|
|
* @copyright Copyright (C) 2013 - 2017 Open Source Matters, Inc. All rights reserved. |
6
|
|
|
* @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License Version 2 or Later |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Joomla\StatsServer\Controllers; |
10
|
|
|
|
11
|
|
|
use Joomla\Controller\AbstractController; |
12
|
|
|
use Joomla\StatsServer\Decorators\ValidateVersion; |
13
|
|
|
use Joomla\StatsServer\Models\StatsModel; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Controller for processing submitted statistics data. |
17
|
|
|
* |
18
|
|
|
* @method \Joomla\StatsServer\WebApplication getApplication() Get the application object. |
19
|
|
|
* @property-read \Joomla\StatsServer\WebApplication $app Application object |
20
|
|
|
* |
21
|
|
|
* @since 1.0 |
22
|
|
|
*/ |
23
|
|
|
class SubmitControllerCreate extends AbstractController |
24
|
|
|
{ |
25
|
|
|
use ValidateVersion; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Statistics model object. |
29
|
|
|
* |
30
|
|
|
* @var StatsModel |
31
|
|
|
* @since 1.0 |
32
|
|
|
*/ |
33
|
|
|
private $model; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Allowed Database Types. |
37
|
|
|
* |
38
|
|
|
* @var array |
39
|
|
|
* @since 1.0 |
40
|
|
|
*/ |
41
|
|
|
private $databaseTypes = [ |
42
|
|
|
'mysql', |
43
|
|
|
'mysqli', |
44
|
|
|
'pgsql', |
45
|
|
|
'pdomysql', |
46
|
|
|
'postgresql', |
47
|
|
|
'sqlazure', |
48
|
|
|
'sqlsrv', |
49
|
|
|
]; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Constructor. |
53
|
|
|
* |
54
|
|
|
* @param StatsModel $model Statistics model object. |
55
|
|
|
* |
56
|
|
|
* @since 1.0 |
57
|
|
|
*/ |
58
|
1 |
|
public function __construct(StatsModel $model) |
59
|
|
|
{ |
60
|
1 |
|
$this->model = $model; |
61
|
1 |
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Execute the controller. |
65
|
|
|
* |
66
|
|
|
* @return boolean |
67
|
|
|
* |
68
|
|
|
* @since 1.0 |
69
|
|
|
*/ |
70
|
4 |
|
public function execute() |
71
|
|
|
{ |
72
|
4 |
|
$input = $this->getInput(); |
73
|
|
|
|
74
|
|
|
$data = [ |
75
|
4 |
|
'php_version' => $input->getRaw('php_version', ''), |
76
|
4 |
|
'db_version' => $input->getRaw('db_version', ''), |
77
|
4 |
|
'cms_version' => $input->getRaw('cms_version', ''), |
78
|
4 |
|
'unique_id' => $input->getString('unique_id'), |
79
|
4 |
|
'db_type' => $input->getString('db_type', ''), |
80
|
4 |
|
'server_os' => $input->getString('server_os'), |
81
|
|
|
]; |
82
|
|
|
|
83
|
|
|
// Backup the original POST before manipulating/validating data |
84
|
4 |
|
$originalData = $data; |
85
|
|
|
|
86
|
|
|
// Validate the submitted data |
87
|
4 |
|
$data['php_version'] = $this->checkPHPVersion($data['php_version']); |
88
|
4 |
|
$data['cms_version'] = $this->checkCMSVersion($data['cms_version']); |
89
|
4 |
|
$data['db_type'] = $this->checkDatabaseType($data['db_type']); |
90
|
4 |
|
$data['db_version'] = $this->validateVersionNumber($data['db_version']); |
91
|
|
|
|
92
|
|
|
// We require at a minimum a unique ID and the CMS version |
93
|
4 |
|
if (empty($data['unique_id']) || empty($data['cms_version'])) |
94
|
|
|
{ |
95
|
2 |
|
$this->getApplication()->getLogger()->info( |
96
|
2 |
|
'Missing required data from request.', |
97
|
2 |
|
['postData' => $originalData] |
98
|
|
|
); |
99
|
|
|
|
100
|
|
|
$response = [ |
101
|
2 |
|
'error' => true, |
102
|
|
|
'message' => 'There was an error storing the data.', |
103
|
|
|
]; |
104
|
|
|
|
105
|
2 |
|
$this->getApplication()->setHeader('HTTP/1.1 500 Internal Server Error', 500, true); |
106
|
2 |
|
$this->getApplication()->setBody(json_encode($response)); |
107
|
|
|
|
108
|
2 |
|
return true; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
// If the below data does not pass tests, we do not accept the POST |
112
|
2 |
|
if ($data['php_version'] === false || $data['cms_version'] === false || $data['db_type'] === false || $data['db_version'] === false) |
113
|
|
|
{ |
114
|
|
|
$response = [ |
115
|
|
|
'error' => true, |
116
|
|
|
'message' => 'Invalid data submission.', |
117
|
|
|
]; |
118
|
|
|
|
119
|
|
|
$this->getApplication()->setHeader('HTTP/1.1 500 Internal Server Error', 500, true); |
120
|
|
|
$this->getApplication()->setBody(json_encode($response)); |
121
|
|
|
|
122
|
|
|
return true; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
// Account for configuration differences with 4.0 |
126
|
2 |
|
if (version_compare($data['cms_version'], '4.0', 'ge')) |
127
|
|
|
{ |
128
|
|
|
// For 4.0 and later, we map `mysql` to the `pdomysql` option to correctly track the database type |
129
|
1 |
|
if ($data['db_type'] === 'mysql') |
130
|
|
|
{ |
131
|
1 |
|
$data['db_type'] = 'pdomysql'; |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
|
135
|
2 |
|
$this->model->save((object) $data); |
136
|
|
|
|
137
|
|
|
$response = [ |
138
|
2 |
|
'error' => false, |
139
|
|
|
'message' => 'Data saved successfully', |
140
|
|
|
]; |
141
|
|
|
|
142
|
2 |
|
$this->getApplication()->setBody(json_encode($response)); |
143
|
|
|
|
144
|
2 |
|
return true; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Check the CMS version. |
149
|
|
|
* |
150
|
|
|
* @param string $version The version number to check. |
151
|
|
|
* |
152
|
|
|
* @return string|boolean The version number on success or boolean false on failure. |
153
|
|
|
* |
154
|
|
|
* @since 1.0 |
155
|
|
|
*/ |
156
|
4 |
View Code Duplication |
private function checkCMSVersion(string $version) |
|
|
|
|
157
|
|
|
{ |
158
|
4 |
|
$version = $this->validateVersionNumber($version); |
159
|
|
|
|
160
|
|
|
// If the version number is invalid, don't go any further |
161
|
4 |
|
if ($version === false) |
162
|
|
|
{ |
163
|
1 |
|
return false; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
// Joomla only uses major.minor.patch so everything else is invalid |
167
|
3 |
|
$explodedVersion = explode('.', $version); |
168
|
|
|
|
169
|
3 |
|
if (count($explodedVersion) > 3) |
170
|
|
|
{ |
171
|
1 |
|
return false; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
// Import the valid release listing |
175
|
2 |
|
$path = APPROOT . '/versions/joomla.json'; |
176
|
|
|
|
177
|
2 |
|
if (!file_exists($path)) |
178
|
|
|
{ |
179
|
|
|
throw new \RuntimeException('Missing Joomla! release listing', 500); |
180
|
|
|
} |
181
|
|
|
|
182
|
2 |
|
$validVersions = json_decode(file_get_contents($path), true); |
183
|
|
|
|
184
|
|
|
// Check that the version is in our valid release list |
185
|
2 |
|
if (!in_array($version, $validVersions)) |
186
|
|
|
{ |
187
|
|
|
return false; |
188
|
|
|
} |
189
|
|
|
|
190
|
2 |
|
return $version; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Check the database type |
195
|
|
|
* |
196
|
|
|
* @param string $database The database type to check. |
197
|
|
|
* |
198
|
|
|
* @return string|boolean The database type on success or boolean false on failure. |
199
|
|
|
* |
200
|
|
|
* @since 1.0 |
201
|
|
|
*/ |
202
|
4 |
|
private function checkDatabaseType(string $database) |
203
|
|
|
{ |
204
|
4 |
|
if (!in_array($database, $this->databaseTypes)) |
205
|
|
|
{ |
206
|
|
|
return false; |
207
|
|
|
} |
208
|
|
|
|
209
|
4 |
|
return $database; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Check the PHP version |
214
|
|
|
* |
215
|
|
|
* @param string $version The version number to check. |
216
|
|
|
* |
217
|
|
|
* @return string|boolean The version number on success or boolean false on failure. |
218
|
|
|
* |
219
|
|
|
* @since 1.0 |
220
|
|
|
*/ |
221
|
4 |
View Code Duplication |
private function checkPHPVersion(string $version) |
|
|
|
|
222
|
|
|
{ |
223
|
4 |
|
$version = $this->validateVersionNumber($version); |
224
|
|
|
|
225
|
|
|
// If the version number is invalid, don't go any further |
226
|
4 |
|
if ($version === false) |
227
|
|
|
{ |
228
|
|
|
return false; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
// We only track versions based on major.minor.patch so everything else is invalid |
232
|
4 |
|
$explodedVersion = explode('.', $version); |
233
|
|
|
|
234
|
4 |
|
if (count($explodedVersion) > 3) |
235
|
|
|
{ |
236
|
|
|
return false; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
// Import the valid release listing |
240
|
4 |
|
$path = APPROOT . '/versions/php.json'; |
241
|
|
|
|
242
|
4 |
|
if (!file_exists($path)) |
243
|
|
|
{ |
244
|
|
|
throw new \RuntimeException('Missing PHP release listing', 500); |
245
|
|
|
} |
246
|
|
|
|
247
|
4 |
|
$validVersions = json_decode(file_get_contents($path), true); |
248
|
|
|
|
249
|
|
|
// Check that the version is in our valid release list |
250
|
4 |
|
if (!in_array($version, $validVersions)) |
251
|
|
|
{ |
252
|
|
|
return false; |
253
|
|
|
} |
254
|
|
|
|
255
|
4 |
|
return $version; |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.