Passed
Push — master ( 52e05d...6f0859 )
by
unknown
08:31 queued 03:15
created

Config::__debugInfo()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 1
b 0
f 0
nc 4
nop 0
dl 0
loc 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Files\Backend\Seafile\Model;
6
7
use ArrayAccess;
8
9
/**
10
 * Class Config.
11
 *
12
 * @property string server Seafile server. FQN or IP address (v4 only).
13
 * @property int port TCP port of Seafile server. Default is 443.
14
 * @property bool ssl Use https (true) or http (false) scheme. Default is true.
15
 * @property string path Base path. Commonly empty.
16
 * @property string user Username for authentication.
17
 * @property string pass Password for authentication.
18
 * @property string sso_auth_user_token Token for SSO user authentication
19
 */
20
class Config implements \ArrayAccess {
21
	private const DEF = [
22
		'server' => 'server_address',
23
		'port' => 'server_port',
24
		'ssl' => 'server_ssl',
25
		'path' => 'server_path',
26
		'user' => 'user',
27
		'pass' => 'password',
28
		'sso_auth_user_token' => 'sso_auth_user_token',
29
	];
30
31
	private const SCHEMA = [
32
		self::DEF['server'] => [
33
			'filter' => FILTER_VALIDATE_DOMAIN,
34
			'flags' => FILTER_FLAG_HOSTNAME,
35
			'options' => ['default' => 'seafile.example.com'],
36
		],
37
		self::DEF['port'] => [
38
			'filter' => FILTER_VALIDATE_INT,
39
			'options' => ['min_range' => 0, 'max_range' => 65535, 'default' => 443],
40
		],
41
		self::DEF['ssl'] => [
42
			'filter' => FILTER_VALIDATE_BOOLEAN,
43
			'options' => ['default' => true],
44
		],
45
		self::DEF['path'] => [
46
			'filter' => FILTER_UNSAFE_RAW,
47
			'flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH,
48
			'options' => ['default' => ''],
49
		],
50
		self::DEF['user'] => [
51
			'filter' => FILTER_UNSAFE_RAW,
52
			'flags' => FILTER_FLAG_STRIP_LOW,
53
			'options' => ['default' => ''],
54
		],
55
		self::DEF['pass'] => [
56
			'filter' => FILTER_DEFAULT,
57
			'options' => ['default' => ''],
58
		],
59
		self::DEF['sso_auth_user_token'] => [
60
			'filter' => FILTER_DEFAULT,
61
			'flags' => FILTER_FLAG_EMPTY_STRING_NULL,
62
			'options' => ['default' => null],
63
		],
64
	];
65
66
	private array $config = [];
67
68
	public function __construct(array $config = []) {
69
		$this->importConfigArray($config);
70
	}
71
72
	/**
73
	 * Get the URL of the Seafile servers REST API.
74
	 */
75
	public function getApiUrl(): string {
76
		$config = $this;
77
78
		$ssl = (bool) $config->ssl;
79
		$defaultPort = $ssl ? 443 : 80;
80
		$port = max(0, min(65535, (int) $config->port)) ?: $defaultPort;
81
		$host = rtrim($config->server, '/');
82
		$path = ltrim($config->path, '/');
83
84
		$url = sprintf('http%s://%s:%d/%s', $ssl ? 's' : '', $host, $port, $path);
85
86
		return rtrim($url, '/');
87
	}
88
89
	/**
90
	 * read-only properties.
91
	 *
92
	 * @noinspection MagicMethodsValidityInspection
93
	 * @noinspection RedundantSuppression
94
	 */
95
	public function __get(string $name): mixed {
96
		if (!isset(self::DEF[$name])) {
97
			throw new \OutOfBoundsException("Not a property: \"{$name}\"");
98
		}
99
100
		return $this->config[self::DEF[$name]];
101
	}
102
103
	/**
104
	 * init configuration data.
105
	 *
106
	 * set all named properties from associative array, overwriting self with defaults
107
	 * from the schema.
108
	 */
109
	public function importConfigArray(array $config): void {
110
		$result = [];
111
		foreach (self::SCHEMA as $name => $definition) {
112
			$result[$name] =
113
				array_key_exists($name, $config) ?
114
					$config[$name] :
115
					$this->config[$name] ?? $definition['options']['default'] ?? null;
116
		}
117
		$filtered = filter_var_array($result, self::SCHEMA);
118
119
		if (!is_array($filtered)) {
120
			throw new \UnexpectedValueException('Failed to filter Seafile configuration values.');
121
		}
122
123
		$this->config = $filtered;
124
	}
125
126
	/**
127
	 * Hide its internal state from var_dump().
128
	 *
129
	 * Note: The xdebug extension may break this behavior.
130
	 * You should not rely on it if you have debugging extensions installed.
131
	 */
132
	public function __debugInfo(): array {
133
		$info = $this->config;
134
		$info['password'] = is_string($info['password']) ? '*' : null;
135
		$info['sso_auth_user_token'] = is_string($info['sso_auth_user_token']) ? '*' : null;
136
137
		return $info;
138
	}
139
140
	/* ArrayAccess implementation */
141
142
	public function offsetExists(mixed $offset): bool {
143
		return isset($this->config[$offset]);
144
	}
145
146
	public function offsetGet(mixed $offset): mixed {
147
		return $this->config[$offset];
148
	}
149
150
	public function offsetSet(mixed $offset, mixed $value): void {
151
		trigger_error('modification by write is undefined behaviour', E_USER_WARNING);
152
	}
153
154
	public function offsetUnset(mixed $offset): void {
155
		trigger_error('modification by delete is undefined behaviour', E_USER_WARNING);
156
	}
157
}
158