Completed
Push — master ( 2df1ff...31a2b9 )
by Michael
04:54
created

SubmitDataController::checkPHPVersion()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 35

Duplication

Lines 35
Ratio 100 %

Code Coverage

Tests 8
CRAP Score 6.4222

Importance

Changes 0
Metric Value
dl 35
loc 35
ccs 8
cts 13
cp 0.6153
rs 9.0488
c 0
b 0
f 0
cc 5
nc 5
nop 1
crap 6.4222
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\Repositories\StatisticsRepository;
14
use League\Flysystem\FileNotFoundException;
15
use League\Flysystem\Filesystem;
16
use Zend\Diactoros\Response\JsonResponse;
17
18
/**
19
 * Controller for processing submitted statistics data.
20
 *
21
 * @method         \Joomla\Application\WebApplication  getApplication()  Get the application object.
22
 * @property-read  \Joomla\Application\WebApplication  $app              Application object
23
 */
24
class SubmitDataController extends AbstractController
25
{
26
	use ValidateVersion;
27
28
	/**
29
	 * Statistics repository.
30
	 *
31
	 * @var  StatisticsRepository
32
	 */
33
	private $repository;
34
35
	/**
36
	 * Filesystem adapter for the snapshots space.
37
	 *
38
	 * @var  Filesystem
39
	 */
40
	private $filesystem;
41
42
	/**
43
	 * Allowed Database Types.
44
	 *
45
	 * @var  array
46
	 */
47
	private $databaseTypes = [
48
		'mysql',
49
		'mysqli',
50
		'pgsql',
51
		'pdomysql',
52
		'postgresql',
53
		'sqlazure',
54
		'sqlsrv',
55
	];
56
57
	/**
58
	 * Constructor.
59
	 *
60
	 * @param   StatisticsRepository  $repository  Statistics repository.
61
	 * @param   Filesystem            $filesystem  Filesystem adapter for the versions space.
62
	 */
63 5
	public function __construct(StatisticsRepository $repository, Filesystem $filesystem)
64
	{
65 5
		$this->repository = $repository;
66 5
		$this->filesystem = $filesystem;
67 5
	}
68
69
	/**
70
	 * Execute the controller.
71
	 *
72
	 * @return  boolean
73
	 */
74 5
	public function execute()
75
	{
76 5
		$input = $this->getInput();
77
78
		$data = [
79 5
			'php_version' => $input->getRaw('php_version', ''),
80 5
			'db_version'  => $input->getRaw('db_version', ''),
81 5
			'cms_version' => $input->getRaw('cms_version', ''),
82 5
			'unique_id'   => $input->getString('unique_id'),
83 5
			'db_type'     => $input->getString('db_type', ''),
84 5
			'server_os'   => $input->getString('server_os'),
85
		];
86
87
		// Backup the original POST before manipulating/validating data
88 5
		$originalData = $data;
89
90
		// Validate the submitted data
91 5
		$data['php_version'] = $this->checkPHPVersion($data['php_version']);
92 5
		$data['cms_version'] = $this->checkCMSVersion($data['cms_version']);
93 5
		$data['db_type']     = $this->checkDatabaseType($data['db_type']);
94 5
		$data['db_version']  = $this->validateVersionNumber($data['db_version']);
95
96
		// We require at a minimum a unique ID and the CMS version
97 5
		if (empty($data['unique_id']) || (empty($data['cms_version']) && $data['cms_version'] !== false))
98
		{
99 1
			$this->getApplication()->getLogger()->info(
100 1
				'Missing required data from request.',
101 1
				['postData' => $originalData]
102
			);
103
104
			/** @var JsonResponse $response */
105 1
			$response = $this->getApplication()->getResponse();
106 1
			$response = $response->withPayload(
107
				[
108 1
					'error'   => true,
109
					'message' => 'There was an error storing the data.',
110
				]
111
			);
112 1
			$response = $response->withStatus(500);
113
114 1
			$this->getApplication()->setResponse($response);
115
116 1
			return true;
117
		}
118
119
		// If the below data does not pass tests, we do not accept the POST
120 4
		if ($data['php_version'] === false || $data['cms_version'] === false || $data['db_type'] === false || $data['db_version'] === false)
121
		{
122
			/** @var JsonResponse $response */
123 1
			$response = $this->getApplication()->getResponse();
124 1
			$response = $response->withPayload(
125
				[
126 1
					'error'   => true,
127
					'message' => 'Invalid data submission.',
128
				]
129
			);
130 1
			$response = $response->withStatus(500);
131
132 1
			$this->getApplication()->setResponse($response);
133
134 1
			return true;
135
		}
136
137
		// Account for configuration differences with 4.0
138 3
		if (version_compare($data['cms_version'], '4.0', 'ge'))
139
		{
140
			// For 4.0 and later, we map `mysql` to the `pdomysql` option to correctly track the database type
141 1
			if ($data['db_type'] === 'mysql')
142
			{
143 1
				$data['db_type'] = 'pdomysql';
144
			}
145
		}
146
147 3
		$this->repository->save((object) $data);
148
149
		/** @var JsonResponse $response */
150 3
		$response = $this->getApplication()->getResponse();
151 3
		$response = $response->withPayload(
152
			[
153 3
				'error'   => false,
154
				'message' => 'Data saved successfully',
155
			]
156
		);
157
158 3
		$this->getApplication()->setResponse($response);
159
160 3
		return true;
161
	}
162
163
	/**
164
	 * Check the CMS version.
165
	 *
166
	 * @param   string  $version  The version number to check.
167
	 *
168
	 * @return  string|boolean  The version number on success or boolean false on failure.
169
	 */
170 5 View Code Duplication
	private function checkCMSVersion(string $version)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
171
	{
172 5
		$version = $this->validateVersionNumber($version);
173
174
		// If the version number is invalid, don't go any further
175 5
		if ($version === false)
176
		{
177 1
			return false;
178
		}
179
180
		// Joomla only uses major.minor.patch so everything else is invalid
181 4
		$explodedVersion = explode('.', $version);
182
183 4
		if (\count($explodedVersion) > 3)
184
		{
185
			return false;
186
		}
187
188
		try
189
		{
190 4
			$validVersions = json_decode($this->filesystem->read('joomla.json'), true);
191
		}
192
		catch (FileNotFoundException $exception)
193
		{
194
			throw new \RuntimeException('Missing Joomla! release listing', 500, $exception);
195
		}
196
197
		// Check that the version is in our valid release list
198 4
		if (!\in_array($version, $validVersions))
199
		{
200 1
			return false;
201
		}
202
203 3
		return $version;
204
	}
205
206
	/**
207
	 * Check the database type
208
	 *
209
	 * @param   string  $database  The database type to check.
210
	 *
211
	 * @return  string|boolean  The database type on success or boolean false on failure.
212
	 */
213 5
	private function checkDatabaseType(string $database)
214
	{
215 5
		if (!\in_array($database, $this->databaseTypes))
216
		{
217
			return false;
218
		}
219
220 5
		return $database;
221
	}
222
223
	/**
224
	 * Check the PHP version
225
	 *
226
	 * @param   string  $version  The version number to check.
227
	 *
228
	 * @return  string|boolean  The version number on success or boolean false on failure.
229
	 */
230 5 View Code Duplication
	private function checkPHPVersion(string $version)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
231
	{
232 5
		$version = $this->validateVersionNumber($version);
233
234
		// If the version number is invalid, don't go any further
235 5
		if ($version === false)
236
		{
237
			return false;
238
		}
239
240
		// We only track versions based on major.minor.patch so everything else is invalid
241 5
		$explodedVersion = explode('.', $version);
242
243 5
		if (\count($explodedVersion) > 3)
244
		{
245
			return false;
246
		}
247
248
		try
249
		{
250 5
			$validVersions = json_decode($this->filesystem->read('php.json'), true);
251
		}
252
		catch (FileNotFoundException $exception)
253
		{
254
			throw new \RuntimeException('Missing PHP release listing', 500, $exception);
255
		}
256
257
		// Check that the version is in our valid release list
258 5
		if (!\in_array($version, $validVersions))
259
		{
260
			return false;
261
		}
262
263 5
		return $version;
264
	}
265
}
266