| Line 55... |
Line 55... |
| 55 |
*/
|
55 |
*/
|
| 56 |
|
56 |
|
| 57 |
class Users {
|
57 |
class Users {
|
| 58 |
|
58 |
|
| 59 |
/**
|
59 |
/**
|
| 60 |
* @var string[] $dbDefinition Contains the configuration for the class
|
60 |
* @var string[] $configuration Contains the configuration for the class
|
| 61 |
*
|
61 |
*
|
| 62 |
* May be modified by the calling program. Must be replicated in userDataSource class
|
62 |
* May be modified by the calling program. Must be replicated in userDataSource class
|
| 63 |
*/
|
63 |
*/
|
| 64 |
private $dbDefinition = array(
|
64 |
protected $configuration = array(
|
| 65 |
/*
|
65 |
/*
|
| 66 |
* what to use for html input fields
|
66 |
* what to use for html input fields
|
| 67 |
* These are passed to sprintf, with label, fieldname, title, placeholder and current value, in that order
|
67 |
* These are passed to sprintf, with label, fieldname, title, placeholder and current value, in that order
|
| 68 |
*/
|
68 |
*/
|
| 69 |
'screens' => array (
|
69 |
'screens' => array (
|
| Line 118... |
Line 118... |
| 118 |
) // table users
|
118 |
) // table users
|
| 119 |
) // tables
|
119 |
) // tables
|
| 120 |
);
|
120 |
);
|
| 121 |
|
121 |
|
| 122 |
/** @var string[] $data Contains the information for the current logged in user */
|
122 |
/** @var string[] $data Contains the information for the current logged in user */
|
| 123 |
private $data = array();
|
123 |
protected $data = array();
|
| 124 |
/** @var string[] $errors Contains errors that can occur */
|
124 |
/** @var string[] $errors Contains errors that can occur */
|
| 125 |
private $errors = array();
|
125 |
protected $errors = array();
|
| 126 |
/** @var string[] $workingOn During administration, contains the record being modified */
|
126 |
/** @var string[] $workingOn During administration, contains the record being modified */
|
| 127 |
private $workingOn = array();
|
127 |
protected $workingOn = array();
|
| 128 |
|
128 |
|
| 129 |
/**
|
129 |
/**
|
| 130 |
* constructor for an instance of the class
|
130 |
* constructor for an instance of the class
|
| 131 |
*
|
131 |
*
|
| 132 |
* Anything in $customFields will be recursively merged with $dbDefinition, overwriting
|
132 |
* Anything in $customFields will be recursively merged with $configuration, overwriting
|
| 133 |
* as necessary.
|
133 |
* as necessary.
|
| 134 |
*
|
134 |
*
|
| 135 |
* @param string[] $customFields array to merge into $dbDefinition
|
135 |
* @param string[] $customFields array to merge into $configuration
|
| 136 |
*/
|
136 |
*/
|
| 137 |
public function __construct( $customFields = array() ) {
|
137 |
public function __construct( $customFields = array() ) {
|
| 138 |
if ( $customFields ) {
|
138 |
if ( $customFields ) {
|
| 139 |
$this->dbDefinition = array_merge_recursive( $this->dbDefinition, $customFields );
|
139 |
$this->configuration = array_merge_recursive( $this->configuration, $customFields );
|
| 140 |
}
|
140 |
}
|
| 141 |
} // constructor
|
141 |
} // constructor
|
| 142 |
|
142 |
|
| 143 |
/**
|
143 |
/**
|
| 144 |
* getter for $this->errors
|
144 |
* getter for $this->errors
|
| Line 202... |
Line 202... |
| 202 |
/**
|
202 |
/**
|
| 203 |
* Validates a connection and, on success, populates $data
|
203 |
* Validates a connection and, on success, populates $data
|
| 204 |
*
|
204 |
*
|
| 205 |
* Function will validate the username and password passed in, using
|
205 |
* Function will validate the username and password passed in, using
|
| 206 |
* data connection $connection. On success, populates class member $data
|
206 |
* data connection $connection. On success, populates class member $data
|
| 207 |
* with the values from the database (only those listed in $dbDefinition)
|
207 |
* with the values from the database (only those listed in $configuration)
|
| 208 |
*
|
208 |
*
|
| 209 |
* On Failure, appends $error with a failure string
|
209 |
* On Failure, appends $error with a failure string
|
| 210 |
*
|
210 |
*
|
| 211 |
* @param string $username The username to be matched in database
|
211 |
* @param string $username The username to be matched in database
|
| 212 |
* @param string $password The password (unencrypted) the user entered
|
212 |
* @param string $password The password (unencrypted) the user entered
|
| 213 |
* @param usersDataSource $connection A connection to the data source
|
213 |
* @param usersDataSource $connection A connection to the data source
|
| 214 |
*
|
214 |
*
|
| 215 |
*/
|
215 |
*/
|
| 216 |
private function validate( $username, $password, $connection ) {
|
216 |
protected function validate( $username, $password, $connection ) {
|
| 217 |
$result = $connection->getPassword( $username );
|
217 |
$result = $connection->getPassword( $username );
|
| 218 |
if ( password_verify( $password, $result['pass'] ) ) {
|
218 |
if ( password_verify( $password, $result['pass'] ) ) {
|
| 219 |
$result = $connection->getRecord( $username );
|
219 |
$result = $connection->getRecord( $username );
|
| 220 |
$this->data['id'] = $result['id'];
|
220 |
$this->data['id'] = $result['id'];
|
| 221 |
foreach ( $this->dbDefinition['tables']['users']['fields'] as $key => $record ) {
|
221 |
foreach ( $this->configuration['tables']['users']['fields'] as $key => $record ) {
|
| 222 |
if ( $key != 'pass' )
|
222 |
if ( $key != 'pass' )
|
| 223 |
$this->data[$key] = $result[$key];
|
223 |
$this->data[$key] = $result[$key];
|
| 224 |
}
|
224 |
}
|
| 225 |
} else {
|
225 |
} else {
|
| 226 |
$this->errors[] = 'Login Failed: Unknown username or password';
|
226 |
$this->errors[] = 'Login Failed: Unknown username or password';
|
| 227 |
foreach ( $this->dbDefinition['tables']['users']['fields'] as $key => $record ) {
|
227 |
foreach ( $this->configuration['tables']['users']['fields'] as $key => $record ) {
|
| 228 |
$this->data[$key] = null;
|
228 |
$this->data[$key] = null;
|
| 229 |
}
|
229 |
}
|
| 230 |
}
|
230 |
}
|
| 231 |
} // validate
|
231 |
} // validate
|
| 232 |
|
232 |
|
| Line 275... |
Line 275... |
| 275 |
/**
|
275 |
/**
|
| 276 |
* Simple helper script to calculate next script to call
|
276 |
* Simple helper script to calculate next script to call
|
| 277 |
*
|
277 |
*
|
| 278 |
* Returns one of three URL strings, in order of precedence
|
278 |
* Returns one of three URL strings, in order of precedence
|
| 279 |
* $nextScript
|
279 |
* $nextScript
|
| 280 |
* $dbDefinition['screens']['validateScript']
|
280 |
* $configuration['screens']['validateScript']
|
| 281 |
* PHP_SELF
|
281 |
* PHP_SELF
|
| 282 |
*
|
282 |
*
|
| 283 |
* @param string $nextScript URL to call
|
283 |
* @param string $nextScript URL to call
|
| 284 |
* @return string URL
|
284 |
* @return string URL
|
| 285 |
*/
|
285 |
*/
|
| 286 |
private function getNextScript( $nextScript = null ) {
|
286 |
protected function getNextScript( $nextScript = null ) {
|
| 287 |
if ( ! isset( $nextScript ) ) {
|
287 |
if ( ! isset( $nextScript ) ) {
|
| 288 |
$nextScript = $this->dbDefinition['screens']['validateScript'] ?:
|
288 |
$nextScript = $this->configuration['screens']['validateScript'] ?:
|
| 289 |
htmlentities($_SERVER["PHP_SELF"]);
|
289 |
htmlentities($_SERVER["PHP_SELF"]);
|
| 290 |
}
|
290 |
}
|
| 291 |
return $nextScript;
|
291 |
return $nextScript;
|
| 292 |
}
|
292 |
}
|
| 293 |
|
293 |
|
| Line 299... |
Line 299... |
| 299 |
*
|
299 |
*
|
| 300 |
* @param string $nextScript URL to call form
|
300 |
* @param string $nextScript URL to call form
|
| 301 |
*
|
301 |
*
|
| 302 |
* @return string HTML code for display
|
302 |
* @return string HTML code for display
|
| 303 |
*/
|
303 |
*/
|
| 304 |
private function logInScreen( $nextScript = null ) {
|
304 |
protected function logInScreen( $nextScript = null ) {
|
| 305 |
$return = sprintf(
|
305 |
$return = sprintf(
|
| 306 |
$this->dbDefinition['screens']['login form'],
|
306 |
$this->configuration['screens']['login form'],
|
| 307 |
$this->getNextScript( $nextScript ),
|
307 |
$this->getNextScript( $nextScript ),
|
| 308 |
$this->dbDefinition['screens']['loginScreen']
|
308 |
$this->configuration['screens']['loginScreen']
|
| 309 |
);
|
309 |
);
|
| 310 |
$return .= $this->errors();
|
310 |
$return .= $this->errors();
|
| 311 |
$this->clearErrors();
|
311 |
$this->clearErrors();
|
| 312 |
return $return;
|
312 |
return $return;
|
| 313 |
}
|
313 |
}
|
| Line 326... |
Line 326... |
| 326 |
*
|
326 |
*
|
| 327 |
* Knows how to handle INPUT types TEXT, TEXTAREA, PASSWORD and
|
327 |
* Knows how to handle INPUT types TEXT, TEXTAREA, PASSWORD and
|
| 328 |
* special html type boolean, which is checkboxes.
|
328 |
* special html type boolean, which is checkboxes.
|
| 329 |
*
|
329 |
*
|
| 330 |
* @param string $field name of the field to populate
|
330 |
* @param string $field name of the field to populate
|
| 331 |
* @param string[] $record Record from $dbDefinition[...][fields]
|
331 |
* @param string[] $record Record from $configuration[...][fields]
|
| 332 |
* @param string $value the current value to put in INPUT
|
332 |
* @param string $value the current value to put in INPUT
|
| 333 |
*
|
333 |
*
|
| 334 |
* @return string An HTML INPUT entity
|
334 |
* @return string An HTML INPUT entity
|
| 335 |
*/
|
335 |
*/
|
| 336 |
private function makeHTMLField ( $field, $record, $value ) {
|
336 |
protected function makeHTMLField ( $field, $record, $value ) {
|
| 337 |
$return = array();
|
337 |
$return = array();
|
| 338 |
$temp = sprintf( $this->dbDefinition['html input fields'][$record['html type']],
|
338 |
$temp = sprintf( $this->configuration['html input fields'][$record['html type']],
|
| 339 |
$record['label'] ?: $field,
|
339 |
$record['label'] ?: $field,
|
| 340 |
$this->dbDefinition['input prefix'] . $field,
|
340 |
$this->configuration['input prefix'] . $field,
|
| 341 |
!empty($record['instructions']) ? $record['instructions'] : '',
|
341 |
!empty($record['instructions']) ? $record['instructions'] : '',
|
| 342 |
!empty($record['hint']) ? $record['hint'] : '',
|
342 |
!empty($record['hint']) ? $record['hint'] : '',
|
| 343 |
$field
|
343 |
$field
|
| 344 |
);
|
344 |
);
|
| 345 |
|
345 |
|
| Line 373... |
Line 373... |
| 373 |
*
|
373 |
*
|
| 374 |
* @return string HTML containing all of the INPUT records a user can edit
|
374 |
* @return string HTML containing all of the INPUT records a user can edit
|
| 375 |
*/
|
375 |
*/
|
| 376 |
public function editScreen() {
|
376 |
public function editScreen() {
|
| 377 |
$return = array();
|
377 |
$return = array();
|
| 378 |
$return[] = $this->dbDefinition['screens']['adminScreen'];
|
378 |
$return[] = $this->configuration['screens']['adminScreen'];
|
| 379 |
$return[] = "<input type='hidden' name='id' value=" . $this->workingOn['id'] . "'>\n";
|
379 |
$return[] = "<input type='hidden' name='id' value=" . $this->workingOn['id'] . "'>\n";
|
| 380 |
foreach ( $this->dbDefinition['tables']['users']['fields'] as $field => $record ) {
|
380 |
foreach ( $this->configuration['tables']['users']['fields'] as $field => $record ) {
|
| 381 |
// if this field is restricted and we are not admin, just skip it
|
381 |
// if this field is restricted and we are not admin, just skip it
|
| 382 |
// also skip if it is our record
|
382 |
// also skip if it is our record
|
| 383 |
if ( isset( $record['restrict'] ) && ( $this->data['id'] == $this->workingOn['id'] ) )
|
383 |
if ( isset( $record['restrict'] ) && ( $this->data['id'] == $this->workingOn['id'] ) )
|
| 384 |
continue;
|
384 |
continue;
|
| 385 |
// now process the field
|
385 |
// now process the field
|
| Line 393... |
Line 393... |
| 393 |
*
|
393 |
*
|
| 394 |
* Initializes all fields to something non-null and sets id to -1
|
394 |
* Initializes all fields to something non-null and sets id to -1
|
| 395 |
*
|
395 |
*
|
| 396 |
* @return string[] An array initialized with all records needed
|
396 |
* @return string[] An array initialized with all records needed
|
| 397 |
*/
|
397 |
*/
|
| 398 |
private function emptyWorkingOn() {
|
398 |
protected function emptyWorkingOn() {
|
| 399 |
$new = array();
|
399 |
$new = array();
|
| 400 |
$new['id'] = -1;
|
400 |
$new['id'] = -1;
|
| 401 |
foreach ( $this->dbDefinition['tables']['users']['fields'] as $field => $record ) {
|
401 |
foreach ( $this->configuration['tables']['users']['fields'] as $field => $record ) {
|
| 402 |
if ( isset( $record['default'] ) ) {
|
402 |
if ( isset( $record['default'] ) ) {
|
| 403 |
$new[$field] = $record['default'];
|
403 |
$new[$field] = $record['default'];
|
| 404 |
} else {
|
404 |
} else {
|
| 405 |
switch ($record['html type']) {
|
405 |
switch ($record['html type']) {
|
| 406 |
case 'text' :
|
406 |
case 'text' :
|
| Line 455... |
Line 455... |
| 455 |
// default to working on ourself
|
455 |
// default to working on ourself
|
| 456 |
if ( ! ( isset( $this->workingOn ) && count( $this->workingOn ) ) ) {
|
456 |
if ( ! ( isset( $this->workingOn ) && count( $this->workingOn ) ) ) {
|
| 457 |
$this->workingOn = $this->data;
|
457 |
$this->workingOn = $this->data;
|
| 458 |
}
|
458 |
}
|
| 459 |
// we have no data, so we should create a form for them to enter something
|
459 |
// we have no data, so we should create a form for them to enter something
|
| 460 |
if ( ! isset( $_REQUEST[$this->dbDefinition['input prefix'] . $this->dbDefinition['tables']['users']['form test']] ) ) {
|
460 |
if ( ! isset( $_REQUEST[$this->configuration['input prefix'] . $this->configuration['tables']['users']['form test']] ) ) {
|
| 461 |
// create the screen
|
461 |
// create the screen
|
| 462 |
$return = $this->editScreen();
|
462 |
$return = $this->editScreen();
|
| 463 |
if ( $this->data['admin'] ) {
|
463 |
if ( $this->data['admin'] ) {
|
| 464 |
$return .= $this->allUsersHTML( $connection );
|
464 |
$return .= $this->allUsersHTML( $connection );
|
| 465 |
}
|
465 |
}
|
| 466 |
return sprintf( $this->dbDefinition['screens']['edit form'],
|
466 |
return sprintf( $this->configuration['screens']['edit form'],
|
| 467 |
$nextScript,
|
467 |
$nextScript,
|
| 468 |
$return
|
468 |
$return
|
| 469 |
);
|
469 |
);
|
| 470 |
} else { // we are processing
|
470 |
} else { // we are processing
|
| 471 |
$data = array();
|
471 |
$data = array();
|
| 472 |
foreach ( $this->dbDefinition['tables']['users']['fields'] as $field => $record ) {
|
472 |
foreach ( $this->configuration['tables']['users']['fields'] as $field => $record ) {
|
| 473 |
// if this field is restricted it is our record, skip it
|
473 |
// if this field is restricted it is our record, skip it
|
| 474 |
if ( isset( $record['restrict'] ) && ( $this->data['id'] == $this->workingOn['id'] ) )
|
474 |
if ( isset( $record['restrict'] ) && ( $this->data['id'] == $this->workingOn['id'] ) )
|
| 475 |
continue;
|
475 |
continue;
|
| 476 |
$htmlFieldName = $this->dbDefinition['input prefix'] . $field;
|
476 |
$htmlFieldName = $this->configuration['input prefix'] . $field;
|
| 477 |
$temp = '';
|
477 |
$temp = '';
|
| 478 |
switch ( $record['html type'] ) {
|
478 |
switch ( $record['html type'] ) {
|
| 479 |
case 'password':
|
479 |
case 'password':
|
| 480 |
if ( ! empty( $_REQUEST[$htmlFieldName] ) ) {
|
480 |
if ( ! empty( $_REQUEST[$htmlFieldName] ) ) {
|
| 481 |
$data[$field] = password_hash( $_REQUEST[$htmlFieldName], PASSWORD_DEFAULT );
|
481 |
$data[$field] = password_hash( $_REQUEST[$htmlFieldName], PASSWORD_DEFAULT );
|
| 482 |
if ( isset( $this->dbDefinition['tables']['users']['fields']['last password change'] ) ) {
|
482 |
if ( isset( $this->configuration['tables']['users']['fields']['last password change'] ) ) {
|
| 483 |
$data['last password change'] = date("YmdHis");
|
483 |
$data['last password change'] = date("YmdHis");
|
| 484 |
}
|
484 |
}
|
| 485 |
}
|
485 |
}
|
| 486 |
break;
|
486 |
break;
|
| 487 |
case 'boolean' :
|
487 |
case 'boolean' :
|