Unser Image Hoster ist ein voll funktionsfähiges, browserbasiertes Script System zum Hochladen, Verwalten und Moderieren von Bildern. Nutzer können Bilder direkt über ein übersichtliches Frontend hochladen, dabei wird automatisch ein Captcha für Sicherheit verwendet. Jedes Bild wird in Originalgröße gespeichert und zusätzlich als Thumbnail generiert, sodass eine schnelle Vorschau möglich ist.
Administratoren erhalten über ein integriertes Dashboard vollen Zugriff auf alle hochgeladenen Bilder. Sie können Inhalte freigeben, löschen oder den Überblick über Nutzeraktivitäten behalten. Das System verwendet eine SQLite-Datenbank, ist sofort einsatzbereit und erstellt bei der ersten Nutzung alle erforderlichen Dateien und Ordner automatisch.
Mit dem Dreamcodes Image Hoster können kleine Communities, Blogs oder Projekte einfach eigene Bildbibliotheken betreiben, ohne auf externe Dienste angewiesen zu sein. Alle Daten werden lokal verarbeitet, Uploads erfolgen sicher und selbstständig, und die Plattform ist modular erweiterbar, etwa für E-Mail-Benachrichtigungen, RSS-Feeds oder erweiterte Moderationsfunktionen.
<?php
// Nach Installation Datei löschen!
set_time_limit(0);
error_reporting(E_ALL);
ini_set('display_errors', 1);
$root = __DIR__;
// 1. Ordnerstruktur
$dirs = [
'public',
'public/assets',
'uploads',
'uploads/thumbs',
'api',
'admin',
'src',
'data'
];
function makeDirs($root, $dirs) {
foreach ($dirs as $d) {
$p = $root . DIRECTORY_SEPARATOR . $d;
if (!is_dir($p)) mkdir($p, 0755, true);
}
}
makeDirs($root, $dirs);
// 2. .env erzeugen
$envPath = $root . '/.env';
if(!file_exists($envPath)){
$envContent = <<<ENV
DB_DRIVER=sqlite
DB_SQLITE_PATH={$root}/data/imagehost.sqlite
ADMIN_USER=admin
ADMIN_PASS=admin123
BASE_URL=http://localhost
UPLOAD_DIR={$root}/uploads
ENV;
file_put_contents($envPath, $envContent);
}
// 3. SQLite DB anlegen
$dbFile = $root . '/data/imagehost.sqlite';
if(!file_exists($dbFile)){
$pdo = new PDO('sqlite:' . $dbFile);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec("PRAGMA journal_mode = WAL");
$pdo->exec("
CREATE TABLE IF NOT EXISTS images (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename TEXT NOT NULL,
thumb TEXT NOT NULL,
original_name TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
uploaded_by TEXT,
is_enabled INTEGER DEFAULT 1
);
");
$pdo->exec("
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
passhash TEXT,
role TEXT DEFAULT 'admin',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
");
$hash = password_hash('admin123', PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT OR IGNORE INTO users (username, passhash) VALUES ('admin', :p)");
$stmt->execute([':p'=>$hash]);
}
// 4. Dateien erzeugen
function writeFile($file, $content){
$dir = dirname($file);
if(!is_dir($dir)) mkdir($dir,0755,true);
file_put_contents($file,$content);
@chmod($file,0644);
}
// --- src/config.php ---
$config = <<<'PHP'
<?php
$root = dirname(__DIR__);
$envFile = $root . '/.env';
$env = [];
if(file_exists($envFile)){
foreach(file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line){
$line = trim($line);
if($line===''||$line[0]==='#') continue;
if(strpos($line,'=')===false) continue;
[$k,$v] = explode('=', $line,2);
$env[trim($k)] = trim($v);
}
}
return [
'db_driver'=>$env['DB_DRIVER']??'sqlite',
'db_sqlite_path'=>$env['DB_SQLITE_PATH']??$root.'/data/imagehost.sqlite',
'admin_user'=>$env['ADMIN_USER']??'admin',
'admin_pass'=>$env['ADMIN_PASS']??'admin123',
'base_url'=>rtrim($env['BASE_URL']??'','/'),
'upload_dir'=>$env['UPLOAD_DIR']??$root.'/uploads'
];
PHP;
writeFile($root.'/src/config.php',$config);
// --- src/db.php ---
$db = <<<'PHP'
<?php
function getPdo(){
static $pdo=null;
if($pdo) return $pdo;
$cfg = require __DIR__.'/config.php';
$pdo = new PDO('sqlite:'.$cfg['db_sqlite_path']);
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
return $pdo;
}
PHP;
writeFile($root.'/src/db.php',$db);
// --- src/captcha.php ---
$captcha = <<<'PHP'
<?php
session_start();
function captchaQuestion(){
$a=random_int(1,9);
$b=random_int(1,9);
$_SESSION['captcha_answer']=$a+$b;
return "Was ist $a + $b ?";
}
function captchaCheck($val){
if(!isset($_SESSION['captcha_answer'])) return false;
$ok = ((int)$val === (int)$_SESSION['captcha_answer']);
unset($_SESSION['captcha_answer']);
return $ok;
}
PHP;
writeFile($root.'/src/captcha.php',$captcha);
// --- public/index.php ---
$index = <<<'PHP'
<?php
require_once __DIR__.'/../src/config.php';
require_once __DIR__.'/../src/captcha.php';
session_start();
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Image Host</title>
<link rel="stylesheet" href="assets/style.css">
</head>
<body>
<div class="container">
<header class="card"><h1>Image Host Service</h1></header>
<section class="card">
<h3>Bild hochladen</h3>
<input type="file" id="fileInput">
<div style="margin-top:8px">
<label id="captchaQuestion" class="small">Lade Captcha...</label>
<input id="captchaAnswer" class="input" placeholder="Antwort">
</div>
<div style="margin-top:8px">
<button class="btn" onclick="upload()">Hochladen</button>
</div>
<div id="result" class="small" style="margin-top:12px"></div>
</section>
<footer class="footer card">
<div>Made with ❤️ by <a href="https://www.dreamcodes.net" target="_blank">Dreamcodes</a></div>
</footer>
</div>
<script src="assets/app.js"></script>
</body>
</html>
PHP;
writeFile($root.'/public/index.php',$index);
// --- public/assets/style.css ---
$style = <<<'CSS'
body{font-family:Arial,sans-serif;background:#f6f8f9;margin:0;color:#222}
.container{max-width:900px;margin:20px auto;padding:12px}
.card{background:#fff;padding:12px;border-radius:10px;box-shadow:0 4px 12px rgba(0,0,0,0.05)}
.input{width:100%;padding:8px;margin-top:4px;border:1px solid #ccc;border-radius:6px}
.btn{padding:8px 12px;background:#1f7a8c;color:#fff;border:none;border-radius:6px;cursor:pointer}
.footer{margin-top:12px;font-size:12px;color:#666;text-align:center}
.small{font-size:12px;color:#666}
CSS;
writeFile($root.'/public/assets/style.css',$style);
// --- public/assets/app.js ---
$js = <<<'JS'
function ajax(url,data,cb){
const fd=new FormData();
for(let k in data) fd.append(k,data[k]);
fetch(url,{method:'POST',body:fd}).then(r=>r.json()).then(cb);
}
function loadCaptcha(){
fetch('/api/captcha.php').then(r=>r.json()).then(d=>{
document.getElementById('captchaQuestion').innerText=d.question;
});
}
function upload(){
const file=document.getElementById('fileInput').files[0];
const captcha=document.getElementById('captchaAnswer').value;
if(!file){ alert('Bitte Datei wählen'); return; }
ajax('/api/upload.php',{file:file,captcha:captcha},function(res){
const r=document.getElementById('result');
if(res.ok) r.innerHTML='Hochgeladen: <a href="'+res.url+'" target="_blank">'+res.url+'</a><br><img src="'+res.thumb+'">';
else r.innerText=res.error||'Fehler';
loadCaptcha();
});
}
window.addEventListener('load',loadCaptcha);
JS;
writeFile($root.'/public/assets/app.js',$js);
// --- api/captcha.php ---
$apiCaptcha = <<<'PHP'
<?php
require_once __DIR__.'/../src/captcha.php';
session_start();
header('Content-Type: application/json; charset=utf-8');
$q = captchaQuestion();
echo json_encode(['question'=>$q]);
PHP;
writeFile($root.'/api/captcha.php',$apiCaptcha);
// --- api/upload.php ---
$apiUpload = <<<'PHP'
<?php
require_once __DIR__.'/../src/config.php';
require_once __DIR__.'/../src/db.php';
require_once __DIR__.'/../src/captcha.php';
session_start();
header('Content-Type: application/json; charset=utf-8');
$cfg=require __DIR__.'/../src/config.php';
$pdo=getPdo();
if(!captchaCheck($_POST['captcha']??'')){
echo json_encode(['ok'=>false,'error'=>'Captcha falsch']); exit;
}
if(empty($_FILES['file'])){ echo json_encode(['ok'=>false,'error'=>'Keine Datei']); exit; }
$file=$_FILES['file'];
$ext=strtolower(pathinfo($file['name'],PATHINFO_EXTENSION));
if(!in_array($ext,['jpg','jpeg','png','gif'])){ echo json_encode(['ok'=>false,'error'=>'Nur jpg/png/gif erlaubt']); exit; }
$fname=uniqid().'.'.$ext;
$path=$cfg['upload_dir'].'/'.$fname;
if(!move_uploaded_file($file['tmp_name'],$path)){
echo json_encode(['ok'=>false,'error'=>'Upload fehlgeschlagen']); exit;
}
// thumbnail
$thumbFile=$cfg['upload_dir'].'/thumbs/'.$fname;
list($w,$h)=getimagesize($path);
$thumbW=200; $thumbH=intval($h*($thumbW/$w));
$thumbImg=imagecreatetruecolor($thumbW,$thumbH);
switch($ext){
case 'jpg': case 'jpeg': $src=imagecreatefromjpeg($path); break;
case 'png': $src=imagecreatefrompng($path); break;
case 'gif': $src=imagecreatefromgif($path); break;
}
imagecopyresampled($thumbImg,$src,0,0,0,0,$thumbW,$thumbH,$w,$h);
switch($ext){
case 'jpg': case 'jpeg': imagejpeg($thumbImg,$thumbFile,85); break;
case 'png': imagepng($thumbImg,$thumbFile); break;
case 'gif': imagegif($thumbImg,$thumbFile); break;
}
imagedestroy($thumbImg);
imagedestroy($src);
$stmt=$pdo->prepare("INSERT INTO images (filename,thumb,original_name,uploaded_by) VALUES (:f,:t,:o,:u)");
$stmt->execute([':f'=>$fname,':t'=>'uploads/thumbs/'.$fname,':o'=>$file['name'],':u'=>$_SERVER['REMOTE_ADDR']]);
$url=rtrim($cfg['base_url'],'/').'/uploads/'.$fname;
$thumb=rtrim($cfg['base_url'],'/').'/uploads/thumbs/'.$fname;
echo json_encode(['ok'=>true,'url'=>$url,'thumb'=>$thumb]);
PHP;
writeFile($root.'/api/upload.php',$apiUpload);
// --- admin/index.php (Login Form) ---
$adminIndex = <<<'PHP'
<?php
session_start();
if(isset($_SESSION['admin_logged']) && $_SESSION['admin_logged']===true){
header("Location: dashboard.php"); exit;
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Admin Login</title>
<link rel="stylesheet" href="../public/assets/style.css">
</head>
<body>
<div class="container">
<header class="card"><h1>Admin Login</h1></header>
<section class="card">
<form method="POST" action="dashboard.php">
<label>Benutzername</label>
<input type="text" name="username" class="input" required>
<label>Passwort</label>
<input type="password" name="password" class="input" required>
<button type="submit" class="btn">Login</button>
</form>
</section>
<footer class="footer card">
<div>Made with ❤️ by <a href="https://www.dreamcodes.net" target="_blank">Dreamcodes</a></div>
</footer>
</div>
</body>
</html>
PHP;
writeFile($root.'/admin/index.php',$adminIndex);
// --- admin/dashboard.php ---
$adminDashboard = <<<'PHP'
<?php
session_start();
require_once __DIR__.'/../src/config.php';
require_once __DIR__.'/../src/db.php';
$cfg=require __DIR__.'/../src/config.php';
$pdo=getPdo();
if($_SERVER['REQUEST_METHOD']==='POST'){
$u=$_POST['username']??'';
$p=$_POST['password']??'';
$stmt=$pdo->prepare("SELECT * FROM users WHERE username=:u");
$stmt->execute([':u'=>$u]);
$user=$stmt->fetch(PDO::FETCH_ASSOC);
if($user && password_verify($p,$user['passhash'])){
$_SESSION['admin_logged']=true;
} else { $error="Falscher Benutzername oder Passwort"; }
}
if(!isset($_SESSION['admin_logged']) || $_SESSION['admin_logged']!==true){
include 'index.php';
exit;
}
$images=$pdo->query("SELECT * FROM images ORDER BY created_at DESC")->fetchAll(PDO::FETCH_ASSOC);
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Admin Dashboard</title>
<link rel="stylesheet" href="../public/assets/style.css">
</head>
<body>
<div class="container">
<header class="card"><h1>Admin Dashboard</h1></header>
<section class="card">
<h3>Moderation</h3>
<table border="1" width="100%" cellpadding="6">
<tr><th>ID</th><th>Bild</th><th>Original</th><th>IP</th><th>Erstellt</th><th>Aktion</th></tr>
<?php foreach($images as $img): ?>
<tr>
<td><?=htmlspecialchars($img['id'])?></td>
<td><img src="../<?=$img['thumb']?>" width="100"></td>
<td><?=htmlspecialchars($img['original_name'])?></td>
<td><?=htmlspecialchars($img['uploaded_by'])?></td>
<td><?=$img['created_at']?></td>
<td>
<form method="POST" action="dashboard.php">
<input type="hidden" name="delete_id" value="<?=$img['id']?>">
<button type="submit" class="btn" onclick="return confirm('Löschen?')">Löschen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</table>
</section>
<footer class="footer card">
<div>Made with ❤️ by <a href="https://www.dreamcodes.net" target="_blank">Dreamcodes</a></div>
</footer>
</div>
<?php
if($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['delete_id'])){
$id=(int)$_POST['delete_id'];
$img=$pdo->query("SELECT * FROM images WHERE id=$id")->fetch(PDO::FETCH_ASSOC);
if($img){
@unlink($cfg['upload_dir'].'/'.$img['filename']);
@unlink($cfg['upload_dir'].'/thumbs/'.$img['filename']);
$pdo->exec("DELETE FROM images WHERE id=$id");
header("Location: dashboard.php");
exit;
}
}
?>
</body>
</html>
PHP;
writeFile($root.'/admin/dashboard.php',$adminDashboard);
echo "<h2>Installation abgeschlossen!</h2>";
echo "<p>Frontend: <a href='public/index.php'>public/index.php</a></p>";
echo "<p>Admin Dashboard: <a href='admin/index.php'>admin/index.php</a></p>";
echo "<p>Uploads: uploads/ | Thumbnails: uploads/thumbs/ | SQLite DB: data/imagehost.sqlite</p>";
echo "<p>Bitte diese Setup-Datei nach der Installation löschen!</p>";
?>