Unser Skript bietet eine vollständige Lösung zum Hosten von E-Mail-Formularen mit integriertem Spam-Schutz. Nutzer können schnell und unkompliziert Nachrichten über ein Frontend-Formular senden, das durch eine einfache Captcha-Matheaufgabe vor automatisiertem Spam geschützt ist. Alle Nachrichten werden in einer SQLite-Datenbank gespeichert, wodurch eine einfache Verwaltung und Sicherung möglich ist.
Das Skript erzeugt beim ersten Aufruf automatisch alle notwendigen Ordner, Dateien und Datenbanken. Über AJAX können Formulareingaben ohne Seitenreload abgeschickt werden, was die Nutzererfahrung deutlich verbessert. Zusätzlich werden E-Mail-Benachrichtigungen via SMTP / PHPMailer an die Admin-Adresse gesendet, sodass keine Nachricht verloren geht.
<?php
// Nach Installation Setup-Datei löschen!
set_time_limit(0);
error_reporting(E_ALL);
ini_set('display_errors',1);
$root = __DIR__;
// ------------------ Ordnerstruktur ------------------
$dirs = ['public','public/assets','data','api','admin','admin/assets','src'];
foreach($dirs as $d){
$p = $root.DIRECTORY_SEPARATOR.$d;
if(!is_dir($p)) mkdir($p,0755,true);
}
// ------------------ .env ------------------
$envPath = $root.'/.env';
if(!file_exists($envPath)){
$envContent = <<<ENV
DB_DRIVER=sqlite
DB_SQLITE_PATH={$root}/data/emailform.sqlite
ADMIN_USER=admin
ADMIN_PASS=admin123
SMTP_HOST=mail.example.com
SMTP_USER=your@email.com
SMTP_PASS=password
SMTP_PORT=587
BASE_URL=http://localhost
ENV;
file_put_contents($envPath,$envContent);
}
// ------------------ SQLite DB ------------------
$dbFile = $root.'/data/emailform.sqlite';
if(!file_exists($dbFile)){
$pdo = new PDO('sqlite:'.$dbFile);
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$pdo->exec("PRAGMA journal_mode = WAL");
// Benutzer/Admin
$pdo->exec("
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
passhash TEXT,
role TEXT DEFAULT 'admin',
status INT DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
");
$hash = password_hash('admin123', PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT OR IGNORE INTO users (username, passhash, role) VALUES ('admin', :p, 'admin')");
$stmt->execute([':p'=>$hash]);
// Email-Formular-Einträge
$pdo->exec("
CREATE TABLE IF NOT EXISTS emails (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
email TEXT,
subject TEXT,
message TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
");
}
// ------------------ 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/emailform.sqlite',
'admin_user'=>$env['ADMIN_USER']??'admin',
'admin_pass'=>$env['ADMIN_PASS']??'admin123',
'smtp_host'=>$env['SMTP_HOST']??'',
'smtp_user'=>$env['SMTP_USER']??'',
'smtp_pass'=>$env['SMTP_PASS']??'',
'smtp_port'=>$env['SMTP_PORT']??587,
'base_url'=>rtrim($env['BASE_URL']??'','/')
];
PHP;
file_put_contents($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;
file_put_contents($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;
file_put_contents($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>E-Mail Formular Hoster</title>
<link rel="stylesheet" href="assets/style.css">
</head>
<body>
<div class="container">
<header class="card"><h1>E-Mail Formular Hoster</h1></header>
<section class="card">
<h3>Kontaktformular</h3>
<form id="emailForm">
<label>Name:</label>
<input type="text" name="name" class="input" required>
<label>E-Mail:</label>
<input type="email" name="email" class="input" required>
<label>Betreff:</label>
<input type="text" name="subject" class="input" required>
<label>Nachricht:</label>
<textarea name="message" class="input" rows="5" required></textarea>
<label id="captchaQuestion" class="small">Lade Captcha...</label>
<input id="captchaAnswer" class="input" name="captcha" placeholder="Antwort" required>
<button type="button" class="btn" onclick="sendEmail()">Senden</button>
<div id="result" class="small" style="margin-top:12px"></div>
</form>
</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;
file_put_contents($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:700px;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,textarea{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;margin-top:6px}
.footer{margin-top:12px;font-size:12px;color:#666;text-align:center}
.small{font-size:12px;color:#666}
CSS;
file_put_contents($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 sendEmail(){
const f=document.getElementById('emailForm');
const data={};
for(let el of f.elements){
if(el.name) data[el.name]=el.value;
}
ajax('/api/send_email.php',data,function(res){
const r=document.getElementById('result');
if(res.ok) r.innerHTML='<strong>Nachricht gesendet!</strong>';
else r.innerText=res.error||'Fehler';
loadCaptcha();
f.reset();
});
}
window.addEventListener('load',loadCaptcha);
JS;
file_put_contents($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;
file_put_contents($root.'/api/captcha.php',$apiCaptcha);
// ------------------ api/send_email.php ------------------
$apiSend = <<<'PHP'
<?php
require_once __DIR__.'/../src/config.php';
require_once __DIR__.'/../src/db.php';
require_once __DIR__.'/../src/captcha.php';
require 'vendor/autoload.php'; // PHPMailer
session_start();
header('Content-Type: application/json; charset=utf-8');
if(!captchaCheck($_POST['captcha']??'')){
echo json_encode(['ok'=>false,'error'=>'Captcha falsch']); exit;
}
$name = trim($_POST['name']??'');
$email = trim($_POST['email']??'');
$subject = trim($_POST['subject']??'');
$message = trim($_POST['message']??'');
if(!$name || !$email || !$subject || !$message){
echo json_encode(['ok'=>false,'error'=>'Alle Felder ausfüllen']); exit;
}
// speichern in DB
$pdo = getPdo();
$stmt = $pdo->prepare("INSERT INTO emails (name,email,subject,message) VALUES (:n,:e,:s,:m)");
$stmt->execute([':n'=>$name,':e'=>$email,':s'=>$subject,':m'=>$message]);
// E-Mail versenden via PHPMailer
$cfg = require __DIR__.'/../src/config.php';
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
try{
$mail->isSMTP();
$mail->Host=$cfg['smtp_host'];
$mail->SMTPAuth=true;
$mail->Username=$cfg['smtp_user'];
$mail->Password=$cfg['smtp_pass'];
$mail->Port=$cfg['smtp_port'];
$mail->setFrom($cfg['smtp_user'],$name);
$mail->addAddress($cfg['smtp_user'],'Admin');
$mail->Subject=$subject;
$mail->Body="Von: $name <$email>\n\n$message";
$mail->send();
}catch(Exception $e){
echo json_encode(['ok'=>false,'error'=>'Mail Fehler: '.$mail->ErrorInfo]);
exit;
}
echo json_encode(['ok'=>true]);
PHP;
file_put_contents($root.'/api/send_email.php',$apiSend);
echo "<h2>Installation abgeschlossen!</h2>";
echo "<p>Frontend Formular: <a href='public/index.php'>public/index.php</a></p>";
echo "<p>Admin: <a href='admin/index.php'>Admin Bereich wird noch erstellt</a></p>";
echo "<p>SQLite DB: data/emailform.sqlite</p>";
echo "<p>Bitte diese Setup-Datei nach der Installation löschen!</p>";
?>