|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* * ******************************************************************************** |
|
4
|
|
|
* (c) 2011-15 GÉANT on behalf of the GN3, GN3plus and GN4 consortia |
|
5
|
|
|
* License: see the LICENSE file in the root directory |
|
6
|
|
|
* ********************************************************************************* */ |
|
7
|
|
|
?> |
|
8
|
|
|
<?php |
|
9
|
|
|
|
|
10
|
|
|
/** |
|
11
|
|
|
* This file contains the Profile class. |
|
12
|
|
|
* |
|
13
|
|
|
* @author Stefan Winter <[email protected]> |
|
14
|
|
|
* @author Tomasz Wolniewicz <[email protected]> |
|
15
|
|
|
* |
|
16
|
|
|
* @package Developer |
|
17
|
|
|
* |
|
18
|
|
|
*/ |
|
19
|
|
|
/** |
|
20
|
|
|
* necessary includes |
|
21
|
|
|
*/ |
|
22
|
|
|
require_once('Helper.php'); |
|
23
|
|
|
require_once('IdP.php'); |
|
24
|
|
|
require_once('EAP.php'); |
|
25
|
|
|
require_once('X509.php'); |
|
26
|
|
|
require_once('EntityWithDBProperties.php'); |
|
27
|
|
|
require_once('devices/devices.php'); |
|
28
|
|
|
|
|
29
|
|
|
define("HIDDEN", -1); |
|
30
|
|
|
define("AVAILABLE", 0); |
|
31
|
|
|
define("UNAVAILABLE", 1); |
|
32
|
|
|
define("INCOMPLETE", 2); |
|
33
|
|
|
define("NOTCONFIGURED", 3); |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* This class represents an EAP Profile. |
|
37
|
|
|
* Profiles can inherit attributes from their IdP, if the IdP has some. Otherwise, |
|
38
|
|
|
* one can set attribute in the Profile directly. If there is a conflict between |
|
39
|
|
|
* IdP-wide and Profile-wide attributes, the more specific ones (i.e. Profile) win. |
|
40
|
|
|
* |
|
41
|
|
|
* @author Stefan Winter <[email protected]> |
|
42
|
|
|
* @author Tomasz Wolniewicz <[email protected]> |
|
43
|
|
|
* |
|
44
|
|
|
* @license see LICENSE file in root directory |
|
45
|
|
|
* |
|
46
|
|
|
* @package Developer |
|
47
|
|
|
*/ |
|
48
|
|
|
class Profile extends EntityWithDBProperties { |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* This array holds the supported EAP types (in "array" OUTER/INNER representation). They are not synced against the DB after instantiation. |
|
52
|
|
|
* |
|
53
|
|
|
* @var array |
|
54
|
|
|
*/ |
|
55
|
|
|
private $priv_eaptypes; |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* Class constructor for existing profiles (use IdP::newProfile() to actually create one). Retrieves all attributes and |
|
59
|
|
|
* supported EAP types from the DB and stores them in the priv_ arrays. |
|
60
|
|
|
* |
|
61
|
|
|
* @param int $p_id identifier of the profile in the DB |
|
62
|
|
|
* @param IdP $idp_object optionally, the institution to which this Profile belongs. Saves the construction of the IdP instance. If omitted, an extra query and instantiation is executed to find out. |
|
63
|
|
|
*/ |
|
64
|
|
|
public function __construct($p_id, $idp_object = 0) { |
|
65
|
|
|
debug(3, "--- BEGIN Constructing new Profile object ... ---\n"); |
|
66
|
|
|
|
|
67
|
|
|
$this->databaseType = "INST"; |
|
68
|
|
|
$this->entityOptionTable = "profile_option"; |
|
69
|
|
|
$this->entityIdColumn = "profile_id"; |
|
70
|
|
|
$this->identifier = $p_id; |
|
71
|
|
|
$this->attributes = []; |
|
72
|
|
|
|
|
73
|
|
|
$profile = DBConnection::exec($this->databaseType, "SELECT inst_id, realm, use_anon_outer, checkuser_outer, checkuser_value, verify_userinput_suffix as verify, hint_userinput_suffix as hint FROM profile WHERE profile_id = $p_id"); |
|
74
|
|
|
debug(4, $profile); |
|
75
|
|
|
if (!$profile || $profile->num_rows == 0) { |
|
76
|
|
|
debug(2, "Profile $p_id not found in database!\n"); |
|
77
|
|
|
throw new Exception("Profile $p_id not found in database!"); |
|
78
|
|
|
return; |
|
|
|
|
|
|
79
|
|
|
} |
|
80
|
|
|
$a = mysqli_fetch_object($profile); |
|
81
|
|
|
if (!($idp_object instanceof IdP)) { |
|
82
|
|
|
$this->institution = $a->inst_id; |
|
83
|
|
|
$idp = new IdP($this->institution); |
|
84
|
|
|
} else { |
|
85
|
|
|
$idp = $idp_object; |
|
86
|
|
|
$this->institution = $idp->name; |
|
87
|
|
|
} |
|
88
|
|
|
$temparray = []; |
|
89
|
|
|
$optioninstance = Options::instance(); |
|
90
|
|
|
|
|
91
|
|
|
$this->realm = $a->realm; |
|
92
|
|
|
$this->use_anon_outer = $a->use_anon_outer; |
|
93
|
|
|
$this->lang_index = CAT::get_lang(); |
|
94
|
|
|
$this->inst_name = $idp->name; |
|
95
|
|
|
|
|
96
|
|
|
$this->checkuser_outer = $a->checkuser_outer; |
|
|
|
|
|
|
97
|
|
|
$this->checkuser_value = $a->checkuser_value; |
|
|
|
|
|
|
98
|
|
|
$this->verify = $a->verify; |
|
|
|
|
|
|
99
|
|
|
$this->hint = $a->hint; |
|
|
|
|
|
|
100
|
|
|
|
|
101
|
|
|
// fetch all atributes from this profile from DB |
|
102
|
|
|
|
|
103
|
|
|
$AllAttributes = DBConnection::exec($this->databaseType, "SELECT option_name, option_value, device_id, eap_method_id as method, row |
|
104
|
|
|
FROM $this->entityOptionTable |
|
105
|
|
|
WHERE $this->entityIdColumn = $this->identifier"); |
|
106
|
|
|
|
|
107
|
|
|
while ($a = mysqli_fetch_object($AllAttributes)) { |
|
108
|
|
|
|
|
109
|
|
|
$optinfo = $optioninstance->optionType($a->option_name); |
|
110
|
|
|
$lang = ""; |
|
111
|
|
|
if ($optinfo['type'] != "file") { |
|
112
|
|
|
$temparray[] = [ |
|
113
|
|
|
"name" => $a->option_name, |
|
114
|
|
|
"value" => $a->option_value, |
|
115
|
|
|
"level" => ($a->device_id == NULL && $a->method == 0 ? "Profile" : "Method" ), |
|
116
|
|
|
"row" => $a->row, |
|
117
|
|
|
"device" => $a->device_id, |
|
118
|
|
|
"flag" => $optinfo['flag'], |
|
119
|
|
|
"eapmethod" => EAP::EAPMethodArrayFromId($a->method)]; |
|
120
|
|
|
} else { |
|
121
|
|
|
// suppress E_NOTICE on the following... we are testing *if* |
|
122
|
|
|
// we have a serialized value - so not having one is fine and |
|
123
|
|
|
// shouldn't throw E_NOTICE |
|
124
|
|
|
if (@unserialize($a->option_value) !== FALSE) { // multi-lang |
|
125
|
|
|
$content = unserialize($a->option_value); |
|
126
|
|
|
$lang = $content['lang']; |
|
127
|
|
|
$content = $content['content']; |
|
128
|
|
|
} else { // single lang, direct content |
|
129
|
|
|
$content = $a->option_value; |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
$content = base64_decode($content); |
|
133
|
|
|
|
|
134
|
|
|
$temparray[] = [ |
|
135
|
|
|
"name" => $a->option_name, |
|
136
|
|
|
"value" => ( $lang == "" ? $content : serialize(['lang' => $lang, 'content' => $content])), |
|
137
|
|
|
"level" => ($a->device_id == NULL && $a->method == 0 ? "Profile" : "Method" ), |
|
138
|
|
|
"row" => $a->row, |
|
139
|
|
|
"flag" => $optinfo['flag'], |
|
140
|
|
|
"device" => $a->device_id, |
|
141
|
|
|
"eapmethod" => EAP::EAPMethodArrayFromId($a->method)]; |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
/* |
|
|
|
|
|
|
145
|
|
|
"name" => $a->option_name, |
|
146
|
|
|
"row" => $a->row, |
|
147
|
|
|
"level" => ($a->device_id == NULL && $a->method == NULL ? "Profile" : "Method" ), |
|
148
|
|
|
"device" => $a->device_id, |
|
149
|
|
|
"eapmethod" => $a->method); |
|
150
|
|
|
|
|
151
|
|
|
*/ |
|
152
|
|
|
} |
|
153
|
|
|
// add internal attributes |
|
154
|
|
|
|
|
155
|
|
|
$temparray[] = ["name" => "internal:profile_count", |
|
156
|
|
|
"value" => $idp->profileCount(), |
|
157
|
|
|
"level" => "Profile", |
|
158
|
|
|
"row" => 0, |
|
159
|
|
|
"flag" => NULL, |
|
160
|
|
|
"device" => NULL, |
|
161
|
|
|
"eapmethod" => NULL]; |
|
162
|
|
|
|
|
163
|
|
|
$temparray[] = ["name" => "internal:checkuser_outer", |
|
164
|
|
|
"value" => $this->checkuser_outer, |
|
165
|
|
|
"level" => "Profile", |
|
166
|
|
|
"row" => 0, |
|
167
|
|
|
"flag" => NULL, |
|
168
|
|
|
"device" => NULL, |
|
169
|
|
|
"eapmethod" => NULL]; |
|
170
|
|
|
|
|
171
|
|
|
$temparray[] = ["name" => "internal:checkuser_value", |
|
172
|
|
|
"value" => $this->checkuser_value, |
|
173
|
|
|
"level" => "Profile", |
|
174
|
|
|
"row" => 0, |
|
175
|
|
|
"flag" => NULL, |
|
176
|
|
|
"device" => NULL, |
|
177
|
|
|
"eapmethod" => NULL]; |
|
178
|
|
|
|
|
179
|
|
|
$temparray[] = ["name" => "internal:verify_userinput_suffix", |
|
180
|
|
|
"value" => $this->verify, |
|
181
|
|
|
"level" => "Profile", |
|
182
|
|
|
"row" => 0, |
|
183
|
|
|
"flag" => NULL, |
|
184
|
|
|
"device" => NULL, |
|
185
|
|
|
"eapmethod" => NULL]; |
|
186
|
|
|
|
|
187
|
|
|
$temparray[] = ["name" => "internal:hint_userinput_suffix", |
|
188
|
|
|
"value" => $this->hint, |
|
189
|
|
|
"level" => "Profile", |
|
190
|
|
|
"row" => 0, |
|
191
|
|
|
"flag" => NULL, |
|
192
|
|
|
"device" => NULL, |
|
193
|
|
|
"eapmethod" => NULL]; |
|
194
|
|
|
|
|
195
|
|
|
// strip local@ off of the realm value |
|
196
|
|
|
$strippedrealm = preg_replace('/^.*@/', '', $this->realm); |
|
197
|
|
|
$temparray[] = ["name" => "internal:realm", |
|
198
|
|
|
"value" => $strippedrealm, |
|
199
|
|
|
"level" => "Profile", |
|
200
|
|
|
"row" => 0, |
|
201
|
|
|
"flag" => NULL, |
|
202
|
|
|
"device" => NULL, |
|
203
|
|
|
"eapmethod" => NULL]; |
|
204
|
|
|
// FALSE or TRUE |
|
|
|
|
|
|
205
|
|
|
$temparray[] = ["name" => "internal:use_anon_outer", |
|
206
|
|
|
"value" => $this->use_anon_outer, |
|
207
|
|
|
"level" => "Profile", |
|
208
|
|
|
"row" => 0, |
|
209
|
|
|
"flag" => NULL, |
|
210
|
|
|
"device" => NULL, |
|
211
|
|
|
"eapmethod" => NULL]; |
|
212
|
|
|
// the local part, if set (otherwise use default value) |
|
213
|
|
|
if (preg_match('/@/', $this->realm)) { |
|
214
|
|
|
$temparray[] = ["name" => "internal:anon_local_value", |
|
215
|
|
|
"value" => substr($this->realm, 0, strpos($this->realm, '@')), |
|
216
|
|
|
"level" => "Profile", |
|
217
|
|
|
"row" => 0, |
|
218
|
|
|
"flag" => NULL, |
|
219
|
|
|
"device" => NULL, |
|
220
|
|
|
"eapmethod" => NULL]; |
|
221
|
|
|
} else { |
|
222
|
|
|
$temparray[] = ["name" => "internal:anon_local_value", |
|
223
|
|
|
"value" => "anonymous", |
|
224
|
|
|
"level" => "Profile", |
|
225
|
|
|
"row" => 0, |
|
226
|
|
|
"flag" => NULL, |
|
227
|
|
|
"device" => NULL, |
|
228
|
|
|
"eapmethod" => NULL]; |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
// now, fetch IdP-wide attributes |
|
232
|
|
|
|
|
233
|
|
|
$idpoptions = $idp->getAttributes(); |
|
234
|
|
|
|
|
235
|
|
|
foreach ($idpoptions as $the_attr) |
|
236
|
|
|
$temparray[] = [ |
|
237
|
|
|
"name" => $the_attr["name"], |
|
238
|
|
|
"value" => $the_attr["value"], |
|
239
|
|
|
"level" => $the_attr["level"], |
|
240
|
|
|
"row" => $the_attr["row"], |
|
241
|
|
|
"flag" => $the_attr["flag"], |
|
242
|
|
|
"device" => NULL, |
|
243
|
|
|
"eapmethod" => NULL, |
|
244
|
|
|
]; |
|
245
|
|
|
|
|
246
|
|
|
// check sanity (device and eapmethod are mutually exclusive) and first batch of adding (method level) |
|
247
|
|
|
|
|
248
|
|
|
foreach ($temparray as $attrib) { |
|
249
|
|
|
if ($attrib["device"] != NULL && $attrib["eapmethod"] != NULL) |
|
250
|
|
|
debug(2, "Sanity check failed - device and eapmethod are set!\n"); |
|
251
|
|
|
} |
|
252
|
|
|
|
|
253
|
|
|
foreach ($temparray as $attrib) { |
|
254
|
|
|
if ($attrib["device"] != NULL || $attrib["eapmethod"] != NULL) |
|
255
|
|
|
$this->attributes[] = $attrib; |
|
256
|
|
|
} |
|
257
|
|
|
// pick all attributes which are profile specific and place into final array if no eap/device-specific exists |
|
258
|
|
|
|
|
259
|
|
View Code Duplication |
foreach ($temparray as $attrib) { |
|
|
|
|
|
|
260
|
|
|
if ($attrib["level"] == "Profile") { |
|
261
|
|
|
$ignore = ""; |
|
262
|
|
|
foreach ($this->attributes as $approved_attrib) |
|
263
|
|
|
if ($attrib["name"] == $approved_attrib["name"] && $approved_attrib["level"] != "IdP" && $approved_attrib["level"] != "Profile") |
|
264
|
|
|
$ignore = "YES"; |
|
265
|
|
|
if ($ignore != "YES") |
|
266
|
|
|
$this->attributes[] = $attrib; |
|
267
|
|
|
} |
|
268
|
|
|
} |
|
269
|
|
|
|
|
270
|
|
|
// now, add IdP-wide attribs |
|
271
|
|
|
|
|
272
|
|
View Code Duplication |
foreach ($temparray as $attrib) { |
|
|
|
|
|
|
273
|
|
|
if ($attrib["level"] == "IdP") { |
|
274
|
|
|
$ignore = ""; |
|
275
|
|
|
foreach ($this->attributes as $approved_attrib) |
|
276
|
|
|
if ($attrib["name"] == $approved_attrib["name"] && $approved_attrib["level"] != "IdP") |
|
277
|
|
|
$ignore = "YES"; |
|
278
|
|
|
if ($ignore != "YES") |
|
279
|
|
|
$this->attributes[] = $attrib; |
|
280
|
|
|
} |
|
281
|
|
|
} |
|
282
|
|
|
|
|
283
|
|
|
$this->name = getLocalisedValue($this->getAttributes('profile:name', 0, 0), $this->lang_index); |
|
284
|
|
|
|
|
285
|
|
|
$eap_m = DBConnection::exec($this->databaseType, "SELECT eap_method_id |
|
286
|
|
|
FROM supported_eap supp |
|
287
|
|
|
WHERE supp.profile_id = $this->identifier |
|
288
|
|
|
ORDER by preference"); |
|
289
|
|
|
$returnarray = []; |
|
290
|
|
|
while ($eap = (mysqli_fetch_object($eap_m))) { |
|
291
|
|
|
$eaptype = EAP::EAPMethodArrayFromId($eap->eap_method_id); |
|
292
|
|
|
$returnarray[] = $eaptype; |
|
293
|
|
|
} |
|
294
|
|
|
debug(4, "Looks like this profile supports the following EAP types: "); |
|
295
|
|
|
debug(4, $returnarray); |
|
296
|
|
|
$this->priv_eaptypes = $returnarray; |
|
297
|
|
|
|
|
298
|
|
|
debug(3, "--- END Constructing new Profile object ... ---\n"); |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
/** |
|
302
|
|
|
* find a profile, given its realm |
|
303
|
|
|
*/ |
|
304
|
|
|
public static function profileFromRealm($realm) { |
|
305
|
|
|
$exec_query = DBConnection::exec($this->databaseType, "SELECT profile_id FROM profile WHERE realm LIKE '%@$realm'"); |
|
|
|
|
|
|
306
|
|
|
if ($a = mysqli_fetch_object($exec_query)) { |
|
307
|
|
|
return $a->profile_id; |
|
308
|
|
|
} else |
|
309
|
|
|
return FALSE; |
|
310
|
|
|
} |
|
311
|
|
|
|
|
312
|
|
|
/** |
|
313
|
|
|
* update the last_changed timestamp for this profile |
|
314
|
|
|
*/ |
|
315
|
|
|
public function updateFreshness() { |
|
316
|
|
|
DBConnection::exec($this->databaseType, "UPDATE profile SET last_change = CURRENT_TIMESTAMP WHERE profile_id = $this->identifier"); |
|
317
|
|
|
} |
|
318
|
|
|
|
|
319
|
|
|
/** |
|
320
|
|
|
* gets the last-modified timestamp (useful for caching "dirty" check) |
|
321
|
|
|
*/ |
|
322
|
|
|
public function getFreshness() { |
|
323
|
|
|
$exec_update = DBConnection::exec($this->databaseType, "SELECT last_change FROM profile WHERE profile_id = $this->identifier"); |
|
324
|
|
|
if ($a = mysqli_fetch_object($exec_update)) { |
|
325
|
|
|
return $a->last_change; |
|
326
|
|
|
} |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
|
/** |
|
330
|
|
|
* tests if the configurator needs to be regenerated |
|
331
|
|
|
* returns the configurator path or NULL if regeneration is required |
|
332
|
|
|
*/ |
|
333
|
|
|
|
|
334
|
|
|
/** |
|
335
|
|
|
* This function tests if the configurator needs to be regenerated (properties of the Profile may have changed since the last configurator generation). |
|
336
|
|
|
* |
|
337
|
|
|
* @param string $device device ID to check |
|
338
|
|
|
* @return mixed a string with the path to the configurator download, or NULL if it needs to be regenerated |
|
339
|
|
|
*/ |
|
340
|
|
|
public function testCache($device) { |
|
341
|
|
|
$returnValue = NULL; |
|
342
|
|
|
$escapedDevice = DBConnection::escape_value($this->databaseType, $device); |
|
343
|
|
|
$result = DBConnection::exec($this->databaseType, "SELECT download_path, mime, UNIX_TIMESTAMP(installer_time) AS tm FROM downloads WHERE profile_id = $this->identifier AND device_id = '$escapedDevice' AND lang = '$this->lang_index'"); |
|
344
|
|
|
if ($result && $cache = mysqli_fetch_object($result)) { |
|
345
|
|
|
$exec_update = DBConnection::exec($this->databaseType, "SELECT UNIX_TIMESTAMP(last_change) AS last_change FROM profile WHERE profile_id = $this->identifier"); |
|
346
|
|
|
if ($lc = mysqli_fetch_object($exec_update)->last_change) { |
|
347
|
|
|
if ($lc < $cache->tm) { |
|
348
|
|
|
debug(4, "Installer cached:$cache->download_path\n"); |
|
349
|
|
|
$returnValue = ['cache'=>$cache->download_path,'mime'=>$cache->mime]; |
|
350
|
|
|
} |
|
351
|
|
|
} |
|
352
|
|
|
} |
|
353
|
|
|
return $returnValue; |
|
354
|
|
|
} |
|
355
|
|
|
|
|
356
|
|
|
/** |
|
357
|
|
|
* Updates database with new installler location |
|
358
|
|
|
* |
|
359
|
|
|
* @param string device the device identifier string |
|
360
|
|
|
* @param string path the path where the new installer can be found |
|
361
|
|
|
*/ |
|
362
|
|
|
public function updateCache($device, $path,$mime) { |
|
363
|
|
|
$escapedDevice = DBConnection::escape_value($this->databaseType, $device); |
|
364
|
|
|
$escapedPath = DBConnection::escape_value($this->databaseType, $path); |
|
365
|
|
|
DBConnection::exec($this->databaseType, "INSERT INTO downloads (profile_id,device_id,download_path,mime,lang,installer_time) |
|
366
|
|
|
VALUES ($this->identifier, '$escapedDevice', '$escapedPath', '$mime', '$this->lang_index', CURRENT_TIMESTAMP ) |
|
367
|
|
|
ON DUPLICATE KEY UPDATE download_path = '$escapedPath', mime = '$mime', installer_time = CURRENT_TIMESTAMP"); |
|
368
|
|
|
} |
|
369
|
|
|
|
|
370
|
|
|
/** |
|
371
|
|
|
* Log a new download for our stats |
|
372
|
|
|
* |
|
373
|
|
|
* @param device the device id string |
|
374
|
|
|
* @param area either admin or user |
|
375
|
|
|
* @return TRUE if incrementing worked, FALSE if not |
|
376
|
|
|
*/ |
|
377
|
|
|
public function incrementDownloadStats($device, $area) { |
|
378
|
|
|
$device = DBConnection::escape_value($this->databaseType, $device); |
|
379
|
|
|
if ($area == "admin" || $area == "user") { |
|
380
|
|
|
DBConnection::exec(Profile::$DB_TYPE, "INSERT INTO downloads (profile_id, device_id, lang, downloads_$area) VALUES ($this->identifier, '$device','$this->lang_index', 1) ON DUPLICATE KEY UPDATE downloads_$area = downloads_$area + 1"); |
|
381
|
|
|
return TRUE; |
|
382
|
|
|
} |
|
383
|
|
|
return FALSE; |
|
384
|
|
|
} |
|
385
|
|
|
|
|
386
|
|
|
/** |
|
387
|
|
|
* Retrieve current download stats from database, either for one specific device or for all devices |
|
388
|
|
|
* @param string $device the device id string |
|
389
|
|
|
* @return mixed user downloads of this profile; if device is given, returns the counter as int, otherwise an array with devicename => counter |
|
390
|
|
|
*/ |
|
391
|
|
|
public function getUserDownloadStats($device = 0) { |
|
392
|
|
|
$returnarray = []; |
|
393
|
|
|
$numbers_q = DBConnection::exec($this->databaseType, "SELECT device_id, SUM(downloads_user) AS downloads_user FROM downloads WHERE profile_id = $this->identifier GROUP BY device_id"); |
|
394
|
|
|
while ($a = mysqli_fetch_object($numbers_q)) |
|
395
|
|
|
$returnarray[$a->device_id] = $a->downloads_user; |
|
396
|
|
|
if ($device !== 0) { |
|
397
|
|
|
if (isset($returnarray[$device])) |
|
398
|
|
|
return $returnarray[$device]; |
|
399
|
|
|
else |
|
400
|
|
|
return 0; |
|
401
|
|
|
} |
|
402
|
|
|
// we should pretty-print the device names |
|
403
|
|
|
$finalarray = []; |
|
404
|
|
|
$devlist = Devices::listDevices(); |
|
405
|
|
|
foreach ($returnarray as $dev_id => $count) |
|
406
|
|
|
if (isset($devlist[$dev_id])) |
|
407
|
|
|
$finalarray[$devlist[$dev_id]['display']] = $count; |
|
408
|
|
|
return $finalarray; |
|
409
|
|
|
} |
|
410
|
|
|
|
|
411
|
|
|
/** |
|
412
|
|
|
* adds an attribute to this profile; not the usual function from EntityWithDBProperties |
|
413
|
|
|
* because this class also has per-EAP-type and per-device sub-settings |
|
414
|
|
|
* |
|
415
|
|
|
* @param string $attr_name name of the attribute to set |
|
|
|
|
|
|
416
|
|
|
* @param string $attr_value value of the attribute to set |
|
|
|
|
|
|
417
|
|
|
* @param int $eap_type identifier of the EAP type in the database. 0 if the attribute is valid for all EAP types. |
|
|
|
|
|
|
418
|
|
|
* @param string $device identifier of the device in the databse. Omit the argument if attribute is valid for all devices. |
|
419
|
|
|
*/ |
|
420
|
|
|
public function addAttribute($attrName, $attrValue, $eapType, $device = 0) { |
|
421
|
|
|
$escapedAttrName = DBConnection::escape_value(Profile::$DB_TYPE, $attrName); |
|
422
|
|
|
$escapedAttrValue = DBConnection::escape_value(Profile::$DB_TYPE, $attrValue); |
|
423
|
|
|
|
|
424
|
|
|
DBConnection::exec($this->databaseType, "INSERT INTO $this->entityOptionTable ($this->entityIdColumn, option_name, option_value, eap_method_id" . ($device !== 0 ? ",device_id" : "") . ") |
|
425
|
|
|
VALUES(". $this->identifier . ", '$escapedAttrName', '$escapedAttrValue', $eapType" . ($device !== 0 ? ",'". DBConnection::escape_value($this->databaseType, $device) . "'" : "" ) . ")"); |
|
426
|
|
|
$this->updateFreshness(); |
|
427
|
|
|
} |
|
428
|
|
|
|
|
429
|
|
|
/** |
|
430
|
|
|
* register new supported EAP method for this profile |
|
431
|
|
|
* |
|
432
|
|
|
* @param array $type The EAP Type, as defined in class EAP |
|
433
|
|
|
* @param int $preference preference of this EAP Type. If a preference value is re-used, the order of EAP types of the same preference level is undefined. |
|
434
|
|
|
* |
|
435
|
|
|
*/ |
|
436
|
|
|
public function addSupportedEapMethod($type, $preference) { |
|
437
|
|
|
DBConnection::exec($this->databaseType, "INSERT INTO supported_eap (profile_id, eap_method_id, preference) VALUES (" |
|
438
|
|
|
. $this->identifier . ", " |
|
439
|
|
|
. EAP::EAPMethodIdFromArray($type) . ", " |
|
440
|
|
|
. $preference . ")"); |
|
441
|
|
|
$this->updateFreshness(); |
|
442
|
|
|
} |
|
443
|
|
|
|
|
444
|
|
|
/** |
|
445
|
|
|
* Deletes the profile from database and uninstantiates itself. |
|
446
|
|
|
* |
|
447
|
|
|
*/ |
|
448
|
|
|
public function destroy() { |
|
449
|
|
|
DBConnection::exec($this->databaseType, "DELETE FROM profile_option WHERE profile_id = $this->identifier"); |
|
450
|
|
|
DBConnection::exec($this->databaseType, "DELETE FROM supported_eap WHERE profile_id = $this->identifier"); |
|
451
|
|
|
DBConnection::exec($this->databaseType, "DELETE FROM profile WHERE profile_id = $this->identifier"); |
|
452
|
|
|
unset($this); |
|
453
|
|
|
} |
|
454
|
|
|
|
|
455
|
|
|
/** |
|
456
|
|
|
* Removes all supported EAP methods |
|
457
|
|
|
*/ |
|
458
|
|
|
public function flushSupportedEapMethods() { |
|
459
|
|
|
DBConnection::exec($this->databaseType, "DELETE FROM supported_eap WHERE profile_id = $this->identifier"); |
|
460
|
|
|
$this->updateFreshness(); |
|
461
|
|
|
} |
|
462
|
|
|
|
|
463
|
|
|
/** Toggle anonymous outer ID support. |
|
464
|
|
|
* |
|
465
|
|
|
* @param boolean $shallwe TRUE to enable outer identities (needs valid $realm), FALSE to disable |
|
466
|
|
|
* |
|
467
|
|
|
*/ |
|
468
|
|
|
public function setAnonymousIDSupport($shallwe) { |
|
469
|
|
|
DBConnection::exec($this->databaseType, "UPDATE profile SET use_anon_outer = " . ($shallwe == true ? "1" : "0") . " WHERE profile_id = $this->identifier"); |
|
|
|
|
|
|
470
|
|
|
} |
|
471
|
|
|
|
|
472
|
|
|
/** Toggle special username for realm checks |
|
473
|
|
|
* |
|
474
|
|
|
* @param boolean $shallwe TRUE to enable outer identities (needs valid $realm), FALSE to disable |
|
475
|
|
|
* @param string $localpart the username |
|
476
|
|
|
* |
|
477
|
|
|
*/ |
|
478
|
|
|
public function setRealmCheckUser($shallwe,$localpart = NULL) { |
|
479
|
|
|
DBConnection::exec($this->databaseType, |
|
480
|
|
|
"UPDATE profile SET checkuser_outer = " . ($shallwe == true ? "1" : "0") . |
|
|
|
|
|
|
481
|
|
|
( $localpart !== NULL ? ", checkuser_value = '$localpart' " : "") . |
|
482
|
|
|
" WHERE profile_id = $this->identifier"); |
|
483
|
|
|
} |
|
484
|
|
|
|
|
485
|
|
|
/** should username be verified or even prefilled? |
|
486
|
|
|
* |
|
487
|
|
|
*/ |
|
488
|
|
|
public function setInputVerificationPreference($verify,$hint) { |
|
489
|
|
|
DBConnection::exec($this->databaseType, |
|
490
|
|
|
"UPDATE profile SET verify_userinput_suffix = " . ($verify == true ? "1" : "0") . |
|
491
|
|
|
", hint_userinput_suffix = ". ($hint == true ? "1" : "0") . |
|
492
|
|
|
" WHERE profile_id = $this->identifier"); |
|
493
|
|
|
} |
|
494
|
|
|
|
|
495
|
|
|
/** |
|
496
|
|
|
* Specifies the realm of this profile. |
|
497
|
|
|
* |
|
498
|
|
|
* @param string $realm the realm (potentially with the local@ part that should be used for anonymous identities) |
|
499
|
|
|
*/ |
|
500
|
|
|
public function setRealm($realm) { |
|
501
|
|
|
$escapedRealm = DBConnection::escape_value($this->databaseType, $realm); |
|
502
|
|
|
DBConnection::exec(Profile::$DB_TYPE, "UPDATE profile SET realm = '$escapedRealm' WHERE profile_id = $this->identifier"); |
|
503
|
|
|
$this->realm = $escapedRealm; |
|
504
|
|
|
} |
|
505
|
|
|
|
|
506
|
|
|
/** |
|
507
|
|
|
* Produces an array of EAP methods supported by this profile, ordered by preference |
|
508
|
|
|
* |
|
509
|
|
|
* @param int $complete_only if set and non-zero limits the output to methods with complete information |
|
510
|
|
|
* @return array list of EAP methods, (in "array" OUTER/INNER representation) |
|
511
|
|
|
*/ |
|
512
|
|
|
public function getEapMethodsinOrderOfPreference($complete_only = 0) { |
|
513
|
|
|
$temparray = []; |
|
514
|
|
|
|
|
515
|
|
|
if ($complete_only == 0) { |
|
516
|
|
|
return $this->priv_eaptypes; |
|
517
|
|
|
} else { |
|
518
|
|
|
foreach ($this->priv_eaptypes as $type) |
|
519
|
|
|
if ($this->isEapTypeDefinitionComplete($type) === true) |
|
520
|
|
|
$temparray[] = $type; |
|
521
|
|
|
return($temparray); |
|
522
|
|
|
} |
|
523
|
|
|
} |
|
524
|
|
|
|
|
525
|
|
|
/** Returns an array of the profile's attributes. |
|
526
|
|
|
* |
|
527
|
|
|
* @param string option_name the name of a specific option. If set, only returns option values for this option name |
|
528
|
|
|
* @param eapmethod the EAP type, in array ("OUTER/INNER") notation. If set, returns only attributes which are specific to that EAP type |
|
529
|
|
|
* @param string device the device ID string. If set, returns only attributes which are specific to that device |
|
530
|
|
|
* @return array attributes of the profile |
|
531
|
|
|
*/ |
|
532
|
|
|
public function getAttributes($option_name = 0, $eapmethod = 0, $device = 0) { |
|
533
|
|
|
|
|
534
|
|
|
$outarray = []; |
|
535
|
|
|
$temparray = []; |
|
536
|
|
|
if ($eapmethod) { |
|
537
|
|
|
foreach ($this->attributes as $the_attr) |
|
538
|
|
|
if ($the_attr["eapmethod"] == $eapmethod) |
|
539
|
|
|
$temparray[] = $the_attr; |
|
540
|
|
|
} else |
|
541
|
|
|
if ($device) { |
|
542
|
|
|
foreach ($this->attributes as $the_attr) |
|
543
|
|
|
if ($the_attr["device"] == $device) |
|
544
|
|
|
$temparray[] = $the_attr; |
|
545
|
|
|
}; |
|
546
|
|
|
|
|
547
|
|
|
foreach ($this->attributes as $the_attr) |
|
548
|
|
|
if ($the_attr["device"] == NULL && $the_attr["eapmethod"] == NULL) |
|
549
|
|
|
$temparray[] = $the_attr; |
|
550
|
|
|
|
|
551
|
|
|
|
|
552
|
|
|
// return only options by one name, if asked for |
|
553
|
|
|
|
|
554
|
|
|
if ($option_name) { |
|
555
|
|
|
foreach ($temparray as $the_attr) |
|
556
|
|
|
if ($the_attr["name"] == $option_name) |
|
557
|
|
|
$outarray[] = $the_attr; |
|
558
|
|
|
} else { |
|
559
|
|
|
$outarray = $temparray; |
|
560
|
|
|
} |
|
561
|
|
|
|
|
562
|
|
|
return $outarray; |
|
563
|
|
|
} |
|
564
|
|
|
|
|
565
|
|
|
/** |
|
566
|
|
|
* Performs a sanity check for a given EAP type - did the admin submit enough information to create installers for him? |
|
567
|
|
|
* |
|
568
|
|
|
* @param array $eaptype the EAP type in "array" OUTER/INNER representation |
|
569
|
|
|
* @return mixed TRUE if the EAP type is complete; an array of missing attribues if it's incomplete; FALSE if it's incomplete for other reasons |
|
570
|
|
|
*/ |
|
571
|
|
|
public function isEapTypeDefinitionComplete($eaptype) { |
|
572
|
|
|
$missing = []; |
|
573
|
|
|
// TLS, TTLS, PEAP outer phase need a CA certficate and a Server Name |
|
574
|
|
|
if ($eaptype["OUTER"] == PEAP || $eaptype["OUTER"] == TLS || $eaptype["OUTER"] == TTLS || $eaptype["OUTER"] == FAST) { |
|
575
|
|
|
|
|
576
|
|
|
$cn_option = $this->getAttributes("eap:server_name", $eaptype); |
|
|
|
|
|
|
577
|
|
|
$ca_option = $this->getAttributes("eap:ca_file", $eaptype); |
|
|
|
|
|
|
578
|
|
|
/* echo "<pre>"; |
|
|
|
|
|
|
579
|
|
|
print_r($options); |
|
580
|
|
|
echo "</pre>"; */ |
|
581
|
|
|
if (count($ca_option) > 0 && count($cn_option) > 0) {// see if we have at least one root CA cert |
|
582
|
|
|
foreach ($ca_option as $one_ca) { |
|
583
|
|
|
$x509 = new X509(); |
|
584
|
|
|
$ca_parsed = $x509->processCertificate($one_ca['value']); |
|
585
|
|
|
if ($ca_parsed['root'] == 1) |
|
586
|
|
|
return true; |
|
587
|
|
|
} |
|
588
|
|
|
$missing[] = "eap:ca_file"; |
|
589
|
|
|
} |
|
590
|
|
|
if (count($ca_option) == 0) |
|
591
|
|
|
$missing[] = "eap:ca_file"; |
|
592
|
|
|
if (count($cn_option) == 0) |
|
593
|
|
|
$missing[] = "eap:server_name"; |
|
594
|
|
|
return $missing; |
|
595
|
|
|
} elseif ($eaptype["OUTER"] == PWD || $eaptype["INNER"] == NE_SILVERBULLET) { |
|
596
|
|
|
/* |
|
|
|
|
|
|
597
|
|
|
$cn_option = $this->getAttributes("eap:server_name", $eaptype); |
|
598
|
|
|
if (count($cn_option) > 0) */ |
|
599
|
|
|
return true; |
|
600
|
|
|
/* $missing[] = "eap:server_name"; |
|
|
|
|
|
|
601
|
|
|
return $missing; */ |
|
602
|
|
|
} |
|
603
|
|
|
|
|
604
|
|
|
// we have no idea; let's say false |
|
605
|
|
|
|
|
606
|
|
|
return false; |
|
607
|
|
|
} |
|
608
|
|
|
|
|
609
|
|
|
/** |
|
610
|
|
|
* list all devices marking their availabiblity and possible redirects |
|
611
|
|
|
* |
|
612
|
|
|
* @param string $locale for text-based attributes, either returns values for the default value, or if specified here, in the locale specified |
|
613
|
|
|
* @return array of device ids display names and their status |
|
614
|
|
|
*/ |
|
615
|
|
|
public function listDevices($locale = 0) { |
|
616
|
|
|
if ($locale == 0) |
|
617
|
|
|
$locale = $this->lang_index; |
|
618
|
|
|
$redirect_url = 0; |
|
|
|
|
|
|
619
|
|
|
$message = 0; |
|
|
|
|
|
|
620
|
|
|
$returnarray = []; |
|
621
|
|
|
$redirect = $this->getAttributes("device-specific:redirect", 0, 0); |
|
622
|
|
|
if ($redirect) { |
|
|
|
|
|
|
623
|
|
|
$v = unserialize($redirect[0]['value']); |
|
624
|
|
|
return [['id' => '0', 'redirect' => $v['content']]]; |
|
625
|
|
|
} |
|
626
|
|
|
$preferred_eap = $this->getEapMethodsinOrderOfPreference(1); |
|
627
|
|
|
$EAP_options = []; |
|
628
|
|
|
foreach (Devices::listDevices() as $d => $D) { |
|
629
|
|
|
$factory = new DeviceFactory($d); |
|
630
|
|
|
$dev = $factory->device; |
|
631
|
|
|
$redirect_url = getLocalisedValue($this->getAttributes("device-specific:redirect", 0, $d), $locale); |
|
632
|
|
|
$dev_status = AVAILABLE; |
|
633
|
|
|
if(isset($D['options']) && isset($D['options']['message']) && $D['options']['message']) |
|
634
|
|
|
$message = $D['options']['message']; |
|
635
|
|
|
else |
|
636
|
|
|
$message = 0; |
|
637
|
|
|
|
|
638
|
|
|
if ($redirect_url === 0) { |
|
|
|
|
|
|
639
|
|
|
if(isset($D['options']) && isset($D['options']['redirect']) && $D['options']['redirect']) { |
|
640
|
|
|
$dev_status = HIDDEN; |
|
641
|
|
|
} else { |
|
642
|
|
|
$eap = $dev->getPreferredEapType($preferred_eap); |
|
643
|
|
|
if ($eap) { |
|
644
|
|
|
if (isset($EAP_options["eap-specific:customtext"][serialize($eap)])) |
|
645
|
|
|
$eap_customtext = $EAP_options["eap-specific:customtext"][serialize($eap)]; |
|
646
|
|
|
else { |
|
647
|
|
|
$eap_customtext = getLocalisedValue($this->getAttributes("eap-specific:customtext", $eap, 0), $locale); |
|
648
|
|
|
$EAP_options["eap-specific:customtext"][serialize($eap)] = $eap_customtext; |
|
649
|
|
|
} |
|
650
|
|
|
$device_customtext = getLocalisedValue($this->getAttributes("device-specific:customtext", 0, $d), $locale); |
|
651
|
|
|
} else { |
|
652
|
|
|
$dev_status = UNAVAILABLE; |
|
653
|
|
|
} |
|
654
|
|
|
} |
|
655
|
|
|
} |
|
656
|
|
|
$returnarray[] = ['id' => $d, 'display' => $D['display'], 'status' => $dev_status, 'redirect' => $redirect_url, 'eap_customtext' => $eap_customtext, 'device_customtext' => $device_customtext, 'message' => $message, 'options'=>$D['options']]; |
|
|
|
|
|
|
657
|
|
|
} |
|
658
|
|
|
return $returnarray; |
|
659
|
|
|
} |
|
660
|
|
|
|
|
661
|
|
|
/** |
|
662
|
|
|
* prepare profile attributes for device modules |
|
663
|
|
|
* Gets profile attributes taking into account the most specific level on which they may be defined |
|
664
|
|
|
* as wel as the chosen language. |
|
665
|
|
|
* can be called with an optional $eap argument |
|
666
|
|
|
* |
|
667
|
|
|
* @param array $eap if specified, retrieves attributes specific to the given EAP type |
|
668
|
|
|
* @return array list of attributes in collapsed style (index is the attrib name, value is an array of different values) |
|
669
|
|
|
*/ |
|
670
|
|
|
public function getCollapsedAttributes($eap = 0) { |
|
671
|
|
|
$attr = $this->getAttributes(0, $eap); |
|
672
|
|
|
$temp1 = []; |
|
673
|
|
|
foreach ($attr as $b) { |
|
674
|
|
|
$name = $b['name']; |
|
675
|
|
|
$temp1[] = $name; |
|
676
|
|
|
$level = $b['level']; |
|
677
|
|
|
// $S[$l] = $z[$l]; |
|
|
|
|
|
|
678
|
|
|
$value = $b['value']; |
|
679
|
|
|
if (!isset($temp[$name][$level])) |
|
680
|
|
|
$temp[$name][$level] = []; |
|
|
|
|
|
|
681
|
|
|
if ($b['flag'] == 'ML') { |
|
682
|
|
|
$v = unserialize($value); |
|
683
|
|
|
$value = [$v['lang'] => $v['content']]; |
|
684
|
|
|
} |
|
685
|
|
|
$temp[$name][$level][] = $value; |
|
|
|
|
|
|
686
|
|
|
$flags[$name] = $b['flag']; |
|
|
|
|
|
|
687
|
|
|
} |
|
688
|
|
|
foreach ($temp1 as $name) { |
|
689
|
|
|
if ($flags[$name] == 'ML') { |
|
|
|
|
|
|
690
|
|
|
$S = []; |
|
691
|
|
View Code Duplication |
if (isset($temp[$name]['Profile'])) { |
|
|
|
|
|
|
692
|
|
|
foreach ($temp[$name]['Profile'] as $z) |
|
693
|
|
|
foreach ($z as $l => $w) |
|
694
|
|
|
$S[$l] = $w; |
|
695
|
|
|
} |
|
696
|
|
View Code Duplication |
if (!$S && isset($temp[$name]['IdP'])) { |
|
|
|
|
|
|
697
|
|
|
foreach ($temp[$name]['IdP'] as $z) |
|
698
|
|
|
foreach ($z as $l => $w) |
|
699
|
|
|
$S[$l] = $w; |
|
700
|
|
|
} |
|
701
|
|
|
$out[$name]['langs'] = $S; |
|
|
|
|
|
|
702
|
|
|
if (isset($S[$this->lang_index]) || isset($S['C'])) |
|
703
|
|
|
$out[$name][0] = (isset($S[$this->lang_index])) ? $S[$this->lang_index] : $S['C']; |
|
|
|
|
|
|
704
|
|
|
} else { |
|
705
|
|
|
if (isset($temp[$name]['Method'])) |
|
706
|
|
|
$out[$name] = $temp[$name]['Method']; |
|
707
|
|
|
elseif (isset($temp[$name]['Profile'])) |
|
708
|
|
|
$out[$name] = $temp[$name]['Profile']; |
|
709
|
|
|
else |
|
710
|
|
|
$out[$name] = $temp[$name]['IdP']; |
|
711
|
|
|
} |
|
712
|
|
|
} |
|
713
|
|
|
return($out); |
|
714
|
|
|
} |
|
715
|
|
|
|
|
716
|
|
|
/** |
|
717
|
|
|
* |
|
718
|
|
|
*/ |
|
719
|
|
|
public function getSufficientConfig() { |
|
720
|
|
|
$result = DBConnection::exec($this->databaseType, "SELECT sufficient_config FROM profile WHERE profile_id = " . $this->identifier); |
|
721
|
|
|
$r = mysqli_fetch_row($result); |
|
722
|
|
|
/* echo "<pre>"; |
|
|
|
|
|
|
723
|
|
|
print_r($r); |
|
724
|
|
|
echo "</pre>"; */ |
|
725
|
|
|
if ($r[0] === NULL) { // we have never recorded the state; do it now |
|
726
|
|
|
// this case only occurs during DB migration from |
|
727
|
|
|
// 1.0 to 1.1 until everybody has run their profile |
|
728
|
|
|
// view or updated once |
|
729
|
|
|
$this->prepShowtime(); |
|
730
|
|
|
return $this->getSufficientConfig(); |
|
731
|
|
|
} elseif ($r[0] == "0") { |
|
732
|
|
|
return FALSE; |
|
733
|
|
|
} else { |
|
734
|
|
|
return TRUE; |
|
735
|
|
|
} |
|
736
|
|
|
} |
|
737
|
|
|
|
|
738
|
|
|
/** |
|
739
|
|
|
* Checks if the profile has enough information to have something to show to end users. This does not necessarily mean |
|
740
|
|
|
* that there's a fully configured EAP type - it is sufficient if a redirect has been set for at least one device. |
|
741
|
|
|
* |
|
742
|
|
|
* @return boolean TRUE if enough information for showtime is set; FALSE if not |
|
743
|
|
|
*/ |
|
744
|
|
|
public function readyForShowtime() { |
|
745
|
|
|
$proper_config = FALSE; |
|
746
|
|
|
$attribs = $this->getCollapsedAttributes(); |
|
747
|
|
|
// do we have enough to go live? Check if any of the configured EAP methods is completely configured ... |
|
748
|
|
|
if (sizeof($this->getEapMethodsinOrderOfPreference(1)) > 0) |
|
749
|
|
|
$proper_config = TRUE; |
|
750
|
|
|
// if not, it could still be that general redirect has been set |
|
751
|
|
|
if (!$proper_config) { |
|
752
|
|
|
if (isset($attribs['device-specific:redirect'])) |
|
753
|
|
|
$proper_config = TRUE; |
|
754
|
|
|
// TODO: or maybe just a per-device redirect? would be good enough... |
|
755
|
|
|
} |
|
756
|
|
|
// do we know at least one SSID to configure, or work with wired? If not, it's not ready... |
|
757
|
|
|
if (!isset($attribs['media:SSID']) && |
|
758
|
|
|
!isset($attribs['media:SSID_with_legacy']) && |
|
759
|
|
|
(!isset(Config::$CONSORTIUM['ssid']) || count(Config::$CONSORTIUM['ssid']) == 0) && |
|
760
|
|
|
!isset($attribs['media:wired'])) |
|
761
|
|
|
$proper_config = FALSE; |
|
762
|
|
|
return $proper_config; |
|
763
|
|
|
} |
|
764
|
|
|
|
|
765
|
|
|
/** |
|
766
|
|
|
* set the showtime and QR-user attributes if prepShowTime says that there is enough info *and* the admin flagged the profile for showing |
|
767
|
|
|
*/ |
|
768
|
|
|
public function prepShowtime() { |
|
769
|
|
|
$proper_config = $this->readyForShowtime(); |
|
770
|
|
|
if ($proper_config) |
|
771
|
|
|
DBConnection::exec($this->databaseType, "UPDATE profile SET sufficient_config = TRUE WHERE profile_id = " . $this->identifier); |
|
772
|
|
|
else |
|
773
|
|
|
DBConnection::exec($this->databaseType, "UPDATE profile SET sufficient_config = FALSE WHERE profile_id = " . $this->identifier); |
|
774
|
|
|
$attribs = $this->getCollapsedAttributes(); |
|
775
|
|
|
// if not enough info to go live, set FALSE |
|
776
|
|
|
// even if enough info is there, admin has the ultimate say: |
|
777
|
|
|
// if he doesn't want to go live, no further checks are needed, set FALSE as well |
|
778
|
|
|
if (!$proper_config || !isset($attribs['profile:production']) || (isset($attribs['profile:production']) && $attribs['profile:production'][0] != "on")) { |
|
779
|
|
|
DBConnection::exec($this->databaseType, "UPDATE profile SET showtime = FALSE WHERE profile_id = " . $this->identifier); |
|
780
|
|
|
return; |
|
781
|
|
|
} else { |
|
782
|
|
|
DBConnection::exec($this->databaseType, "UPDATE profile SET showtime = TRUE WHERE profile_id = " . $this->identifier); |
|
783
|
|
|
return; |
|
784
|
|
|
} |
|
785
|
|
|
} |
|
786
|
|
|
|
|
787
|
|
|
/** |
|
788
|
|
|
* Checks if the profile is shown (showable) to end users |
|
789
|
|
|
* @return boolean TRUE if profile is shown; FALSE if not |
|
790
|
|
|
*/ |
|
791
|
|
|
public function getShowtime() { |
|
792
|
|
|
$result = DBConnection::exec($this->databaseType, "SELECT showtime FROM profile WHERE profile_id = " . $this->identifier); |
|
793
|
|
|
$r = mysqli_fetch_row($result); |
|
794
|
|
|
/* echo "<pre>"; |
|
|
|
|
|
|
795
|
|
|
print_r($r); |
|
796
|
|
|
echo "</pre>"; */ |
|
797
|
|
|
if ($r[0] == "0") |
|
798
|
|
|
return FALSE; |
|
799
|
|
|
else |
|
800
|
|
|
return TRUE; |
|
801
|
|
|
} |
|
802
|
|
|
|
|
803
|
|
|
/** |
|
804
|
|
|
* current language |
|
805
|
|
|
* @var string |
|
806
|
|
|
*/ |
|
807
|
|
|
private $lang_index; |
|
808
|
|
|
|
|
809
|
|
|
/** |
|
810
|
|
|
* DB identifier of the parent institution of this profile |
|
811
|
|
|
* @var int |
|
812
|
|
|
*/ |
|
813
|
|
|
public $institution; |
|
814
|
|
|
|
|
815
|
|
|
/** |
|
816
|
|
|
* name of the parent institution of this profile in the current language |
|
817
|
|
|
* @var string |
|
818
|
|
|
*/ |
|
819
|
|
|
public $inst_name; |
|
820
|
|
|
|
|
821
|
|
|
/** |
|
822
|
|
|
* realm of this profile (empty string if unset) |
|
823
|
|
|
* @var string |
|
824
|
|
|
*/ |
|
825
|
|
|
public $realm; |
|
826
|
|
|
|
|
827
|
|
|
/** |
|
828
|
|
|
* boolean value: should anonymous outer IDs be used or not? |
|
829
|
|
|
* @var boolean |
|
830
|
|
|
*/ |
|
831
|
|
|
public $use_anon_outer; |
|
832
|
|
|
|
|
833
|
|
|
} |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return,dieorexitstatements that have been added for debug purposes.In the above example, the last
return falsewill never be executed, because a return statement has already been met in every possible execution path.