
DU findest die Fehler
DU fragst dann mal Tante KI für mich
so machen wir das auch in Zukunft

Ich brauch die KI nur um hübscher zu machen und ab und zu um Fehler zu finden.
Den Rest mach ich, sonst wär es ja auch Langweilig
Code: Alles auswählen
date_default_timezone_set('Europe/Berlin');
Code: Alles auswählen
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Code: Alles auswählen
https://www.mobirise-tutorials.com/download-limited/download.php?token=0fe48becdb3ad63ba06cf294a71f306a
Code: Alles auswählen
https://www.mobirise-tutorials.com/download-limited/download.php?token=c5f095df695698589c49f37f376cead3
Code: Alles auswählen
<?php
date_default_timezone_set('Europe/Berlin');
$storageFile = __DIR__ . "/tokens.json";
$protectedDir = __DIR__ . "/schutz";
$logFile = __DIR__ . "/download.log";
$blacklist = ['.htaccess', '.gitignore'];
// Tokens laden
$tokens = file_exists($storageFile) ? json_decode(file_get_contents($storageFile), true) : [];
// Abgelaufene Tokens automatisch bereinigen
foreach ($tokens as $tk => $entry) {
if (time() > $entry['expires']) {
unset($tokens[$tk]);
}
}
file_put_contents($storageFile, json_encode($tokens), LOCK_EX);
// Token prüfen
if (!isset($_GET['token'])) die("❌ Ungültiger Zugriff");
$token = $_GET['token'];
if (!isset($tokens[$token])) die("❌ Ungültiger oder abgelaufener Token");
$entry = $tokens[$token];
if (time() > $entry['expires']) {
unset($tokens[$token]);
file_put_contents($storageFile, json_encode($tokens), LOCK_EX);
die("⏰ Der Link ist abgelaufen");
}
// Funktion: Download-Log
function writeLog($token, $file)
{
global $logFile;
$entryLog = date("Y-m-d H:i:s") . " | Token: $token | Datei: $file | IP: " . $_SERVER['REMOTE_ADDR'] . "\n";
file_put_contents($logFile, $entryLog, FILE_APPEND);
}
// Einzeldatei ausliefern
if (isset($_GET['file'])) {
$file = $_GET['file']; // kann auch unterordner/datei.txt sein
if (!in_array($file, $entry['files']) || in_array(basename($file), $blacklist))
die("❌ Datei nicht freigegeben");
$downloads = $tokens[$token]['downloads'][$file] ?? 0;
if ($downloads >= $entry['maxDownloads']) die("⚠️ Max Downloads für diese Datei erreicht");
$tokens[$token]['downloads'][$file] = $downloads + 1;
file_put_contents($storageFile, json_encode($tokens), LOCK_EX);
writeLog($token, $file);
$filePath = $protectedDir . "/" . $file;
if (!file_exists($filePath)) die("❌ Datei nicht gefunden");
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
exit;
}
// ZIP-Download
if(isset($_GET['zip'])){
$zipFile = tempnam(sys_get_temp_dir(), 'dlzip') . ".zip";
$zip = new ZipArchive();
if($zip->open($zipFile, ZipArchive::CREATE) !== TRUE) die("❌ Konnte ZIP nicht erstellen");
$added = false; // Prüfen, ob überhaupt Dateien hinzugefügt wurden
foreach($entry['files'] as $f){
$filePath = $protectedDir . "/" . $f;
if(!file_exists($filePath)) continue;
// Max-Downloads prüfen
$downloads = $tokens[$token]['downloads'][$f] ?? 0;
if($downloads >= $entry['maxDownloads']) continue;
$zip->addFile($filePath, $f);
$tokens[$token]['downloads'][$f] = $downloads + 1;
writeLog($token, $f);
$added = true;
}
if(!$added){
$zip->close();
unlink($zipFile);
die("⚠️ Alle Dateien haben das Max-Download-Limit erreicht");
}
file_put_contents($storageFile, json_encode($tokens), LOCK_EX);
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="download_bundle.zip"');
header('Content-Length: ' . filesize($zipFile));
readfile($zipFile);
unlink($zipFile);
exit;
}
// Bootstrap-Ausgabe: Liste der freigegebenen Dateien
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Freigegebene Dateien</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {max-width: 800px; margin: 0 auto;}
.subfolder { margin-left: 20px; display: none; }
.folder { font-weight: bold; }
/* Visuelles Feedback für klickbare Ordner-LIs */
li.folder-item { cursor: pointer; user-select: none; }
/* Buttons bleiben klickbar */
a.btn { cursor: pointer; }
/* Innerhalb der geöffneten Subfolder-Zeile Standardcursor, außer auf dem Button */
.subfolder .list-group-item { cursor: default; }
.subfolder .list-group-item a.btn { cursor: pointer; }
/* ✅ Fix für Smartphones: Zeilen umbrechen statt Overflow */
@media (max-width: 767px) {
.list-group-item.d-flex {
flex-wrap: wrap !important;
text-align: left;
}
.list-group-item.d-flex span,
.list-group-item.d-flex a.btn {
margin-top: 6px;
max-width: 100%;
word-break: break-word;
}
}
/* Umbrechen des Hinweistexts "(klicken zum Öffnen/Schließen)" innerhalb der Ordnerzeile */
@media (max-width: 767px) {
/* Die Kopfzeile des Ordners darf umbrechen */
.folder.d-flex {
flex-wrap: wrap !important;
align-items: flex-start;
}
/* Erster <span> (Ordnername) darf schrumpfen statt Overflow zu erzwingen */
.folder.d-flex > span:first-child {
min-width: 0;
}
/* Zweiter <span> (Hinweistext) springt in eigene Zeile und darf umbrechen */
.folder.d-flex > span + span {
flex: 0 0 100%;
margin-top: 4px;
white-space: normal;
overflow-wrap: anywhere; /* bricht auch lange/zusammenhängende Strings */
word-break: break-word; /* Fallback */
}
}
</style>
</head>
<body class="bg-light">
<div class="container py-4">
<!-- deaktiviert - eventueller Link zur Homepage
<h3> ↗️ <a href="https://www.Deine-Domain.de/" target="_blank">Deine-Domain.de</a></h3><br>
-->
<h2>📂 Freigegebene Dateien</h2>
<p>Gültig bis: <?= date("d.m.Y H:i", $entry['expires']) ?></p>
<?php
// Dateien nach Ordner sortieren
$folders = [];
$rootFiles = [];
foreach ($entry['files'] as $f) {
if (strpos($f, "/") !== false) {
$folders[$f] = $f;
} else {
$rootFiles[] = $f;
}
}
// Root-Dateien (nur Button lädt herunter, <li> selbst ist NICHT klickbar)
if ($rootFiles) {
echo "<ul class='list-group mb-3'>";
foreach ($rootFiles as $f) {
$downloads = $entry['downloads'][$f] ?? 0;
$max = $entry['maxDownloads'];
$disabled = $downloads >= $max ? "disabled" : "";
$downloadUrl = "?token=$token&file=" . urlencode($f);
echo "<li class='list-group-item d-flex justify-content-between align-items-center'>";
echo htmlspecialchars($f) . " ($downloads/$max)";
if (!$disabled) {
echo " <a href='" . htmlspecialchars($downloadUrl, ENT_QUOTES) . "' class='btn btn-sm btn-primary ms-3'>📥 Download</a>";
}
echo "</li>";
}
echo "</ul>";
}
// Unterordner (ganzer <li> toggelt, Download NUR über Button im Subfolder)
if ($folders) {
// Button: Alles auf-/zuklappen
echo "<div class='d-flex justify-content-end mb-2'>";
echo "<button type='button' id='toggleAllBtn' class='btn btn-outline-secondary btn-sm'>Alles aufklappen</button>";
echo "</div>";
echo "<ul class='list-group' id='foldersList'>";
foreach ($folders as $f) {
$downloads = $entry['downloads'][$f] ?? 0;
$max = $entry['maxDownloads'];
$disabled = $downloads >= $max ? "disabled" : "";
$downloadUrl = "?token=$token&file=" . urlencode($f);
$folderId = md5($f);
echo "<li class='list-group-item folder-item' data-folder-id='" . $folderId . "'>";
// Titelzeile
echo "<div class='folder d-flex justify-content-between align-items-center'>";
echo "<span>📁 " . htmlspecialchars($f) . "</span>";
echo "<span class='text-muted small ms-2'>(klicken zum Öffnen/Schließen)</span>";
echo "</div>";
// Subfolder-Inhalt: eigener Eintrag mit ausschließlich Button-Download
echo "<div class='subfolder list-group mt-1' id='" . $folderId . "'>";
echo "<div class='list-group-item d-flex justify-content-between align-items-center'>";
echo "<span>" . htmlspecialchars($f) . " ($downloads/$max)</span>";
if (!$disabled) {
echo "<a href='" . htmlspecialchars($downloadUrl, ENT_QUOTES) . "' class='btn btn-sm btn-primary'>📥 Download</a>";
}
echo "</div>";
echo "</div>";
echo "</li>";
}
echo "</ul>";
}
?>
<p class="mt-3">
<a href='?token=<?= $token ?>&zip=1' class="btn btn-success">📦 Alles als ZIP herunterladen</a>
</p>
<script>
// Toggle-Funktion (beibehalten für direkte Aufrufe)
function toggleFolder(id){
const el = document.getElementById(id);
if (!el) return;
el.style.display = (el.style.display==='none' || el.style.display==='') ? 'block' : 'none';
}
// GANZES LI eines Ordners toggelt auf/zu.
// – Klicks auf Buttons/Links und innerhalb des Subfolder-Inhalts lösen KEIN Toggle aus.
document.addEventListener('click', function(e){
if (e.target.closest('a, button')) return; // Buttons/Links: nichts toggeln
if (e.target.closest('.subfolder')) return; // Klick im Subfolder-Inhalt: nicht toggeln
const li = e.target.closest('li.folder-item');
if (!li) return;
const id = li.getAttribute('data-folder-id');
if (!id) return;
toggleFolder(id);
}, {passive:true});
// --- Alles auf-/zuklappen ---
(function(){
const btn = document.getElementById('toggleAllBtn');
if (!btn) return;
function anyClosed(){
const subs = document.querySelectorAll('.subfolder');
for (const el of subs){
if (el.style.display === '' || el.style.display === 'none') return true;
}
return false;
}
function setAll(open){
const subs = document.querySelectorAll('.subfolder');
subs.forEach(el => { el.style.display = open ? 'block' : 'none'; });
btn.textContent = open ? 'Alles zuklappen' : 'Alles aufklappen';
}
// Initialer Button-Text je nach Zustand
btn.textContent = anyClosed() ? 'Alles aufklappen' : 'Alles zuklappen';
btn.addEventListener('click', function(){
const open = anyClosed(); // wenn irgendeiner zu ist -> alle öffnen, sonst alle schließen
setAll(open);
});
})();
</script>
</div>
</body>
</html>
Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste