initial
15
composer.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.0"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
],
|
||||
"require": {
|
||||
"tinymce/tinymce": "*",
|
||||
"phpmailer/phpmailer": "dev-master",
|
||||
"php-imap/php-imap": "^2.0"
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
212
composer.lock
generated
Normal file
@@ -0,0 +1,212 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "273d2592d3c90db120bdd9644b0975a0",
|
||||
"packages": [
|
||||
{
|
||||
"name": "php-imap/php-imap",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barbushin/php-imap.git",
|
||||
"reference": "cc1a49a3f68090db182183c59ffbc09055d59f5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barbushin/php-imap/zipball/cc1a49a3f68090db182183c59ffbc09055d59f5b",
|
||||
"reference": "cc1a49a3f68090db182183c59ffbc09055d59f5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"PhpImap": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD 3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sergey Barbushin",
|
||||
"email": "barbushin@gmail.com",
|
||||
"homepage": "http://linkedin.com/in/barbushin"
|
||||
}
|
||||
],
|
||||
"description": "PHP class to access mailbox by POP3/IMAP/NNTP using IMAP extension",
|
||||
"homepage": "https://github.com/barbushin/php-imap",
|
||||
"keywords": [
|
||||
"imap",
|
||||
"mail",
|
||||
"php"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/barbushin/php-imap/issues",
|
||||
"source": "https://github.com/barbushin/php-imap/tree/master"
|
||||
},
|
||||
"time": "2015-09-16T07:40:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "312ed95ab03e7f3f0316191e5bfb9f920b705825"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/312ed95ab03e7f3f0316191e5bfb9f920b705825",
|
||||
"reference": "312ed95ab03e7f3f0316191e5bfb9f920b705825",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-hash": "*",
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
|
||||
"doctrine/annotations": "^1.2.6 || ^1.13.3",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3.2",
|
||||
"phpcompatibility/php-compatibility": "^9.3.5",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"squizlabs/php_codesniffer": "^3.7.2",
|
||||
"yoast/phpunit-polyfills": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
|
||||
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
|
||||
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
|
||||
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
|
||||
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
|
||||
"psr/log": "For optional PSR-3 debug logging",
|
||||
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
|
||||
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PHPMailer\\PHPMailer\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marcus Bointon",
|
||||
"email": "phpmailer@synchromedia.co.uk"
|
||||
},
|
||||
{
|
||||
"name": "Jim Jagielski",
|
||||
"email": "jimjag@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Andy Prevost",
|
||||
"email": "codeworxtech@users.sourceforge.net"
|
||||
},
|
||||
{
|
||||
"name": "Brent R. Matzelle"
|
||||
}
|
||||
],
|
||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/master"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Synchro",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-06-08T09:54:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tinymce/tinymce",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tinymce/tinymce-dist.git",
|
||||
"reference": "6a37da4822eebcd2706793454b07bd891c5277a8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/tinymce/tinymce-dist/zipball/6a37da4822eebcd2706793454b07bd891c5277a8",
|
||||
"reference": "6a37da4822eebcd2706793454b07bd891c5277a8",
|
||||
"shasum": ""
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "component",
|
||||
"extra": {
|
||||
"component": {
|
||||
"scripts": [
|
||||
"tinymce.js",
|
||||
"plugins/*/plugin.js",
|
||||
"themes/*/theme.js",
|
||||
"models/*/model.js",
|
||||
"icons/*/icons.js"
|
||||
],
|
||||
"files": [
|
||||
"tinymce.min.js",
|
||||
"plugins/*/plugin.min.js",
|
||||
"themes/*/theme.min.js",
|
||||
"models/*/model.min.js",
|
||||
"skins/**",
|
||||
"icons/*/icons.min.js"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT-only"
|
||||
],
|
||||
"description": "Web based JavaScript HTML WYSIWYG editor control.",
|
||||
"homepage": "https://www.tiny.cloud/",
|
||||
"keywords": [
|
||||
"contenteditable",
|
||||
"editing",
|
||||
"html",
|
||||
"javascript",
|
||||
"rich editor",
|
||||
"rich text",
|
||||
"rich text editor",
|
||||
"richtext",
|
||||
"rte",
|
||||
"text",
|
||||
"tinymce",
|
||||
"wysiwyg"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/tinymce/tinymce-dist/tree/6.4.2"
|
||||
},
|
||||
"time": "2023-04-26T10:48:15+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"phpmailer/phpmailer": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "8.0"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
18
conf/internalpages.conf
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"accounts": "Zugänge",
|
||||
"members": "Mitglieder",
|
||||
"newmember": "Neues Mitglied",
|
||||
"documents": "Dokumente",
|
||||
"emailinbox": "Postfach",
|
||||
"download": "",
|
||||
"deletedocument": "",
|
||||
"editmember": "",
|
||||
"payings": "",
|
||||
"mail": "",
|
||||
"bulkmail": "Emailverteiler",
|
||||
"logout": "",
|
||||
"savemail": "Ideenboard",
|
||||
"planboard": "",
|
||||
"projectsmanagement": "Förderprojekte"
|
||||
}
|
||||
|
||||
12
conf/publicpages.conf
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"index": "Startseite",
|
||||
"projects": "Projekte",
|
||||
"donate": "Spenden",
|
||||
"membership": "Mitgliedschaft",
|
||||
"contact": "Kontakt",
|
||||
"imprint": "Impressum",
|
||||
"login": "",
|
||||
"register": "",
|
||||
"newpassword": "",
|
||||
"setpassword": ""
|
||||
}
|
||||
4
ffajs.kdev4
Normal file
@@ -0,0 +1,4 @@
|
||||
[Project]
|
||||
CreatedFrom=
|
||||
Manager=KDevCustomBuildSystem
|
||||
Name=ffajs
|
||||
BIN
images/icons/key.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
81
include/accounts.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Accounts extends Renderer {
|
||||
public function __construct(?string $templateName) {
|
||||
parent::__construct($templateName);
|
||||
$this->renderInactiveUsers();
|
||||
$this->renderActiveUsers();
|
||||
}
|
||||
|
||||
private function renderInactiveUsers(): void {
|
||||
$result = mysqli_query($this->dbConnection, 'SELECT * FROM user WHERE active=0');
|
||||
$content = '<tbody>';
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$content .= '<tr><td>' . $row['username'] . '</td><td>' . $this->decode($row['realname'], $row['salt'])
|
||||
. '</td><td>' . $this->decode($row['email'], $row['salt']) . '</td>'
|
||||
. '<td><button type="submit" name="action" value="activate:' . $row['username'] . '">Aktivieren</button>'
|
||||
. '<button type="submit" name="action" value="delete:' . $row['username'] . '">Löschen</button></td></tr>';
|
||||
}
|
||||
$content .= '</tbody>';
|
||||
$this->content['inactive_accounts'] = $content;
|
||||
}
|
||||
|
||||
private function renderActiveUsers(): void {
|
||||
$result = mysqli_query($this->dbConnection, 'SELECT * FROM user WHERE active=1');
|
||||
$content = '<tbody>';
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$content .= '<tr><td>' . $row['username'] . '</td><td>' . $this->decode($row['realname'], $row['salt'])
|
||||
. '</td><td>' . $this->decode($row['email'], $row['salt']) . '</td>'
|
||||
. '<td><button type="submit" name="action" value="delete:' . $row['username'] . '">Löschen</button></td></tr>';
|
||||
}
|
||||
$content .= '</tbody>';
|
||||
$this->content['active_accounts'] = $content;
|
||||
}
|
||||
|
||||
protected function formAction(): void {
|
||||
$actionParams = explode(':', trim(filter_input(INPUT_POST, 'action', FILTER_SANITIZE_STRING)));
|
||||
switch ($actionParams[0]) {
|
||||
case 'activate':
|
||||
$this->activateAccount($actionParams[1]);
|
||||
break;
|
||||
case 'delete':
|
||||
$this->deleteAccount($actionParams[1]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function activateAccount(string $accountName): void {
|
||||
$emailTo = 'Vorstand Förderverein AJS <foerderverein-ajs@gmx.de>';
|
||||
mysqli_begin_transaction($this->dbConnection);
|
||||
mysqli_query($this->dbConnection, sprintf('UPDATE `user` SET `active`=1 WHERE `username`="%s"', $accountName));
|
||||
mysqli_commit($this->dbConnection);
|
||||
$result = mysqli_query($this->dbConnection, 'SELECT * FROM user WHERE `username` = lower("' . trim(filter_input(INPUT_POST, 'username', FILTER_SANITIZE_ADD_SLASHES)) . '")');
|
||||
$user = mysqli_fetch_assoc($result);
|
||||
$message = 'Dein Account "' . $accountName . '" wurde aktiviert.';
|
||||
$headers = 'From: ' . $emailTo . "\r\n" .
|
||||
'Reply-To: ' . $emailTo . "\r\n" .
|
||||
'X-Mailer: PHP/' . phpversion();
|
||||
mail($user['email'], 'Zugang zu internem Bereich beantragt', $message, $headers);
|
||||
header('Location: accounts', true, 301);
|
||||
die();
|
||||
}
|
||||
|
||||
private function deleteAccount(string $accountName): void {
|
||||
$emailTo = 'Vorstand Förderverein AJS <foerderverein-ajs@gmx.de>';
|
||||
$result = mysqli_query($this->dbConnection, 'SELECT * FROM user WHERE `username` = lower("' . trim(filter_input(INPUT_POST, 'username', FILTER_SANITIZE_ADD_SLASHES)) . '")');
|
||||
$user = mysqli_fetch_assoc($result);
|
||||
mysqli_begin_transaction($this->dbConnection);
|
||||
mysqli_query($this->dbConnection, sprintf('UPDATE `user` SET `active`=-1 WHERE `username`="%s"', $accountName));
|
||||
mysqli_commit($this->dbConnection);
|
||||
$message = 'Der Account "' . $accountName . '" wurde als gelöscht markiert.';
|
||||
$headers = 'From: ' . $emailTo . "\r\n" .
|
||||
'Reply-To: ' . $emailTo . "\r\n" .
|
||||
'X-Mailer: PHP/' . phpversion();
|
||||
mail($user['email'], 'Zugang zu internem Bereich beantragt', $message, $headers);
|
||||
header('Location: accounts', true, 301);
|
||||
die();
|
||||
}
|
||||
}
|
||||
57
include/bulkmail.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Bulkmail extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Betreff', 'type' => 'text', 'size' => 50, 'name' => 'subject', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'optional' => false],
|
||||
['label' => 'Text', 'type' => 'textarea', 'name' => 'body', 'combine_with_next_line' => false, 'filter' => FILTER_UNSAFE_RAW, 'optional' => false, 'rows' => 20, 'cols' => '60'],
|
||||
['label' => 'Signatur', 'type' => 'combobox', 'size' => 5, 'name' => 'signature', 'combine_with_next_line' => false,
|
||||
'values' => ['Persönliche Signatur', 'Vorstandssignatur'],
|
||||
],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Email an alle aktiven Mitglieder absenden';
|
||||
|
||||
protected function formAction(): void {
|
||||
$this->sendEmail($this->generateSubject(), $this->generateBody(), $this->generateSignature(filter_input(INPUT_POST, 'signature')));
|
||||
}
|
||||
|
||||
protected function generateSubject(): string {
|
||||
return filter_input(INPUT_POST, 'subject', FILTER_SANITIZE_STRING);
|
||||
}
|
||||
|
||||
protected function generateBody(): string {
|
||||
return preg_replace('/(<script(.*)\/script>|<iframe(.*)\/iframe>)/', '', filter_input(INPUT_POST, 'body'));
|
||||
}
|
||||
|
||||
protected function sendEmail(string $subject, string $body, string $signature): void {
|
||||
$mail = $this->initSmtpMailer();;
|
||||
$bccRecipients = $this->loadReceivers();
|
||||
try {
|
||||
$mail->setFrom('foerderverein-ajs@gmx.de', 'Förderverein der August-Jaspert-Schule');
|
||||
$mail->addReplyTo('foerderverein-ajs@gmx.de', 'Förderverein der August-Jaspert-Schule');
|
||||
$mail->addAddress('vorstand@fvajs.de', 'Vorstand des FVAJS');
|
||||
foreach ($bccRecipients as $recipient) {
|
||||
$mail->addBCC($recipient);
|
||||
}
|
||||
$this->sendMail($mail, $subject, $body, $signature);
|
||||
} catch (Exception $e) {
|
||||
$this->templateName = 'error_smtp';
|
||||
}
|
||||
$this->templateName = 'bulkmail_success';
|
||||
$this->content['recipients'] = implode('<br />', $bccRecipients);
|
||||
}
|
||||
|
||||
protected function loadReceivers(): array {
|
||||
$query = 'SELECT c.first_name, c.last_name, c.email, c.salt
|
||||
FROM clubmember c
|
||||
JOIN clubmember_status cs
|
||||
ON cs.id = c.membership_status
|
||||
WHERE cs.status_text = "Mitgliedschaft bestätigt"';
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
$recipientsList = [];
|
||||
while ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
$recipientsList[] = $this->decode($row['email'], $row['salt']);
|
||||
}
|
||||
return $recipientsList;
|
||||
}
|
||||
}
|
||||
29
include/contact.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Contact extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Ihre Nachricht an uns:', 'type' => 'textarea', 'size' => 50, 'name' => 'message', 'combine_with_next_line' => false,
|
||||
'rows' => 14, 'cols' => 100],
|
||||
['label' => 'Ihr Name', 'type' => 'text', 'size' => 50, 'name' => 'sendername', 'combine_with_next_line' => false],
|
||||
['label' => 'Ihre Email-Adresse', 'type' => 'text', 'size' => 50, 'name' => 'senderemail', 'combine_with_next_line' => false],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Nachricht absenden';
|
||||
|
||||
protected function formAction(): void {
|
||||
$message = filter_input(INPUT_POST, 'message', FILTER_SANITIZE_STRING);
|
||||
$senderName = filter_input(INPUT_POST, 'sendername', FILTER_SANITIZE_STRING);
|
||||
$senderEmail = filter_input(INPUT_POST, 'senderemail', FILTER_SANITIZE_EMAIL);
|
||||
$noForm = trim($message) !== '';
|
||||
if (!$noForm) {
|
||||
$this->errors[] = 'Leider haben Sie keine Nachricht an uns hinterlassen. Bitte versuchen Sie es nochmal.';
|
||||
return;
|
||||
}
|
||||
$mail = $this->initSmtpMailer();
|
||||
$mail->setFrom(($senderEmail !== '') ? $senderEmail : 'foerderverein-ajs@gmx.de', ($senderName !== '') ? $senderName: 'Anonymer Sender');
|
||||
$mail->addReplyTo(($senderEmail !== '') ? $senderEmail : 'foerderverein-ajs@gmx.de', ($senderName !== '') ? $senderName: 'Anonymer Sender');
|
||||
$mail->addAddress('foerderverein-ajs@gmx.de', 'Vorstand Förderverein AJS');
|
||||
$this->sendMail($mail, 'Kontaktformular', $message, '');
|
||||
$this->templateName = 'message_success';
|
||||
}
|
||||
}
|
||||
17
include/deletedocument.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Deletedocument extends Renderer {
|
||||
|
||||
public function render(): void {
|
||||
if ($_SESSION['userid'] === 0 && in_array($this->getScriptName() , $this->internalMenuItems, false)) {
|
||||
$this->templateName = 'login_error';
|
||||
parent::render();
|
||||
return;
|
||||
}
|
||||
$query = 'DELETE FROM `document` WHERE `title` = "' . filter_input(INPUT_POST, 'file', FILTER_SANITIZE_ADD_SLASHES) . '"';
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
@unlink('/var/shared/fvajs/' . filter_input(INPUT_GET, 'ts', FILTER_SANITIZE_STRING));
|
||||
echo '';
|
||||
}
|
||||
}
|
||||
72
include/documents.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Documents extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Dokumenttitel', 'type' => 'text', 'size' => 50, 'name' => 'documenttitle', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'optional' => false],
|
||||
['label' => 'Dokumentdatei', 'type' => 'file', 'size' => 50000, 'name' => 'document', 'combine_with_next_line' => false, 'optional' => true],
|
||||
['label' => 'Oder Datei erstellen aus', 'type' => 'textarea', 'cols' => 80, 'rows' => '15', 'name' => 'newtext', 'combine_with_next_line' => false, 'optional' => true],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Dokument hinzufügen';
|
||||
protected string $encType = 'multipart/form-data';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function formAction(): void {
|
||||
$this->formCheckFields();
|
||||
if (count($this->errors) === 0) {
|
||||
$newFileName = $this->generateRandomString(64);
|
||||
$salt = $this->generateRandomString();
|
||||
$this->saveFile($newFileName, $salt);
|
||||
$query = sprintf('INSERT INTO ffajs.document
|
||||
(title, original_filename, local_filename, salt)
|
||||
VALUES("%s", "%s", "%s", "%s")', trim(filter_input(INPUT_POST, 'documenttitle', $this->formFields[0]['filter'])),
|
||||
$this->getOriginalFileName(),
|
||||
$newFileName, $salt);
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
}
|
||||
}
|
||||
|
||||
protected function formCheckFields(): bool {
|
||||
parent::formCheckFields();
|
||||
$result = mysqli_query($this->dbConnection, 'SELECT `id` FROM `document` WHERE `title` = "' . trim(filter_input(INPUT_POST, 'documenttitle', $this->formFields[0]['filter'])) . '"');
|
||||
if (mysqli_num_rows($result) > 0) {
|
||||
$this->errors['documenttitle'] = 'Der Titel existiert bereits';
|
||||
}
|
||||
return count($this->errors) === 0;
|
||||
}
|
||||
|
||||
protected function saveFile(string $newFileName, string $salt): void {
|
||||
if (trim(filter_input(INPUT_POST, 'newtext', FILTER_SANITIZE_STRING)) !== '') {
|
||||
$content = filter_input(INPUT_POST, 'newtext', FILTER_SANITIZE_STRING);
|
||||
} elseif ($_FILES['document']['tmp_name']) {
|
||||
$content = file_get_contents($_FILES['document']['tmp_name']);
|
||||
} else {
|
||||
$this->errors['newtext'] = 'Es muss eine Datei hochgeladen oder hier ein Text eingegeben werden.';
|
||||
return;
|
||||
}
|
||||
$this->saveFileLocal($newFileName, $content, $salt);
|
||||
}
|
||||
|
||||
protected function generateContent(): void {
|
||||
$result = mysqli_query($this->dbConnection, 'SELECT * FROM `document` ORDER BY `title`');
|
||||
$tableBody = '';
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$tableBody .= '<tr>';
|
||||
$tableBody .= '<td>' . $row['title'] . '</td>';
|
||||
$tableBody .= '<td>' . $row['original_filename'] . '</td>';
|
||||
$tableBody .= '<td><a href="download?file=' . $row['local_filename'] . '">Download</a></td>';
|
||||
$tableBody .= '<td><button type="button" name="delete" value="' . $row['local_filename'] . '">Löschen</button></td>';
|
||||
$tableBody .= '</tr>';
|
||||
}
|
||||
$this->content['documents'] = $tableBody;
|
||||
}
|
||||
|
||||
protected function getOriginalFileName(): string {
|
||||
return trim(filter_input(INPUT_POST, 'newtext', FILTER_SANITIZE_STRING)) !== ''
|
||||
? trim(filter_input(INPUT_POST, 'documenttitle', $this->formFields[0]['filter'])) . '.txt'
|
||||
: $_FILES['document']['name'];
|
||||
}
|
||||
}
|
||||
31
include/download.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Download extends Renderer {
|
||||
|
||||
public function render(): void {
|
||||
if ($_SESSION['userid'] === 0 && in_array($this->getScriptName() , $this->internalMenuItems, false)) {
|
||||
$this->templateName = 'login_error';
|
||||
parent::render();
|
||||
return;
|
||||
}
|
||||
$params = $this->getUriParams();
|
||||
$query = sprintf('SELECT `original_filename`, `salt` FROM `document` WHERE `local_filename` = "%s"', $params['file']);
|
||||
$result = mysqli_query($this->dbConnection, $query);
|
||||
if (mysqli_num_rows($result) < 1) {
|
||||
die ('Datei nicht gefunden');
|
||||
}
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
$encryptedFile = file_get_contents('/var/shared/fvajs/' . $params['file']);
|
||||
$decryptedFile = $this->decode($encryptedFile, $row['salt']);
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header("Cache-Control: no-cache, must-revalidate");
|
||||
header("Expires: 0");
|
||||
header('Content-Disposition: attachment; filename="' . $row['original_filename'] . '"');
|
||||
header('Content-Length: ' . strlen($decryptedFile));
|
||||
header('Pragma: public');
|
||||
flush();
|
||||
echo $decryptedFile;
|
||||
}
|
||||
}
|
||||
89
include/editmember.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Editmember extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Nachname', 'type' => 'text', 'size' => 50, 'name' => 'lastname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'last_name', 'optional' => false],
|
||||
['label' => 'Vorname', 'type' => 'text', 'size' => 50, 'name' => 'firstname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'first_name', 'optional' => false],
|
||||
['label' => 'Straße', 'type' => 'text', 'size' => 50, 'name' => 'streetname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'street', 'optional' => false],
|
||||
['label' => 'Plz', 'type' => 'text', 'size' => 5, 'name' => 'zip', 'combine_with_next_line' => true, 'regex' => '/^([0-9]{5})$/', 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'zip', 'optional' => false],
|
||||
['label' => 'Ort', 'type' => 'text', 'size' => 40, 'name' => 'town', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'town', 'optional' => false],
|
||||
['label' => 'Birthday', 'type' => 'date', 'size' => 50, 'name' => 'birthdate', 'combine_with_next_line' => false, 'regex' => '/^((19|20)([0-9]){2}-[0-9]{2})-([0-9]{2})$/', 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'birthdate', 'optional' => false],
|
||||
['label' => 'Phone', 'type' => 'text', 'size' => 50, 'name' => 'phone', 'combine_with_next_line' => false, '/^0([0-9]{2,6})([ ]{0,1})([-\/]{0,1})([ ]{0,1})([0-9 ]{4,25})$/', 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'phone', 'optional' => false],
|
||||
['label' => 'Email', 'type' => 'email', 'size' => 50, 'name' => 'email', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_EMAIL, 'dbfield' => 'email', 'optional' => true],
|
||||
['label' => 'Name des Kindes', 'type' => 'text', 'size' => 50, 'name' => 'childname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'child_name', 'optional' => true],
|
||||
['label' => 'Straße des Kindes', 'type' => 'text', 'size' => 50, 'name' => 'childstreet', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'child_street', 'optional' => true],
|
||||
['label' => 'Gewählter Beitrag', 'type' => 'number', 'size' => 50, 'name' => 'subscription', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'subscription', 'optional' => false],
|
||||
['label' => 'Geldinstitut', 'type' => 'text', 'size' => 50, 'name' => 'bankname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'bank_name', 'optional' => true],
|
||||
['label' => 'IBAN', 'type' => 'text', 'size' => 50, 'name' => 'iban', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'iban', 'optional' => true],
|
||||
['label' => 'BIC', 'type' => 'text', 'size' => 50, 'name' => 'bic', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'bic', 'optional' => true],
|
||||
['label' => 'Kontoinhaber', 'type' => 'text', 'size' => 50, 'name' => 'accountmember', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'account_member_name', 'optional' => true],
|
||||
['label' => 'Mitgliedsstatus', 'type' => 'dbselect', 'size' => 0, 'name' => 'status', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'membership_status',
|
||||
'sourcedb' => 'clubmember_status', 'optionfield' => 'status_text', 'encryption' => false],
|
||||
['label' => 'Position im Verein', 'type' => 'dbselect', 'size' => 0, 'name' => 'position', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'position_id',
|
||||
'sourcedb' => 'clubmember_position', 'optionfield' => 'description', 'encryption' => false, 'with_null_field' => true],
|
||||
['label' => 'Online-Account', 'type' => 'dbselect', 'size' => 0, 'name' => 'user_id', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'user_id',
|
||||
'sourcedb' => 'user', 'optionfield' => 'username', 'encryption' => false, 'with_null_field' => true],
|
||||
];
|
||||
protected string $dbTable = 'clubmember';
|
||||
protected bool $dbGenerateSaltField = true;
|
||||
protected bool $dbUpdate = true;
|
||||
protected string $formSendButtonLabel = 'Änderungen speichern';
|
||||
protected bool $saveAllFields = true;
|
||||
|
||||
public function __construct(?string $templateName = null) {
|
||||
parent::__construct($templateName);
|
||||
$id = $this->getUriParams()['id'];
|
||||
$this->loadUserData($id);
|
||||
}
|
||||
|
||||
protected function loadUserData(string $id): void {
|
||||
$query = sprintf("SELECT c.first_name as firstname, c.last_name as lastname, c.street as streetname, c.zip, c.town, c.birthdate, c.phone, c.email, "
|
||||
. " c.child_name as childname, c.child_street as childstreet, c.subscription, c.bank_name as bankname, c.iban , c.bic , "
|
||||
. " c.account_member_name as accountmember, c.membership_status as status, c.position_id as position, c.user_id as user_id, c.salt "
|
||||
. "FROM clubmember c "
|
||||
. "WHERE c.id = %d", $id);
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
if (mysqli_num_rows($dbResult) === 0) {
|
||||
$this->templateName = 'notfound_error';
|
||||
return;
|
||||
}
|
||||
$line = mysqli_fetch_assoc($dbResult);
|
||||
$salt = $line['salt'];
|
||||
array_walk($line, function(&$item, $key) use ($salt) {
|
||||
if (!isset($item)) {
|
||||
return;
|
||||
} elseif ($this->fieldHasToBeEncrypted($key)) {
|
||||
$item = $this->decode($item, $salt);
|
||||
}
|
||||
});
|
||||
$this->predefines = $line;
|
||||
}
|
||||
|
||||
protected function formAction(): void {
|
||||
if (!$this->formCheckFields()) {
|
||||
return;
|
||||
}
|
||||
$saltQuery = "SELECT id, membership_status, salt FROM clubmember c WHERE id=" . $this->getUriParams()['id'];
|
||||
$dbResult = mysqli_query($this->dbConnection, $saltQuery);
|
||||
if (!$dbResult) {
|
||||
return;
|
||||
}
|
||||
$oldDataRow = mysqli_fetch_assoc($dbResult);
|
||||
$this->salt = $oldDataRow['salt'];
|
||||
$this->saveToDb();
|
||||
if (filter_input(INPUT_POST, 'status', FILTER_SANITIZE_NUMBER_INT) != $oldDataRow['membership_status']) {
|
||||
$this->saveMembershipStatusChangeHistory($oldDataRow['id'], $oldDataRow['membership_status'],
|
||||
filter_input(INPUT_POST, 'status', FILTER_SANITIZE_NUMBER_INT));
|
||||
}
|
||||
$this->cleanFields = false;
|
||||
$this->messages[] = 'Mitglied erfolgreich bearbeitet.';
|
||||
}
|
||||
|
||||
protected function saveMembershipStatusChangeHistory(string $clubmemberId, string $oldStatus, string $newStatus): void {
|
||||
$query = sprintf("INSERT INTO ffajs.clubmember_status_history (clubmember_id, changer_id, old_status_id, new_status_id, change_timestamp) "
|
||||
. "VALUES(%d, %d, %d, %d, now()); ",
|
||||
$clubmemberId, $_SESSION['userid'], $oldStatus, $newStatus);
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
}
|
||||
}
|
||||
72
include/emailinbox.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
require 'renderer.php';
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
class Emailinbox extends Renderer {
|
||||
|
||||
public function __construct(?string $templateName = null) {
|
||||
parent::__construct();
|
||||
if (!$this->connectToImap()) {
|
||||
$this->templateName = 'imaperror';
|
||||
}
|
||||
}
|
||||
|
||||
protected function readEmailHeaders(): array {
|
||||
$cleanedHeaders = [];
|
||||
try {
|
||||
$mailsIds = $this->mbox->searchMailbox('ALL');
|
||||
} catch(PhpImap\Exceptions\ConnectionException $ex) {
|
||||
echo "IMAP connection failed: " . implode(",", $ex->getErrors('all'));
|
||||
die();
|
||||
}
|
||||
|
||||
if(!$mailsIds) {
|
||||
die('Mailbox is empty');
|
||||
}
|
||||
$headers = $this->mbox->getMailsInfo($mailsIds);
|
||||
foreach ($headers as $header) {
|
||||
try {
|
||||
$cleanedHeaders[trim($header->msgno)] = [
|
||||
'title' => $header->subject,
|
||||
'date' => \DateTime::createFromFormat('D, d M Y H:i:s O', str_replace(' (CET)', '', $header->date))->setTimezone(new DateTimeZone('Europe/Berlin')),
|
||||
'from' => $header->from,
|
||||
'unread' => !$header->seen,
|
||||
];
|
||||
} catch (\exception $err) {
|
||||
}
|
||||
}
|
||||
return $cleanedHeaders;
|
||||
}
|
||||
|
||||
protected function getDateObjectFromString(string $dateString) {
|
||||
$date = DateTime::createFromFormat(DateTimeInterface::RFC1123, $dateString);
|
||||
if (!$date) {
|
||||
$date = DateTime::createFromFormat(DateTimeInterface::RFC1123, substr($dateString, 0, -6));
|
||||
}
|
||||
if (!$date) {
|
||||
$date = DateTime::createFromFormat('d M Y H:i:s O', $dateString);
|
||||
}
|
||||
if (!$date) {
|
||||
echo $dateString;
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
protected function generateContent(): void {
|
||||
$headers = $this->readEmailHeaders();
|
||||
uasort($headers, ['Emailinbox', 'compareDateTimes']);
|
||||
array_walk($headers, function(&$item, $key) {
|
||||
$newItem = '<tr>';
|
||||
$newItem .= '<td style="white-space:nowrap">' . ($item['date'] === false ? '' : $item['date']->format('d.m.Y H:i:s')) . '</td>';
|
||||
$newItem .= '<td><a href="mail?uid=' . $key . '">' . ($item['unread'] === 'U' ? '<b>' : '') . $item['title'] . ($item['unread'] === 'u' ? '</b>' : '') . '</td>';
|
||||
$newItem .= '<td>' . $item['from'] . '</td>';
|
||||
$newItem .= '</tr>';
|
||||
$item = $newItem;
|
||||
});
|
||||
$this->content['mails'] = implode('', $headers);
|
||||
}
|
||||
|
||||
protected function compareDateTimes($item1, $item2): int {
|
||||
return $item2['date'] <=> $item1['date'];
|
||||
}
|
||||
}
|
||||
7
include/footer.php
Normal file
@@ -0,0 +1,7 @@
|
||||
</main>
|
||||
<footer>
|
||||
<span class="footer-copyright">(c) 2022 Förderverein August-Jaspert-Schule e.V.</span>
|
||||
<a href="imprint.php" class="footer-imprint">Impressum</span>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
13
include/header.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Förderverein August-Jaspert-Schule e.V.</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/main.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Förderverein August-Jaspert-Schule e.V.</h1>
|
||||
</header>
|
||||
<?php include 'include/menu.php'; ?>
|
||||
<main>
|
||||
31
include/login.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Login extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Benutzername', 'type' => 'text', 'size' => 50, 'name' => 'username', 'combine_with_next_line' => false],
|
||||
['label' => 'Paßwort', 'type' => 'password', 'size' => 50, 'name' => 'password', 'combine_with_next_line' => false],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Einloggen';
|
||||
|
||||
protected function formAction(): void {
|
||||
$this->userId = 0;
|
||||
$result = mysqli_query($this->dbConnection, 'SELECT * FROM user WHERE `username` = lower("' . trim(filter_input(INPUT_POST, 'username', FILTER_SANITIZE_ADD_SLASHES)) . '")');
|
||||
if ($result->num_rows !== 1) {
|
||||
$this->errors[] = 'Benutzer und/oder Paßwort falsch';
|
||||
return;
|
||||
}
|
||||
$user = $result->fetch_assoc();
|
||||
if (!password_verify(filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING), $user['password'])) {
|
||||
$this->errors[] = 'Benutzer und/oder Paßwort falsch';
|
||||
return;
|
||||
}
|
||||
if ($user['active'] !== '1') {
|
||||
$this->errors[] = 'Dein Zugang ist noch nicht freigeschaltet.';
|
||||
return;
|
||||
}
|
||||
$_SESSION['userid'] = $user['id'];
|
||||
header('Location: accounts', true, 301);
|
||||
die();
|
||||
}
|
||||
}
|
||||
11
include/logout.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Logout extends Renderer {
|
||||
public function __construct(?string $templateName = null) {
|
||||
session_start();
|
||||
$_SESSION['userid'] = 0;
|
||||
session_write_close();
|
||||
header('Location: index', true, 301);
|
||||
}
|
||||
}
|
||||
34
include/mail.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
require 'mailhandling.php';
|
||||
|
||||
class Mail extends Mailhandling {
|
||||
// protected $mbox = null;
|
||||
protected $uid = 0;
|
||||
|
||||
public function __construct(?string $templateName = null) {
|
||||
parent::__construct();
|
||||
if (!$this->connectToImap()) {
|
||||
$this->templateName = 'imaperror';
|
||||
return;
|
||||
}
|
||||
$this->uid = $this->getUriParams()['uid'];
|
||||
$this->content['uid'] = $this->uid;
|
||||
}
|
||||
|
||||
protected function generateContent(): void {
|
||||
$messageStructure = imap_fetchstructure($this->mbox, $this->uid);
|
||||
$this->fetchEmailHeader($this->content);
|
||||
$this->fetchEmailBody($messageStructure, $this->content, 'INBOX', FT_PEEK);
|
||||
$this->renderAttachments($messageStructure);
|
||||
}
|
||||
|
||||
protected function renderAttachments($messageStructure): void {
|
||||
$attachments = $this->getAttachments($messageStructure);
|
||||
$contentArray = [];
|
||||
foreach ($attachments as $attachment) {
|
||||
$contentArray[] = $attachment['filename'];
|
||||
}
|
||||
$this->content['attachments'] = implode('<br>', $contentArray);
|
||||
}
|
||||
}
|
||||
82
include/mailhandling.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
require 'renderer.php';
|
||||
|
||||
class Mailhandling extends Renderer {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
if (!$this->connectToImap()) {
|
||||
$this->templateName = 'imaperror';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function fetchEmailHeader(array &$content): void {
|
||||
$header = imap_headerinfo($this->mbox, $this->uid);
|
||||
$content['sender'] = imap_utf8($header->fromaddress);
|
||||
$content['receiver'] = imap_utf8($header->toaddress);
|
||||
$content['subject'] = imap_utf8($header->subject);
|
||||
$content['senddate'] = date('d.m.Y H:i:s', strtotime($header->date));
|
||||
}
|
||||
|
||||
protected function fetchEmailBody($messageStructure, array &$content): void {
|
||||
$message = imap_fetchbody($this->mbox, $this->uid, 1.1, FT_PEEK);
|
||||
if($message == '') {
|
||||
$message = imap_fetchbody($this->mbox, $this->uid, 1, FT_PEEK);
|
||||
}
|
||||
$decodedMessage = quoted_printable_decode($message);
|
||||
if (isset($messageStructure->parts) && isset($messageStructure->parts[1]) && isset($messageStructure->parts[1]->parameters)
|
||||
&& isset($messageStructure->parts[1]->parameters) && is_array($messageStructure->parts[1]->parameters) && isset($messageStructure->parts[1]->parameters[0]->value) && strtolower($messageStructure->parts[1]->parameters[0]->value) != 'utf-8') {
|
||||
$decodedMessage = utf8_encode($decodedMessage);
|
||||
}
|
||||
$content['emailbody'] = nl2br($decodedMessage);
|
||||
}
|
||||
|
||||
|
||||
protected function getAttachments($structure): array {
|
||||
$attachments = [];
|
||||
if(isset($structure->parts) && count($structure->parts)) {
|
||||
for($i = 0; $i < count($structure->parts); $i++) {
|
||||
$attachments[$i] = [
|
||||
'is_attachment' => false,
|
||||
'filename' => '',
|
||||
'name' => '',
|
||||
'attachment' => ''];
|
||||
|
||||
if($structure->parts[$i]->ifdparameters) {
|
||||
foreach($structure->parts[$i]->dparameters as $object) {
|
||||
if(strtolower($object->attribute) == 'filename') {
|
||||
$attachments[$i]['is_attachment'] = true;
|
||||
$attachments[$i]['filename'] = $object->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($structure->parts[$i]->ifparameters) {
|
||||
foreach($structure->parts[$i]->parameters as $object) {
|
||||
if(strtolower($object->attribute) == 'name') {
|
||||
$attachments[$i]['is_attachment'] = true;
|
||||
$attachments[$i]['name'] = $object->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($attachments[$i]['is_attachment']) {
|
||||
$attachments[$i]['attachment'] = imap_fetchbody($this->mbox, $this->uid, $i+1);
|
||||
if($structure->parts[$i]->encoding == 3) { // 3 = BASE64
|
||||
$attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']);
|
||||
}
|
||||
elseif($structure->parts[$i]->encoding == 4) { // 4 = QUOTED-PRINTABLE
|
||||
$attachments[$i]['attachment'] = quoted_printable_decode($attachments[$i]['attachment']);
|
||||
}
|
||||
}
|
||||
if ($attachments[$i]['is_attachment']) {
|
||||
}
|
||||
}
|
||||
}
|
||||
$realAttachments = array_filter($attachments, function($attachment) {
|
||||
return $attachment['is_attachment'];
|
||||
});
|
||||
return $realAttachments;
|
||||
}
|
||||
}
|
||||
30
include/members.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Members extends Renderer {
|
||||
public function __construct(?string $templateName = null) {
|
||||
parent::__construct($templateName);
|
||||
$result = mysqli_query($this->dbConnection,
|
||||
'SELECT c.*, cs.`status_text`, (SELECT ph.`payment_date` FROM `paying_history` ph WHERE ph.`clubmember_id` = c.`id` ORDER BY `payment_date` DESC LIMIT 1) as last_payment '
|
||||
. 'FROM `clubmember` c '
|
||||
. 'JOIN `clubmember_status` cs '
|
||||
. ' ON cs.`id` = c.`membership_status` '
|
||||
. 'WHERE cs.`status_text` NOT IN ("Mitgliedschaft abgelehnt", "Mitgliedschaft gekündigt") '
|
||||
. 'ORDER BY c.`last_name`, c.`first_name`');
|
||||
$tableBody = '<tbody>';
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$tableBody .= '<tr>'
|
||||
. '<td>' . $row['id'] . '</td>'
|
||||
. '<td>' . $this->decode($row['last_name'], $row['salt']) . ', ' . $this->decode($row['first_name'], $row['salt']) . '</td>'
|
||||
. '<td>' . $this->decode($row['email'], $row['salt']) . '</td>'
|
||||
. '<td>' . $row['last_payment'] . '</td>'
|
||||
. '<td>' . $row['membership_start'] . '</td>'
|
||||
. '<td>' . $row['status_text'] . '</td>'
|
||||
. '<td><a href="editmember?id=' . $row['id'] . '">Bearbeiten</a> '
|
||||
. '<a href="payings?id=' . $row['id'] . '">Zahlungen</a></td>'
|
||||
. '</tr>';
|
||||
}
|
||||
$tableBody .= '</tbody>';
|
||||
$this->content['memberlist'] = $tableBody;
|
||||
}
|
||||
}
|
||||
125
include/membership.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Membership extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Vorname', 'type' => 'text', 'size' => 50, 'name' => 'firstname', 'combine_with_next_line' => false],
|
||||
['label' => 'Nachname', 'type' => 'text', 'size' => 50, 'name' => 'lastname', 'combine_with_next_line' => false],
|
||||
['label' => 'Straße (mit Hausnummer)', 'type' => 'text', 'size' => 50, 'name' => 'street', 'combine_with_next_line' => false],
|
||||
['label' => 'Plz', 'type' => 'text', 'size' => 5, 'name' => 'zip', 'combine_with_next_line' => true],
|
||||
['label' => 'Ort', 'type' => 'text', 'size' => 40, 'name' => 'town', 'combine_with_next_line' => false],
|
||||
['label' => 'Geburtsdatum', 'type' => 'date', 'size' => 50, 'name' => 'birthdate', 'combine_with_next_line' => false],
|
||||
['label' => 'Telefon-Nr.', 'type' => 'text', 'size' => 50, 'name' => 'phone', 'combine_with_next_line' => false],
|
||||
['label' => 'Email-Adresse', 'type' => 'email', 'size' => 50, 'name' => 'email', 'combine_with_next_line' => false],
|
||||
['label' => 'Name des Kindes (Optional)', 'type' => 'text', 'size' => 50, 'name' => 'childname', 'combine_with_next_line' => false],
|
||||
['label' => 'Straße des Kindes (Optional)', 'type' => 'text', 'size' => 50, 'name' => 'childstreet', 'combine_with_next_line' => false],
|
||||
['label' => 'Gewählter Jahresbeitrag', 'type' => 'combobox', 'size' => 50, 'name' => 'payheight', 'combine_with_next_line' => false,
|
||||
'values' => ['12 €', '25 €', '50 €', '60 €', '100 €', 'Selbst wählen'], 'default' => '25 €',],
|
||||
['label' => 'Höhe des freien Beitrags (Optional)', 'type' => 'number', 'size' => 50, 'name' => 'freepayheight', 'value' => 0, 'combine_with_next_line' => false],
|
||||
['label' => 'Ich stimme der elektronischen Verarbeitung und Speicherung meiner Daten zu', 'type' => 'checkbox', 'size' => 1, 'name' => 'accept_electronical_usage', 'value' => 1],
|
||||
['type' => 'spacer', 'value' => ''],
|
||||
['type' => 'infotext', 'label' => '<h3>(Optional) Bankeinzugsinformationen</h3>'],
|
||||
['label' => 'Geldinstitut', 'type' => 'text', 'size' => 50, 'name' => 'bankname', 'combine_with_next_line' => false],
|
||||
['label' => 'IBAN', 'type' => 'text', 'size' => 50, 'name' => 'iban', 'combine_with_next_line' => false],
|
||||
['label' => 'BIC', 'type' => 'text', 'size' => 50, 'name' => 'bic', 'combine_with_next_line' => false],
|
||||
['label' => 'Kontoinhaber', 'type' => 'text', 'size' => 50, 'name' => 'accountmembername', 'combine_with_next_line' => false],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Mitgliedschaftsantrag vorausgefüllt beantragen';
|
||||
|
||||
protected function formAction(): void {
|
||||
$formData['firstname'] = trim(filter_input(INPUT_POST, 'firstname', FILTER_SANITIZE_STRING));
|
||||
$formData['lastname'] = trim(filter_input(INPUT_POST, 'lastname', FILTER_SANITIZE_STRING));
|
||||
$formData['street'] = trim(filter_input(INPUT_POST, 'street', FILTER_SANITIZE_STRING));
|
||||
$formData['zip'] = trim(filter_input(INPUT_POST, 'zip', FILTER_SANITIZE_STRING));
|
||||
$formData['town'] = trim(filter_input(INPUT_POST, 'town', FILTER_SANITIZE_STRING));
|
||||
$formData['birthDate'] = trim(filter_input(INPUT_POST, 'birthdate', FILTER_SANITIZE_STRING));
|
||||
$formData['phoneNumber'] = trim(filter_input(INPUT_POST, 'phone', FILTER_SANITIZE_STRING));
|
||||
$formData['email'] = trim(filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING));
|
||||
$formData['childName'] = trim(filter_input(INPUT_POST, 'childname', FILTER_SANITIZE_STRING));
|
||||
$formData['childStreet'] = trim(filter_input(INPUT_POST, 'childstreet', FILTER_SANITIZE_STRING));
|
||||
$formData['payHeight'] = trim(filter_input(INPUT_POST, 'payheight', FILTER_SANITIZE_STRING));
|
||||
$formData['bankname'] = trim(filter_input(INPUT_POST, 'bankname', FILTER_SANITIZE_STRING));
|
||||
$formData['iban'] = trim(filter_input(INPUT_POST, 'iban', FILTER_SANITIZE_STRING));
|
||||
$formData['bic'] = trim(filter_input(INPUT_POST, 'bic', FILTER_SANITIZE_STRING));
|
||||
$formData['agreedElectronicalHandling'] = intval(filter_input(INPUT_POST, 'accept_electronical_usage', FILTER_SANITIZE_NUMBER_INT));
|
||||
$formData['accountmembername'] = trim(filter_input(INPUT_POST, 'accountmembername', FILTER_SANITIZE_STRING));
|
||||
$this->checkFormData($formData);
|
||||
$this->saveNewMember($formData);
|
||||
$this->sendEmail($formData);
|
||||
}
|
||||
|
||||
protected function checkFormData(array $formData): void {
|
||||
if ($formData['payHeight'] === 'Selbst wählen') {
|
||||
$formData['payHeight'] = filter_input(INPUT_POST, 'freepayheight', FILTER_SANITIZE_NUMBER_INT);
|
||||
}
|
||||
if (!preg_match('/^([0-9]{5})$/', $formData['zip'])) {
|
||||
$this->errors['zip'] = 'Die Postleitzahl ist nicht korrekt';
|
||||
}
|
||||
if (!preg_match('/^((19|20)([0-9]){2}-[0-9]{2})-([0-9]{2})$/', $formData['birthDate']) || (DateTimeImmutable::createFromFormat('Y-m-d', $formData['birthDate']))->getTimestamp() > time()) {
|
||||
$this->errors['birthdate'] = 'Das eingegebene Geburtsdatum ist nicht korrekt';
|
||||
}
|
||||
if (!preg_match('/^0([0-9]{2,6})([ ]{0,1})([-\/]{0,1})([ ]{0,1})([0-9 ]{4,25})$/', $formData['phoneNumber'])) {
|
||||
$this->errors['phone'] = 'Die Telefonnummer ist nicht korrekt';
|
||||
}
|
||||
if (!filter_var($formData['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
$this->errors['email'] = 'Die Email-Adresse ist inkorrekt';
|
||||
}
|
||||
if ($formData['agreedElectronicalHandling'] !== 1) {
|
||||
$this->errors['accept_electronical_usage'] = 'Für die Online-Registrierung müssen Sie der elektronischen Verarbeitung zustimmen';
|
||||
}
|
||||
}
|
||||
|
||||
protected function saveNewMember(array $formData): void {
|
||||
$salt = $this->generateRandomString();
|
||||
$query = sprintf("INSERT INTO ffajs.clubmember( "
|
||||
. " first_name, last_name, street, zip, town, "
|
||||
. " birthdate, phone, email, child_name, child_street, "
|
||||
. " subscription, bank_name, iban, bic, account_member_name, "
|
||||
. " membership_status, salt) "
|
||||
. "VALUES('%s', '%s', '%s', '%s', '%s', "
|
||||
. " '%s', '%s', '%s', '%s', '%s', "
|
||||
. " '%s', '%s', '%s', '%s', '%s', "
|
||||
. " %d, '%s') ",
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'firstname', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'lastname', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'street', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'zip', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'town', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'birthDate', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'phoneNumber', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'email', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'childName', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'childStreet', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'payHeight', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'bankname', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'iban', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'bic', $salt),
|
||||
$this->getDbEncryptedValueIfNeeded($formData, 'accountmembername', $salt),
|
||||
1,
|
||||
$salt);
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
}
|
||||
|
||||
protected function sendEmail(array $formData): void {
|
||||
$noForm = count($this->errors) === 0;
|
||||
if ($noForm) {
|
||||
$data = ['Name' => $formData['firstname'], $formData['lastname'], 'Strasse' => $formData['street'], 'Ort' => $formData['zip'] . ' ' . $formData['town'],
|
||||
'Geburtstag' => $formData['birthDate'], 'Telefon' => $formData['phoneNumber'], 'Email' => $formData['email'],
|
||||
'Name des Kindes' => $formData['childName'], 'Straße des Kindes' => $formData['childStreet'],
|
||||
'Gewünschter Mitgliedsbeitrag' => $formData['payHeight'], 'Geldinstitut' => $formData['bankname'],
|
||||
'IBAN' => $formData['iban'], 'BIC' => $formData['bic'], 'Kontoinhaber' => $formData['accountmembername'],
|
||||
'Elektronischer Verarbeitung zugestimmg' => $formData['agreedElectronicalHandling']
|
||||
];
|
||||
$mail = $this->initSmtpMailer();
|
||||
$mail->setFrom($formData['email'], $formData['firstname'] . ' ' . $formData['lastname']);
|
||||
$mail->addReplyTo($formData['email'], $formData['firstname'] . ' ' . $formData['lastname']);
|
||||
$mail->addAddress('foerderverein-ajs@gmx.de', 'Vorstand Förderverein AJS');
|
||||
$message = '';
|
||||
foreach ($data as $field => $value) {
|
||||
$message .= $field . ': ' . $value . "\n";
|
||||
}
|
||||
$this->sendMail($mail, 'Mitgliedsantrag', $message, '');
|
||||
$this->templateName = 'membership_success';
|
||||
}
|
||||
}
|
||||
}
|
||||
38
include/newmember.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Newmember extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Nachname', 'type' => 'text', 'size' => 50, 'name' => 'lastname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'last_name', 'optional' => false],
|
||||
['label' => 'Vorname', 'type' => 'text', 'size' => 50, 'name' => 'firstname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'first_name', 'optional' => false],
|
||||
['label' => 'Straße', 'type' => 'text', 'size' => 50, 'name' => 'streetname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'street', 'optional' => false],
|
||||
['label' => 'Plz', 'type' => 'text', 'size' => 5, 'name' => 'zip', 'combine_with_next_line' => true, 'regex' => '/^([0-9]{5})$/', 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'zip', 'optional' => false],
|
||||
['label' => 'Ort', 'type' => 'text', 'size' => 40, 'name' => 'town', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'town', 'optional' => false],
|
||||
['label' => 'Birthday', 'type' => 'date', 'size' => 50, 'name' => 'birthdate', 'combine_with_next_line' => false, 'regex' => '/^((19|20)([0-9]){2}-[0-9]{2})-([0-9]{2})$/', 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'birthdate', 'optional' => false],
|
||||
['label' => 'Phone', 'type' => 'text', 'size' => 50, 'name' => 'phone', 'combine_with_next_line' => false, '/^0([0-9]{2,6})([ ]{0,1})([-\/]{0,1})([ ]{0,1})([0-9 ]{4,25})$/', 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'phone', 'optional' => false],
|
||||
['label' => 'Email', 'type' => 'email', 'size' => 50, 'name' => 'email', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_EMAIL, 'dbfield' => 'email', 'optional' => true],
|
||||
['label' => 'Name des Kindes', 'type' => 'text', 'size' => 50, 'name' => 'childname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'child_name', 'optional' => true],
|
||||
['label' => 'Straße des Kindes', 'type' => 'text', 'size' => 50, 'name' => 'childstreet', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'child_street', 'optional' => true],
|
||||
['label' => 'Gewählter Beitrag', 'type' => 'number', 'size' => 50, 'name' => 'subscription', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'subscription', 'optional' => false],
|
||||
['label' => 'Geldinstitut', 'type' => 'text', 'size' => 50, 'name' => 'bankname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'bank_name', 'optional' => true],
|
||||
['label' => 'IBAN', 'type' => 'text', 'size' => 50, 'name' => 'iban', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'iban', 'optional' => true],
|
||||
['label' => 'BIC', 'type' => 'text', 'size' => 50, 'name' => 'bic', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'bic', 'optional' => true],
|
||||
['label' => 'Kontoinhaber', 'type' => 'text', 'size' => 50, 'name' => 'accountmember', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'account_member_name', 'optional' => true],
|
||||
['label' => 'Mitgliedsstatus', 'type' => 'dbselect', 'size' => 0, 'name' => 'status', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'membership_status',
|
||||
'sourcedb' => 'clubmember_status', 'optionfield' => 'status_text', 'encryption' => false],
|
||||
['label' => 'Position im Verein', 'type' => 'dbselect', 'size' => 0, 'name' => 'position', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'position_id',
|
||||
'sourcedb' => 'clubmember_position', 'optionfield' => 'description', 'encryption' => false, 'with_null_field' => true],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Eintragen';
|
||||
protected string $dbTable = 'clubmember';
|
||||
protected bool $dbGenerateSaltField = true;
|
||||
|
||||
protected function formAction(): void {
|
||||
if (!$this->formCheckFields()) {
|
||||
return;
|
||||
}
|
||||
$this->saveToDb();
|
||||
$this->cleanFields = true;
|
||||
$this->messages[] = 'Mitglied erfolgreich eingetragen.';
|
||||
}
|
||||
}
|
||||
40
include/newpassword.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Newpassword extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Email-Adresse', 'type' => 'email', 'size' => 50, 'name' => 'email', 'combine_with_next_line' => false],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Login-Name zusenden und Paßwort-Reset anfordern';
|
||||
|
||||
protected function formAction(): void {
|
||||
$email = trim(filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL));
|
||||
$query = 'SELECT id, realname, email, username, salt FROM user';
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
while ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
if ($email === $this->decode($row['email'], $row['salt'])) {
|
||||
$salt = $row['salt'];
|
||||
$this->sendResetEmail($row['id'], $row['username'], $this->decode($row['email'], $salt), $this->decode($row['realname'], $salt));
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->templateName = 'newpassword_done';
|
||||
}
|
||||
|
||||
protected function sendResetEmail(int $id, string $username, string $emailAddress, string $realName) {
|
||||
$resetId = $this->generateRandomString();
|
||||
$query = 'update user set recreate_db_hash="' . $resetId . '" where id=' . $id;
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
$mail = $this->initSmtpMailer();
|
||||
$mail->setFrom('foerderverein-ajs@gmx.de', 'Förderverein der August-Jaspert-Schule');
|
||||
$mail->addReplyTo('foerderverein-ajs@gmx.de', 'Förderverein der August-Jaspert-Schule');
|
||||
$mail->addAddress($emailAddress, $realName);
|
||||
$this->sendMail($mail, 'Passwort zurücksetzen für ' . filter_input(INPUT_SERVER, 'SERVER_NAME'), $this->getEmailBody($username, $realName, $resetId), $this->generateSignature(''));
|
||||
}
|
||||
|
||||
protected function getEmailBody(string $username, string $realname, string $code) {
|
||||
$rawBody = file_get_contents('templates/resetaccountmailbody.html');
|
||||
return str_replace(['{{name}}', '{{username}}', '{{server}}', '{{code}}', '{{protocol}}'],
|
||||
[$realname, $username, filter_input(INPUT_SERVER, 'SERVER_NAME'), $code, (filter_input(INPUT_SERVER, 'HTTPS') ? 's' : '') ], $rawBody);
|
||||
}
|
||||
}
|
||||
76
include/payings.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Payings extends Renderer {
|
||||
// ['label' => 'Nachname', 'type' => 'text', 'size' => 50, 'name' => 'lastname', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'last_name', 'optional' => false],
|
||||
protected array $formFields = [
|
||||
['label' => 'Datum', 'type' => 'date', 'size' => 10, 'name' => 'date', 'combine_with_next_line' => false,
|
||||
'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'payment_date', 'optional' => false, 'encryption' => false],
|
||||
['label' => 'Betrag', 'type' => 'number', 'size' => 10, 'name' => 'value', 'combine_with_next_line' => false,
|
||||
'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'payment_height', 'optional' => false, 'encryption' => false],
|
||||
['label' => '', 'type' => 'hidden', 'size'=> 1, 'name' => 'clubmember-id', 'value' => 0, 'combine_with_next_line' => false,
|
||||
'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'clubmember_id', 'optional' => false, 'encryption' => false],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Zahlung eintragen';
|
||||
protected string $dbTable = 'paying_history';
|
||||
|
||||
public function __construct(?string $templateName = null) {
|
||||
parent::__construct($templateName);
|
||||
$id = $this->getUriParams()['id'];
|
||||
$this->formFields[2]['value'] = $id;
|
||||
$this->loadUserData($id);
|
||||
}
|
||||
|
||||
protected function loadUserData(string $id): void {
|
||||
$query = sprintf("SELECT c.first_name, c.last_name, c.salt "
|
||||
. "FROM clubmember c "
|
||||
. "WHERE c.id = %d", $id);
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
if (mysqli_num_rows($dbResult) === 0) {
|
||||
$this->templateName = 'notfound_error';
|
||||
return;
|
||||
}
|
||||
$line = mysqli_fetch_assoc($dbResult);
|
||||
$salt = $line['salt'];
|
||||
$this->content['member-name'] = $this->decode($line['last_name'], $salt) . ', ' . $this->decode($line['first_name'], $salt);
|
||||
$this->predefines = $line;
|
||||
}
|
||||
|
||||
protected function generateContent(): void {
|
||||
$this->loadPayHistory($this->getUriParams()['id']);
|
||||
}
|
||||
|
||||
protected function loadPayHistory(string $id): void {
|
||||
$query = sprintf("SELECT ph.payment_date, ph.payment_height, u.realname, u.salt "
|
||||
. "FROM paying_history ph "
|
||||
. "JOIN `user` u "
|
||||
. " ON u.id = ph.registered_by_id "
|
||||
. "WHERE ph.clubmember_id = %d "
|
||||
. "ORDER BY payment_date DESC", $id);
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
$tableBody = '';
|
||||
while ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
$tableBody .= '<tr>';
|
||||
$tableBody .= '<td>' . $row['payment_date'] . '</td>';
|
||||
$tableBody .= '<td>' . $row['payment_height'] . '</td>';
|
||||
$tableBody .= '<td>' . $this->decode($row['realname'], $row['salt']) . '</td>';
|
||||
$tableBody .= '</tr>';
|
||||
}
|
||||
$this->content['payings'] = $tableBody;
|
||||
}
|
||||
|
||||
protected function formAction(): void {
|
||||
if (!$this->formCheckFields()) {
|
||||
return;
|
||||
}
|
||||
$this->saveToDb();
|
||||
$this->cleanFields = true;
|
||||
}
|
||||
|
||||
protected function createDbKeyValues(): array {
|
||||
$data = parent::createDbKeyValues();
|
||||
$data['keys'][] = '`registered_by_id`';
|
||||
$data['values'][] = $_SESSION['userid'];
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
137
include/planboard.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Planboard extends Renderer {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function generateContent(): void {
|
||||
$this->setOwnColor();
|
||||
$this->setColorLegend();
|
||||
$this->setContentTopics();
|
||||
}
|
||||
|
||||
protected function setOwnColor(): void {
|
||||
$query = sprintf('SELECT c.color
|
||||
FROM `user` u
|
||||
JOIN color c
|
||||
ON c.id = u.color_id
|
||||
WHERE u.id = %d', $_SESSION['userid']);
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
$row = mysqli_fetch_assoc($dbResult);
|
||||
$this->content['owncolor'] = (!$row) ? '000000' : $row['color'];
|
||||
}
|
||||
|
||||
protected function setColorLegend(): void {
|
||||
$legendData = [];
|
||||
$query = 'SELECT c.color, c2.last_name, c2.first_name, u.realname, u.salt usalt, c2.salt csalt
|
||||
FROM `user` u
|
||||
JOIN color c
|
||||
ON c.id = u.color_id
|
||||
LEFT JOIN clubmember c2
|
||||
ON c2.user_id = u.id
|
||||
WHERE u.active = 1';
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
while ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
$legendData[] = '<div style="color:#' . $row['color'] . '">' . (($row['last_name'])
|
||||
? $this->decode($row['last_name'], $row['csalt']) . ', ' . $this->decode($row['first_name'], $row['csalt'])
|
||||
: $this->decode($row['realname'], $row['usalt'])) . '</div>';
|
||||
}
|
||||
$this->content['colors'] = implode('', $legendData);
|
||||
}
|
||||
|
||||
protected function setContentTopics(): void {
|
||||
$topics = $this->getAllTopics();
|
||||
$prerenderedTopics = [];
|
||||
foreach ($topics as $topic) {
|
||||
$prerenderedTopics[] = '<option value="' . $topic['id'] . '">' . $topic['title'] . '</option>';
|
||||
}
|
||||
$this->content['topics'] = implode('', $prerenderedTopics);
|
||||
}
|
||||
|
||||
public function render(): void {
|
||||
$action = filter_input(INPUT_POST, 'action', FILTER_SANITIZE_STRING);
|
||||
if ($action === 'generate') {
|
||||
$this->generateDiscussion();
|
||||
return;
|
||||
}
|
||||
if ($action === 'fetchtopic') {
|
||||
$this->fetchTopic();
|
||||
return;
|
||||
}
|
||||
if ($action === 'setshortdescription') {
|
||||
$this->setShortDescription();
|
||||
return;
|
||||
}
|
||||
if ($action == 'setdiscussion') {
|
||||
$this->setDiscussion();
|
||||
}
|
||||
parent::render();
|
||||
}
|
||||
|
||||
protected function generateDiscussion(): void {
|
||||
$topicName = TRIM(filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING));
|
||||
if ($topicName === '') {
|
||||
echo '{"error": "Der Topic darf nicht leer sein."}';
|
||||
return;
|
||||
}
|
||||
$query = sprintf('SELECT id
|
||||
FROM discussion d
|
||||
where title = "%s"', $topicName);
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
if (mysqli_num_rows($dbResult) > 0) {
|
||||
echo '{"error": "Der Topic existiert schon."}';
|
||||
return;
|
||||
}
|
||||
$query = sprintf('INSERT INTO discussion (title, short_description, discussion) VALUES ("%s", "", "[]")', $topicName);
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
$id = mysqli_insert_id($this->dbConnection);
|
||||
$output = [
|
||||
'topics' => $this->getAllTopics(),
|
||||
'id' => $id,
|
||||
];
|
||||
echo json_encode($output);
|
||||
}
|
||||
|
||||
protected function getAllTopics(): array {
|
||||
$query = 'SELECT d.id, d.title
|
||||
FROM discussion d
|
||||
ORDER BY d.title ';
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
$result = [];
|
||||
while ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
$result[] = ['id' => $row['id'], 'title' => $row['title'] ];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function fetchTopic(): void {
|
||||
$query = sprintf('SELECT short_description, discussion
|
||||
FROM discussion d
|
||||
WHERE id = %d', TRIM(filter_input(INPUT_POST, 'id', FILTER_SANITIZE_STRING)));
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
$row = mysqli_fetch_assoc($dbResult);
|
||||
$result = [
|
||||
'shortdescription' => ($row ? $row['short_description'] : ''),
|
||||
'discussion' => ($row ? $row['discussion'] : '[]'),
|
||||
];
|
||||
echo json_encode($result);
|
||||
}
|
||||
|
||||
protected function setShortDescription(): void {
|
||||
$query = sprintf('UPDATE discussion SET short_description = "%s" WHERE id = %d',
|
||||
filter_input(INPUT_POST, 'text', FILTER_SANITIZE_ADD_SLASHES),
|
||||
filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT));
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
echo '{"result":"success"}';
|
||||
}
|
||||
|
||||
protected function setDiscussion(): void {
|
||||
$query = sprintf('UPDATE discussion SET discussion = "%s" WHERE id = %d',
|
||||
filter_input(INPUT_POST, 'text', FILTER_SANITIZE_ADD_SLASHES),
|
||||
filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT));
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
echo '{"result":"success"}';
|
||||
}
|
||||
}
|
||||
31
include/projects.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Projects extends Renderer {
|
||||
protected function generateContent(): void {
|
||||
$query = 'SELECT p.short_title, p.description, pt.caption
|
||||
FROM project p
|
||||
JOIN project_type pt
|
||||
ON pt.id = p.project_type_id
|
||||
ORDER BY pt.order_id, p.short_title';
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
$previousSection = '';
|
||||
$output = '';
|
||||
while ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
if ($row['caption'] != $previousSection) {
|
||||
if ($output !== '') {
|
||||
$output .= '</ul>';
|
||||
}
|
||||
$output .= '<h3>' . $row['caption'] . '</h3><ul>';
|
||||
$previousSection = $row['caption'];
|
||||
}
|
||||
$output .= '<li>' . $row['short_title'];
|
||||
if (trim($row['description']) != '') {
|
||||
$output .= ' - ' . $row['description'];
|
||||
}
|
||||
$output .= '</li>';
|
||||
}
|
||||
$output .= '</ul>';
|
||||
$this->content['projects'] = $output;
|
||||
}
|
||||
}
|
||||
114
include/projectsmanagement.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Projectsmanagement extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Projekt', 'type' => 'dbselect', 'size' => 0, 'name' => 'shorttitle', 'combine_with_next_line' => true, 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'shorttitle',
|
||||
'sourcedb' => 'project', 'optionfield' => 'short_title', 'encryption' => false, 'with_null_field' => true],
|
||||
['label' => '', 'type' => 'text', 'size' => 20, 'name' => 'new_title', 'combine_with_next_line' => true, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'shorttitle',
|
||||
'optional' => true],
|
||||
['label' => '', 'type' => 'button', 'size' => 0, 'name' => 'addproject', 'combine_with_next_line' => false, 'filter' => false, 'text' => 'Projekt hinzufügen'],
|
||||
['label' => 'Kurze Beschreibung', 'type' => 'text', 'size' => 50, 'name' => 'description', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_STRING, 'dbfield' => 'description',
|
||||
'optionial' => true],
|
||||
['label' => 'Projektart', 'type' => 'dbselect', 'size' => 0, 'name' => 'projecttype', 'combine_with_next_line' => false, 'filter' => FILTER_SANITIZE_NUMBER_INT, 'dbfield' => 'project_type_id',
|
||||
'sourcedb' => 'project_type', 'optionfield' => 'caption', 'encryption' => false, 'with_null_field' => false],
|
||||
];
|
||||
protected bool $isAjaxForm = true;
|
||||
|
||||
public function render(): void {
|
||||
$action = trim(filter_input(INPUT_POST, 'action', FILTER_SANITIZE_STRING));
|
||||
if ($action != '') {
|
||||
switch ($action) {
|
||||
case 'create':
|
||||
$this->createProject();
|
||||
break;
|
||||
case 'getdetails':
|
||||
$this->getDetails();
|
||||
break;
|
||||
case 'setdescription':
|
||||
$this->setDescription();
|
||||
break;
|
||||
case 'setprojecttype':
|
||||
$this->setProjectType();
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
parent::render();
|
||||
}
|
||||
|
||||
protected function createProject(): void {
|
||||
$newName = trim(filter_input(INPUT_POST, 'newname', FILTER_SANITIZE_STRING));
|
||||
if ($newName == '') {
|
||||
echo '{"error": "Jedes Projekt benötigt einen Namen."}';
|
||||
return;
|
||||
}
|
||||
$query = sprintf('select id from project p where short_title = "%s"', $newName);
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
if (mysqli_num_rows($dbResult) > 0) {
|
||||
echo '{"error": "Ein Projekt mit dem Namen existiert bereits."}';
|
||||
return;
|
||||
}
|
||||
$query = sprintf('INSERT INTO project (short_title, description, project_type_id)
|
||||
SELECT "%s", "", id
|
||||
FROM project_type p
|
||||
WHERE caption = "Fortlaufende Projekte"', $newName);
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
$id = mysqli_insert_id($this->dbConnection);
|
||||
$query = 'SELECT id, short_title FROM project p ORDER BY short_title';
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
$list = [];
|
||||
while ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
$list[] = ['id' => $row['id'], 'title' => $row['short_title'] ];
|
||||
}
|
||||
echo json_encode(['list' => $list, 'id' => $id]);
|
||||
}
|
||||
|
||||
protected function setDescription(): void {
|
||||
$newDescription = trim(filter_input(INPUT_POST, 'description', FILTER_SANITIZE_ADD_SLASHES));
|
||||
$query = sprintf('UPDATE project SET description = "%s" WHERE id = "%d"', $newDescription, filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT));
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
echo '{}';
|
||||
}
|
||||
|
||||
protected function getDetails(): void {
|
||||
$query = sprintf('SELECT description, project_type_id FROM project WHERE id = %d', filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT));
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
if ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
echo json_encode(['description' => $row['description'], 'projecttype' => $row['project_type_id']]);
|
||||
} else {
|
||||
echo json_encode(['description' => '', 'projecttype' => '1']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function setProjectType(): void {
|
||||
$newProjectType = trim(filter_input(INPUT_POST, 'newtype', FILTER_SANITIZE_NUMBER_INT));
|
||||
$query = sprintf('UPDATE project SET project_type_id = "%d" WHERE id = "%d"', $newProjectType, filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT));
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
echo '{}';
|
||||
}
|
||||
|
||||
protected function generateContent(): void {
|
||||
$typesQuery = 'SELECT * FROM project_type ORDER BY id';
|
||||
$typesResult = mysqli_query($this->dbConnection, $typesQuery);
|
||||
$types = [];
|
||||
while ($row = mysqli_fetch_assoc($typesResult)) {
|
||||
$types[$row['id'] ] = $row['caption'];
|
||||
}
|
||||
$query = 'SELECT * FROM project ORDER BY short_title';
|
||||
$result = mysqli_query($this->dbConnection, $query);
|
||||
$overviewHtml = '<table><thead><tr><th>Projekt</th><th>Projekttyp</th><tr><thead><tbody>';
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$overviewHtml .= '<tr><td>' . $row['short_title'] . '</td>';
|
||||
$overviewHtml .= '<td><select name="project_type" data="' . $row['id'] . '">';
|
||||
foreach ($types as $id => $type) {
|
||||
$overviewHtml .= '<option value="' . $id . '"' . ($id == $row['project_type_id'] ? ' selected' : '') . '>' . $type . '</option>';
|
||||
}
|
||||
$overviewHtml .= '</select></td>';
|
||||
$overviewHtml .= '</tr>';
|
||||
}
|
||||
$overviewHtml .= '</tbody></table>';
|
||||
$this->content['projects'] = $overviewHtml;
|
||||
}
|
||||
}
|
||||
76
include/register.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Register extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Gewünscher Benutzername', 'type' => 'text', 'size' => 50, 'name' => 'username', 'combine_with_next_line' => false],
|
||||
['label' => 'Vollständiger Name', 'type' => 'text', 'size' => 50, 'name' => 'fullname', 'combine_with_next_line' => false],
|
||||
['label' => 'Email-Adresse', 'type' => 'email', 'size' => 50, 'name' => 'email', 'combine_with_next_line' => false],
|
||||
['label' => 'Gewünschtes Paßwort', 'type' => 'password', 'size' => 50, 'name' => 'password', 'combine_with_next_line' => false],
|
||||
['label' => 'Paßwort wiederholen', 'type' => 'password', 'size' => 50, 'name' => 'password2', 'combine_with_next_line' => false],
|
||||
['label' => 'Ich stimme der Speicherung meiner Daten zu.', 'type' => 'checkbox', 'size' => 50, 'name' => 'accept', 'combine_with_next_line' => false,
|
||||
'value' => 1],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Zugang beantragen';
|
||||
|
||||
protected function formAction(): void {
|
||||
$this->writeToDb();
|
||||
$this->sendEmail();
|
||||
$this->templateName = 'register_successful';
|
||||
}
|
||||
|
||||
protected function formCheckFields(): bool {
|
||||
$username = trim(filter_input(INPUT_POST, 'username', FILTER_SANITIZE_ADD_SLASHES));
|
||||
$user = mysqli_query($this->dbConnection, 'SELECT * FROM user WHERE `username` = lower("' . $username . '")');
|
||||
if ($user->num_rows !== 0) {
|
||||
$this->errors[] = 'Der Benutzername existiert bereits.';
|
||||
}
|
||||
if (!preg_match('/^([a-z0-9]{3,16})$/', $username)) {
|
||||
$this->errors['username'] = 'Der Benutzername darf nur aus Buchstaben (ohne Umlaute) und Zahlen bestehen und muss zwischen drei und sechzen Zeichen lang sein.';
|
||||
}
|
||||
if (!filter_var(strtolower(trim(filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL)), FILTER_VALIDATE_EMAIL))) {
|
||||
$this->errors['email'] = 'Die Email-Adresse ist inkorrekt';
|
||||
}
|
||||
if (strlen(filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING)) < 8) {
|
||||
$this->errors['password'] = 'Das gewählte Paßwort ist zu kurz (Minimum: 8 Zeichen).';
|
||||
}
|
||||
if (filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING) !== filter_input(INPUT_POST, 'password2', FILTER_SANITIZE_STRING)) {
|
||||
$this->errors['password2'] = 'Die Paßwörter stimmen nicht überein.';
|
||||
}
|
||||
if (filter_input(INPUT_POST, 'accept', FILTER_SANITIZE_NUMBER_INT) !== '1') {
|
||||
$this->errors['accept'] = 'Sie müssen der Speicherung Ihrer Daten zustimmen.';
|
||||
}
|
||||
return (count($errors) === 0);
|
||||
}
|
||||
|
||||
protected function writeToDb(): void {
|
||||
$salt = $this->generateRandomString();
|
||||
$encryptedName = $this->encode(trim(filter_input(INPUT_POST, 'fullname', FILTER_SANITIZE_STRING), $salt));
|
||||
$email = strtolower(trim(filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL)));
|
||||
$encryptedEmail = $this->encode($email, $salt);
|
||||
$query = sprintf("INSERT INTO ffajs.`user` (username, password, realname, email, active, save_data_accepted, salt, color_id) "
|
||||
. "VALUES('%s', '%s', '%s', '%s', 0, %d, '%s', (SELECT c.id
|
||||
FROM color c
|
||||
left join `user` u
|
||||
on u.color_id = c.id
|
||||
where u.id is null
|
||||
order by rand()
|
||||
limit 1))",
|
||||
strtolower(trim(filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING))),
|
||||
password_hash(filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING), PASSWORD_DEFAULT),
|
||||
$encryptedName,
|
||||
$encryptedEmail,
|
||||
filter_input(INPUT_POST, 'accept', FILTER_SANITIZE_NUMBER_INT) ?: 0,
|
||||
$salt);
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
}
|
||||
|
||||
protected function sendEmail(): void {
|
||||
$mail = $this->initSmtpMailer();
|
||||
$mail->setFrom('foerderverein-ajs@gmx.de', 'Förderverein der August-Jaspert-Schule');
|
||||
$mail->addReplyTo('foerderverein-ajs@gmx.de', 'Förderverein der August-Jaspert-Schule');
|
||||
$mail->addAddress('foerderverein-ajs@gmx.de', 'Förderverein der August-Jaspert-Schule');
|
||||
$message = 'Ein neuer Antrag auf Benutzerzugang wurde gestellt';
|
||||
$this->sendMail($mail, 'Zugang zu internem Bereich beantragt', $message, '');
|
||||
}
|
||||
}
|
||||
517
include/renderer.php
Normal file
@@ -0,0 +1,517 @@
|
||||
<?php
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\SMTP;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
use PhpImap\Mailbox;
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
class Renderer {
|
||||
protected string $templateName;
|
||||
private array $menuItems = [];
|
||||
protected array $internalMenuItems = [];
|
||||
protected $hiddenCount = 0;
|
||||
protected array $predefines = [];
|
||||
protected array $errors = [];
|
||||
protected array $formFields = [];
|
||||
protected string $formSendButtonLabel = '';
|
||||
protected bool $isAjaxForm = false;
|
||||
protected string $encType = 'application/x-www-form-urlencoded';
|
||||
protected $dbConnection;
|
||||
protected string $encryptionKey = 'CXOoBDbt0qjJ6zlTILGVsFIZTE0aTZUC';
|
||||
protected array $content = [];
|
||||
protected string $dbTable = '';
|
||||
protected bool $dbGenerateSaltField = false;
|
||||
protected bool $dbUpdate = false;
|
||||
protected bool $cleanFields = false;
|
||||
protected array $messages = [];
|
||||
protected string $salt = '';
|
||||
private string $website = '';
|
||||
protected bool $saveAllFields = false;
|
||||
protected string $imapServer = 'imap.gmx.net';
|
||||
protected int $imapPort = 993;
|
||||
protected string $smtpServer = 'mail.gmx.net';
|
||||
protected int $smtpPort = 465;
|
||||
protected string $emailUser = 'foerderverein-ajs@gmx.de';
|
||||
protected string $emailPassword = 'HarheimerWeg16';
|
||||
protected $mbox;
|
||||
|
||||
public function __construct(?string $templateName = null) {
|
||||
session_start();
|
||||
$this->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_STRING)) !== '') {
|
||||
$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 = '<menu>';
|
||||
$scriptName = $this->getScriptName();
|
||||
foreach ($this->menuItems as $page => $link) {
|
||||
if (substr($page, 0, 8) === '$hidden:') {
|
||||
continue;
|
||||
}
|
||||
$menu .= '<a href="' . $link . '"' . ($link === $scriptName ? 'class="active"' : '') . '>' . $page . '</a>';
|
||||
}
|
||||
if (isset($_SESSION) && $_SESSION['userid'] === 0) {
|
||||
$menu .= '<a href="login" class="login"><img src="' . (filter_input(INPUT_SERVER, 'HTTP_HOST') == 'localhost' ? '/ffajs' : '') .
|
||||
'/images/icons/key.png" class="menu-icon" alt="login" /></a>';
|
||||
} else {
|
||||
$menu .= '<div class="internal-menu-main"><span class="intern">Verwaltung</span><div class="internal-menu-sub">';
|
||||
foreach ($this->internalMenuItems as $page => $link) {
|
||||
if (substr($page, 0, 8) === '$hidden:') {
|
||||
continue;
|
||||
}
|
||||
$menu .= '<a class="intern" href="' . $link . '"' . ($link === $scriptName ? 'class="active"' : '') . '>' . $page . '</a>';
|
||||
}
|
||||
$menu .= '</div></div>';
|
||||
$menu .= '<a href="logout" class="login"><img src="' . (filter_input(INPUT_SERVER, 'HTTP_HOST') == 'localhost' ? '/ffajs' : '') .
|
||||
'/images/icons/key.png" class="menu-icon" alt="logout" /></a>';
|
||||
}
|
||||
$menu .= '</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
|
||||
? '<div class="error">' . implode('<br />', $this->errors) . '</div>'
|
||||
: '';
|
||||
$messagesHtml = count($this->messages) > 0
|
||||
? '<div class="messages">' . implode('<br />', $this->messages) . '</div>'
|
||||
: '';
|
||||
$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 '<input type="' . $inputType . '" name="' . $fieldName . '" size="' . $fieldLength . '" value="' . filter_input(INPUT_POST, $fieldName, FILTER_SANITIZE_STRING) . '" />';
|
||||
if (isset($errors[$fieldName])) {
|
||||
echo '<span class="error">' . $errors[$fieldName] . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
protected function renderForm(): string {
|
||||
$form = '<form method="post" action="' . $this->getUrl() . '" enctype="' . $this->encType . '"><table class="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 .= '<span class="error">' . $this->errors[$this->formFields[$formFieldIndex]['name'] ] . '</span>';
|
||||
}
|
||||
if (!isset($this->formFields[$formFieldIndex]['combine_with_next_line'] ) || !$this->formFields[$formFieldIndex]['combine_with_next_line']) {
|
||||
$form .= '<tr><th>' . $label . '</th><td>' . $input . '</td><td>' . $error . '</td></tr>';
|
||||
$label = '';
|
||||
$input = '';
|
||||
$error = '';
|
||||
}
|
||||
}
|
||||
$form .= '</table>';
|
||||
if (!$this->isAjaxForm) {
|
||||
$form .= '<button type="submit" name="action" value="submit">' . $this->formSendButtonLabel . '</button>';
|
||||
}
|
||||
$form .= '<button type="reset">Zurücksetzen</button>';
|
||||
$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 '<label for="' . $this->formFields[$index]['name'] . '">' . $this->formFields[$index]['label'] . '</label>';
|
||||
}
|
||||
|
||||
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 = '<select size="1" id="' . $this->formFields[$index]['name']
|
||||
. '" name="' . $this->formFields[$index]['name'] . '" size="' . $this->formFields[$index]['size'] . '"'
|
||||
. ' value="' . $this->inputValue($index) . '">';
|
||||
$inputValue = $this->inputValue($index);
|
||||
foreach ($this->formFields[$index]['values'] as $value) {
|
||||
$inputField .= '<option value="' . $value . '"';
|
||||
if ($value == $inputValue || (isset($this->formFields[$index]['default']) && $inputValue == '' && $value == $this->formFields[$index]['default'])) {
|
||||
$inputField .= ' selected';
|
||||
}
|
||||
$inputField .= '>' . $value . '</option>';
|
||||
}
|
||||
$inputField .= '</select>';
|
||||
return $inputField;
|
||||
}
|
||||
|
||||
protected function renderStandardInput(int $index): string {
|
||||
return '<input type="' . $this->formFields[$index]['type'] . '" id="' . $this->formFields[$index]['name'] .
|
||||
'" name="' . $this->formFields[$index]['name'] . '" size="' . $this->formFields[$index]['size'] . '"' .
|
||||
' value="' . $this->inputValue($index) . '" />';
|
||||
}
|
||||
|
||||
protected function renderTextarea(int $index): string {
|
||||
return '<textarea id="' . $this->formFields[$index]['name'] .'" '
|
||||
. 'name="' . $this->formFields[$index]['name'] . '" cols="' . $this->formFields[$index]['cols'] . '" '
|
||||
. 'rows="' . $this->formFields[$index]['rows'] . '">' . $this->inputValue($index) . '</textarea>';
|
||||
}
|
||||
|
||||
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 = '<select id="' . $this->formFields[$index]['name'] . '" '
|
||||
. 'name="' . $this->formFields[$index]['name'] . '">';
|
||||
if (isset($this->formFields[$index]['with_null_field']) && $this->formFields[$index]['with_null_field'] === true) {
|
||||
$selectField .= '<option value="NULL">---</option>';
|
||||
}
|
||||
while ($row = mysqli_fetch_assoc($dbResult)) {
|
||||
$selectField .= '<option value="' . $row['id'] . '"';
|
||||
if ($row['id'] == $inputValue) {
|
||||
$selectField .= ' selected';
|
||||
}
|
||||
$selectField .= '>' . $row['label'] . '</option>';
|
||||
}
|
||||
$selectField .= '</select>';
|
||||
return $selectField;
|
||||
}
|
||||
|
||||
protected function renderButton(int $index): string {
|
||||
return '<button id="' . $this->formFields[$index]['name'] . '" name="' . $this->formFields[$index]['name'] . '">' . $this->formFields[$index]['text'] . '</button>';
|
||||
}
|
||||
|
||||
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_STRING) ?: '';
|
||||
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_STRING);
|
||||
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 {
|
||||
return openssl_decrypt($toDecode, 'aes-256-cbc', $this->encryptionKey, 0, $salt);
|
||||
}
|
||||
|
||||
|
||||
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): void {
|
||||
$completeBody = $body . $signature . $this->emailLegalInformation();
|
||||
$mail->Subject = $subject;
|
||||
$mail->Body = $completeBody;
|
||||
$mail->AltBody = 'Diese Email benötigt HTML-Ansicht';
|
||||
$mail->send();
|
||||
}
|
||||
|
||||
protected function connectToImap(): bool {
|
||||
$this->mbox = new PhpImap\Mailbox(
|
||||
'{' . $this->imapServer . ':' . $this->imapPort . '/imap/ssl}INBOX',
|
||||
$this->emailUser,
|
||||
$this->emailPassword,
|
||||
__DIR__,
|
||||
'UTF-8',
|
||||
true,
|
||||
false
|
||||
);
|
||||
$this->mbox->setConnectionArgs(
|
||||
CL_EXPUNGE,
|
||||
3,
|
||||
[]
|
||||
);
|
||||
/* $this->mbox = imap_open ("{" . $this->imapServer . ":" . $this->imapPort . "/imap/ssl}INBOX", $this->emailUser, $this->emailPassword);
|
||||
if ($this->mbox === false) {
|
||||
$errors = imap_errors();
|
||||
$this->errors = is_array($errors) ? $errors : [$errors];
|
||||
}*/
|
||||
return ($this->mbox !== false);
|
||||
}
|
||||
|
||||
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 '<p>-------------<br/>'
|
||||
. $sender .'<br/><br/>'
|
||||
. 'Verein der Freunde und Förderer der August-Jaspert-Schule e.V.<br/>'
|
||||
. 'Harheimer Weg 16<br/>'
|
||||
. '60437 Frankfurt<br/>'
|
||||
. 'Email: foerderverein-ajs@gmx.de<br/>'
|
||||
. 'Homepage: https://fvajs.de<br/>'
|
||||
. 'Registergerich: Amtsgerich Frankfurt a.M. <Registernummer>'
|
||||
. 'Vertretungsberechtigt: Lucas Fastabend, Alexandra <nachname>, Torsten Schulz'
|
||||
. '</p>';
|
||||
}
|
||||
|
||||
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'] . ')');
|
||||
}
|
||||
|
||||
}
|
||||
71
include/savemail.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
require 'mailhandling.php';
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
class Savemail extends Mailhandling {
|
||||
// protected $mbox = null;
|
||||
protected $uid = 0;
|
||||
|
||||
public function __construct(?string $templateName = null) {
|
||||
parent::__construct();
|
||||
if (!$this->connectToImap()) {
|
||||
$this->templateName = 'imaperror';
|
||||
return;
|
||||
}
|
||||
$this->uid = $this->getUriParams()['uid'];
|
||||
$this->type = $this->getUriParams()['type'];
|
||||
$this->content['uid'] = $this->uid;
|
||||
if ($this->type === 'content') {
|
||||
$this->saveEmailBody();
|
||||
}
|
||||
}
|
||||
|
||||
protected function saveEmailBody(): void {
|
||||
$messageStructure = imap_fetchstructure($this->mbox, $this->uid);
|
||||
$this->fetchEmailHeader($this->content);
|
||||
$this->fetchEmailBody($messageStructure, $this->content);
|
||||
$content = $this->generateBodyContent();
|
||||
$newFileName = $this->generateRandomString(64);
|
||||
$salt = $this->generateRandomString();
|
||||
$breaks = array("<br />","<br>","<br/>");
|
||||
$rerenderedContent = str_ireplace($breaks, "\r\n", $content);
|
||||
$this->saveFileLocal($newFileName, $rerenderedContent, $salt);
|
||||
$this->generateDocumentTitle();
|
||||
$query = sprintf('INSERT INTO ffajs.document
|
||||
(title, original_filename, local_filename, salt)
|
||||
VALUES("%s", "%s", "%s", "%s")', $this->content['saved-title'],
|
||||
$this->content['saved-title'],
|
||||
$newFileName, $salt);
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
}
|
||||
|
||||
protected function generateBodyContent(): string {
|
||||
return 'Von: ' . $this->content['sender'] . "\n"
|
||||
. 'An: ' . $this->content['receiver'] . "\n"
|
||||
. 'Datum: ' . $this->content['senddate'] . "\n"
|
||||
. 'Betreff: ' . $this->content['subject'] . "\n\n"
|
||||
. $this->content['emailbody'];
|
||||
}
|
||||
|
||||
protected function generateDocumentTitle(): void {
|
||||
$originalSubject = $this->content['subject'];
|
||||
$count = 0;
|
||||
$found = false;
|
||||
do {
|
||||
$query = sprintf('SELECT id
|
||||
FROM document d
|
||||
WHERE lower(trim(d.title)) = lower(trim("%s"))', $originalSubject);
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
if (mysqli_num_rows($dbResult) > 0) {
|
||||
$found = true;
|
||||
$counter = 0;
|
||||
if (preg_match('/(.*):(\d+)$/', trim($originalSubject))) {
|
||||
$counter = preg_split('/(.*):(\d+)$/', trim($originalSubject));
|
||||
$originalSubject = preg_replace('/(.*):(\d+)$/', '{1}', $originalSubject);
|
||||
}
|
||||
$originalSubject .= ':' . (++$counter);
|
||||
}
|
||||
} while ($found === true && ($count++ < 10));
|
||||
$this->content['saved-title'] = $originalSubject;
|
||||
}
|
||||
}
|
||||
52
include/setpassword.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
include 'renderer.php';
|
||||
|
||||
class Setpassword extends Renderer {
|
||||
protected array $formFields = [
|
||||
['label' => 'Benutzername', 'type' => 'text', 'size' => 50, 'name' => 'username', 'combine_with_next_line' => false],
|
||||
['label' => '', 'type' => 'hidden', 'name' => 'code', 'combine_with_next_line' => false, 'size' => 50],
|
||||
['label' => 'Neues Paßwort', 'type' => 'password', 'name' => 'newpassword1', 'combine_with_next_line' => false, 'size' => 50],
|
||||
['label' => 'Paßwort wiederolen', 'type' => 'password', 'name' => 'newpassword2', 'combine_with_next_line' => false, 'size' => 50],
|
||||
];
|
||||
protected string $formSendButtonLabel = 'Neues Paßwort setzen';
|
||||
protected array $errors = [];
|
||||
|
||||
protected function generateContent(): void {
|
||||
$this->formFields[1]['value'] = filter_input(INPUT_GET, 'code', FILTER_SANITIZE_STRING);
|
||||
}
|
||||
|
||||
protected function formAction(): void {
|
||||
if (!$this->formCheckFields()) {
|
||||
return;
|
||||
}
|
||||
$query = 'UPDATE user SET password="' . password_hash(filter_input(INPUT_POST, 'newpassword1', FILTER_SANITIZE_STRING), PASSWORD_DEFAULT) . '", recreate_db_hash = NULL ' .
|
||||
'WHERE username="' . trim(filter_input(INPUT_POST, 'username', FILTER_SANITIZE_ADD_SLASHES)) . '"';
|
||||
mysqli_query($this->dbConnection, $query);
|
||||
$this->templateName = 'passwordresettet';
|
||||
}
|
||||
|
||||
protected function formCheckFields(): bool {
|
||||
$userName = trim(filter_input(INPUT_POST, 'username', FILTER_SANITIZE_ADD_SLASHES));
|
||||
if (!preg_match('/^([a-z0-9]{3,16})$/', $userName)) {
|
||||
$this->errors['username'] = 'Der Benutzername darf nur aus Buchstaben (ohne Umlaute) und Zahlen bestehen und muss zwischen drei und sechzen Zeichen lang sein.';
|
||||
} else {
|
||||
$query = 'SELECT id, recreate_db_hash FROM user WHERE username="' . $userName . '"';
|
||||
$dbResult = mysqli_query($this->dbConnection, $query);
|
||||
if (mysqli_num_rows($dbResult) == 0) {
|
||||
$this->errors['username'] = 'Der Benutzername ist nicht vergeben';
|
||||
} else {
|
||||
$row = mysqli_fetch_assoc($dbResult);
|
||||
if ($row['recreate_db_hash'] !== filter_input(INPUT_POST, 'code', FILTER_SANITIZE_STRING)) {
|
||||
$this->errors[] = 'Ungültige Anfrage. Bitte beginnen Sie den Vorgan von vorne.';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strlen(filter_input(INPUT_POST, 'newpassword1', FILTER_SANITIZE_STRING)) < 8) {
|
||||
$this->errors['newpassword1'] = 'Das gewählte Paßwort ist zu kurz (Minimum: 8 Zeichen).';
|
||||
}
|
||||
if (filter_input(INPUT_POST, 'newpassword2', FILTER_SANITIZE_STRING) !== filter_input(INPUT_POST, 'newpassword1', FILTER_SANITIZE_STRING)) {
|
||||
$this->errors['newpassword2'] = 'Die Paßwörter stimmen nicht überein.';
|
||||
}
|
||||
return (count($this->errors) === 0);
|
||||
}
|
||||
}
|
||||
15
index.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
if (isset($_REQUEST['q']) && substr($_REQUEST['q'], -4) === '.php') {
|
||||
$url = substr($_REQUEST['q'], 0, -4);
|
||||
header('Location: ' . $url, true, 301);
|
||||
die();
|
||||
}
|
||||
if (isset($_REQUEST['q']) && file_exists('include/' . $_REQUEST['q'] . '.php')) {
|
||||
include 'include/' . $_REQUEST['q'] . '.php';
|
||||
$className = ucfirst($_REQUEST['q']);
|
||||
$renderer = new $className(null);
|
||||
} else {
|
||||
include 'include/renderer.php';
|
||||
$renderer = new Renderer(null);
|
||||
}
|
||||
$renderer->render();
|
||||
6
info/exclude
Normal file
@@ -0,0 +1,6 @@
|
||||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
||||
132
libs/imap_driver.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
class ImapDriver {
|
||||
private $fp;
|
||||
public $error;
|
||||
private $commandCounter = "00000001";
|
||||
public $lastResponse = array();
|
||||
public $lastEndline = "";
|
||||
|
||||
public function init(string $host, int $port): bool {
|
||||
$errno = 0;
|
||||
$errstr = '';
|
||||
if (!($this->fp = fsockopen($host, $port, $errno, $errstr, 15))) {
|
||||
$this->error = "Could not connect to host ($errno) $errstr";
|
||||
return false;
|
||||
}
|
||||
if (!stream_set_timeout($this->fp, 15)) {
|
||||
$this->error = "Could not set timeout";
|
||||
return false;
|
||||
}
|
||||
fgets($this->fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
private function close(): void {
|
||||
fclose($this->fp);
|
||||
}
|
||||
|
||||
private function command(string $command): void {
|
||||
$this->lastResponse = array();
|
||||
$this->lastEndline = "";
|
||||
fwrite($this->fp, "$this->commandCounter $command\r\n");
|
||||
while ($line = trim(fgets($this->fp))) {
|
||||
$encodedLine = mb_convert_encoding($line, 'UTF-8');
|
||||
$line_arr = preg_split('/\s+/', $encodedLine, 0, PREG_SPLIT_NO_EMPTY);
|
||||
if (count($line_arr) > 0) {
|
||||
$code = array_shift($line_arr);
|
||||
if (strtoupper($code) == $this->commandCounter) {
|
||||
$this->lastEndline = join(' ', $line_arr);
|
||||
break;
|
||||
}
|
||||
$this->lastResponse[] = $line;
|
||||
} else {
|
||||
$this->lastResponse[] = $line;
|
||||
}
|
||||
}
|
||||
$this->incrementCounter();
|
||||
}
|
||||
|
||||
private function incrementCounter(): void {
|
||||
$this->commandCounter = sprintf('%08d', intval($this->commandCounter) + 1);
|
||||
}
|
||||
|
||||
public function login(string $login, string $pwd): bool {
|
||||
$this->command("LOGIN $login $pwd");
|
||||
if (preg_match('~^OK~', $this->lastEndline)) {
|
||||
return true;
|
||||
}
|
||||
$this->error = join(', ', $this->lastResponse);
|
||||
$this->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
public function selectFolder(string $folder): bool{
|
||||
$this->command("SELECT $folder");
|
||||
if (preg_match('~^OK~', $this->lastEndline)) {
|
||||
return true;
|
||||
}
|
||||
$this->error = join(', ', $this->lastResponse);
|
||||
$this->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUidsBySearch(string $criteria): array|false {
|
||||
$this->command("SEARCH $criteria");
|
||||
if (preg_match('~^OK~', $this->lastEndline)
|
||||
&& is_array($this->lastResponse)
|
||||
&& count($this->lastResponse) == 1) {
|
||||
$splitted_response = explode(' ', $this->lastResponse[0]);
|
||||
$uids = array();
|
||||
foreach ($splitted_response as $item) {
|
||||
if (preg_match('~^\d+$~', $item)) {
|
||||
$uids[] = $item;
|
||||
}
|
||||
}
|
||||
return $uids;
|
||||
}
|
||||
$this->error = join(', ', $this->lastResponse);
|
||||
$this->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getHeadersFromUid(int $uid): array|false {
|
||||
$this->command("FETCH $uid BODY.PEEK[HEADER]");
|
||||
if (!preg_match('~^OK~', $this->lastEndline)) {
|
||||
array_shift($this->lastResponse);
|
||||
$headers = array();
|
||||
$prev_match = '';
|
||||
foreach ($this->lastResponse as $item) {
|
||||
$match = [];
|
||||
if (preg_match('~^([a-z][a-z0-9-_]+):~is', $item, $match)) {
|
||||
$header_name = strtolower($match[1]);
|
||||
$prev_match = $header_name;
|
||||
$headers[$header_name] = trim(substr($item, strlen($header_name) + 1));
|
||||
|
||||
} else {
|
||||
$headers[] .= " " . $item;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
$this->error = join(', ', $this->lastResponse);
|
||||
$this->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getEmail(string|int $uid): array|false {
|
||||
$this->command('FETCH ' . $uid . ' BODY');
|
||||
if (preg_match('~^OK~', $this->lastEndline)) {
|
||||
return $this->parseEmailBody($this->lastResponse[0]);
|
||||
}
|
||||
$this->error = join(', ', $this->lastResponse);
|
||||
$this->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function parseEmailBody(string $body): array {
|
||||
$contentStart = stripos($body, 'body (');
|
||||
$content = substr($body, $contentStart + 6, -1);
|
||||
print_r($content);die;
|
||||
return [];
|
||||
}
|
||||
}
|
||||
2
nbproject/private/private.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
index.file=index.php
|
||||
url=http://localhost/ffajs/
|
||||
8
nbproject/project.properties
Normal file
@@ -0,0 +1,8 @@
|
||||
auxiliary.org-netbeans-modules-html-editor-lib.default-html-public-id=HTML5
|
||||
include.path=${php.global.include.path}
|
||||
php.version=PHP_80
|
||||
source.encoding=UTF-8
|
||||
src.dir=.
|
||||
tags.asp=false
|
||||
tags.short=false
|
||||
web.root=.
|
||||
9
nbproject/project.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.php.project</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/php-project/1">
|
||||
<name>ffajs</name>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
||||
2
script/jquery-3.6.3.min.js
vendored
Normal file
7
script/jquery-ui.min.css
vendored
Normal file
6
script/jquery-ui.min.js
vendored
Normal file
1
script/tinymce
Symbolic link
@@ -0,0 +1 @@
|
||||
../vendor/tinymce/tinymce
|
||||
BIN
style/images/ui-icons_444444_256x240.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
style/images/ui-icons_555555_256x240.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
style/images/ui-icons_777620_256x240.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
style/images/ui-icons_777777_256x240.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
style/images/ui-icons_cc0000_256x240.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
style/images/ui-icons_ffffff_256x240.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
7
style/jquery-ui.min.css
vendored
Normal file
5
style/jquery-ui.structure.min.css
vendored
Normal file
5
style/jquery-ui.theme.min.css
vendored
Normal file
196
style/main.css
Normal file
@@ -0,0 +1,196 @@
|
||||
html, body {
|
||||
width:100%;
|
||||
height:100%;
|
||||
background-color:#fff;
|
||||
margin:0;
|
||||
}
|
||||
.head-background {
|
||||
background-image: url(https://image.jimcdn.com/app/cms/image/transf/none/path/sa7b67a2d4fc6e657/backgroundarea/ib8dbdf53b879f821/version/1560373724/image.jpg);
|
||||
height: 18em;
|
||||
width:100%;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
display:inline-block;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0.8;
|
||||
z-index: 0;
|
||||
}
|
||||
header {
|
||||
position: fixed;
|
||||
top: 1.5em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
h1, h2, h3, menu{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
}
|
||||
h1 {
|
||||
color:#fff;
|
||||
text-align:center;
|
||||
line-height:3;
|
||||
}
|
||||
h2 {
|
||||
padding-top:0.5em;
|
||||
font-size:1.3em;
|
||||
}
|
||||
h3 {
|
||||
font-size:1.1em;
|
||||
font-weight:bold;
|
||||
}
|
||||
a {
|
||||
color: #00b;
|
||||
text-decoration:none;
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
menu {
|
||||
background-color: rgba(68,68,68,0.5);
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
line-height: 2;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
left:0;
|
||||
right:0;
|
||||
}
|
||||
menu > a.intern,
|
||||
menu > div > span.intern {
|
||||
color: #ffb;
|
||||
font-size:1.2em;
|
||||
}
|
||||
menu > a:not(.intern) {
|
||||
color: #fff;
|
||||
font-size:1.2em;
|
||||
}
|
||||
menu > a {
|
||||
font-weight: normal;
|
||||
padding: 0 1em;
|
||||
line-height: 2;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
transition: background 0.27s;
|
||||
}
|
||||
menu > a:hover {
|
||||
font-weight:normal;
|
||||
background-color: rgba(224,224,224,0.4);
|
||||
}
|
||||
menu > a.active {
|
||||
font-weight:bold;
|
||||
}
|
||||
menu > a > .menu-icon {
|
||||
max-width:16px;
|
||||
max-height:16px;
|
||||
}
|
||||
menu > .login {
|
||||
float: right;
|
||||
}
|
||||
menu .internal-menu-main {
|
||||
display:inline-block;
|
||||
}
|
||||
menu .internal-menu-sub {
|
||||
padding: 0 6px;
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
min-width: 160px;
|
||||
border: 1px solid #666666;
|
||||
z-index: 1;
|
||||
box-shadow: 1px 1px 0 #aaa;
|
||||
}
|
||||
menu .internal-menu-sub a {
|
||||
display: block;
|
||||
text-align:left;
|
||||
color: #fa0;
|
||||
text-shadow: -0.5px 0.5px #666;
|
||||
}
|
||||
menu .internal-menu-sub a:hover {
|
||||
background-color: rgba(224, 224, 224, 0.2);
|
||||
}
|
||||
menu .internal-menu-main:hover {
|
||||
color:#ff0000;
|
||||
}
|
||||
menu .internal-menu-main:hover .internal-menu-sub {
|
||||
display: block;
|
||||
}
|
||||
menu .header-main-space {
|
||||
height:9.5em;
|
||||
}
|
||||
main {
|
||||
padding: 0 10%;
|
||||
background-color: #e0e0e0;
|
||||
position: absolute;
|
||||
bottom: 2em;
|
||||
top: 18em;
|
||||
left:0;
|
||||
right:0;
|
||||
z-index: 0;
|
||||
}
|
||||
footer {
|
||||
display:block;
|
||||
position:fixed;
|
||||
height: 2em;
|
||||
background-color:#e0e0e0;
|
||||
bottom:0;
|
||||
width:100%;
|
||||
line-height:2em;
|
||||
}
|
||||
footer > span,
|
||||
footer > a{
|
||||
padding: 0 1em;
|
||||
}
|
||||
.footer-imprint {
|
||||
float:right;
|
||||
}
|
||||
.error {
|
||||
color: #c00;
|
||||
}
|
||||
.form th {
|
||||
text-align: left;
|
||||
}
|
||||
.messages {
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
.content {
|
||||
background-color: #fff;
|
||||
height: 100%;
|
||||
padding: 0.5em 1em;
|
||||
overflow: auto;
|
||||
margin-top: -1.2em;
|
||||
}
|
||||
.toggle-collapse {
|
||||
border: 1px solid #333;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.emailattachments {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.planboard-discussion {
|
||||
border: 1px solid #000000;
|
||||
padding: 2px 2px 2px 16px;
|
||||
min-height: 5em;
|
||||
width:99%;
|
||||
cursor:text;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
.planboard-settings > div {
|
||||
display: inline-block;
|
||||
width: 49%;
|
||||
vertical-align: top;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
26
templates/accounts.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<h2>Nicht bearbeitete Anfragen</h2>
|
||||
<form action="accounts.php" method="post">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Benutzername</th>
|
||||
<th>Realname</th>
|
||||
<th>Email-Adresse</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{inactive_accounts}}
|
||||
</table>
|
||||
<h2>Aktive Zugänge</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Benutzername</th>
|
||||
<th>Realname</th>
|
||||
<th>Email-Adresse</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{active_accounts}}
|
||||
</table>
|
||||
</form>
|
||||
11
templates/bulkmail.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<script src="/script/tinymce/tinymce.min.js" referrerpolicy="origin"></script>
|
||||
<h2>Versende eine Email an alle aktiven Mitglieder</h2>
|
||||
{{form}}
|
||||
<script>
|
||||
tinymce.init({
|
||||
selector: 'textarea',
|
||||
toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat',
|
||||
tinycomments_mode: 'embedded',
|
||||
promotion: false
|
||||
});
|
||||
</script>
|
||||
2
templates/bulkmail_success.html
Normal file
@@ -0,0 +1,2 @@
|
||||
Email erfolgreich versendet an: <br/>
|
||||
{{recipients}}
|
||||
9
templates/contact.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<h2>Gerne sind wir für Sie da</h2>
|
||||
<p>Sie können uns gerne eine Email senden an <a href="mailto:foerderverein-ajs@gmx.de?subject=Anfrage an den Förderverein August-Jaspert-Schule">foerderverein-ajs@gmx.de</a>.
|
||||
<form method="post" action="contact.php">
|
||||
<h2>Oder Sie senden uns hier eine Nachricht.</h2>
|
||||
Hinweis: Die Daten die Sie hier eingeben, werden nicht gespeichert, sondern direkt an den Vorstand per Email gesendet.<br/>
|
||||
Ihr Name und Ihre Email-Adresse sind keine Pflichtfelder. Aber natürlich können wir Ihnen nur Antworten, wenn Sie uns Ihre Email-Adresse mitteilen.
|
||||
{{errors}}
|
||||
{{form}}
|
||||
|
||||
50
templates/documents.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<script>
|
||||
let fileName = '';
|
||||
$(document).ready(function() {
|
||||
$('#toggle-collapse').click(function() {
|
||||
$('#new-document').toggle();
|
||||
console.log($(this).css('display'));
|
||||
$('#toggle-collapse').text($('#new-document').is(':hidden') ? '+' : '-');
|
||||
});
|
||||
$("[name='delete']").click(function() {
|
||||
fileName = $(this).parent().parent().children().first().text();
|
||||
$("#yesno").val = false;
|
||||
$("#yesno").text('Soll "' + fileName + '" wirklich gelöscht werden?');
|
||||
$("#yesno").dialog({
|
||||
close: function(event, ui) { console.log(event, ui); }
|
||||
});
|
||||
$("#yesno").data("callback", yesNoCallback).dialog('open');
|
||||
});
|
||||
function yesNoCallback(result) {
|
||||
if (result === true) {
|
||||
$.post('deletedocument',
|
||||
{
|
||||
'file': fileName
|
||||
}).done(function(result) {
|
||||
document.location.href = 'documents?ts=' + Date.now();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<div>
|
||||
<h2><span id="toggle-collapse" class="toggle-collapse">+</span>Neues Dokument hinzufügen</h2>
|
||||
<div id="new-document" style="display:none">
|
||||
{{form}}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Documenttitel</th>
|
||||
<th>Original-Dateiname</th>
|
||||
<th>Link</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{documents}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
16
templates/donate.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<h2>Ihre Spenden sind uns Willkommen</h2>
|
||||
<p>Damit der Verein auch Zukünftig viele Projekte unterstützen, weiter das Frühstück liefern und auch Klassenfahrten unterstützen kann, sind wir auf Ihre Hilfe angewiesen.</p>
|
||||
<p>Das Gute: Als Gemeinnützer Verein können Sie von uns eine Spendenbescheinigung erhalten, die Sie dann Steuerlich geltend machen können. Sprechen Sie uns gerne darauf an.</p>
|
||||
<h3>Spendenkonto</h3>
|
||||
<p>Frankfurter Volksbank<br/>
|
||||
IBAN: DE51 5019 0000 6000 6097 20<br/>
|
||||
BIC: FFVBDEFF</p>
|
||||
<h3>Rechtliche Hinweise</h3>
|
||||
<h4>Spenden bis 200 Euro</h4>
|
||||
Sofern die Spende maximal 200 Euro beträgt, benötigt das Finanzamt nicht zwingend eine Spendenbescheinigung zur steuerliche Absetzung der Spende. Hier genügt es der Bundesfinanzverwaltung, wenn der Spender eine Buchungsbestätigung seiner Bank als Nachweis zusammen mit seiner Steuererklärung beim Finanzamt einreicht. Es handelt sich um einen vereinfachten Spenden-Nachweis. Darauf müssen folgende Informationen enthalten sein:<br/>
|
||||
Name und Kontonummer von Empfänger & Spender<br/>
|
||||
Betrag (in Euro) & Buchungstag<br/>
|
||||
Steuerbegünstigter Zweck<br/>
|
||||
Angabe, ob es sich um eine Spende oder um einen Mitgliedsbeitrag handelt<br/>
|
||||
<h4>Spenden über 200 Euro</h4>
|
||||
Übersteigt die Spende den Grenzwert von 200 Euro, benötigt das Finanzamt vom Spender eine vom Verein ausgestellte Spendenbescheinigung, also einen Nachweis über den erhaltenen Betrag. Fragen Sie einfach nach, z.B. über unser <a href="/contact">Kontaktformular</a>.
|
||||
2
templates/editmember.html
Normal file
@@ -0,0 +1,2 @@
|
||||
{{messages}}
|
||||
{{form}}
|
||||
15
templates/emailinbox.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{{errors}}
|
||||
<div class="emailinbox">
|
||||
<div class="emailinbox-headers">
|
||||
<h3>Emails:</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
{{mails}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="emailinbox-folders">
|
||||
<h3>Ordner:</h3>
|
||||
{{folders}}
|
||||
</div>
|
||||
</div>
|
||||
1
templates/error_smtp.html
Normal file
@@ -0,0 +1 @@
|
||||
Die Email konnte nicht gesendet werden.
|
||||
4
templates/footer.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<footer>
|
||||
<span class="footer-copyright">(c) 2022 Förderverein <a href="https://www.august-jaspert-schule.com" target="_blank">August-Jaspert-Schule e.V.</a></span>
|
||||
<a href="imprint" class="footer-imprint">Impressum</a>
|
||||
</footer>
|
||||
3
templates/header.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>
|
||||
<h1>Förderverein August-Jaspert-Schule e.V.</h1>
|
||||
</header>
|
||||
3
templates/imaperror.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<h2>Fehler mit dem Postfach</h2>
|
||||
<p>Die Verbindung zum Postfach konnte nicht hergestellt werden.</p>
|
||||
{{errors}}
|
||||
15
templates/imprint.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<h2>Verein der Freunde und Förderer der August-Jaspert-Schule e. V.</h2>
|
||||
Harheimer Weg 16<br/>
|
||||
60437 Frankfurt am Main (Bonames)<br/>
|
||||
Email: foerderverein-AJS@gmx.de</br>
|
||||
Tel: xxx-xxxxxxx
|
||||
<h2>Vorstand</h2>
|
||||
<ul class="nospec">
|
||||
<li>Vorsitzender: Lucas Fastabend</li>
|
||||
<li>Kassenwartin: Alexandra Grabmann</li>
|
||||
<li>Schriftführer: Torsten Schulz</li>
|
||||
</ul>
|
||||
<h2>Amtliche Informationen</h2>
|
||||
Registergericht: Amtsgericht Frankfurt a.M., Gerichtsstraße 2, 60313 Frankfurt am Main<br/>
|
||||
Vereinsregisternummer: <br/>
|
||||
Umsatzsteueridentifkationsnummer: <br/>
|
||||
5
templates/index.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<h2>Willkommen beim Verein der Freunde und Förderer der August-Jaspert-Schule e. V.</h2>
|
||||
<p>Der Förderverein wurde im Jahr 2005 von Eltern und Lehrern der Schule mit dem Ziel gegründet, die pädagogischen, kulturellen und sozialen Aufgaben an der August-Jaspert-Schule durch Bereitstellung zusätzlicher Mittel zu unterstützen.</p>
|
||||
<p>Der Verein hat sich zum Ziel gesetzt, die vielfältige Bildung alles Kinder an unserer Schule durch materielle und finanzielle Unterstützung zu erweitern, soweit dies nicht aus dem Schul-Etat geleistet werden kann.</p>
|
||||
<p>Wir arbeiten eng mit dem Schulelternbeirat und dem Kollegium der August-Jaspert-Schule zusammen.</p>
|
||||
<p>Über Anregungen, Wünsche und Verbesserungsvorschläge sowie über tatkräftige Hilfe freuen wir uns immer.</p>
|
||||
5
templates/login.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<h2>Login</h2>
|
||||
{{errors}}
|
||||
{{form}}
|
||||
<a href="register">Login beantragen</a><br/>
|
||||
<a href="newpassword">Benutzername/Paßwort vergessen</a>
|
||||
1
templates/login_error.html
Normal file
@@ -0,0 +1 @@
|
||||
<div class="error">Diese Seite ist nur mit Login zugänglich</div>
|
||||
29
templates/mail.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<a href="emailinbox">Zurück zum Posteingang</a><br/>
|
||||
<a href="savemail?type=content&uid={{uid}}">Email-Text als Datei speichern</a> (Der Betreff wird als Dateiname verwendet, wenn noch nicht vorhanden. Ansonsten wird ein Ergänzung vorgesetzt.)<br/><br/>
|
||||
<table class="form">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Von</th>
|
||||
<td>{{sender}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>An</th>
|
||||
<td>{{receiver}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<td>{{senddate}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Betreff</th>
|
||||
<td>{{subject}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="emailbody">
|
||||
{{emailbody}}
|
||||
</div>
|
||||
<div class="emailattachments">
|
||||
<h2>Anhänge</h2>
|
||||
{{attachments}}
|
||||
</div>
|
||||
15
templates/members.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<a href="newmember">Neues Mitglied eintragen</a>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Mitglieds-Nr.</th>
|
||||
<th>Name</th>
|
||||
<th>Email-Adresse</th>
|
||||
<th>Letzte Zahlung</th>
|
||||
<th>Mitglied seit</th>
|
||||
<th>Mitgliedsstatus</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{memberlist}}
|
||||
</table>
|
||||
8
templates/membership.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<h2>Sie möchten Mitglied werden?</h2>
|
||||
<p>Selbstverständlich freuen wir uns über jede*n der/die bei uns im Förderverein Mitglied werden möchte.</p>
|
||||
<p>Füllen Sie einfach (alle) Felder hier aus, und wir melden uns schnellstmöglich wieder bei Ihnen.</p>
|
||||
<h3>Hinweis</h3>
|
||||
Die hier eingegebenen Daten werden per Email an den Vorstand des Fördervereins gesendet.<br/>
|
||||
Das absenden dieses Formulares ist noch keine rechtlich bindende Mitgliedschaft. Wir werden Ihnen nach Absenden ein vorausgefülltes Formular zusenden, welches Sie uns dann nur noch unterschrieben zurücksenden müssen.
|
||||
<br/><br/>
|
||||
{{form}}
|
||||
3
templates/membership_success.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<h2>Vielen Dank!</h2>
|
||||
Wir werden Ihre Daten prüfen und senden Ihnen dann umgehend den Vorausgefüllten Mitgliedsantrag zu, den Sie dann nur noch unterschrieben zurück senden müssen.
|
||||
|
||||
2
templates/message_success.html
Normal file
@@ -0,0 +1,2 @@
|
||||
<h2>Vielen Dank für Ihre Anfrage.</h2>
|
||||
Wir werden sie schnellstmöglich bearbeiten und uns ggf. wieder bei Ihnen welden.
|
||||
2
templates/newmember.html
Normal file
@@ -0,0 +1,2 @@
|
||||
{{messages}}
|
||||
{{form}}
|
||||
6
templates/newpassword.html
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
<h2>Zugangsdaten anfordern</h2>
|
||||
{{errors}}
|
||||
Bitte geben Sie Ihre Email-Adresse an. Falls diese hinterlegt ist, senden wir Ihnen Ihren Benutzernamen, sowie einen Link zum zurücksetzen des Paßwortes zu.
|
||||
{{form}}
|
||||
<a href="login">Zum Login</a><br/>
|
||||
1
templates/newpassword_done.html
Normal file
@@ -0,0 +1 @@
|
||||
Die Email wurde versendet. Sollten Sie keine erhalten, schauen Sie bitte in Ihren Spam-Ordner. Sollten Sie auch da keine Email finden, <a href="/register">beantragen Sie bitte einen neuen Account</a>.
|
||||
0
templates/none.html
Normal file
48
templates/page.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Förderverein August-Jaspert-Schule e.V.</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/main.css" />
|
||||
<link href="style/jquery-ui.min.css" rel="stylesheet">
|
||||
<script type="text/javascript" src="script/jquery-3.6.3.min.js"></script>
|
||||
<script src="script/jquery-ui.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="head-background"></div>
|
||||
{{menu}}
|
||||
{{header}}
|
||||
<div class="header-main-space"></div>
|
||||
<main>
|
||||
<div class="content">
|
||||
{{content}}
|
||||
</div>
|
||||
</main>
|
||||
{{footer}}
|
||||
<div id="yesno" title="Sind Sie sicher?">Zum testen</div>
|
||||
</body>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#yesno").dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 400,
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
buttons: {
|
||||
"Ja, wirklich löschen": function(event) {
|
||||
$(this).dialog( "close" );
|
||||
$(this).data("callback")(true);
|
||||
},
|
||||
"Nein, nicht löschen": function() {
|
||||
$("#yesno").val = 1;
|
||||
$(this).dialog( "close" );
|
||||
$(this).data("callback")(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
|
||||
1
templates/passwordresettet.html
Normal file
@@ -0,0 +1 @@
|
||||
Das neue Paßwort wurde gesetzt. Bitte loggen Sie sich <a href="/login">hier</a> ein.
|
||||
14
templates/payings.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<h2>Zahlungen von {{member-name}}</h2>
|
||||
{{form}}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Betrag</th>
|
||||
<th>Eingetragen von</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{payings}}
|
||||
</tbody>
|
||||
</table>
|
||||
188
templates/planboard.html
Normal file
@@ -0,0 +1,188 @@
|
||||
Ideenboard
|
||||
Diskussions-Topic: <select id="topic">
|
||||
<option value="new">Neu</option>
|
||||
{{topics}}
|
||||
</select>
|
||||
<input type="text" name="newtopic" id="newtopic" />
|
||||
<button type="button" id="generate">Erstellen</button><br/>
|
||||
<div class="planboard-settings">
|
||||
<div>
|
||||
Kurzbeschreibung:<br/>
|
||||
<textarea cols="50" rows="4" id="shortdescription"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
Farblegende:<br/>
|
||||
{{colors}}
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div id="textboard" class="planboard-discussion">
|
||||
</div>
|
||||
<script>
|
||||
var text;
|
||||
var activeLine = -1;
|
||||
var ownColor= "{{owncolor}}";
|
||||
$(document).ready(function() {
|
||||
text = [
|
||||
];
|
||||
$("#topic").change(function() {
|
||||
if ($(this).val() !== 'new') {
|
||||
$("#newtopic").hide();
|
||||
$("#generate").hide();
|
||||
} else {
|
||||
$("#newtopic").show();
|
||||
$("#generate").show();
|
||||
}
|
||||
$.post('planboard', {
|
||||
'action': 'fetchtopic',
|
||||
'id': $(this).val()
|
||||
},
|
||||
null,
|
||||
'json'
|
||||
).done(function(response) {
|
||||
text = JSON.parse(response.discussion);
|
||||
renderText();
|
||||
$("#shortdescription").val(response.shortdescription);
|
||||
});
|
||||
});
|
||||
$("#generate").click(function() {
|
||||
$.post("planboard", {
|
||||
"action": "generate",
|
||||
"name": $("#newtopic").val()
|
||||
},
|
||||
null,
|
||||
'json'
|
||||
).done(function(response) {
|
||||
if ("error" in response) {
|
||||
alert(response.error);
|
||||
return;
|
||||
}
|
||||
$("#topic > option").remove();
|
||||
let newItem = $('<option>Neu</option>');
|
||||
newItem.attr('id', 'new');
|
||||
$("#topic").append(newItem);
|
||||
response.topics.forEach(function(item) {
|
||||
let newItem = $('<option></option>');
|
||||
newItem.attr('id', item.id);
|
||||
newItem.text(item.title);
|
||||
if (item.id == response.id) {
|
||||
newItem.attr('selected', 'selected');
|
||||
}
|
||||
$("#topic").append(newItem);
|
||||
});
|
||||
}).fail(function(message) {
|
||||
alert(message);
|
||||
});
|
||||
});
|
||||
$("#textboard").click(function(event) {
|
||||
if (typeof $(event.target).attr("id") !== 'undefined' && $(event.target).attr("id") === 'editor') {
|
||||
return;
|
||||
}
|
||||
const eventPosition = {'x': event.pageX, 'y': event.pageY};
|
||||
const divPosition = {'x': $(this).offset().left, 'y': $(this).offset().top};
|
||||
const clickPosition = relativePosition(divPosition, eventPosition);
|
||||
if (clickPosition.x < 16) {
|
||||
return;
|
||||
}
|
||||
let line = Math.floor(clickPosition.y / 20);
|
||||
$(this).children("input").remove();
|
||||
line = Math.min(text.length - 1, line);
|
||||
if (line === -1) {
|
||||
text[0] = {'color': ownColor, 'text': ''};
|
||||
line = 0;
|
||||
}
|
||||
if (text[line].color != ownColor) {
|
||||
alert('Diese Zeile kannst Du nicht editieren, sondern nur der Ersteller.');
|
||||
return;
|
||||
}
|
||||
createTextInput(line);
|
||||
});
|
||||
$("#shortdescription").focusout(function() {
|
||||
$.post("planboard", {
|
||||
"action": "setshortdescription",
|
||||
"id": $("#topic").val(),
|
||||
"text": $(this).val(),
|
||||
},
|
||||
null,
|
||||
"json"
|
||||
);
|
||||
});
|
||||
renderText();
|
||||
});
|
||||
function createTextInput(line) {
|
||||
let textInput = $("<input>");
|
||||
textInput.css({"position": "absolute", "top": " " + (line * 22) + "px", "left": "16px", "width": "calc(100% - 24px)", "color": "#" + ownColor});
|
||||
textInput.attr('id', "editor");
|
||||
textInput.val(text[line].text);
|
||||
textInput.focusout(setNewText);
|
||||
textInput.keypress(function(event){
|
||||
var keycode = (event.keyCode ? event.keyCode : event.which);
|
||||
if(keycode == '13'){
|
||||
setNewText();
|
||||
}
|
||||
});
|
||||
$("#textboard").append(textInput);
|
||||
$("#editor").focus();
|
||||
activeLine = line;
|
||||
}
|
||||
function relativePosition(parentPosition, eventPosition) {
|
||||
return {'x': Math.round(eventPosition.x - parentPosition.x), 'y': Math.round(eventPosition.y - parentPosition.y)};
|
||||
}
|
||||
function numLines(text) {
|
||||
return text.split("<br>").length;
|
||||
}
|
||||
function renderText() {
|
||||
$("#textboard").text('');
|
||||
text.forEach(function(item) {
|
||||
let line = $("<div>");
|
||||
line.html(item.text);
|
||||
line.css({"color": "#" + item.color});
|
||||
$("#textboard").append(line);
|
||||
});
|
||||
renderAddLine();
|
||||
renderRemoveLine();
|
||||
}
|
||||
function setNewText() {
|
||||
text[activeLine].text = $("#editor").val();
|
||||
sendDiscussion();
|
||||
renderText();
|
||||
}
|
||||
function renderAddLine() {
|
||||
for (line = -1; line < text.length; ++line) {
|
||||
var addIcon = $('<div>></div>');
|
||||
addIcon.css({'position':'absolute', 'left':0, 'top': 11 + line * 22, 'cursor':'pointer'});
|
||||
addIcon.click(function(event) {
|
||||
let newLine = (($(this).position().top - 11) / 22) + 1;
|
||||
text.splice(newLine, 0, {'color': ownColor, 'text':''});
|
||||
renderText();
|
||||
createTextInput(newLine);
|
||||
sendDiscussion();
|
||||
});
|
||||
$("#textboard").append(addIcon);
|
||||
}
|
||||
}
|
||||
function renderRemoveLine() {
|
||||
for (line = 0; line < text.length; ++line) {
|
||||
var addIcon = $('<div>-</div>');
|
||||
addIcon.css({'position':'absolute', 'left':0, 'top': line * 22, 'cursor':'pointer'});
|
||||
addIcon.click(function(event) {
|
||||
let line = ($(this).position().top) / 22;
|
||||
text.splice(line, 1);
|
||||
renderText();
|
||||
sendDiscussion();
|
||||
});
|
||||
$("#textboard").append(addIcon);
|
||||
}
|
||||
}
|
||||
function sendDiscussion() {
|
||||
$.post("planboard", {
|
||||
"action": "setdiscussion",
|
||||
"id": $("#topic").val(),
|
||||
"text": JSON.stringify(text),
|
||||
},
|
||||
null,
|
||||
"json"
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
3
templates/projects.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<h2>Förderübersicht</h2>
|
||||
<p>Der Verein unterstützt die Schule und ihre Schüler*innen mit verschiedenen Maßnahmen. Das können fortlaufende Projekte sein oder auch spezielle, einmalige Maßnahmen.</p>
|
||||
{{projects}}
|
||||
115
templates/projectsmanagement.html
Normal file
@@ -0,0 +1,115 @@
|
||||
{{form}}
|
||||
{{projects}}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("form").submit(function(event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
$("#addproject").click(function() {
|
||||
$.post("projectsmanagement", {
|
||||
'action': 'create',
|
||||
'newname': $("#new_title").val(),
|
||||
},
|
||||
null,
|
||||
"json"
|
||||
).done(function(response) {
|
||||
if ("error" in response) {
|
||||
alert(response.error);
|
||||
return;
|
||||
}
|
||||
$("#shorttitle > option:not(:first-child)").remove();
|
||||
response.list.forEach(function(item) {
|
||||
let newItem = $("<option></option>");
|
||||
newItem.attr("id", item.id);
|
||||
newItem.text(item.title);
|
||||
if (item.id == response.id) {
|
||||
newItem.attr("selected", "selected");
|
||||
}
|
||||
$("#shorttitle").append(newItem);
|
||||
});
|
||||
}).fail(function(response) {
|
||||
alert(response);
|
||||
});
|
||||
});
|
||||
$("#shorttitle").change(function() {
|
||||
if ($(this).val() !== 'NULL') {
|
||||
$("#new_title").hide();
|
||||
$("#addproject").hide();
|
||||
} else {
|
||||
$("#new_title").show();
|
||||
$("#addproject").show();
|
||||
}
|
||||
$.post("projectsmanagement", {
|
||||
"action": "getdetails",
|
||||
"id": $("#shorttitle").val()
|
||||
},
|
||||
null,
|
||||
"json"
|
||||
).done(function(response) {
|
||||
if ("error" in response) {
|
||||
$("#description").val("");
|
||||
$("#projecttype option:first").attr('selected','selected');
|
||||
alert(response.error);
|
||||
return;
|
||||
}
|
||||
$("#description").val(response.description);
|
||||
$("#projecttype").val(response.projecttype);
|
||||
}).fail(function() {
|
||||
$("#shorttitle").val("NULL");
|
||||
$("#description").val("");
|
||||
$("#projecttype option:first").attr('selected','selected');
|
||||
});
|
||||
});
|
||||
$("#description").focusout(function() {
|
||||
if ($("#shorttitle").val() === "NULL") {
|
||||
return;
|
||||
}
|
||||
console.log($("#shorttitle").val());
|
||||
$.post("projectsmanagement", {
|
||||
"action": "setdescription",
|
||||
"id": $("#shorttitle").val(),
|
||||
"description": $("#description").val()
|
||||
},
|
||||
null,
|
||||
"json"
|
||||
).done(function(response) {
|
||||
if ("error" in response) {
|
||||
alert(response.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
$("#projecttype").change(function() {
|
||||
$.post("projectsmanagement", {
|
||||
"action": "setprojecttype",
|
||||
"id": $("#shorttitle").val(),
|
||||
"newtype": $("#projecttype").val()
|
||||
},
|
||||
null,
|
||||
"json"
|
||||
).done(function(response) {
|
||||
if ("error" in response) {
|
||||
alert(response.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
$("select").change(function() {
|
||||
if ($(this).attr('name') === 'project_type') {
|
||||
$.post(
|
||||
'/projectsmanagement',
|
||||
{
|
||||
'action': 'setprojecttype',
|
||||
'id': $(this).attr('data'),
|
||||
'newtype': $(this).val()
|
||||
},
|
||||
null,
|
||||
'json'
|
||||
).done(function(response) {
|
||||
if ("error" in response) {
|
||||
alert(response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
7
templates/register.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<h2>Zugang beantragen</h2>
|
||||
<div>
|
||||
<h3>Hinweis</h3>
|
||||
Alle Angaben außer dem Benutzernamen werden verschlüsselt gespeichert.
|
||||
</div>
|
||||
{{form}}
|
||||
<div>Sie können der Speicherung Ihrer Daten jederzeit Widersprechen. Eine einfache Email an <hier email> genügt.</div>
|
||||
1
templates/register_successful.html
Normal file
@@ -0,0 +1 @@
|
||||
Der Zugang zum internen Bereich wurde beantragt. Wir bearbeiten den Antrag schnellstmöglich und melden uns dann.
|
||||
5
templates/resetaccountmailbody.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<p>Sehr geehrte/r {{name}},</p>
|
||||
<p>Vielen Dank für Ihre Anfrage. Ihr Benutzername lautet: <b>{{username}}</b>
|
||||
<p>Wenn Sie Ihr Paßwort zurücksetzen möchten, klicken hier: <a href="http{{protocol}}://{{server}}/setpassword?code={{code}}">http{{protocol}}://{{server}}/setpassword?code={{code}}</a>
|
||||
<p>Wenn Sie die Daten nicht angefordert haben, können Sie die Email ignorieren, es wird keine Änderungen an Ihrem Account geben.</p>
|
||||
<p>Vielen Dank<br/>
|
||||
4
templates/savemail.html
Normal file
@@ -0,0 +1,4 @@
|
||||
Datei unter dem Titel <b>{{saved-title}}</b> abgelegt.<br/>
|
||||
<a href="documents">Zur Dokumente-Übersicht</a><br/>
|
||||
<a href="emailinbox">Zur Email-Übersicht</a><br/>
|
||||
<a href="mail?uid={{uid}}">Zurück zur Email "{{subject}}"</a><br/>
|
||||
2
templates/setpassword.html
Normal file
@@ -0,0 +1,2 @@
|
||||
{{errors}}
|
||||
{{form}}
|
||||
25
vendor/autoload.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitb3a3dfb766a515d49b7f8665bad574b3::getLoader();
|
||||
585
vendor/composer/ClassLoader.php
vendored
Normal file
@@ -0,0 +1,585 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var ?string */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<int, string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, string[]>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
* @psalm-var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var ?string */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param ?string $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array<int, string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classMap Class to filename map
|
||||
* @psalm-param array<string, string> $classMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||
*
|
||||
* @return self[]
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
359
vendor/composer/InstalledVersions.php
vendored
Normal file
@@ -0,0 +1,359 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints((string) $constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require __DIR__ . '/installed.php';
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array()) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
21
vendor/composer/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
10
vendor/composer/autoload_classmap.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
);
|
||||
10
vendor/composer/autoload_namespaces.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'PhpImap' => array($vendorDir . '/php-imap/php-imap/src'),
|
||||
);
|
||||
10
vendor/composer/autoload_psr4.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
|
||||
);
|
||||
38
vendor/composer/autoload_real.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInitb3a3dfb766a515d49b7f8665bad574b3
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitb3a3dfb766a515d49b7f8665bad574b3', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitb3a3dfb766a515d49b7f8665bad574b3', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
47
vendor/composer/autoload_static.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3
|
||||
{
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'P' =>
|
||||
array (
|
||||
'PHPMailer\\PHPMailer\\' => 20,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'PHPMailer\\PHPMailer\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixesPsr0 = array (
|
||||
'P' =>
|
||||
array (
|
||||
'PhpImap' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/php-imap/php-imap/src',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$prefixDirsPsr4;
|
||||
$loader->prefixesPsr0 = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$prefixesPsr0;
|
||||
$loader->classMap = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
203
vendor/composer/installed.json
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "php-imap/php-imap",
|
||||
"version": "2.0.3",
|
||||
"version_normalized": "2.0.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barbushin/php-imap.git",
|
||||
"reference": "cc1a49a3f68090db182183c59ffbc09055d59f5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barbushin/php-imap/zipball/cc1a49a3f68090db182183c59ffbc09055d59f5b",
|
||||
"reference": "cc1a49a3f68090db182183c59ffbc09055d59f5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"time": "2015-09-16T07:40:39+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"PhpImap": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD 3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sergey Barbushin",
|
||||
"email": "barbushin@gmail.com",
|
||||
"homepage": "http://linkedin.com/in/barbushin"
|
||||
}
|
||||
],
|
||||
"description": "PHP class to access mailbox by POP3/IMAP/NNTP using IMAP extension",
|
||||
"homepage": "https://github.com/barbushin/php-imap",
|
||||
"keywords": [
|
||||
"imap",
|
||||
"mail",
|
||||
"php"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/barbushin/php-imap/issues",
|
||||
"source": "https://github.com/barbushin/php-imap/tree/master"
|
||||
},
|
||||
"install-path": "../php-imap/php-imap"
|
||||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "312ed95ab03e7f3f0316191e5bfb9f920b705825"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/312ed95ab03e7f3f0316191e5bfb9f920b705825",
|
||||
"reference": "312ed95ab03e7f3f0316191e5bfb9f920b705825",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-hash": "*",
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
|
||||
"doctrine/annotations": "^1.2.6 || ^1.13.3",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3.2",
|
||||
"phpcompatibility/php-compatibility": "^9.3.5",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"squizlabs/php_codesniffer": "^3.7.2",
|
||||
"yoast/phpunit-polyfills": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
|
||||
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
|
||||
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
|
||||
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
|
||||
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
|
||||
"psr/log": "For optional PSR-3 debug logging",
|
||||
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
|
||||
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
|
||||
},
|
||||
"time": "2023-06-08T09:54:07+00:00",
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PHPMailer\\PHPMailer\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marcus Bointon",
|
||||
"email": "phpmailer@synchromedia.co.uk"
|
||||
},
|
||||
{
|
||||
"name": "Jim Jagielski",
|
||||
"email": "jimjag@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Andy Prevost",
|
||||
"email": "codeworxtech@users.sourceforge.net"
|
||||
},
|
||||
{
|
||||
"name": "Brent R. Matzelle"
|
||||
}
|
||||
],
|
||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/master"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Synchro",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"install-path": "../phpmailer/phpmailer"
|
||||
},
|
||||
{
|
||||
"name": "tinymce/tinymce",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tinymce/tinymce-dist.git",
|
||||
"reference": "6a37da4822eebcd2706793454b07bd891c5277a8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/tinymce/tinymce-dist/zipball/6a37da4822eebcd2706793454b07bd891c5277a8",
|
||||
"reference": "6a37da4822eebcd2706793454b07bd891c5277a8",
|
||||
"shasum": ""
|
||||
},
|
||||
"time": "2023-04-26T10:48:15+00:00",
|
||||
"default-branch": true,
|
||||
"type": "component",
|
||||
"extra": {
|
||||
"component": {
|
||||
"scripts": [
|
||||
"tinymce.js",
|
||||
"plugins/*/plugin.js",
|
||||
"themes/*/theme.js",
|
||||
"models/*/model.js",
|
||||
"icons/*/icons.js"
|
||||
],
|
||||
"files": [
|
||||
"tinymce.min.js",
|
||||
"plugins/*/plugin.min.js",
|
||||
"themes/*/theme.min.js",
|
||||
"models/*/model.min.js",
|
||||
"skins/**",
|
||||
"icons/*/icons.min.js"
|
||||
]
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT-only"
|
||||
],
|
||||
"description": "Web based JavaScript HTML WYSIWYG editor control.",
|
||||
"homepage": "https://www.tiny.cloud/",
|
||||
"keywords": [
|
||||
"contenteditable",
|
||||
"editing",
|
||||
"html",
|
||||
"javascript",
|
||||
"rich editor",
|
||||
"rich text",
|
||||
"rich text editor",
|
||||
"richtext",
|
||||
"rte",
|
||||
"text",
|
||||
"tinymce",
|
||||
"wysiwyg"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/tinymce/tinymce-dist/tree/6.4.2"
|
||||
},
|
||||
"install-path": "../tinymce/tinymce"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
"dev-package-names": []
|
||||
}
|
||||
54
vendor/composer/installed.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => '__root__',
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => NULL,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => true,
|
||||
),
|
||||
'versions' => array(
|
||||
'__root__' => array(
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => NULL,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'php-imap/php-imap' => array(
|
||||
'pretty_version' => '2.0.3',
|
||||
'version' => '2.0.3.0',
|
||||
'reference' => 'cc1a49a3f68090db182183c59ffbc09055d59f5b',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../php-imap/php-imap',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'phpmailer/phpmailer' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => '312ed95ab03e7f3f0316191e5bfb9f920b705825',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
|
||||
'aliases' => array(
|
||||
0 => '9999999-dev',
|
||||
),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'tinymce/tinymce' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => '6a37da4822eebcd2706793454b07bd891c5277a8',
|
||||
'type' => 'component',
|
||||
'install_path' => __DIR__ . '/../tinymce/tinymce',
|
||||
'aliases' => array(
|
||||
0 => '9999999-dev',
|
||||
),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
26
vendor/composer/platform_check.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 50500)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.5.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||