RApiHalHelper::getWebserviceClient()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 3
nc 4
nop 1
1
<?php
2
/**
3
 * @package     Redcore
4
 * @subpackage  Api
5
 *
6
 * @copyright   Copyright (C) 2008 - 2021 redWEB.dk. All rights reserved.
7
 * @license     GNU General Public License version 2 or later, see LICENSE.
8
 */
9
10
defined('JPATH_BASE') or die;
11
12
jimport('joomla.filesystem.folder');
13
14
use Joomla\Utilities\ArrayHelper;
15
16
/**
17
 * Interface to handle api calls
18
 *
19
 * @package     Redcore
20
 * @subpackage  Api
21
 * @since       1.2
22
 */
23
class RApiHalHelper
24
{
25
	/**
26
	 * An array to hold webservices xmls
27
	 *
28
	 * @var    array
29
	 * @since  1.2
30
	 */
31
	public static $webservices = array();
32
33
	/**
34
	 * An array to hold installed Webservices data
35
	 *
36
	 * @var    array
37
	 * @since  1.2
38
	 */
39
	public static $installedWebservices = null;
40
41
	/**
42
	 * Method to transform XML to array and get XML attributes
43
	 *
44
	 * @param   SimpleXMLElement  $xmlElement      XML object to transform
45
	 * @param   boolean           $onlyAttributes  return only attributes or all elements
46
	 *
47
	 * @return  array
48
	 *
49
	 * @since   1.2
50
	 */
51
	public static function getXMLElementAttributes($xmlElement, $onlyAttributes = true)
52
	{
53
		$transformedXML = json_decode(json_encode((array) $xmlElement), true);
54
55
		return $onlyAttributes ? $transformedXML['@attributes'] : $transformedXML;
56
	}
57
58
	/**
59
	 * Get Webservices path
60
	 *
61
	 * @return  string
62
	 *
63
	 * @since   1.2
64
	 */
65
	public static function getWebservicesPath()
66
	{
67
		return JPATH_ROOT . '/' . self::getWebservicesRelativePath();
68
	}
69
70
	/**
71
	 * Get Webservices path
72
	 *
73
	 * @return  string
74
	 *
75
	 * @since   1.2
76
	 */
77
	public static function getWebservicesRelativePath()
78
	{
79
		return 'media/redcore/webservices';
80
	}
81
82
	/**
83
	 * Get Default scopes for all webservices
84
	 *
85
	 * @return  array
86
	 *
87
	 * @since   1.2
88
	 */
89
	public static function getDefaultScopes()
90
	{
91
		return array(
92
			array('scope' => 'site.create',
93
				'scopeDisplayName' => JText::_('JSITE') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_CREATE')),
94
			array('scope' => 'site.read',
95
				'scopeDisplayName' => JText::_('JSITE') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_READ')),
96
			array('scope' => 'site.update',
97
				'scopeDisplayName' => JText::_('JSITE') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_UPDATE')),
98
			array('scope' => 'site.delete',
99
				'scopeDisplayName' => JText::_('JSITE') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_DELETE')),
100
			array('scope' => 'site.task',
101
				'scopeDisplayName' => JText::_('JSITE') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_TASKS')),
102
			array('scope' => 'site.documentation',
103
				'scopeDisplayName' => JText::_('JSITE') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_DOCUMENTATION')),
104
			array('scope' => 'administrator.create',
105
				'scopeDisplayName' => JText::_('JADMINISTRATOR') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_CREATE')),
106
			array('scope' => 'administrator.read',
107
				'scopeDisplayName' => JText::_('JADMINISTRATOR') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_READ')),
108
			array('scope' => 'administrator.update',
109
				'scopeDisplayName' => JText::_('JADMINISTRATOR') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_UPDATE')),
110
			array('scope' => 'administrator.delete',
111
				'scopeDisplayName' => JText::_('JADMINISTRATOR') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_DELETE')),
112
			array('scope' => 'administrator.task',
113
				'scopeDisplayName' => JText::_('JADMINISTRATOR') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_TASKS')),
114
			array('scope' => 'administrator.documentation',
115
				'scopeDisplayName' => JText::_('JADMINISTRATOR') . ' - ' . JText::_('LIB_REDCORE_API_OAUTH2_CLIENTS_SCOPES_ALL_WEBSERVICES_DOCUMENTATION')),
116
		);
117
	}
118
119
	/**
120
	 * Method to transform XML to array and get XML attributes
121
	 *
122
	 * @param   SimpleXMLElement|Array  $element  XML object or array
123
	 * @param   string                  $key      Key to check
124
	 * @param   boolean                 $default  Default value to return
125
	 *
126
	 * @return  boolean
127
	 *
128
	 * @since   1.2
129
	 */
130
	public static function isAttributeTrue($element, $key, $default = false)
131
	{
132
		if (!isset($element[$key]))
133
		{
134
			return $default;
135
		}
136
137
		return strtolower($element[$key]) == "true" ? true : false;
138
	}
139
140
	/**
141
	 * Method to transform XML to array and get XML attributes
142
	 *
143
	 * @param   SimpleXMLElement|Array  $element  XML object or array
144
	 * @param   string                  $key      Key to check
145
	 * @param   string                  $default  Default value to return
146
	 *
147
	 * @return  boolean
148
	 *
149
	 * @since   1.2
150
	 */
151
	public static function attributeToString($element, $key, $default = '')
152
	{
153
		if (!isset($element[$key]))
154
		{
155
			return $default;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $default returns the type string which is incompatible with the documented return type boolean.
Loading history...
156
		}
157
158
		$value = (string) $element[$key];
159
160
		return !empty($value) ? $value : $default;
0 ignored issues
show
Bug Best Practice introduced by
The expression return ! empty($value) ? $value : $default returns the type string which is incompatible with the documented return type boolean.
Loading history...
161
	}
162
163
	/**
164
	 * Method to get Task from request
165
	 *
166
	 * @return  string Task name
167
	 *
168
	 * @since   1.2
169
	 */
170
	public static function getTask()
171
	{
172
		$command = JFactory::getApplication()->input->get('task', '');
173
174
		// Check for array format.
175
		$filter = JFilterInput::getInstance();
176
177
		if (is_array($command))
178
		{
179
			$command = $filter->clean(array_pop(array_keys($command)), 'cmd');
0 ignored issues
show
Bug introduced by
array_keys($command) cannot be passed to array_pop() as the parameter $array expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

179
			$command = $filter->clean(array_pop(/** @scrutinizer ignore-type */ array_keys($command)), 'cmd');
Loading history...
180
		}
181
		else
182
		{
183
			$command = $filter->clean($command, 'cmd');
184
		}
185
186
		// Check for a controller.task command.
187
		if (strpos($command, '.') !== false)
188
		{
189
			// Explode the controller.task command.
190
			list ($type, $task) = explode('.', $command);
191
		}
192
		else
193
		{
194
			$task = $command;
195
		}
196
197
		return $task;
198
	}
199
200
	/**
201
	 * Loading of webservice XML file
202
	 *
203
	 * @param   string  $client             Client
204
	 * @param   string  $webserviceName     Webservice name
205
	 * @param   string  $version            Version of the webservice
206
	 * @param   string  $path               Path to webservice files
207
	 * @param   bool    $showNotifications  Show notifications
208
	 *
209
	 * @throws Exception
210
	 * @return  array  List of objects
211
	 */
212
	public static function getWebservices($client = '', $webserviceName = '', $version = '1.0.0', $path = '', $showNotifications = false)
213
	{
214
		if (empty(self::$webservices) || (!empty($webserviceName) && empty(self::$webservices[$client][$webserviceName][$version])))
215
		{
216
			try
217
			{
218
				self::loadWebservices($client, $webserviceName, $version, $path);
219
			}
220
			catch (Exception $e)
221
			{
222
				if ($showNotifications)
223
				{
224
					JFactory::getApplication()->enqueueMessage($e->getMessage(), 'message');
225
				}
226
				else
227
				{
228
					throw $e;
229
				}
230
			}
231
		}
232
233
		if (empty($webserviceName))
234
		{
235
			return self::$webservices;
236
		}
237
238
		if (!empty(self::$webservices[$client][$webserviceName][$version]))
239
		{
240
			return self::$webservices[$client][$webserviceName][$version];
241
		}
242
243
		return array();
244
	}
245
246
	/**
247
	 * Loading of related XML files
248
	 *
249
	 * @param   string  $client             Client
250
	 * @param   string  $webserviceName     Webservice name
251
	 * @param   string  $version            Version of the webservice
252
	 * @param   string  $path               Path to webservice files
253
	 * @param   bool    $showNotifications  Show notifications
254
	 *
255
	 * @throws Exception
256
	 * @return  array  List of objects
257
	 */
258
	public static function loadWebservices($client = '', $webserviceName = '', $version = '1.0.0', $path = '', $showNotifications = false)
259
	{
260
		if (empty($webserviceName))
261
		{
262
			$folders             = JFolder::folders(self::getWebservicesPath(), '.', true);
263
			$webserviceXmls[' '] = JFolder::files(self::getWebservicesPath(), '.xml');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$webserviceXmls was never initialized. Although not strictly required by PHP, it is generally a good practice to add $webserviceXmls = array(); before regardless.
Loading history...
264
265
			foreach ($folders as $folder)
266
			{
267
				$webserviceXmls[$folder] = JFolder::files(self::getWebservicesPath() . '/' . $folder, '.xml');
268
			}
269
270
			foreach ($webserviceXmls as $webserviceXmlPath => $webservices)
271
			{
272
				foreach ($webservices as $webservice)
273
				{
274
					try
275
					{
276
						// Version, Extension and Client are already part of file name
277
						$xml = self::loadWebserviceConfiguration($webservice, $version = '', $extension = '', trim($webserviceXmlPath));
278
279
						if (!empty($xml))
280
						{
281
							$client                                                            = self::getWebserviceClient($xml);
282
							$version                                                           = !empty($xml->config->version) ? (string) $xml->config->version : $version;
283
							$xml->webservicePath                                               = trim($webserviceXmlPath);
0 ignored issues
show
Bug introduced by
The property webservicePath does not seem to exist on SimpleXMLElement.
Loading history...
284
							self::$webservices[$client][(string) $xml->config->name][$version] = $xml;
285
						}
286
					}
287
					catch (Exception $e)
288
					{
289
						if ($showNotifications)
290
						{
291
							JFactory::getApplication()->enqueueMessage($e->getMessage(), 'message');
292
						}
293
						else
294
						{
295
							throw $e;
296
						}
297
					}
298
				}
299
			}
300
		}
301
		else
302
		{
303
			try
304
			{
305
				$xml = self::loadWebserviceConfiguration($webserviceName, $version, 'xml', $path, $client);
0 ignored issues
show
Bug introduced by
$webserviceName of type string is incompatible with the type array expected by parameter $webserviceName of RApiHalHelper::loadWebserviceConfiguration(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

305
				$xml = self::loadWebserviceConfiguration(/** @scrutinizer ignore-type */ $webserviceName, $version, 'xml', $path, $client);
Loading history...
306
307
				if (!empty($xml))
308
				{
309
					$client                                                            = self::getWebserviceClient($xml);
310
					$version                                                           = !empty($xml->config->version) ? (string) $xml->config->version : $version;
311
					$xml->webservicePath                                               = trim($path);
312
					self::$webservices[$client][(string) $xml->config->name][$version] = $xml;
313
				}
314
			}
315
			catch (Exception $e)
316
			{
317
				if ($showNotifications)
318
				{
319
					JFactory::getApplication()->enqueueMessage($e->getMessage(), 'message');
320
				}
321
				else
322
				{
323
					throw $e;
324
				}
325
			}
326
		}
327
	}
328
329
	/**
330
	 * Method to finds the full real file path, checking possible overrides
331
	 *
332
	 * @param   string  $client          Client
333
	 * @param   string  $webserviceName  Name of the webservice
334
	 * @param   string  $version         Suffixes to the file name (ex. 1.0.0)
335
	 * @param   string  $extension       Extension of the file to search
336
	 * @param   string  $path            Path to webservice files
337
	 *
338
	 * @return  string  The full path to the api file
339
	 *
340
	 * @since   1.2
341
	 */
342
	public static function getWebserviceFile($client, $webserviceName, $version = '', $extension = 'xml', $path = '')
343
	{
344
		JLoader::import('joomla.filesystem.path');
345
346
		if (!empty($webserviceName))
347
		{
348
			$version        = !empty($version) ? array(JPath::clean($version)) : array('1.0.0');
349
			$webservicePath = !empty($path) ? self::getWebservicesPath() . '/' . $path : self::getWebservicesPath();
350
351
			// Search for suffixed versions. Example: content.1.0.0.xml
352
			if (!empty($version))
353
			{
354
				foreach ($version as $suffix)
355
				{
356
					$rawPath = $webserviceName . '.' . $suffix;
357
					$rawPath = !empty($extension) ? $rawPath . '.' . $extension : $rawPath;
358
					$rawPath = !empty($client) ? $client . '.' . $rawPath : $rawPath;
359
360
					if ($configurationFullPath = JPath::find($webservicePath, $rawPath))
361
					{
362
						return $configurationFullPath;
363
					}
364
				}
365
			}
366
367
			// Standard version
368
			$rawPath = !empty($extension) ? $webserviceName . '.' . $extension : $webserviceName;
369
			$rawPath = !empty($client) ? $client . '.' . $rawPath : $rawPath;
370
371
			return JPath::find($webservicePath, $rawPath);
0 ignored issues
show
Bug Best Practice introduced by
The expression return JPath::find($webservicePath, $rawPath) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
372
		}
373
374
		return null;
375
	}
376
377
	/**
378
	 * Load configuration file and set all Api parameters
379
	 *
380
	 * @param   array   $webserviceName  Name of the webservice file
381
	 * @param   string  $version         Suffixes for loading of webservice configuration file
382
	 * @param   string  $extension       File extension name
383
	 * @param   string  $path            Path to webservice files
384
	 * @param   string  $client          Client
385
	 *
386
	 * @return  SimpleXMLElement  Loaded configuration object
387
	 *
388
	 * @since   1.2
389
	 * @throws  Exception
390
	 */
391
	public static function loadWebserviceConfiguration($webserviceName, $version = '', $extension = 'xml', $path = '', $client = '')
392
	{
393
		// Check possible overrides, and build the full path to api file
394
		$configurationFullPath = self::getWebserviceFile($client, strtolower($webserviceName), $version, $extension, $path);
0 ignored issues
show
Bug introduced by
$webserviceName of type array is incompatible with the type string expected by parameter $string of strtolower(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

394
		$configurationFullPath = self::getWebserviceFile($client, strtolower(/** @scrutinizer ignore-type */ $webserviceName), $version, $extension, $path);
Loading history...
395
396
		if (!is_readable($configurationFullPath))
397
		{
398
			throw new Exception(JText::_('LIB_REDCORE_API_HAL_WEBSERVICE_CONFIGURATION_FILE_UNREADABLE'));
399
		}
400
401
		$content = @file_get_contents($configurationFullPath);
402
403
		if (is_string($content))
404
		{
405
			return new SimpleXMLElement($content);
406
		}
407
408
		return null;
409
	}
410
411
	/**
412
	 * Upload Webservices config files to redcore media location
413
	 *
414
	 * @param   array  $files  The array of Files (file descriptor returned by PHP)
415
	 *
416
	 * @return  boolean  Returns true if Upload was successful
417
	 */
418
	public static function uploadWebservice($files = array())
419
	{
420
		$uploadOptions = array(
421
			'allowedFileExtensions' => 'xml',
422
			'allowedMIMETypes'      => 'application/xml, text/xml',
423
			'overrideExistingFile'  => true,
424
		);
425
426
		foreach ($files as $key => &$file)
427
		{
428
			$objectFile = new JObject($file);
0 ignored issues
show
Deprecated Code introduced by
The class JObject has been deprecated: 4.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

428
			$objectFile = /** @scrutinizer ignore-deprecated */ new JObject($file);
Loading history...
429
430
			try
431
			{
432
				$content     = file_get_contents($objectFile->tmp_name);
0 ignored issues
show
Bug introduced by
The property tmp_name does not seem to exist on JObject.
Loading history...
433
				$fileContent = null;
434
435
				if (is_string($content))
436
				{
437
					$fileContent = new SimpleXMLElement($content);
438
				}
439
440
				$name    = (string) $fileContent->config->name;
441
				$version = !empty($fileContent->config->version) ? (string) $fileContent->config->version : '1.0.0';
442
443
				$client = self::getWebserviceClient($fileContent);
444
445
				$file['name'] = $client . '.' . $name . '.' . $version . '.xml';
446
			}
447
			catch (Exception $e)
448
			{
449
				unset($files[$key]);
450
				JFactory::getApplication()->enqueueMessage(JText::_('COM_REDCORE_WEBSERVICES_WEBSERVICE_FILE_NOT_VALID'), 'message');
451
			}
452
		}
453
454
		return RFilesystemFile::uploadFiles($files, self::getWebservicesPath() . '/upload', $uploadOptions);
0 ignored issues
show
Bug Best Practice introduced by
The expression return RFilesystemFile::...pload', $uploadOptions) returns the type array|array<mixed,array<string,mixed|string>> which is incompatible with the documented return type boolean.
Loading history...
455
	}
456
457
	/**
458
	 * Method to save the OAuth2 scopes
459
	 *
460
	 * @param   string  $client             Client
461
	 * @param   string  $webservice         Webservice name
462
	 * @param   array   $scopes             Scopes defined in webservice
463
	 * @param   bool    $showNotifications  Show notification after each Action
464
	 *
465
	 * @throws  Exception
466
	 * @return  bool   True on success, false on failure.
467
	 */
468
	public static function saveOAuth2Scopes($client, $webservice, $scopes = array(), $showNotifications = true)
469
	{
470
		$db = JFactory::getDbo();
471
472
		try
473
		{
474
			$db->transactionStart();
475
476
			$query = $db->getQuery(true)
477
				->delete('#__redcore_oauth_scopes')->where($db->qn('scope') . ' LIKE ' . $db->q($client . '.' . $webservice . '.%'));
478
			$db->setQuery($query);
479
			$db->execute();
480
481
			foreach ($scopes as $scope)
482
			{
483
				$query = $db->getQuery(true)
484
					->insert('#__redcore_oauth_scopes')->set($db->qn('scope') . ' = ' . $db->q($scope['scope']));
485
				$db->setQuery($query);
486
				$db->execute();
487
			}
488
489
			$db->transactionCommit();
490
		}
491
		catch (Exception $e)
492
		{
493
			$db->transactionRollback();
494
495
			if ($showNotifications)
496
			{
497
				JFactory::getApplication()->enqueueMessage(JText::_('COM_REDCORE_WEBSERVICES_WEBSERVICE_SCOPE_ERROR'), 'error');
498
			}
499
		}
500
	}
501
502
	/**
503
	 * Get list of all webservices from Redcore parameters
504
	 *
505
	 * @return  array  Array or table with columns columns
506
	 */
507
	public static function getInstalledWebservices()
508
	{
509
		if (!isset(self::$installedWebservices))
510
		{
511
			self::$installedWebservices = array();
512
			$db                         = JFactory::getDbo();
513
514
			$query = $db->getQuery(true)
515
				->select('*')
516
				->from('#__redcore_webservices')
517
				->order('created_date ASC');
518
519
			$db->setQuery($query);
520
			$webservices = $db->loadObjectList();
521
522
			if (!empty($webservices))
523
			{
524
				foreach ($webservices as $webservice)
525
				{
526
					self::$installedWebservices[$webservice->client][$webservice->name][$webservice->version] = ArrayHelper::fromObject($webservice);
527
				}
528
			}
529
		}
530
531
		return self::$installedWebservices;
532
	}
533
534
	/**
535
	 * Get installed webservice options
536
	 *
537
	 * @param   string  $client          Client
538
	 * @param   string  $webserviceName  Webservice Name
539
	 * @param   string  $version         Webservice version
540
	 *
541
	 * @return  array  Array of webservice options
542
	 */
543
	public static function getInstalledWebservice($client, $webserviceName, $version)
544
	{
545
		// Initialise Installed webservices
546
		$webservices = self::getInstalledWebservices();
547
548
		if (!empty($webservices[$client][$webserviceName][$version]))
549
		{
550
			return $webservices[$client][$webserviceName][$version];
551
		}
552
553
		return null;
554
	}
555
556
	/**
557
	 * Checks if specific Webservice is installed and active
558
	 *
559
	 * @param   string  $client          Client
560
	 * @param   string  $webserviceName  Webservice Name
561
	 * @param   string  $version         Webservice version
562
	 *
563
	 * @return  array  Array or table with columns columns
564
	 */
565
	public static function isPublishedWebservice($client, $webserviceName, $version)
566
	{
567
		$installedWebservices = self::getInstalledWebservices();
568
569
		if (!empty($installedWebservices))
570
		{
571
			if (empty($version))
572
			{
573
				$version = self::getNewestWebserviceVersion($client, $webserviceName);
574
			}
575
576
			$webservice = $installedWebservices[$client][$webserviceName][$version];
577
578
			return !empty($webservice['state']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return ! empty($webservice['state']) returns the type boolean which is incompatible with the documented return type array.
Loading history...
579
		}
580
581
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
582
	}
583
584
	/**
585
	 * Checks if specific Webservice is installed and active
586
	 *
587
	 * @param   string  $client          Client
588
	 * @param   string  $webserviceName  Webservice Name
589
	 *
590
	 * @return  array  Array or table with columns columns
591
	 */
592
	public static function getNewestWebserviceVersion($client, $webserviceName)
593
	{
594
		$installedWebservices = self::getInstalledWebservices();
595
596
		if (!empty($installedWebservices) && isset($installedWebservices[$client][$webserviceName]))
597
		{
598
			// First element is always newest
599
			foreach ($installedWebservices[$client][$webserviceName] as $version => $webservice)
600
			{
601
				return $version;
602
			}
603
		}
604
605
		return '1.0.0';
0 ignored issues
show
Bug Best Practice introduced by
The expression return '1.0.0' returns the type string which is incompatible with the documented return type array.
Loading history...
606
	}
607
608
	/**
609
	 * Returns Client of the webservice
610
	 *
611
	 * @param   SimpleXMLElement|array  $xmlElement  XML object
612
	 *
613
	 * @return  string
614
	 */
615
	public static function getWebserviceClient($xmlElement)
616
	{
617
		return !empty($xmlElement['client']) && strtolower($xmlElement['client']) == 'administrator' ? 'administrator' : 'site';
618
	}
619
620
	/**
621
	 * Returns Scopes of the webservice
622
	 *
623
	 * @param   array  $filterScopes  Scopes that will be used as a filter
624
	 *
625
	 * @return  array
626
	 */
627
	public static function getWebserviceScopes($filterScopes = array())
628
	{
629
		$options              = array();
630
		$installedWebservices = self::getInstalledWebservices();
631
632
		if (empty($filterScopes))
633
		{
634
			// Options for all webservices
635
			$options[JText::_('COM_REDCORE_OAUTH_CLIENTS_SCOPES_ALL_WEBSERVICES')] = self::getDefaultScopes();
636
		}
637
638
		if (!empty($installedWebservices))
639
		{
640
			foreach ($installedWebservices as $webserviceClient => $webserviceNames)
641
			{
642
				foreach ($webserviceNames as $webserviceName => $webserviceVersions)
643
				{
644
					foreach ($webserviceVersions as $version => $webservice)
645
					{
646
						$webserviceDisplayName = JText::_('J' . $webserviceClient) . ' '
647
							. (!empty($webservice['title']) ? $webservice['title'] : $webserviceName);
648
649
						if (!empty($webservice['scopes']))
650
						{
651
							$scopes = json_decode($webservice['scopes'], true);
652
653
							foreach ($scopes as $scope)
654
							{
655
								$scopeParts = explode('.', $scope['scope']);
656
657
								// For global check of filtered scopes using $client . '.' . $operation
658
								$globalCheck = $scopeParts[0] . '.' . $scopeParts[2];
659
660
								if (empty($filterScopes) || in_array($scope['scope'], $filterScopes) || in_array($globalCheck, $filterScopes))
661
								{
662
									$options[$webserviceDisplayName][] = $scope;
663
								}
664
							}
665
						}
666
					}
667
				}
668
			}
669
		}
670
671
		return $options;
672
	}
673
674
	/**
675
	 * Generate a JWT
676
	 *
677
	 * @param   string  $privateKey  The private key to use to sign the token
678
	 * @param   string  $iss         The issuer, usually the client_id
679
	 * @param   string  $sub         The subject, usually a user_id
680
	 * @param   string  $aud         The audience, usually the URI for the oauth server
681
	 * @param   string  $exp         The expiration date. If the current time is greater than the exp, the JWT is invalid
682
	 * @param   string  $nbf         The "not before" time. If the current time is less than the nbf, the JWT is invalid
683
	 * @param   string  $jti         The "jwt token identifier", or nonce for this JWT
684
	 *
685
	 * @return string  JWT
686
	 */
687
	public static function generateJWT($privateKey, $iss, $sub, $aud, $exp = null, $nbf = null, $jti = null)
688
	{
689
		if (!$exp)
690
		{
691
			$exp = time() + 1000;
692
		}
693
694
		$params = array(
695
			'iss' => $iss,
696
			'sub' => $sub,
697
			'aud' => $aud,
698
			'exp' => $exp,
699
			'iat' => time(),
700
		);
701
702
		if ($nbf)
703
		{
704
			$params['nbf'] = $nbf;
705
		}
706
707
		if ($jti)
708
		{
709
			$params['jti'] = $jti;
710
		}
711
712
		$jwtUtil = new \OAuth2\Encryption\Jwt;
713
714
		return $jwtUtil->encode($params, $privateKey, 'RS256');
715
	}
716
717
	/**
718
	 * Returns list of transform elements
719
	 *
720
	 * @return  array
721
	 */
722
	public static function getTransformElements()
723
	{
724
		static $transformElements = null;
725
726
		if (!is_null($transformElements))
727
		{
728
			return $transformElements;
729
		}
730
731
		$transformElementsFiles = JFolder::files(JPATH_LIBRARIES . '/redcore/api/hal/transform', '.php');
732
		$transformElements      = array();
733
734
		foreach ($transformElementsFiles as $transformElement)
735
		{
736
			if (!in_array($transformElement, array('interface.php', 'base.php')))
737
			{
738
				$name                = str_replace('.php', '', $transformElement);
739
				$transformElements[] = array(
740
					'value' => $name,
741
					'text' => $name,
742
				);
743
			}
744
		}
745
746
		return $transformElements;
747
	}
748
749
	/**
750
	 * Returns transform element that is appropriate to db type
751
	 *
752
	 * @param   string  $type  Database type
753
	 *
754
	 * @return  string
755
	 */
756
	public static function getTransformElementByDbType($type)
757
	{
758
		$type = explode('(', $type);
759
		$type = strtoupper(trim($type[0]));
760
761
		// We do not test for Varchar because fallback Transform Element String
762
		switch ($type)
763
		{
764
			case 'TINYINT':
765
			case 'SMALLINT':
766
			case 'MEDIUMINT':
767
			case 'INT':
768
			case 'BIGINT':
769
				return 'int';
770
			case 'FLOAT':
771
			case 'DOUBLE':
772
			case 'DECIMAL':
773
				return 'float';
774
			case 'DATE':
775
			case 'DATETIME':
776
			case 'TIMESTAMP':
777
			case 'TIME':
778
				return 'datetime';
779
		}
780
781
		return 'string';
782
	}
783
784
	/**
785
	 * Returns uri to the webservice
786
	 *
787
	 * @param   string  $client        Client
788
	 * @param   string  $name          Name
789
	 * @param   string  $version       Version
790
	 * @param   string  $appendApi     Append api at the end or the URI
791
	 * @param   string  $appendFormat  Append format at the end or the URI
792
	 *
793
	 * @return  string
794
	 */
795
	public static function buildWebserviceUri($client, $name, $version, $appendApi = '', $appendFormat = '')
796
	{
797
		$uri = 'webserviceClient=' . $client
798
			. '&webserviceVersion=' . $version;
799
800
		// Views are separated by dash
801
		$view = explode('-', $name);
802
		$name = $view[0];
803
804
		$uri .= '&option=' . $name;
805
806
		if (!empty($view[1]))
807
		{
808
			$uri .= '&view=' . $view[1];
809
		}
810
811
		if (!empty($appendApi))
812
		{
813
			$uri .= '&api=' . $appendApi;
814
		}
815
816
		if (!empty($appendFormat))
817
		{
818
			$uri .= '&format=' . $appendFormat;
819
		}
820
821
		return $uri;
822
	}
823
824
	/**
825
	 * Returns Full URL to the webservice
826
	 *
827
	 * @param   string  $client        Client
828
	 * @param   string  $name          Name
829
	 * @param   string  $version       Version
830
	 * @param   string  $appendApi     Append api at the end or the URI
831
	 * @param   string  $appendFormat  Append format at the end or the URI
832
	 *
833
	 * @return  string
834
	 */
835
	public static function buildWebserviceFullUrl($client, $name, $version, $appendApi = '', $appendFormat = '')
836
	{
837
		$uri = self::buildWebserviceUri($client, $name, $version, $appendApi, $appendFormat);
838
839
		return rtrim(JUri::base(), '/') . '/index.php?' . $uri;
840
	}
841
842
	/**
843
	 * Returns user credentials from globals
844
	 *
845
	 * @return  array
846
	 */
847
	public static function getCredentialsFromGlobals()
848
	{
849
		$credentials = array();
850
		$headers     = RApi::getHeaderVariablesFromGlobals();
851
852
		if (isset($headers['PHP_AUTH_USER']) && isset($headers['PHP_AUTH_PW']))
853
		{
854
			return $credentials = array(
0 ignored issues
show
Unused Code introduced by
The assignment to $credentials is dead and can be removed.
Loading history...
855
				'username'	 => $headers['PHP_AUTH_USER'],
856
				'password'	 => $headers['PHP_AUTH_PW']
857
			);
858
		}
859
860
		return $credentials;
861
	}
862
863
	/**
864
	 * Returns an array of fields from Element Fields properties
865
	 *
866
	 * @param   SimpleXMLElement  $xmlElement   Xml element
867
	 * @param   boolean           $primaryKeys  Only extract primary keys
868
	 *
869
	 * @return  array
870
	 */
871
	public static function getFieldsArray($xmlElement, $primaryKeys = false)
872
	{
873
		$fields = array();
874
875
		if (isset($xmlElement->fields->field))
876
		{
877
			foreach ($xmlElement->fields->field as $field)
878
			{
879
				$fieldAttributes = self::getXMLElementAttributes($field);
880
881
				if (($primaryKeys && self::isAttributeTrue($field, 'isPrimaryField'))
882
					|| !$primaryKeys)
883
				{
884
					$fields[$fieldAttributes['name']] = $fieldAttributes;
885
				}
886
			}
887
		}
888
889
		// If there are no primary keys defined we will use id field as default
890
		if (empty($fields) && $primaryKeys)
891
		{
892
			$fields['id'] = array('name' => 'id', 'transform' => 'int');
893
		}
894
895
		return $fields;
896
	}
897
898
	/**
899
	 * Gets list of filter fields from operation configuration
900
	 *
901
	 * @param   SimpleXMLElement  $configuration   Configuration for current action
902
	 * @param   boolean           $excludeSearch   Exclude the search element, maintaining just the xml-provided fields
903
	 * @param   boolean           $fullDefinition  Gets the full definition of the filter, not just the name
904
	 *
905
	 * @return  array
906
	 *
907
	 * @since   1.3
908
	 */
909
	public static function getFilterFields($configuration, $excludeSearch = false, $fullDefinition = false)
910
	{
911
		// We have one search filter field
912
		$filterFields = array();
913
914
		if (!$excludeSearch)
915
		{
916
			if ($fullDefinition)
917
			{
918
				$filterFields[] = array(
919
					'name' => 'search',
920
					'isRequiredField' => 'false',
921
					'transform' => 'string'
922
				);
923
			}
924
			else
925
			{
926
				$filterFields[] = 'search';
927
			}
928
		}
929
930
		if (!empty($configuration->fields))
931
		{
932
			foreach ($configuration->fields->field as $field)
933
			{
934
				if (self::isAttributeTrue($field, 'isFilterField'))
935
				{
936
					if ($fullDefinition)
937
					{
938
						$required = 'false';
939
940
						if (self::isAttributeTrue($field, 'isRequiredField'))
941
						{
942
							$required = 'true';
943
						}
944
945
						$filterFields[] = array(
946
							'name' => (string) $field['name'],
947
							'isRequiredField' => $required,
948
							'transform' => (isset($field['transform'])) ? (string) $field['transform'] : 'string'
949
						);
950
					}
951
					else
952
					{
953
						$filterFields[] = (string) $field["name"];
954
					}
955
				}
956
			}
957
		}
958
959
		return $filterFields;
960
	}
961
}
962