createPublicMenuItems(); $this->createInternalMenuItems(); if (!isset($_SESSION['userid'])) { $_SESSION['userid'] = 0; } $scriptName = $this->getScriptName(); if (!in_array($scriptName, array_merge($this->menuItems, $this->internalMenuItems))) { header('Location: /', true, 301); return; } $this->templateName = $templateName ?: (!in_array($scriptName, ['ffajs', 'fvajs', '', '/']) ? $scriptName : 'index'); $this->connectDb(); } private function createPublicMenuItems(): void { $this->menuItems = $this->getMenuItemsFromFile('publicpages'); } private function createInternalMenuItems(): void { $this->internalMenuItems = $this->getMenuItemsFromFile('internalpages'); } private function getMenuItemsFromFile(string $fileName): array { $items = json_decode(file_get_contents('conf/' . $fileName . '.conf')); $menu = []; foreach ($items as $url => $caption) { $menu[($caption !== '' ? $caption : '$hidden:0' . $this->hiddenCount++)] = $url; } return $menu; } public function getScriptName(): string { return $this->getSplittedUri()[0]; } public function getUrl(): string { return filter_input(INPUT_SERVER, 'REQUEST_URI'); } protected function getUriParams(): array { $paramPairs = explode('&', $this->getSplittedUri()[1]); $result = []; foreach ($paramPairs as $paramPair) { $pair = explode('=', $paramPair); if (count($pair) === 2) { $result[$pair[0]] = $pair[1]; } } return $result; } protected function getSplittedUri(): array { $scriptNameParts = pathinfo(filter_input(INPUT_SERVER, 'REQUEST_URI')); $uri = $scriptNameParts['filename'] ?: 'index'; return explode('?', $uri); } private function connectDb(): void { $user = 'ffajs'; $password = 'BpAJSis1999xx'; $host = 'tsschulz.de'; $port = 3306; $db = 'ffajs'; $this->dbConnection = mysqli_connect($host, $user, $password, $db, $port); } public function render(): void { if (trim(filter_input(INPUT_POST, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS)) !== '') { $this->formAction(); } $this->website = file_get_contents('templates/page.html'); $this->header(); $this->menu(); if ($_SESSION['userid'] === 0 && in_array($this->getScriptName() , $this->internalMenuItems, false)) { $this->templateName = 'login_error'; } $this->body(); $this->footer(); echo $this->website; } private function header(): void { $this->website = str_replace('{{header}}', file_get_contents('templates/header.html'), $this->website); } private function menu(): void { $menu = ''; $scriptName = $this->getScriptName(); foreach ($this->menuItems as $page => $link) { if (substr($page, 0, 8) === '$hidden:') { continue; } $menu .= '' . $page . ''; } if (isset($_SESSION) && $_SESSION['userid'] === 0) { $menu .= 'login'; } else { $menu .= '
Verwaltung
'; foreach ($this->internalMenuItems as $page => $link) { if (substr($page, 0, 8) === '$hidden:') { continue; } $menu .= '' . $page . ''; } $menu .= '
'; $menu .= 'logout'; } $menu .= '
'; $this->website = str_replace('{{menu}}', $menu, $this->website); } protected function body(): void { $this->generateContent(); $rawContent = file_get_contents('templates/' . $this->templateName . '.html'); $errorHtml = count($this->errors) > 0 ? '
' . implode('
', $this->errors) . '
' : ''; $messagesHtml = count($this->messages) > 0 ? '
' . implode('
', $this->messages) . '
' : ''; $placeholders = ['{{errors}}', '{{form}}', '{{messages}}']; $renderedContent = [$errorHtml, $this->renderForm(), $messagesHtml]; foreach ($this->content as $placeholder => $html) { $placeholders[] = '{{' . $placeholder . '}}'; $renderedContent[] = $html; } $content = str_replace($placeholders, $renderedContent, $rawContent); $this->website = str_replace('{{content}}', $content, $this->website); } private function footer(): void { $this->website = str_replace('{{footer}}', file_get_contents('templates/footer.html'), $this->website); } protected function showInputField(array $errors, string $inputType, string $fieldName, int $fieldLength): void { echo ''; if (isset($errors[$fieldName])) { echo '' . $errors[$fieldName] . ''; } } protected function renderForm(): string { $form = '
'; $label = ''; $input = ''; $error = ''; for ($formFieldIndex = 0; $formFieldIndex < count($this->formFields); ++$formFieldIndex) { $newLabelExtension = $this->renderLabel($formFieldIndex); $label .= (strlen($label) > 0 && strlen($newLabelExtension) > 0 ? ' / ' : '') . $newLabelExtension; $input .= $this->renderInput($formFieldIndex); if (isset($this->formFields[$formFieldIndex]['name']) && isset($this->errors[$this->formFields[$formFieldIndex]['name'] ])) { $error .= '' . $this->errors[$this->formFields[$formFieldIndex]['name'] ] . ''; } if (!isset($this->formFields[$formFieldIndex]['combine_with_next_line'] ) || !$this->formFields[$formFieldIndex]['combine_with_next_line']) { $form .= ''; $label = ''; $input = ''; $error = ''; } } $form .= '
' . $label . '' . $input . '' . $error . '
'; if (!$this->isAjaxForm) { $form .= ''; } $form .= ''; $form .= '
'; return $form; } protected function renderLabel(int $index): string { if (!isset($this->formFields[$index]['name']) && !isset($this->formFields[$index]['label'])) { return ''; } elseif (isset($this->formFields[$index]['label'])) { return $this->formFields[$index]['label']; } return ''; } protected function renderInput(int $index): string { if ($this->formFields[$index]['type'] === 'combobox') { return $this->renderCombobox($index); } if ($this->formFields[$index]['type'] === 'textarea') { return $this->renderTextarea($index); } if ($this->formFields[$index]['type'] === 'infotext') { return ''; } if ($this->formFields[$index]['type'] === 'dbselect') { return $this->renderDbSelect($index); } if ($this->formFields[$index]['type'] === 'spacer') { return ' '; } if ($this->formFields[$index]['type'] === 'button') { return $this->renderButton($index); } return $this->renderStandardInput($index); } protected function renderCombobox(int $index): string { $inputField = ''; return $inputField; } protected function renderStandardInput(int $index): string { return ''; } protected function renderTextarea(int $index): string { return ''; } protected function renderDbSelect(int $index): string { $query = 'SELECT `id`, `' . $this->formFields[$index]['optionfield'] . '` as label FROM `' . $this->formFields[$index]['sourcedb'] . '` ORDER BY `id`'; $dbResult = mysqli_query($this->dbConnection, $query); $inputValue = $this->inputValue($index); $selectField = ''; return $selectField; } protected function renderButton(int $index): string { return ''; } protected function inputValue($index): string { if (isset($this->formFields[$index]['value'])) { return $this->formFields[$index]['value']; } elseif ($this->cleanFields) { return ''; } $value = filter_input(INPUT_POST, $this->formFields[$index]['name'], FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?: ''; if (trim($value) === '' && isset($this->predefines[$this->formFields[$index]['name']])) { $value = $this->predefines[$this->formFields[$index]['name']]; } return $value; } protected function formAction(): void { } protected function formCheckFields(): bool { foreach ($this->formFields as $field) { $value = filter_input(INPUT_POST, $field['name'], isset($field['filter']) ? $field['filter'] : FILTER_SANITIZE_FULL_SPECIAL_CHARS); if (isset($field['optional']) && ($field['optional'] == false) && trim($value) === '' && $field['type'] !== 'file') { $this->errors[$field['name']] = 'Das Feld darf nicht leer sein'; continue; } if (isset($field['regex']) && !preg_match($field['regex'], $value)) { $this->errors[$field['name']] = 'Inkorrekte eingabe'; } } return count($this->errors) === 0; } protected function createDbInsert(): string { $preparedFieldData = $this->createDbKeyValues(); return 'INSERT INTO `' . $this->dbTable . '` (' . implode(', ', $preparedFieldData['keys']) . ') VALUES (' . implode(', ', $preparedFieldData['values']) . ')'; } protected function createKeyValuePairsForUpdate(array $data): string { $resultArray = []; $numEntries = count($data['keys']); for ($i = 0; $i < $numEntries; ++$i) { $resultArray[] = $data['keys'][$i] . ' = ' . $data['values'][$i]; } return implode(', ', $resultArray); } protected function createDbUpdate(): string { $preparedFieldData = $this->createDbKeyValues(); $query = 'UPDATE `' . $this->dbTable . '` SET '; $query .= $this->createKeyValuePairsForUpdate($preparedFieldData); $query .= ' WHERE `id` = ' . $this->getUriParams()['id']; return $query; } protected function saveToDb(): void { $query = $this->dbUpdate ? $this->createDbUpdate() : $this->createDbInsert(); mysqli_query($this->dbConnection, $query); } protected function createDbKeyValues(): array { $keysArray = []; $valuesArray = []; $salt = $this->salt != '' ? $this->salt : $this->generateRandomString(); foreach ($this->formFields as $field) { if (!$this->saveAllFields && isset($field['optional']) && $field['optional'] === true && trim(filter_input(INPUT_POST, $field['name'], $field['filter'])) === '') { continue; } $keysArray[] = '`' . $field['dbfield'] . '`'; if (isset($field['with_null_field']) && filter_input(INPUT_POST, $field['name']) === 'NULL') { $valuesArray[] = 'NULL'; } else { $rawValue = filter_input(INPUT_POST, $field['name'], $field['filter']); $dbValue = $rawValue === '' || (isset($field['encryption']) && $field['encryption'] === false) ? $rawValue : $this->encode($rawValue, $salt); $valuesArray[] = '"' . $dbValue . '"'; } } if ($this->dbGenerateSaltField) { $keysArray[] = '`salt`'; $valuesArray[] = '"' . $salt . '"'; } return ['keys' => $keysArray, 'values' => $valuesArray]; } protected function getDbEncryptedValueIfNeeded(array $formData, string $fieldName, string $salt): mixed { $formField = $this->getFormField($fieldName); if (count($formField) !== 0) { if (!$this->fieldHasToBeEncrypted($fieldName)) { return $formData[$fieldName]; } } return $this->encode($formData[$fieldName], $salt); } protected function getFormField($fieldName): array { foreach ($this->formFields as $formField) { if (!isset($formField['name'])) { continue; } if ($formField['name'] === $fieldName) { return $formField; } } return []; } protected function fieldHasToBeEncrypted(string $fieldName): bool { $formField = $this->getFormField($fieldName); return !isset($formField['encryption']) || $formField['encryption'] !== false; } protected function generateContent(): void { } protected function generateRandomString($length = 16) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } return $randomString; } protected function encode(string $toEncode, string $salt): string { return openssl_encrypt($toEncode, 'aes-256-cbc', $this->encryptionKey, 0, $salt); } protected function decode(string $toDecode, string $salt): string { try { return $toDecode ? openssl_decrypt($toDecode, 'aes-256-cbc', $this->encryptionKey, 0, $salt) : ''; } catch (exception $e) { return ''; } } protected function initSmtpMailer(): PHPMailer { $mail = new PHPMailer(true); $mail->SMTPDebug = SMTP::DEBUG_OFF; $mail->isSMTP(); $mail->Host = $this->smtpServer; $mail->Port = $this->smtpPort; $mail->SMTPAuth = true; $mail->Username = $this->emailUser; $mail->Password = $this->emailPassword; $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; $mail->CharSet = PHPMailer::CHARSET_UTF8; $mail->isHTML(true); return $mail; } protected function sendMail(PHPMailer $mail, string $subject, string $body, string $signature, $attachments = []): void { $completeBody = $body . $signature . $this->emailLegalInformation(); $mail->Subject = $subject; $mail->Body = $completeBody; $mail->AltBody = 'Diese Email benötigt HTML-Ansicht'; foreach ($attachments as $fileName => $attachment) { $mail->addStringAttachment($attachment['content'], $fileName, 'base64', $attachment['type']); } $mail->send(); } protected function connectToImap($folder = ''): bool { $this->imapClientManager = new ClientManager('conf/imap.php'); $this->mbox = $this->imapClientManager->make([ 'host' => $this->imapServer, 'port' => $this->imapPort, 'encryption' => 'ssl', 'validate_cert' => true, 'username' => $this->emailUser, 'password' => $this->emailPassword, 'protocol' => 'imap' ]); $this->mbox->connect(); return $this->mbox->isConnected();; } protected function saveFileLocal(string $newFileName, string $content, string $salt): void { $encodedFile = $this->encode($content, $salt); file_put_contents('/var/shared/fvajs/' . $newFileName, $encodedFile); } protected function emailLegalInformation(): string { return ''; } protected function generateSignature(string $signatureType): string { $sender = ($signatureType === 'Persönliche Signatur') ? $this->generatePersonalSignature() : 'Der Vorstand'; return '

-------------
' . $sender .'

' . 'Verein der Freunde und Förderer der Steffi-Jones-Schule e.V.
' . 'Harheimer Weg 16
' . '60437 Frankfurt
' . 'Email: foerderverein-ajs@gmx.de
' . 'Homepage: https://fvajs.de
' . 'Registergerich: Amtsgerich Frankfurt a.M. ' . 'Vertretungsberechtigt: Lucas Fastabend, Alexandra , Torsten Schulz' . '

'; } protected function generatePersonalSignature(): string { $query = sprintf('SELECT c.first_name, c.last_name, c.salt, cp.description FROM clubmember c JOIN `user` u ON u.id = c.user_id LEFT JOIN clubmember_position cp ON cp.id = c.position_id WHERE u.id = %d', $_SESSION['userid']); $dbResult = mysqli_query($this->dbConnection, $query); $row = mysqli_fetch_assoc($dbResult); $name = $this->decode($row['first_name'], $row['salt']) . ' ' . $this->decode($row['last_name'], $row['salt']); if (trim($row['description']) === '') { return name; } return htmlspecialchars($name . ' (' . $row['description'] . ')'); } function decodeSubject($subject) { return $subject; // Match the encoding and encoded string using a regular expression preg_match_all('/=\?([^?]+)\?([QB])\?([^?]+)\?=/i', $subject, $matches, PREG_SET_ORDER); $decoded = ''; foreach ($matches as $match) { $encoding = $match[1]; $type = $match[2]; $encoded_string = $match[3]; if ($type == 'Q') { $decoded_part = quoted_printable_decode($encoded_string); } elseif ($type == 'B') { $decoded_part = base64_decode($encoded_string); } var_dump($match); if (strtolower($encoding) != 'utf-8') { $decoded_part = iconv($encoding, 'UTF-8', $decoded_part); } $decoded .= str_replace('_', ' ', $decoded_part); } return $decoded; } protected function getMemberList(bool $withId = false): array { $query = <<dbConnection, $query); $entries = []; while ($row = mysqli_fetch_assoc($result)) { $entry = [ 'last_name' => $this->decode($row['last_name'], $row['salt']), 'first_name' => $this->decode($row['first_name'], $row['salt']), 'street' => $this->decode($row['street'], $row['salt']), 'zip' => $this->decode($row['zip'], $row['salt']), 'town' => $this->decode($row['town'], $row['salt']), 'birthdate' => $this->decode($row['birthdate'], $row['salt']), 'phone' => $this->decode($row['phone'], $row['salt']), 'email' => $this->decode($row['email'], $row['salt']), // 'child_name' => $this->decode($row['child_name'], $row['salt']), // 'child_street' => $this->decode($row['child_street'], $row['salt']), 'subscription' => $this->decode($row['subscription'], $row['salt']), 'bank_name' => $this->decode($row['bank_name'], $row['salt']), 'iban' => $this->decode($row['iban'], $row['salt']), 'bic' => $this->decode($row['bic'], $row['salt']), 'account_member_name' => $this->decode($row['account_member_name'], $row['salt']), 'status_text' => $row['status_text'], 'membership_start' => $row['membership_start'], 'last_payment' => $row['last_payment'], 'description' => $row['description'], ]; if ($withId) { $entry['id'] = $row['id']; } $entries[] = $entry; } return $this->sortUserList($entries); } protected function sortUserList($userList): array { usort($userList, function($a, $b) { $nameComparison = stricmp($a['last_name'], $b['last_name']); return ($nameComparison !== 0) ? $nameComparison : stricmp($a['first_name'], $b['first_name']); }); return $userList; } }