null, 'success' => null, 'notice' => null]; private static $userId = null; /** Returns the current login status * * The login status is stored in the session cookie. If it is not even set it means the login is invalid. * * @return bool true if the login status is true, false otherwise */ public static function isLoginValid() { return (isset($_SESSION) && array_key_exists('login', $_SESSION) && $_SESSION['login'] == true); } /** Remove all login data from the session data * * @return void */ public static function logout() { foreach (['login', 'user'] as $key) { unset($_SESSION[$key]); } } /** A little Box with the login status as html entity * * @return string htmlEntity showing the login status */ public static function htmlLoginStatus() { return '
' . 'Datum: ' . date('Y-m-d') . '
' . 'Angemeldet als ' . htmlspecialchars($_SESSION['user']['username']) . '.
' . 'Sitzung beenden' . '
'; } /** Checking if an action is allowed. A present apiKey overrides (and deletes) a present login. * * 1. If apiKey is present: * - chancel current login * - If apiKey is valid for requested action: * - set some session data * - return * 2. If there is a valid Login session: * - return * 3. redirect to Login Page * * @todo rename to authenticate (authorize?) * * @param $action the action we want to get authorized for (default=['login']) * * @retval void */ public static function authentificate($action = ['login']) { // Ensure a session is started session_start(); // check if an apiKey was received if (array_key_exists('apiKey', $_GET)) { self::logout(); $key = ApiKey::loadFromDb($_GET['apiKey']); if (isset($key) && $key->isValidFor($action)) { $user = User::loadFromDb($key->getUserId()); // case valid login: Set the session data $_SESSION = [ 'login' => true, //false, 'apiKey' => $key->getKey(), 'user' => [ 'username' => $user->getLoginName(), 'userId' => $user->getId(), 'userConfig' => $user->getConfig(), ] ]; // we're not logged in, but authorized for the stuff we want to do. So don't redirect return; }; } // if not returned yet: no login, no valid apiKey -> redirect to login page if (!self::isLoginValid()) { header('Location: login?returnToUrl=' . urlencode($_SERVER['REQUEST_URI'] . ($_POST['fragment'] ?? '')), true, 301); exit(); // shouldn't matter } } public static function getMessages() { return self::$message; } public static function addMessage($type, $message) { self::$message[$type] = (self::$message[$type] ?? '') . $message; } /** check password for user * * @param string $loginName user who wants to get in * @param string $password password for the user * * @retval true $password belongs to $loginName * @retval false otherwise */ public static function checkCredentials($loginName, $password) { sleep(1); // just to discourage brute force attacks // Check for dbConnection if (!dbConnector::getDbConnection()) { self::addMessage('error', '
No DbConnection available
'); return false; } $user = User::loadFromDbByLoginName($loginName); // If there is no such user OR the password isn't valid the login fails if ($user == null || !$user->verifyPassword($password)) { sleep(5); // discourage brute force attacks self::addMessage('error', '
Falsches Passwort oder LoginName
'); return false; } session_start(); // case valid login: Set the session data $_SESSION = [ 'login' => true, 'user' => [ 'username' => $user->getLoginName(), 'userId' => $user->getId(), 'userConfig' => json_decode($user->getConfig(), true) ] ]; // Logging Logins logLoginsToJsonFile($_SESSION['user']['username']); self::addMessage('success', '
Anmeldung erfolgreich
'); return true; } /** Checks, if a user is an admin * * @param [type] $userId id of the user to check * @retval true user with id $userId has attribute "isAdmin" * @retval false otherwise */ public static function isUserAdmin($userId) { return self::hasUserAttribute($userId, 'isAdmin'); } public static function getKids($userId = null) { $userId = $userId ?? $_SESSION['user']['userId'] ?? null; $query = 'SELECT * FROM `wkParticipo_Users` ' . 'INNER JOIN `vormundschaft` ON `wkParticipo_Users`.`id` = `vormundschaft`.`kidId` ' . 'WHERE `vormundschaft`.`userId` = :userId;'; $params = [':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT]]; $response = dbConnector::query($query, $params); $kids = []; foreach ($response as $r) { $kids[] = User::fromDbArray($r, ['id' => 'kidId']); } return $kids; } /** Check if one user is ward of another * * @param integer $kidId ID of the ward * @param integer|null $userId ID of the guardian, if null it is tried to read it from the session data * @return boolean true if kid is ward of user, false otherwise */ public static function isWardOf(int $kidId, int $userId = null) { // Try to get the Guard from the session data. $userId = $userId ?? $_SESSION['user']['userId'] ?? null; $query = 'SELECT `kidId` FROM `vormundschaft` WHERE `userId` = :userId AND `kidId` = :kidId;'; $params = [ ':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT], ':kidId' => ['value' => $kidId, 'data_type' => PDO::PARAM_INT] ]; $response = dbConnector::query($query, $params); return (count($response) >= 1); } /** Checks, if a user as a certain attribute * * @param [type] $userId id of the user to check * @param [type] $attributeName string name of the attribute to check * @return boolean */ public static function hasUserAttribute($userId, $attributeName) { // sqlQuery: Select the user if it has the given attribute $query = <<userAttributes`.userId, `wkParticipo_userAttributes`.name FROM `wkParticipo_user<=>userAttributes` LEFT JOIN `wkParticipo_userAttributes` ON `wkParticipo_user<=>userAttributes`.`attributeId` = `wkParticipo_userAttributes`.`id` WHERE `wkParticipo_userAttributes`.name = :attributeName AND userId=:userId; SQL; $params = [ ':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT], ':attributeName' => ['value' => $attributeName, 'data_type' => PDO::PARAM_STR] ]; $attributedUsers = dbConnector::query($query, $params); // Since the id should be unique, there should only be one result this is just for dealing with empty arrays foreach ($attributedUsers as $u) { if ($u['userId'] == $userId) { return true; } } return false; } public static function getEventStarter($sinceDate = null) { $userId = $_SESSION['user']['userId']; if (!$sinceDate) { $sinceDate = 'CURDATE()'; } else { $sinceDate = 'DATE("' . $sinceDate . '")'; } $query = <<= $sinceDate AND `vormundschaft`.`userId` = $userId ORDER BY `wkParticipo_Events`.`date` DESC; SQL; $comingStarts = dbConnector::query($query); return $comingStarts; } } /** Action element of an MaterializeCss (App-)card */ class AppCardAction { private $caption = null; //< Caption for the action private $link = '.'; //< link for the action /** Constructor for the AppAction * * @param string $caption caption for the action * @param string $link link to the action */ public function __construct($caption, $link = '.') { //! @todo input sanitation $this->link = $link; $this->caption = $caption; } /** Create htmlCode for the action * * @return string with htmlCode of the action */ public function htmlCode() { return '' . $this->caption . ''; } /** Create AppCardAction from assoziative array * * @param array $member array with the member values * @return AppCardAction */ public static function fromArray($member) { $caption = $member['caption'] ?? null; $link = $member['link'] ?? '.'; return new AppCardAction($caption, $link); } } /** MaterializeCss card for an App */ class AppCard { private $title = ''; //< title of the card private $description = ''; //< description of the App private $link = null; //< link for the card-content private $imgUrl = null; //< url for an image right under the title private $actionList = []; //< list of actions for the bottom of the card /** * Constructor for the AppCard * * @param string $title title of the card * @param string $description description of the card * @param string $link link for the card-content * @param string $imgUrl url for an image right under the title * @param array $actionList list of actions at the bottom of the card */ public function __construct($title, $description, $link = null, $imgUrl = null, $actionList = []) { //! @todo input sanitation $this->title = $title; $this->description = $description; $this->link = $link; $this->imgUrl = $imgUrl; $this->actionList = $actionList; } /** * Create htmlCode for the AppCard * * @return string html code for the AppCard */ public function htmlCode($options = []) { $extraClass = $options['extraClass'] ?? ''; $actionListCode = ''; foreach ($this->actionList as $a) { $actionListCode .= $a->htmlCode(); } return '
' . '
' . '
' . (($this->link != null) ? ('') : ('')) . '' . $this->title . '' . (($this->link != null) ? ('') : ('')) . (($this->imgUrl != null) ? ('' . $this->title . '') : ('')) . '

' . $this->description . '

' . '
' . '
' . $actionListCode . '
' . '
' . '
'; } /** * Create AppCard from an associative array * * @param array $member array with member as keys and values as the member values * @return AppCard from array values */ public static function fromArray($member) { $title = $member['title'] ?? ''; $description = $member['description'] ?? ''; $link = $member['link'] ?? null; $imgUrl = $member['imgUrl'] ?? null; $actionList = $member['actions'] ?? []; return new AppCard($title, $description, $link, $imgUrl, $actionList); } } /** Generate a html table of the last logins of the users * * @param string $jsonFileName path to the json file with the logged logins * @return string Html table of users last logins */ function lastLoginTable($jsonFileName = 'lastLogins.json') { $lastLogins = json_decode(file_get_contents($jsonFileName), true); $lastLoginsTable = '' . '' . ''; foreach ($lastLogins as $userName => $lastLogins) { $lastLoginsTable .= ''; } $lastLoginsTable .= '
userNamelastLogins
' . $userName . '' . $lastLogins['lastLogins'][0] . '
'; return $lastLoginsTable; } /// Eine Fehler/Warnung/Notiz/Erfolgsmeldung als divBox im String zurückgeben function htmlRetMessage($anRetMessage) { $retHtmlString = ''; if (!empty($anRetMessage)) { $retHtmlString .= '
'; if (!empty($anRetMessage['error'])) { $retHtmlString .= '
'; $retHtmlString .= 'ERROR:
'; $retHtmlString .= $anRetMessage['error']; $retHtmlString .= '
'; } if (!empty($anRetMessage['warning'])) { $retHtmlString .= '
'; $retHtmlString .= 'WARNING:
'; $retHtmlString .= $anRetMessage['warning']; $retHtmlString .= '
'; } if (!empty($anRetMessage['notice'])) { $retHtmlString .= '
'; $retHtmlString .= 'Info:
'; $retHtmlString .= $anRetMessage['notice']; $retHtmlString .= '
'; } if (!empty($anRetMessage['success'])) { $retHtmlString .= '
'; $retHtmlString .= 'SUCCESS:
'; $retHtmlString .= $anRetMessage['success']; $retHtmlString .= '
'; } $retHtmlString .= '
'; } return $retHtmlString; } /** load a MarkdownFile with yaml header * * @param string $fileName filename of the markdown file * @return array associative array('yaml'=>array(..), 'mdText'=>string) containing the yamlHeader as associative array and the markdown text as string */ function loadMarkdownFile($fileName) { // load the whole file $fileText = file_get_contents($fileName); // split at '---' to get ((),yamls,array) $fileParts = preg_split('/[\n]*[-]{3}[\n]/', $fileText, 3); // not all mdFiles have a yamlHeader, so the mdText can be at different indices $yaml = []; $mdText = ''; switch(count($fileParts)) { case 1:{ $mdText = $fileParts[0]; break; } case 3:{ $yaml = Spyc::YAMLLoadString($fileParts[1]); $mdText = $fileParts[2]; break; } default:{ $mdText = $fileText; } } // get a title, if none is in the markdown if (!array_key_exists('title', $yaml)) { // find the first heading, set it as header and remove it from the markdown if (preg_match('/^#(.*)$/m', $mdText, $matches)) { $yaml['title'] = $matches[1]; $mdText = preg_replace('/^#(.*)$/m', '', $mdText, 1); } else { // fallback for the title, if not even one heading is found $yaml['title'] = ''; } } return [ 'yaml' => $yaml, 'mdText' => $mdText ]; } /** Log the Login of an user into a logFile * * @param string $userName name of the user * @param string $fileName filename to log to * @return void */ function logLoginsToJsonFile($userName, $fileName = 'lastLogins.json') { try { $lastLogins = json_decode(file_get_contents($fileName), true); if ($lastLogins == null) { return; } if (!array_key_exists($userName, $lastLogins)) { $lastLogins[$userName] = []; } if (!array_key_exists('lastLogins', $lastLogins[$userName])) { $lastLogins[$userName]['lastLogins'] = []; } $lastLogins[$userName]['lastLogins'] = array_merge([date('Y-m-d H:i:s')], $lastLogins[$userName]['lastLogins']); file_put_contents($fileName, json_encode($lastLogins)); } catch (Exception $e) { // silently ignore errors } } /// @brief Gibt die URL der gerade aufgerufenen Seite zurück function getCurPagesUrl() { $pageURL = 'http'; if ($_SERVER['HTTPS'] == 'on') { $pageURL .= 's'; } $pageURL .= '://'; if ($_SERVER['SERVER_PORT'] != '80') { $pageURL .= $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI']; } else { $pageURL .= $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; } return $pageURL; }