Compare commits

..

3 Commits

Author SHA1 Message Date
niklas.ortmann 95251d23ad Update search-results-controller.php 2026-06-13 12:26:49 +02:00
niklas.ortmann c16bf574ce Update search-results.php 2026-06-13 12:21:38 +02:00
niklas.ortmann 0e44d92baa paginator.js 2026-06-13 12:19:37 +02:00
17 changed files with 171 additions and 847 deletions
+1 -2
View File
@@ -7,7 +7,7 @@
## Login-Informationen für Dummy-User ## Login-Informationen für Dummy-User
`Anmeldename, Passwort, Mailadresse`: `Anmeldename, Passwort, Mailadresse`:
- `max.mustermann, test12345, max.mustermann@web.de` - `max.mustermann, test12345, mustermann@web.de`
## Weitere Voraussetzungen zur Nutzung ## Weitere Voraussetzungen zur Nutzung
- Per Klick auf das Logo gelangt man auf die Home-Seite. - Per Klick auf das Logo gelangt man auf die Home-Seite.
@@ -18,7 +18,6 @@
- Bitte auf die gesetzten TODO's achten. Wenn Inhalte fehlen, sind sie i.d.R. als TODO kommentiert. - Bitte auf die gesetzten TODO's achten. Wenn Inhalte fehlen, sind sie i.d.R. als TODO kommentiert.
- Die Suchseite und Kategorieseite packen momentan alle passenden Beiträge untereinander. Später sollen zunächst 10 - Die Suchseite und Kategorieseite packen momentan alle passenden Beiträge untereinander. Später sollen zunächst 10
Ergebnisse auf einer Seite angezeigt werden. Ergebnisse auf einer Seite angezeigt werden.
- Wenn ein Bild aus einem Beitrag entfernt wird, dann wird noch nicht die Datei im Pfad /uploads gelöscht.
## Besonderheiten des Projektes ## Besonderheiten des Projektes
- Es wurde ein einfacher Beitrags-Editor erstellt. Mit diesem können Beiträge erstellt oder bearbeitet werden. - Es wurde ein einfacher Beitrags-Editor erstellt. Mit diesem können Beiträge erstellt oder bearbeitet werden.
+1 -21
View File
@@ -17,28 +17,8 @@ if (!isset($_SESSION["user"])) {
<input type="text" id="title" name="title" <input type="text" id="title" name="title"
value="<?php echo htmlspecialchars($_SESSION['old_title'] ?? ''); unset($_SESSION['old_title']); ?>" value="<?php echo htmlspecialchars($_SESSION['old_title'] ?? ''); unset($_SESSION['old_title']); ?>"
placeholder="Titel hier eingeben" required> placeholder="Titel hier eingeben" required>
<textarea id="content" name="content" placeholder="Schreibe deinen Beitrag..."><?php if (isset($_SESSION['old_content']) && !empty($_SESSION['old_content'])){echo htmlspecialchars($_SESSION['old_content']); unset($_SESSION['old_content']);}elseif (isset($content) && !empty($content)){echo htmlspecialchars($content);}?></textarea>
<!-- Hier werden die dynamischen divs via JavaScript eingefügt -->
<div id="block-container"></div>
<!-- Plus-Button und das Pop-up-Menü -->
<div id="add-block-control" class="article-editor-scope add-block-control">
<button type="button" id="plus-button" class="article-editor-scope plus-button">+</button>
<div id="block-popup" class="article-editor-scope block-popup hidden">
<button type="button" data-type="text">Textblock</button>
<button type="button" data-type="image">Bild einfügen</button>
</div>
</div>
<!-- Unsichtbares Textfeld, das die JSON-Daten hält und an den Controller postet -->
<textarea id="content" name="content" style="display:none;"><?php
if (isset($_SESSION['old_content']) && !empty($_SESSION['old_content'])){
echo htmlspecialchars($_SESSION['old_content']);
unset($_SESSION['old_content']);
} else {
echo '[]'; // Standardmäßig ein leeres JSON-Array
}
?></textarea>
</main> </main>
<!-- Seitenleiste --> <!-- Seitenleiste -->
+41 -9
View File
@@ -2,19 +2,38 @@
if (session_status() === PHP_SESSION_NONE) { if (session_status() === PHP_SESSION_NONE) {
session_start(); session_start();
} }
$results = $_SESSION["search_results"] ?? []; $all_results = $_SESSION["search_results"] ?? [];
$query = $_SESSION["search_query"] ?? ""; $query = $_SESSION["search_query"] ?? "";
$totalResultsCount = count($all_results);
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10; $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10;
if (!in_array($limit, [10, 20, 50, 100])) { if (!in_array($limit, [10, 20, 50, 100])) {
$limit = 10; $limit = 10;
} }
$results = array_slice($results, 0, $limit);
// Gesamtseitenzahl
$totalPages = max(1, ceil($totalResultsCount / $limit));
// Aktuelle Seite auslesen und validieren
$currentPage = isset($_GET['page']) ? (int)$_GET['page'] : 1;
if ($currentPage < 1) {
$currentPage = 1;
} elseif ($currentPage > $totalPages) {
$currentPage = $totalPages;
}
// Startpunkt im Array berechnen (Offset)
$offset = ($currentPage - 1) * $limit;
// Nur die Ergebnisse für die aktuelle Seite ausschneiden
$results = array_slice($all_results, $offset, $limit);
$resultCount = count($results); $resultCount = count($results);
?> ?>
<noscript>
Bitte JavaScript aktivieren!
</noscript>
<!-- <!--
Seite: Suchergebnisse Seite: Suchergebnisse
Inhalt: Zeigt die Ergebnisse einer Suche an Inhalt: Zeigt die Ergebnisse einer Suche an
@@ -27,8 +46,10 @@ $resultCount = count($results);
<!-- Sortierfuntion Box und Such Box--> <!-- Sortierfuntion Box und Such Box-->
<form id="search-form-id" action="php/controller/search-results-controller.php" method="GET" class="s-res-sidebar-form"> <form id="search-form-id" action="php/controller/search-results-controller.php" method="GET" class="s-res-sidebar-form">
<!-- Dieses Feld hält die aktuelle Seitenzahl für den Submit bereit -->
<div class="s-res-sidebar-box"> <input type="hidden" name="page" id="s-res-page-input" value="<?php echo $currentPage; ?>">
<div class="s-res-sidebar-box">
<h3 class="s-res-sidebar-title">Suche anpassen</h3> <h3 class="s-res-sidebar-title">Suche anpassen</h3>
<input type="search" id="site-search" name="q" placeholder="Suchen..." class="nav__search" value="<?php echo htmlspecialchars($query); ?>" maxlength="50" required> <input type="search" id="site-search" name="q" placeholder="Suchen..." class="nav__search" value="<?php echo htmlspecialchars($query); ?>" maxlength="50" required>
<button type="submit" class="nav__search-button">Suchen</button> <button type="submit" class="nav__search-button">Suchen</button>
@@ -66,7 +87,7 @@ $resultCount = count($results);
<div class="s-res-header"> <div class="s-res-header">
<h1 class="s-res-main-title">Suchergebnisse</h1> <h1 class="s-res-main-title">Suchergebnisse</h1>
<p class="s-res-meta"><?php echo $resultCount; ?> Treffer für Ihre Suchanfrage "<?php echo htmlspecialchars($query); ?>"</p> <p class="s-res-meta"><?php echo $totalResultsCount; ?> Treffer für Ihre Suchanfrage "<?php echo htmlspecialchars($query); ?>"</p>
</div> </div>
<!-- Ergebnisliste --> <!-- Ergebnisliste -->
@@ -115,9 +136,20 @@ $resultCount = count($results);
</div> </div>
<div class="s-res-page-navigation"> <div class="s-res-page-navigation">
<button type="button" class="s-res-page-btn" disabled>&laquo;</button> <button type="button" class="s-res-page-btn" data-page="<?php echo $currentPage - 1; ?>" <?php echo $currentPage <= 1 ? 'disabled' : ''; ?>>
<button type="button" class="s-res-page-btn s-res-page-btn-active">1</button> «
<button type="button" class="s-res-page-btn">&raquo;</button> </button>
<!-- Dynamische Seitenzahlen -->
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
<button type="button"
class="s-res-page-btn <?php echo $i === $currentPage ? 's-res-page-btn-active' : ''; ?>"
data-page="<?php echo $i; ?>">
<?php echo $i; ?>
</button>
<?php endfor; ?>
<button type="button" class="s-res-page-btn" data-page="<?php echo $currentPage + 1; ?>" <?php echo $currentPage >= $totalPages ? 'disabled' : ''; ?>>
»
</button>
</div> </div>
</div> </div>
+26 -28
View File
@@ -8,7 +8,30 @@ include_once 'php/controller/showArticle-controller.php';
<!-- Hauptcontainer für die Beitragsansicht (Ausschließlich der Content-Bereich) --> <!-- Hauptcontainer für die Beitragsansicht (Ausschließlich der Content-Bereich) -->
<main class="article-view-container"> <main class="article-view-container">
<?php include_once "includes/alertMessages.php"?> <?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "internal_error"): ?>
<p class="alert-message is-error">
Es ist ein interner Fehler aufgetreten. Bitte versuche es erneut.
</p>
<?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "missing_id"): ?>
<p class="alert-message is-error">
Es ist ein Fehler aufgetreten. Die ID konnte nicht ausgelesen werden. Bitte versuche es erneut.
</p>
<?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "missing_parameters"): ?>
<p class="alert-message is-error">
Jeder Beitrag muss einen Titel, Kategorie und Inhalt besitzen.
</p>
<?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "article_updated"): ?>
<p class="alert-message is-success">
Dein Beitrag wurde erfolgreich bearbeitet!
</p>
<?php endif; ?>
<?php
unset($_SESSION["message"]);
?>
<!-- Metadaten & Titel --> <!-- Metadaten & Titel -->
<div class="article-view-top-section"> <div class="article-view-top-section">
@@ -31,33 +54,8 @@ include_once 'php/controller/showArticle-controller.php';
<!-- Beitrags-Inhalt --> <!-- Beitrags-Inhalt -->
<div class="article-view-content"> <div class="article-view-content">
<?php if (isset($content)): ?> <?php if (isset($content)): ?>
<?php <!-- nl2br für Zeilenumbrüche -->
// Versuchen, den Inhalt von JSON in ein PHP-Array umzuwandeln <div class="article-view-body"><?php echo nl2br(htmlspecialchars($content)); ?></div>
$blocks = json_decode($content, true);
// Wenn das JSON valide ist und Blöcke enthält
if (json_last_error() === JSON_ERROR_NONE && is_array($blocks)):
foreach ($blocks as $block):
if (isset($block['type']) && isset($block['value'])):
if ($block['type'] === 'text'): ?>
<!-- Textblock mit XSS-Schutz und Erhalt von Zeilenumbrüchen -->
<div class="article-view-body block-text">
<?php echo nl2br(htmlspecialchars($block['value'])); ?>
</div>
<?php elseif ($block['type'] === 'image'): ?>
<!-- Bildblock, der auf den relativen Pfad im uploads-Ordner verweist -->
<div class="article-view-body block-image">
<img src="<?php echo htmlspecialchars($block['value']); ?>" alt="Beitragsbild">
</div>
<?php endif;
endif;
endforeach;
else: ?>
<!-- Fallback: Wenn der Beitrag alten Reintext aus der DB enthält -->
<div class="article-view-body block-text">
<?php echo nl2br(htmlspecialchars($content)); ?>
</div>
<?php endif; ?>
<?php endif; ?> <?php endif; ?>
</div> </div>
+29 -220
View File
@@ -10,7 +10,7 @@ include_once 'php/controller/showArticle-controller.php';
Seite: Beitrag erstellen Seite: Beitrag erstellen
Inhalt: Formular für die Erstellung eines neuen Beitrags Inhalt: Formular für die Erstellung eines neuen Beitrags
--> -->
<form method="post" action="php/controller/updateArticle-controller.php?id=<?php if(isset($id) && !empty($id)){echo htmlspecialchars($id);}else{$_SESSION["message"] = "missing_id";} ?>" id="editor-form" enctype="multipart/form-data" class="article-editor-scope.editor-container article-editor-scope editor-container"> <form method="post" action="php/controller/updateArticle-controller.php?id=<?php if(isset($id) && !empty($id)){echo htmlspecialchars($id);}else{$_SESSION["message"] = "missing_id";} ?>" id="editor-form" class="article-editor-scope.editor-container article-editor-scope editor-container">
<main class="editor-main"> <main class="editor-main">
<?php include_once "includes/alertMessages.php"?> <?php include_once "includes/alertMessages.php"?>
@@ -26,33 +26,8 @@ include_once 'php/controller/showArticle-controller.php';
?>" ?>"
placeholder="Titel hier eingeben" required> placeholder="Titel hier eingeben" required>
<textarea id="content" name="content" placeholder="Schreibe deinen Beitrag..."><?php if (isset($_SESSION['old_content']) && !empty($_SESSION['old_content'])){echo htmlspecialchars($_SESSION['old_content']); unset($_SESSION['old_content']);}elseif (isset($content) && !empty($content)){echo htmlspecialchars($content);}?></textarea>
<!-- Hier werden die dynamischen divs via JavaScript eingefügt -->
<div id="block-container"></div>
<!-- Plus-Button und das Pop-up-Menü -->
<div id="add-block-control" class="article-editor-scope add-block-control">
<button type="button" id="plus-button" class="article-editor-scope plus-button">+</button>
<div id="block-popup" class="article-editor-scope block-popup hidden">
<button type="button" data-type="text">Textblock</button>
<button type="button" data-type="image">Bild einfügen</button>
</div>
</div>
<!-- Unsichtbares Textfeld, das die JSON-Daten hält und an den Controller postet -->
<textarea id="content" name="content" style="display:none;"><?php
if (isset($_SESSION['old_content']) && !empty($_SESSION['old_content'])){
echo htmlspecialchars($_SESSION['old_content']);
unset($_SESSION['old_content']);
}elseif (isset($content) && !empty($content)){
echo htmlspecialchars($content);
} else {
echo '[]';
}
?></textarea>
<!-- unsichtbares Input, um die zu löschenden Bilder zu übergeben-->
<input type="hidden" id="deleted-images" name="deleted_images" value="[]">
</main> </main>
<!-- Seitenleiste --> <!-- Seitenleiste -->
@@ -65,211 +40,45 @@ include_once 'php/controller/showArticle-controller.php';
<div class="sidebar-block"> <div class="sidebar-block">
<label for="category">Kategorie <span class="required">*</span></label> <label for="category">Kategorie <span class="required">*</span></label>
<select id="category" name="category" required> <select id="category" name="category" required>
<option disabled <?php <option disabled selected>Kategorie wählen...</option>
if ((!isset($_SESSION['old_category']) || empty($_SESSION['old_category'])) && (!isset($category) || empty($category))) {
echo 'selected';
}
?>>Kategorie wählen...</option>
<optgroup label="Sprachen"> <optgroup label="Sprachen">
<option value="deutsch" <?php <option value="deutsch">Deutsch</option>
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) { <option value="englisch">Englisch</option>
if ($_SESSION['old_category'] === 'deutsch') { echo 'selected'; } <option value="franzoesisch">Französisch</option>
} elseif (isset($category) && !empty($category)) { <option value="latein">Latein</option>
if ($category === 'deutsch') { echo 'selected'; } <option value="literatur">Literatur</option>
}
?>>Deutsch</option>
<option value="englisch" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'englisch') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'englisch') { echo 'selected'; }
}
?>>Englisch</option>
<option value="franzoesisch" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'franzoesisch') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'franzoesisch') { echo 'selected'; }
}
?>>Französisch</option>
<option value="latein" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'latein') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'latein') { echo 'selected'; }
}
?>>Latein</option>
<option value="literatur" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'literatur') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'literatur') { echo 'selected'; }
}
?>>Literatur</option>
</optgroup> </optgroup>
<optgroup label="MINT"> <optgroup label="MINT">
<option value="mathe" <?php <option value="mathe">Mathematik</option>
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) { <option value="biologie">Biologie</option>
if ($_SESSION['old_category'] === 'mathe') { echo 'selected'; } <option value="chemie">Chemie</option>
} elseif (isset($category) && !empty($category)) { <option value="physik">Physik</option>
if ($category === 'mathe') { echo 'selected'; } <option value="informatik">Informatik</option>
} <option value="astronomie">Astronomie</option>
?>>Mathematik</option>
<option value="biologie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'biologie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'biologie') { echo 'selected'; }
}
?>>Biologie</option>
<option value="chemie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'chemie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'chemie') { echo 'selected'; }
}
?>>Chemie</option>
<option value="physik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'physik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'physik') { echo 'selected'; }
}
?>>Physik</option>
<option value="informatik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'informatik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'informatik') { echo 'selected'; }
}
?>>Informatik</option>
<option value="astronomie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'astronomie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'astronomie') { echo 'selected'; }
}
?>>Astronomie</option>
</optgroup> </optgroup>
<optgroup label="Gesellschaft & Werte"> <optgroup label="Gesellschaft & Werte">
<option value="geschichte" <?php <option value="geschichte">Geschichte</option>
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) { <option value="erdkunde">Erdkunde</option>
if ($_SESSION['old_category'] === 'geschichte') { echo 'selected'; } <option value="sozialkunde">Sozialkunde</option>
} elseif (isset($category) && !empty($category)) { <option value="wirtschaft">Wirtschaftskunde</option>
if ($category === 'geschichte') { echo 'selected'; } <option value="religion">Religion</option>
} <option value="ethik">Ethikunterricht</option>
?>>Geschichte</option> <option value="philosophie">Philosophie</option>
<option value="erdkunde" <?php <option value="psychologie">Psychologie</option>
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) { <option value="kunst">Kunst</option>
if ($_SESSION['old_category'] === 'erdkunde') { echo 'selected'; } <option value="musik">Musik</option>
} elseif (isset($category) && !empty($category)) { <option value="theater">Theater</option>
if ($category === 'erdkunde') { echo 'selected'; }
}
?>>Erdkunde</option>
<option value="sozialkunde" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'sozialkunde') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'sozialkunde') { echo 'selected'; }
}
?>>Sozialkunde</option>
<option value="wirtschaft" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'wirtschaft') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'wirtschaft') { echo 'selected'; }
}
?>>Wirtschaftskunde</option>
<option value="religion" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'religion') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'religion') { echo 'selected'; }
}
?>>Religion</option>
<option value="ethik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'ethik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'ethik') { echo 'selected'; }
}
?>>Ethikunterricht</option>
<option value="philosophie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'philosophie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'philosophie') { echo 'selected'; }
}
?>>Philosophie</option>
<option value="psychologie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'psychologie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'psychologie') { echo 'selected'; }
}
?>>Psychologie</option>
<option value="kunst" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'kunst') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'kunst') { echo 'selected'; }
}
?>>Kunst</option>
<option value="musik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'musik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'musik') { echo 'selected'; }
}
?>>Musik</option>
<option value="theater" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'theater') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'theater') { echo 'selected'; }
}
?>>Theater</option>
</optgroup> </optgroup>
<optgroup label="Technik & Praxis"> <optgroup label="Technik & Praxis">
<option value="technik" <?php <option value="technik">Technik</option>
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) { <option value="werken">Werken</option>
if ($_SESSION['old_category'] === 'technik') { echo 'selected'; } <option value="hauswirtschaft">Hauswirtschaft</option>
} elseif (isset($category) && !empty($category)) { <option value="sport">Sport</option>
if ($category === 'technik') { echo 'selected'; }
}
?>>Technik</option>
<option value="werken" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'werken') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'werken') { echo 'selected'; }
}
?>>Werken</option>
<option value="hauswirtschaft" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'hauswirtschaft') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'hauswirtschaft') { echo 'selected'; }
}
?>>Hauswirtschaft</option>
<option value="sport" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'sport') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'sport') { echo 'selected'; }
}
?>>Sport</option>
</optgroup> </optgroup>
<?php
if (isset($_SESSION['old_category'])) {
unset($_SESSION['old_category']);
}
?>
</select> </select>
</div> </div>
-133
View File
@@ -90,135 +90,6 @@
padding: 18px 12px; padding: 18px 12px;
} }
/* Container für die dynamisch per JS eingefügten Blöcke */
.article-editor-scope #block-container {
width: 100%;
display: flex;
flex-direction: column;
gap: 20px;
}
/* Styling für jeden einzelnen dynamisch generierten Block */
.article-editor-scope .editor-block {
position: relative; /* Wichtig für die absolute Positionierung des Lösch-Buttons */
width: 100%;
padding: 15px;
background-color: #fafafa;
border: 1px dashed #cccccc;
border-radius: 6px;
}
/* Textarea innerhalb eines dynamischen Textblocks */
.article-editor-scope .editor-block textarea {
width: 100%;
min-height: 120px;
padding: 10px;
border: 1px solid #dddddd;
border-radius: 4px;
font-family: inherit;
font-size: 1.1rem;
line-height: 1.6;
resize: vertical;
outline: none;
background: #ffffff;
}
/* Komfort-Löschbutton oben rechts an jedem Block */
.article-editor-scope .delete-block-btn {
position: absolute;
top: -10px;
right: -10px;
width: 24px;
height: 24px;
border-radius: 50%;
background-color: #e74c3c;
color: #ffffff;
border: none;
font-size: 12px;
font-weight: bold;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
transition: background-color 0.2s ease;
}
.article-editor-scope .delete-block-btn:hover {
background-color: #c0392b;
}
/* Steuerungselement für den Plus-Button und das Pop-up */
.article-editor-scope .add-block-control {
position: relative; /* Dient als Anker für das absolut positionierte Pop-up */
margin-top: 10px;
display: inline-block;
align-self: flex-start; /* Verhindert, dass der Button die volle Breite spannt */
}
/* Der runde Plus-Button */
.article-editor-scope .plus-button {
width: 45px;
height: 45px;
border-radius: 50%;
background-color: #3498db;
color: #ffffff;
border: none;
font-size: 26px;
font-weight: 300;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
transition: background-color 0.2s ease, transform 0.2s ease;
}
.article-editor-scope .plus-button:hover {
background-color: #2980b9;
transform: scale(1.05);
}
/* Das Pop-up Menü */
.article-editor-scope .block-popup {
position: absolute;
left: 60px; /* Platziert das Menü rechts neben dem Plus-Button */
top: 50%;
transform: translateY(-50%); /* Zentriert das Menü vertikal zum Button */
background-color: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 8px;
display: flex;
gap: 8px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);
z-index: 999;
white-space: nowrap;
}
/* Die entscheidende Klasse zum Ausblenden */
.article-editor-scope .block-popup.hidden {
display: none !important;
}
/* Buttons im Pop-up (Textblock / Bild einfügen) */
.article-editor-scope .block-popup button {
background-color: #f8f9fa;
border: 1px solid #dcdde1;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
color: #2f3640;
transition: background-color 0.15s ease, border-color 0.15s ease;
}
.article-editor-scope .block-popup button:hover {
background-color: #f1f2f6;
border-color: #b2bec3;
}
/* Responsive Anpassungen unter 760px (für z.B. Smartphones) */ /* Responsive Anpassungen unter 760px (für z.B. Smartphones) */
@media (max-width: 760px) { @media (max-width: 760px) {
.article-editor-scope.editor-container { .article-editor-scope.editor-container {
@@ -242,8 +113,4 @@
border-left: none; border-left: none;
border-top: 1px solid #e0e0e0; border-top: 1px solid #e0e0e0;
} }
.article-editor-scope .editor-block textarea {
min-height: 150px;
}
} }
-31
View File
@@ -105,37 +105,6 @@
cursor: default; cursor: default;
} }
.article-view-content {
margin-bottom: 3rem;
display: flex;
flex-direction: column;
gap: 1.5rem; /* Erzeugt einen sauberen Abstand zwischen den einzelnen Blöcken */
width: 100%;
}
.article-view-body {
font-size: 1.125rem;
color: #2d3748;
width: 100%;
}
.article-view-body.block-text {
white-space: pre-line;
word-break: break-word;
}
.article-view-body.block-image {
display: flex;
justify-content: center; /* Zentriert das Bild horizontal */
}
.article-view-body.block-image img {
max-width: 100%; /* Verhindert das Ausbrechen aus der Lesebreite */
height: auto; /* Behält das originale Seitenverhältnis bei */
border-radius: 6px; /* Optionale leichte Rundung für ein moderneres Layout */
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.03); /* Minimaler, eleganter Schatten */
}
/* Responsive Anpassungen unter 760px (für z.B. Smarticlephones) */ /* Responsive Anpassungen unter 760px (für z.B. Smarticlephones) */
@media (max-width: 760px) { @media (max-width: 760px) {
.article-view-container { .article-view-container {
+1 -6
View File
@@ -15,7 +15,7 @@
<?php endif; ?> <?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "invalid_content"): ?> <?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "invalid_content"): ?>
<p class="alert-message is-error"> <p class="alert-message is-error">
Ein Beitrag muss Inhalt besitzen. Text- und Bildelemente dürfen nicht leer sein! Der Text erlaubt eine Länge von 10 bis maximal 7.000 Zeichen (ca. 1.000 Wörter).
</p> </p>
<?php endif; ?> <?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "invalid_category"): ?> <?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "invalid_category"): ?>
@@ -63,11 +63,6 @@
Dein Beitrag wurde erfolgreich veröffentlicht! Dein Beitrag wurde erfolgreich veröffentlicht!
</p> </p>
<?php endif; ?> <?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "image_upload_error"): ?>
<p class="alert-message is-error">
Das Bild konnte nicht hochgeladen werden. Bitte versuche es erneut oder verwende ein anderes Bildformat.
</p>
<?php endif; ?>
<?php <?php
unset($_SESSION["message"]); unset($_SESSION["message"]);
?> ?>
+2 -1
View File
@@ -52,7 +52,8 @@ if ($pfad === "deleteAccount") {
<link rel="stylesheet" href="css/showArticle.css"> <link rel="stylesheet" href="css/showArticle.css">
<link rel="stylesheet" href="css/message.css"> <link rel="stylesheet" href="css/message.css">
<script src="js/editor.js" async></script> <script src="js/paginator.js" async></script>
<title>EduForge</title> <title>EduForge</title>
</head> </head>
-179
View File
@@ -1,179 +0,0 @@
console.log("Die JavaScript-Datei wurde erfolgreich geladen!");
function initEditor() {
const form = document.getElementById("editor-form");
if (!form) {
console.error("Skript abgebrochen: Formular nicht gefunden!");
return;
} else {
console.log("Formular gefunden und Editor initialisiert:", form);
}
const container = document.getElementById("block-container");
const plusButton = document.getElementById("plus-button");
const popup = document.getElementById("block-popup");
const hiddenContentInput = document.getElementById("content");
const initialImages = [];
// Pop-up umschalten bei Klick auf das Plus
plusButton.addEventListener("click", () => {
popup.classList.toggle("hidden");
});
// Klick auf eine Block-Option im Pop-up
popup.querySelectorAll("button").forEach(btn => {
btn.addEventListener("click", function() {
const type = this.getAttribute("data-type");
addBlockElement(type, "");
popup.classList.add("hidden");
});
});
// Erstellt ein visuelles HTML-Element im Editor
function addBlockElement(type, value = "") {
const blockDiv = document.createElement("div");
blockDiv.classList.add("editor-block");
blockDiv.setAttribute("data-type", type);
// Wenn es ein existierendes Server-Bild beim Laden ist, Pfad im globalen Array sichern
if (type === "image" && value && typeof value === 'string' && value.startsWith('uploads/')) {
initialImages.push(value);
blockDiv.setAttribute("data-value", value);
}
// Löschen-Button
const deleteBtn = document.createElement("button");
deleteBtn.type = "button";
deleteBtn.innerHTML = "✕";
deleteBtn.classList.add("delete-block-btn");
deleteBtn.addEventListener("click", () => {
// ANPASSUNG 2B: Logik hier komplett geleert. Das '✕' entfernt den Block jetzt nur noch sicher aus dem HTML.
blockDiv.remove();
});
blockDiv.appendChild(deleteBtn);
if (type === "text") {
const textarea = document.createElement("textarea");
textarea.placeholder = "Schreibe deinen Textblock...";
textarea.value = value;
blockDiv.appendChild(textarea);
} else if (type === "image") {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = "image/*";
const imgPreview = document.createElement("img");
imgPreview.style.maxWidth = "200px";
imgPreview.style.display = "block";
imgPreview.style.marginTop = "10px";
if (value && typeof value === 'string') {
if (value.startsWith('uploads/') || value.startsWith('data:image/')) {
imgPreview.src = value;
blockDiv.setAttribute("data-value", value);
}
}
fileInput.addEventListener("change", function() {
if (this.files && this.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
imgPreview.src = e.target.result;
blockDiv.setAttribute("data-value", e.target.result);
}
reader.readAsDataURL(this.files[0]);
}
});
blockDiv.appendChild(fileInput);
blockDiv.appendChild(imgPreview);
}
container.appendChild(blockDiv);
}
// beim Abschicken verbleibende Blöcke auslesen UND gelöschte Bilder ermitteln
form.addEventListener("submit", function(e) {
const blocks = [];
const currentImages = [];
// alle aktuell im Formular verbliebenen Blöcke scannen
container.querySelectorAll(".editor-block").forEach(blockDiv => {
const type = blockDiv.getAttribute("data-type");
let value = "";
if (type === "text") {
value = blockDiv.querySelector("textarea").value;
} else if (type === "image") {
const imgTag = blockDiv.querySelector("img");
if (imgTag) {
const srcValue = imgTag.getAttribute("src") || "";
// Wenn es ein neues Bild ist, nutzen wir das data-value (Base64)
if (srcValue.startsWith('data:image/')) {
value = blockDiv.getAttribute("data-value") || "";
} else {
value = srcValue;
}
}
// Pfade sammeln, die der Nutzer NICHT gelöscht hat (für den Abgleich)
if (value && value.startsWith('uploads/')) {
currentImages.push(value);
}
}
blocks.push({ type: type, value: value });
});
// das reguläre unsichtbare Content-Feld befüllen
hiddenContentInput.value = JSON.stringify(blocks);
// Differenz berechnen: Welche Bilder aus 'initialImages' fehlen in 'currentImages' ?
const deletedImages = initialImages.filter(img => !currentImages.includes(img));
// das 'deleted_images'-Feld dynamisch befüllen und an den Controller senden
let deletedInput = document.getElementById("deleted-images");
if (!deletedInput) {
deletedInput = document.createElement("input");
deletedInput.type = "hidden";
deletedInput.id = "deleted-images";
deletedInput.name = "deleted_images";
form.appendChild(deletedInput);
}
deletedInput.value = JSON.stringify(deletedImages);
});
// Existierende Blöcke laden (stellt alte Daten aus der Session wieder her)
try {
const initialBlocks = JSON.parse(hiddenContentInput.value.trim());
if (Array.isArray(initialBlocks)) {
initialBlocks.forEach(b => {
if (b.type === "image" && b.value && typeof b.value === 'string' && !b.value.startsWith('data:image/')) {
let cleanPath = b.value.trim().replace(/\\\//g, '/'); // Verwandelt \/ in /
initialImages.push(cleanPath);
addBlockElement(b.type, cleanPath);
} else {
addBlockElement(b.type, b.value);
}
});
console.log("Erfolgreich registrierte Start-Bilder:", initialImages);
}
} catch(e) {
if (hiddenContentInput.value.trim() !== "") {
addBlockElement("text", hiddenContentInput.value);
}
}
}
// SICHERER START: Prüft, ob das HTML bereits bereit ist
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initEditor);
} else {
// Falls das DOM schon fertig geladen ist, führen wir es direkt aus
initEditor();
}
+27
View File
@@ -0,0 +1,27 @@
function initPaginator() {
const form = document.getElementById('search-form-id');
const pageInput = document.getElementById('s-res-page-input');
const pageButtons = document.querySelectorAll('.s-res-page-navigation .s-res-page-btn');
pageButtons.forEach(button => {
button.addEventListener('click', function() {
if (this.disabled) return;
const targetPage = this.getAttribute('data-page');
if (targetPage && form && pageInput) {
pageInput.value = targetPage;
form.submit();
}
});
});
}
// ist das DOM bereits vollständig aufgebaut?
if (document.readyState === 'loading') {
// Falls noch geladen wird, auf das Event warten
document.addEventListener('DOMContentLoaded', initPaginator);
} else {
// Falls das HTML bereits komplett da ist, sofort ausführen
initPaginator();
}
+10 -54
View File
@@ -24,6 +24,12 @@ require_once '../validator/article-validator.php';
$tags = $_POST['tags'] ?? ''; $tags = $_POST['tags'] ?? '';
// -------------------------------- Validierung der Daten: ------------------------- // -------------------------------- Validierung der Daten: -------------------------
if (!articleAuthorValidator($author)) {
$_SESSION["message"] = "author_not_valid";
header("location: ../../index.php?pfad=createArticle");
exit();
}
if (!articleTitleValidator($title)) { if (!articleTitleValidator($title)) {
$_SESSION["message"] = "invalid_title"; $_SESSION["message"] = "invalid_title";
header("location: ../../index.php?pfad=createArticle"); header("location: ../../index.php?pfad=createArticle");
@@ -58,59 +64,6 @@ require_once '../validator/article-validator.php';
$cleanedTags = array_unique($cleanedTags); $cleanedTags = array_unique($cleanedTags);
$cleanedTags = implode(',', $cleanedTags); $cleanedTags = implode(',', $cleanedTags);
} }
// ----------------- Base64-Bilder verarbeiten und auf Server speichern -----------------
$blocks = json_decode($content, true);
$uploadDir = __DIR__ . '/../../uploads/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
if (is_array($blocks)) {
foreach ($blocks as &$block) {
// sicherstellen, dass 'type' und 'value' existieren:
if (isset($block['type']) && isset($block['value']) && $block['type'] === 'image' && str_starts_with($block['value'], 'data:image/')) {
// Base64-String zerlegen
$parts = explode(',', $block['value']);
// falls der String korrupt ist und kein Komma hat
if (count($parts) < 2) {
continue;
}
$metadata = $parts[0];
$base64Data = $parts[1];
// Dateiendung ermitteln
preg_match('/data:image\/(?<extension>.*?);/', $metadata, $matches);
$extension = $matches['extension'] ?? 'jpg';
if ($extension === 'jpeg') {
$extension = 'jpg';
}
// Eindeutigen Dateinamen generieren
$fileName = 'img_' . uniqid() . '.' . $extension;
$filePath = $uploadDir . $fileName;
// Datei im /uploads speichern:
if (file_put_contents($filePath, base64_decode($base64Data)) !== false) {
// temporären Base64-String durch den echten Pfad ersetzen
$block['value'] = 'uploads/' . $fileName;
} else {
$_SESSION["message"] = "image_upload_error";
header("location: ../../index.php?pfad=createArticle");
exit();
}
}
}
unset($block);
}
// Aktualisiertes Array wieder in JSON konvertieren
$finalContent = json_encode($blocks, JSON_UNESCAPED_UNICODE);
// ----------------- Übertragung der validierten Daten in ArticleManager: --------------------------- // ----------------- Übertragung der validierten Daten in ArticleManager: ---------------------------
try { try {
$articleManager = ArticleManager::getInstance(); $articleManager = ArticleManager::getInstance();
@@ -119,7 +72,7 @@ require_once '../validator/article-validator.php';
// Formulardaten nach erfolgreichem Erstellen aus der Session löschen // Formulardaten nach erfolgreichem Erstellen aus der Session löschen
unset($_SESSION["old_title"], $_SESSION["old_content"], $_SESSION["old_category"], $_SESSION["old_tags"]); unset($_SESSION["old_title"], $_SESSION["old_content"], $_SESSION["old_category"], $_SESSION["old_tags"]);
} catch (\Throwable $e){ } catch (Exception $e){
$_SESSION["message"] = "internal_error"; $_SESSION["message"] = "internal_error";
header("location: ../../index.php?pfad=createArticle"); header("location: ../../index.php?pfad=createArticle");
exit(); exit();
@@ -131,4 +84,7 @@ require_once '../validator/article-validator.php';
exit(); exit();
} }
} }
?> ?>
+5 -1
View File
@@ -62,7 +62,11 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
$_SESSION["message"] = "internal_error"; $_SESSION["message"] = "internal_error";
} }
} }
header("Location: ../../index.php?pfad=search-results");
$sort = $_GET['sort'] ?? 'alphabet';
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10;
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
header("Location: ../../index.php?pfad=search-results&q=" . urlencode($search) . "&sort=" . urlencode($sort) . "&limit=" . $limit . "&page=" . $page);
exit(); exit();
} }
+8 -77
View File
@@ -34,6 +34,12 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
$tags = $_POST['tags'] ?? ''; $tags = $_POST['tags'] ?? '';
// -------------------------------- Validierung der Daten: ------------------------- // -------------------------------- Validierung der Daten: -------------------------
if (!articleAuthorValidator($author)) {
$_SESSION["message"] = "author_not_valid";
header("location: ../../index.php?pfad=updateArticle&id=$id");
exit();
}
if (!articleTitleValidator($title)) { if (!articleTitleValidator($title)) {
$_SESSION["message"] = "invalid_title"; $_SESSION["message"] = "invalid_title";
header("location: ../../index.php?pfad=updateArticle&id=$id"); header("location: ../../index.php?pfad=updateArticle&id=$id");
@@ -69,91 +75,16 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
$cleanedTags = implode(',', $cleanedTags); $cleanedTags = implode(',', $cleanedTags);
} }
// --------------------------------------- Base64-Bilder speichern ---------------------------------------------
$blocks = json_decode($content, true);
$uploadDir = __DIR__ . '/../../uploads/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
// ----------------- Gelöschte Bilder über die JS-Löschliste entfernen ----------------- TODO: Gelöschte Bilder über die JS-Löschliste entfernen
/*if (isset($_POST['deleted_images'])) {
$deletedImages = json_decode($_POST['deleted_images'], true);
// Wir ermitteln den physisch echten, absoluten Pfad zum uploads-Ordner auf der Festplatte
$uploadDir = realpath(__DIR__ . '/../../uploads') . DIRECTORY_SEPARATOR;
if (is_array($deletedImages)) {
foreach ($deletedImages as $imagePath) {
// Nur den reinen Dateinamen heraustrennen (z.B. img_65a123.jpg)
$filename = basename($imagePath);
$fullDeletePath = $uploadDir . $filename;
// Debugging & Löschen:
if (file_exists($fullDeletePath)) {
// Versuchen zu löschen. Wenn es fehlschlägt, Fehlermeldung erzwingen
if (!@unlink($fullDeletePath)) {
$error = error_get_last();
die("Datei existiert, aber PHP darf sie nicht löschen! Grund: " . $error['message']);
}
} else {
// Wenn PHP die Datei an diesem Pfad nicht findet, brechen wir zum Debuggen ab
// die("PHP findet die Datei nicht unter dem Pfad: " . $fullDeletePath);
}
}
}
}*/
// ----------------------- NEU hinzugefügte Base64-Bilder: --------------------------
if (is_array($blocks)) {
foreach ($blocks as &$block) {
// Prüfen, ob der Block ein Bild ist und ein NEUES Bild (Base64-Format) enthält
if (isset($block['type']) && isset($block['value']) && $block['type'] === 'image' && is_string($block['value'])) {
if (str_starts_with($block['value'], 'data:image/')) {
$parts = explode(',', $block['value']);
if (count($parts) >= 2) {
$metadata = $parts[0];
$base64Data = $parts[1];
preg_match('/data:image\/(?<extension>.*?);/', $metadata, $matches);
$extension = $matches['extension'] ?? 'jpg';
if ($extension === 'jpeg') { $extension = 'jpg'; }
$fileName = 'img_' . uniqid() . '.' . $extension;
$filePath = $uploadDir . $fileName;
if (file_put_contents($filePath, base64_decode($base64Data)) !== false) {
$block['value'] = 'uploads/' . $fileName;
} else {
$_SESSION["message"] = "image_upload_error";
header("location: ../../index.php?pfad=updateArticle&id=$id");
exit();
}
}
}
}
}
unset($block);
}
// Aktualisiertes Array wieder in JSON konvertieren
$finalContent = json_encode($blocks, JSON_UNESCAPED_UNICODE);
// ----------------- Übertragung der validierten Daten in ArticleManager: --------------------------- // ----------------- Übertragung der validierten Daten in ArticleManager: ---------------------------
try { try {
$articleManager = ArticleManager::getInstance(); $articleManager = ArticleManager::getInstance();
$article = $articleManager->getArticle($id); $article = $articleManager->getArticle($id);
$article->setTitle($title); $article->setTitle($title);
$article->setContent($finalContent); $article->setContent($content);
$article->setCategory($category); $article->setCategory($category);
$article->setTags($cleanedTags); $article->setTags($cleanedTags);
$articleManager->updateArticle($id ,$article, $author); $articleManager->updateArticle($id ,$article, $author);
} catch (Exception $e){
unset($_SESSION["old_title"], $_SESSION["old_content"], $_SESSION["old_category"], $_SESSION["old_tags"]);
} catch (\Throwable $e){
$_SESSION["message"] = $e->getMessage(); $_SESSION["message"] = $e->getMessage();
header("location: ../../index.php?pfad=updateArticle&id=$id"); header("location: ../../index.php?pfad=updateArticle&id=$id");
exit(); exit();
+2 -10
View File
@@ -13,7 +13,7 @@ class ArticleManager
/** /**
* Diese Methode erstellt, falls noch keine existiert, eine Instanz einer ArticleManager-Implementierung und * Diese Methode erstellt, falls noch keine existiert, eine Instanz einer ArticleManager-Implementierung und
* erstellt Dummy-Beiträge. * erstellt Dummy-Beiträge.
* *
* @throws InternalServerErrorException * @throws InternalServerErrorException
*/ */
public static function getInstance() public static function getInstance()
@@ -145,17 +145,9 @@ class ArticleManager
// Verteilt die 10 Autoren gleichmäßig (ID 1 -> Autor 1, ID 10 -> Autor 10, ID 11 -> Autor 1) // Verteilt die 10 Autoren gleichmäßig (ID 1 -> Autor 1, ID 10 -> Autor 10, ID 11 -> Autor 1)
$authorEmail = $authors[($id - 1) % 10]; $authorEmail = $authors[($id - 1) % 10];
$blockStructure = [
[
'type' => 'text',
'value' => $data[1] // Der originale Text aus dem Dummy-Array
]
];
$jsonContent = json_encode($blockStructure, JSON_UNESCAPED_UNICODE);
$articleManager->addArticle( $articleManager->addArticle(
$data[0], // Titel $data[0], // Titel
$jsonContent, // Inhalt $data[1], // Inhalt
$authorEmail, // Rotierende Autoren-E-Mail $authorEmail, // Rotierende Autoren-E-Mail
$data[2], // Kategorie $data[2], // Kategorie
$data[3] // Tags $data[3] // Tags
+18 -61
View File
@@ -1,5 +1,16 @@
<?php <?php
/**
* Prüft, ob der Autor auch der Eigentümer des Beitrags ist.
* @param $author
* @return true
* TODO: Implement this.
*/
function articleAuthorValidator($author)
{
return true;
}
/** /**
* Prüft, ob der Titel die folgenden Bedingungen erfüllt: * Prüft, ob der Titel die folgenden Bedingungen erfüllt:
* Buchstaben von a-z; A-Z * Buchstaben von a-z; A-Z
@@ -22,73 +33,19 @@ function articleTitleValidator($title)
} }
/** /**
* Prüft, ob der Content valides JSON ist UND ob alle enthaltenen Blöcke * Prüft, ob der Contenttext 10-7000 Zeichen enthält.
* die inhaltlichen Kriterien erfüllen: * @param $content
* Textblöcke sind nicht leer
* Bilder sind in Bildblöcken vorhanden
*
* @param mixed $content Der zu prüfende JSON-String
* @return bool * @return bool
*/ */
function articleContentValidator($content) function articleContentValidator($content)
{ {
// 1. Grundlegende Typprüfung $content = trim($content);
if (!is_string($content)) { $zeichenAnzahl = mb_strlen($content);
if ($zeichenAnzahl <= 7000 && $zeichenAnzahl >= 10) {
return true;
}else{
return false; return false;
} }
// 2. Formale JSON-Prüfung (Kompatibel mit PHP 8.2)
$blocks = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return false;
}
// 3. Inhaltliche Validierung der einzelnen Blöcke
// Falls das JSON zwar valide, aber kein Array ist (z.B. nur ein String/Zahl)
if (!is_array($blocks)) {
return false;
}
// Mindestens ein Block sollte vorhanden sein (optional, verhindert leere Beiträge)
if (empty($blocks)) {
return false;
}
foreach ($blocks as $block) {
// Jeder Block muss die Keys 'type' und 'value' besitzen
if (!isset($block['type']) || !isset($block['value'])) {
return false;
}
$type = $block['type'];
$value = $block['value'];
if ($type === 'text') {
// Validierung für Text: Darf nach dem Trimmen nicht leer sein
if (trim($value) === '') {
return false;
}
} elseif ($type === 'image') {
// Validierung für Bild: Muss entweder mit uploads/ starten (Bestand)
// oder mit data:image/ beginnen (neues Base64-Bild aus dem Editor)
if (!is_string($value)) {
return false;
}
$isValidPath = str_starts_with($value, 'uploads/');
$isValidBase64 = str_starts_with($value, 'data:image/');
if (!$isValidPath && !$isValidBase64) {
return false;
}
} else {
// Unbekannter Blocktyp wird zur Sicherheit abgewiesen
return false;
}
}
// Wenn alle Prüfungen bestanden wurden
return true;
} }
/** /**
-14
View File
@@ -1,14 +0,0 @@
# Verhindert das Auflisten aller Dateien im Ordner
Options -Indexes
# Schaltet die PHP-Ausführung in diesem Ordner komplett ab
<FilesMatch "\.(php|php[0-9]|phtml|pl|py|jsp|sh|cgi)$">
Order Deny,Allow
Deny from all
</FilesMatch>
# erlaubt nur den Zugriff auf folgende Dateien:
<FilesMatch "\.(?i:jpg|jpeg|png|gif|webp|ico)$">
Order Allow,Deny
Allow from all
</FilesMatch>