mirror of
https://git.hexahost.dev/smueller/HexaHost-Frontend.git
synced 2026-06-02 13:28:43 +00:00
Compare commits
19 Commits
dev
...
cc1a48943a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc1a48943a | ||
|
|
dfc781f3ed | ||
|
|
d0e5baa443 | ||
|
|
8afba16905 | ||
|
|
96a5977283 | ||
|
|
ec8686761c | ||
|
|
d3da589a1d | ||
|
|
b6e268855e | ||
|
|
d02377c735 | ||
|
|
d62d6b576d | ||
|
|
2c0138f55d | ||
|
|
2074707c9d | ||
|
|
55f9fdd957 | ||
|
|
ab81d1c49f | ||
|
|
b40ad53d9c | ||
|
|
e5402189ea | ||
|
|
e544720900 | ||
| a5bba86db0 | |||
| d34dbbb079 |
@@ -1,62 +0,0 @@
|
|||||||
name: Release Build (ci → main)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- ci
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
GITEA_HOST: git.hexahost.dev
|
|
||||||
REPO_PATH: smueller/HexaHost-Frontend
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release-build:
|
|
||||||
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout ci (Integration)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
repository-url: https://git.hexahost.dev/smueller/HexaHost-Frontend
|
|
||||||
ref: ci
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: "3.12"
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
|
|
||||||
- name: Run release obfuscation
|
|
||||||
run: python scripts/obfuscate_release.py --root . --hash-assets
|
|
||||||
|
|
||||||
- name: Publish release to main
|
|
||||||
env:
|
|
||||||
GITEA_TOKEN: ${{ github.token }}
|
|
||||||
run: |
|
|
||||||
git config user.name "gitea-actions"
|
|
||||||
git config user.email "actions@local"
|
|
||||||
git remote set-url origin "https://oauth2:${GITEA_TOKEN}@${GITEA_HOST}/${REPO_PATH}.git"
|
|
||||||
git fetch origin main ci
|
|
||||||
|
|
||||||
git add -A
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "No release changes to publish."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
TREE=$(git write-tree)
|
|
||||||
MSG="chore(release): obfuscate and hash production assets [skip ci]"
|
|
||||||
if git show-ref --verify --quiet refs/remotes/origin/main; then
|
|
||||||
PARENT=$(git rev-parse origin/main)
|
|
||||||
COMMIT=$(git commit-tree "$TREE" -p "$PARENT" -m "$MSG")
|
|
||||||
else
|
|
||||||
COMMIT=$(git commit-tree "$TREE" -m "$MSG")
|
|
||||||
fi
|
|
||||||
git push origin "${COMMIT}:refs/heads/main"
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Validiert Commit-Messages nach Conventional Commits
|
|
||||||
# https://www.conventionalcommits.org/
|
|
||||||
|
|
||||||
commit_msg_file="$1"
|
|
||||||
|
|
||||||
first_line=$(sed '/^#/d;/^$/d' "$commit_msg_file" | head -n 1)
|
|
||||||
|
|
||||||
# Merge/Revert von Git erlauben
|
|
||||||
case "$first_line" in
|
|
||||||
Merge\ *|Revert\ *)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
pattern='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\([a-z0-9._-]+\))?!?: .+'
|
|
||||||
|
|
||||||
if ! printf '%s\n' "$first_line" | grep -qE "$pattern"; then
|
|
||||||
echo >&2 "❌ Commit-Message entspricht nicht Conventional Commits."
|
|
||||||
echo >&2 ""
|
|
||||||
echo >&2 " Format: type(scope): description"
|
|
||||||
echo >&2 " Beispiel: feat(products): hide vpc in navigation"
|
|
||||||
echo >&2 ""
|
|
||||||
echo >&2 " Erlaubte types: feat, fix, docs, style, refactor, perf, test, build, ci, chore"
|
|
||||||
echo >&2 " Überspringen: git commit --no-verify"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
63
.github/workflows/obfuscate-main.yml
vendored
63
.github/workflows/obfuscate-main.yml
vendored
@@ -1,63 +0,0 @@
|
|||||||
# Hinweis: Gitea nutzt .gitea/workflows/obfuscate-main.yml (identischer Ablauf).
|
|
||||||
name: Release Build (ci → main)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- ci
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
GITEA_HOST: git.hexahost.dev
|
|
||||||
REPO_PATH: smueller/HexaHost-Frontend
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release-build:
|
|
||||||
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout ci (Integration)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
repository-url: https://git.hexahost.dev/smueller/HexaHost-Frontend
|
|
||||||
ref: ci
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: "3.12"
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
|
|
||||||
- name: Run release obfuscation
|
|
||||||
run: python scripts/obfuscate_release.py --root . --hash-assets
|
|
||||||
|
|
||||||
- name: Publish release to main
|
|
||||||
env:
|
|
||||||
GITEA_TOKEN: ${{ github.token }}
|
|
||||||
run: |
|
|
||||||
git config user.name "gitea-actions"
|
|
||||||
git config user.email "actions@local"
|
|
||||||
git remote set-url origin "https://oauth2:${GITEA_TOKEN}@${GITEA_HOST}/${REPO_PATH}.git"
|
|
||||||
git fetch origin main ci
|
|
||||||
|
|
||||||
git add -A
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "No release changes to publish."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
TREE=$(git write-tree)
|
|
||||||
MSG="chore(release): obfuscate and hash production assets [skip ci]"
|
|
||||||
if git show-ref --verify --quiet refs/remotes/origin/main; then
|
|
||||||
PARENT=$(git rev-parse origin/main)
|
|
||||||
COMMIT=$(git commit-tree "$TREE" -p "$PARENT" -m "$MSG")
|
|
||||||
else
|
|
||||||
COMMIT=$(git commit-tree "$TREE" -m "$MSG")
|
|
||||||
fi
|
|
||||||
git push origin "${COMMIT}:refs/heads/main"
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,7 +13,6 @@ build/
|
|||||||
# Environment variables
|
# Environment variables
|
||||||
.env
|
.env
|
||||||
.cursorrules
|
.cursorrules
|
||||||
.cursor/
|
|
||||||
.cursorrules.txt
|
.cursorrules.txt
|
||||||
.env.local
|
.env.local
|
||||||
.env.development.local
|
.env.development.local
|
||||||
|
|||||||
16
.gitmessage
16
.gitmessage
@@ -1,16 +0,0 @@
|
|||||||
# Conventional Commits – nur die erste nicht-kommentierte Zeile wird verwendet
|
|
||||||
# Format: type(scope): description
|
|
||||||
#
|
|
||||||
# feat Neues Feature
|
|
||||||
# fix Bugfix
|
|
||||||
# docs Dokumentation
|
|
||||||
# style Formatierung (keine Logik)
|
|
||||||
# refactor Umbau ohne Feature/Fix
|
|
||||||
# perf Performance
|
|
||||||
# test Tests
|
|
||||||
# build Build / Dependencies
|
|
||||||
# ci CI/CD
|
|
||||||
# chore Sonstiges
|
|
||||||
#
|
|
||||||
# Beispiel (diese Zeile anpassen und Kommentare löschen oder stehen lassen):
|
|
||||||
# feat(products): hide vpc and vps in navigation
|
|
||||||
74
README.md
74
README.md
@@ -46,7 +46,7 @@ Eine moderne und umfangreiche Website für das Hosting-Unternehmen HexaHost.de a
|
|||||||
- **HTML5** - Semantisches Markup
|
- **HTML5** - Semantisches Markup
|
||||||
- **CSS3** - Moderne Styles mit Custom Properties
|
- **CSS3** - Moderne Styles mit Custom Properties
|
||||||
- **Vanilla JavaScript** - Keine Framework-Dependencies
|
- **Vanilla JavaScript** - Keine Framework-Dependencies
|
||||||
- **Native PHP mail()** - E-Mail-Versand ohne externe Abhängigkeiten
|
- **PHPMailer** - E-Mail-Versand via SMTP
|
||||||
- **Glassmorphism Design** - Moderne Glaseffekte
|
- **Glassmorphism Design** - Moderne Glaseffekte
|
||||||
- **CSS Grid & Flexbox** - Responsive Layouts
|
- **CSS Grid & Flexbox** - Responsive Layouts
|
||||||
- **Inter Font** - Moderne Typografie
|
- **Inter Font** - Moderne Typografie
|
||||||
@@ -73,6 +73,7 @@ HexaHost-Frontend/
|
|||||||
│ ├── sitemap.xml # SEO Sitemap
|
│ ├── sitemap.xml # SEO Sitemap
|
||||||
│ ├── favicon.svg # Website Icon
|
│ ├── favicon.svg # Website Icon
|
||||||
│ ├── .htaccess # Apache Konfiguration
|
│ ├── .htaccess # Apache Konfiguration
|
||||||
|
│ ├── composer.json # PHP Dependencies
|
||||||
│ ├── config/ # ⬅ vom Backend
|
│ ├── config/ # ⬅ vom Backend
|
||||||
│ │ ├── config.php # Allgemeine Konfiguration
|
│ │ ├── config.php # Allgemeine Konfiguration
|
||||||
│ │ └── mail-config.php # E-Mail-Konfiguration
|
│ │ └── mail-config.php # E-Mail-Konfiguration
|
||||||
@@ -126,6 +127,7 @@ HexaHost-Frontend/
|
|||||||
|
|
||||||
### Voraussetzungen
|
### Voraussetzungen
|
||||||
- PHP 8.0 oder höher
|
- PHP 8.0 oder höher
|
||||||
|
- Composer (für PHPMailer)
|
||||||
- Apache mit mod_rewrite (für .htaccess)
|
- Apache mit mod_rewrite (für .htaccess)
|
||||||
- [HexaHost-Backend](../HexaHost-Backend) Repository
|
- [HexaHost-Backend](../HexaHost-Backend) Repository
|
||||||
|
|
||||||
@@ -145,18 +147,24 @@ HexaHost-Frontend/
|
|||||||
cp -r HexaHost-Backend/includes/* HexaHost-Frontend/public/includes/
|
cp -r HexaHost-Backend/includes/* HexaHost-Frontend/public/includes/
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Konfiguration anpassen**
|
3. **PHP Dependencies installieren**
|
||||||
|
```bash
|
||||||
|
cd HexaHost-Frontend/public
|
||||||
|
composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Konfiguration anpassen**
|
||||||
```bash
|
```bash
|
||||||
# mail-config.php mit SMTP-Daten bearbeiten
|
# mail-config.php mit SMTP-Daten bearbeiten
|
||||||
nano config/mail-config.php
|
nano config/mail-config.php
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Lokaler Development Server**
|
5. **Lokaler Development Server**
|
||||||
```bash
|
```bash
|
||||||
php -S localhost:8000 -t public
|
php -S localhost:8000 -t public
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Website öffnen**
|
6. **Website öffnen**
|
||||||
```
|
```
|
||||||
http://localhost:8000
|
http://localhost:8000
|
||||||
```
|
```
|
||||||
@@ -166,51 +174,25 @@ Für den Produktivbetrieb `public/` als Webroot konfigurieren.
|
|||||||
|
|
||||||
### Production-Build & Veröffentlichung
|
### Production-Build & Veröffentlichung
|
||||||
|
|
||||||
| Branch | Zweck |
|
Der Quellcode bleibt auf `dev`, der veröffentlichte Stand liegt auf `main` (ohne Kommentare, obfuskiertes JS).
|
||||||
|--------|--------|
|
|
||||||
| **`dev`** | Entwicklung (lesbarer Code, Kommentare) |
|
|
||||||
| **`ci`** | Integration (du mergst `dev` hierher) |
|
|
||||||
| **`main`** | Release/Produktion (obfuskiert, gehashte Assets — nur per Pipeline) |
|
|
||||||
|
|
||||||
**Ablauf: `dev` → `ci` → `main`**
|
**Voraussetzungen:** Node.js 18+ (inkl. npm), PHP 8+ CLI, Git
|
||||||
|
|
||||||
1. Auf **`dev`** entwickeln und pushen
|
|
||||||
2. **`dev` nach `ci` mergen** (manuell, z. B. in Gitea oder lokal)
|
|
||||||
3. **`ci` pushen** → startet `.gitea/workflows/obfuscate-main.yml`
|
|
||||||
4. Pipeline obfuskiert im Runner-Workspace und publiziert nach **`main`**
|
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Nach fertigen Änderungen auf dev:
|
# Windows
|
||||||
git checkout ci
|
.\scripts\run-build.ps1
|
||||||
git pull origin ci
|
.\scripts\publish-to-main.ps1 -Push
|
||||||
git merge dev
|
|
||||||
git push origin ci
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Bei jedem Push auf **`ci`**:
|
|
||||||
|
|
||||||
1. Checkout von `ci` im temporären Runner-Workspace
|
|
||||||
2. Obfuscation-Build (`scripts/obfuscate_release.py --hash-assets`)
|
|
||||||
3. Ergebnis nach `main` pushen (Bot-Commit mit `[skip ci]`)
|
|
||||||
|
|
||||||
**Nicht** `dev` oder `ci` direkt nach `main` mergen. Der Branch **`ci` bleibt lesbar** — Obfuscation wird nur nach `main` publiziert.
|
|
||||||
|
|
||||||
`ci`-Branch einmalig anlegen (falls noch nicht vorhanden): `git checkout -b ci dev && git push -u origin ci`
|
|
||||||
|
|
||||||
Der Build führt aus:
|
|
||||||
|
|
||||||
- Entfernen von Kommentaren (inkl. Block-Kommentaren) in PHP/JS/CSS
|
|
||||||
- Minify + Obfuscate für JavaScript
|
|
||||||
- Minify für CSS
|
|
||||||
- Kein Source-Map-Output
|
|
||||||
- Hashing von JS/CSS-Dateinamen + automatische Referenz-Anpassung
|
|
||||||
|
|
||||||
Lokal testen (nur in Kopie, nicht committen):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python scripts/obfuscate_release.py --root . --hash-assets
|
# Linux / macOS
|
||||||
|
chmod +x scripts/*.sh
|
||||||
|
./scripts/run-build.sh
|
||||||
|
./scripts/publish-to-main.sh --push
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Details: `scripts/build/README.md`
|
||||||
|
|
||||||
## 🔗 Backend-Integration
|
## 🔗 Backend-Integration
|
||||||
|
|
||||||
Das Backend-Repository enthält folgende wiederverwendbare Komponenten:
|
Das Backend-Repository enthält folgende wiederverwendbare Komponenten:
|
||||||
@@ -226,11 +208,13 @@ Detaillierte Informationen zu den Backend-Komponenten finden Sie in der [Backend
|
|||||||
|
|
||||||
## 📧 E-Mail-Konfiguration
|
## 📧 E-Mail-Konfiguration
|
||||||
|
|
||||||
Die E-Mail-Funktionalität nutzt die native PHP-`mail()`-Funktion. In `public/config/mail-config.php` müssen mindestens Absender und Empfänger gesetzt werden:
|
Die E-Mail-Funktionalität benötigt eine SMTP-Konfiguration in `public/config/mail-config.php`:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
define('SMTP_FROM_EMAIL', 'kontakt@hexahost.de');
|
define('SMTP_HOST', 'mail.example.com');
|
||||||
define('SMTP_TO_EMAIL', 'info@hexahost.de');
|
define('SMTP_PORT', 587);
|
||||||
|
define('SMTP_USER', 'noreply@hexahost.de');
|
||||||
|
define('SMTP_PASS', 'your-password');
|
||||||
```
|
```
|
||||||
|
|
||||||
Siehe `docs/README-EMAIL-SETUP.md` für detaillierte Anweisungen.
|
Siehe `docs/README-EMAIL-SETUP.md` für detaillierte Anweisungen.
|
||||||
@@ -257,7 +241,7 @@ Siehe `docs/README-EMAIL-SETUP.md` für detaillierte Anweisungen.
|
|||||||
|
|
||||||
### Kontaktformular
|
### Kontaktformular
|
||||||
- Server-seitige Validierung
|
- Server-seitige Validierung
|
||||||
- E-Mail-Versand via native PHP mail()
|
- E-Mail-Versand via SMTP
|
||||||
- CSRF-Schutz
|
- CSRF-Schutz
|
||||||
- Auto-Fill basierend auf URL-Parametern
|
- Auto-Fill basierend auf URL-Parametern
|
||||||
- FAQ-Sektion mit Accordion
|
- FAQ-Sektion mit Accordion
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* HexaHost.de Konfiguration
|
|
||||||
*
|
|
||||||
* HINWEIS: Diese Datei ist veraltet!
|
|
||||||
*
|
|
||||||
* Die Konfiguration wurde nach mail-config.php verschoben.
|
|
||||||
* Bitte verwenden Sie stattdessen:
|
|
||||||
*
|
|
||||||
* require_once 'config/mail-config.php';
|
|
||||||
*
|
|
||||||
* Diese Datei wird nur aus Kompatibilitätsgründen beibehalten.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Lade die neue Konfiguration
|
|
||||||
|
|
||||||
require_once __DIR__ . '/mail-config.php';
|
require_once __DIR__ . '/mail-config.php';
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -1,30 +1,31 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* HexaHost.de Mail Configuration
|
|
||||||
*
|
|
||||||
* Dieses Projekt versendet E-Mails nativ über PHP mail().
|
|
||||||
* Es sind keine externen Bibliotheken oder Composer-Installationen erforderlich.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// E-Mail Adressen
|
|
||||||
define('SMTP_FROM_EMAIL', 'kontakt@hexahost.de'); // Absender-E-Mail
|
|
||||||
define('SMTP_TO_EMAIL', 'info@hexahost.de'); // Empfänger-E-Mail für Kontaktformular
|
|
||||||
|
|
||||||
// Sicherheitseinstellungen
|
|
||||||
define('ENABLE_CSRF_PROTECTION', true); // CSRF-Schutz aktivieren
|
|
||||||
define('ENABLE_RATE_LIMITING', true); // Rate-Limiting aktivieren
|
|
||||||
define('MAX_REQUESTS_PER_HOUR', 5); // Max. Anfragen pro Stunde
|
|
||||||
|
|
||||||
// Spam-Schutz Einstellungen
|
define('SMTP_HOST', 'smtp.ihre-domain.de');
|
||||||
define('ENABLE_SPAM_PROTECTION', true); // Spam-Schutz aktivieren
|
define('SMTP_PORT', 587);
|
||||||
define('MAX_MESSAGE_LENGTH', 5000); // Max. Nachrichtenlänge
|
define('SMTP_USERNAME', 'kontakt@ihre-domain.de');
|
||||||
define('MIN_MESSAGE_LENGTH', 10); // Min. Nachrichtenlänge
|
define('SMTP_PASSWORD', 'ihr-smtp-passwort');
|
||||||
|
|
||||||
|
|
||||||
|
define('SMTP_FROM_EMAIL', 'kontakt@hexahost.de');
|
||||||
|
define('SMTP_TO_EMAIL', 'info@hexahost.de');
|
||||||
|
|
||||||
|
|
||||||
|
define('ENABLE_CSRF_PROTECTION', true);
|
||||||
|
define('ENABLE_RATE_LIMITING', true);
|
||||||
|
define('MAX_REQUESTS_PER_HOUR', 10);
|
||||||
|
|
||||||
|
|
||||||
|
define('ENABLE_SPAM_PROTECTION', true);
|
||||||
|
define('MAX_MESSAGE_LENGTH', 5000);
|
||||||
|
define('MIN_MESSAGE_LENGTH', 10);
|
||||||
|
|
||||||
|
|
||||||
|
define('DEBUG_MODE', false);
|
||||||
|
define('LOG_EMAILS', true);
|
||||||
|
|
||||||
// Debug-Einstellungen (nur für Entwicklung)
|
|
||||||
define('DEBUG_MODE', false); // Debug-Modus (true/false)
|
|
||||||
define('LOG_EMAILS', true); // E-Mails loggen (true/false)
|
|
||||||
|
|
||||||
// Zusätzliche Sicherheitsheader
|
|
||||||
define('ADDITIONAL_HEADERS', [
|
define('ADDITIONAL_HEADERS', [
|
||||||
'X-Mailer' => 'HexaHost.de Contact Form',
|
'X-Mailer' => 'HexaHost.de Contact Form',
|
||||||
'X-Priority' => '3',
|
'X-Priority' => '3',
|
||||||
@@ -35,22 +36,27 @@ define('ADDITIONAL_HEADERS', [
|
|||||||
'Precedence' => 'bulk'
|
'Precedence' => 'bulk'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Erlaubte Domains für E-Mail-Adressen (optional)
|
|
||||||
define('ALLOWED_EMAIL_DOMAINS', [
|
define('ALLOWED_EMAIL_DOMAINS', [
|
||||||
// Leer lassen für alle Domains zu erlauben
|
|
||||||
// 'gmail.com',
|
|
||||||
// 'outlook.com',
|
|
||||||
// 'web.de',
|
|
||||||
// 'gmx.de'
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Blacklist für E-Mail-Adressen (optional)
|
|
||||||
define('BLACKLISTED_EMAILS', [
|
define('BLACKLISTED_EMAILS', [
|
||||||
// 'spam@example.com',
|
|
||||||
// 'test@test.com'
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Überprüfung der E-Mail-Adressen
|
|
||||||
|
if (!defined('SMTP_HOST') || !defined('SMTP_USERNAME') || !defined('SMTP_PASSWORD')) {
|
||||||
|
die('SMTP-Konfiguration ist unvollständig. Bitte überprüfen Sie die mail-config.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!filter_var(SMTP_FROM_EMAIL, FILTER_VALIDATE_EMAIL)) {
|
if (!filter_var(SMTP_FROM_EMAIL, FILTER_VALIDATE_EMAIL)) {
|
||||||
die('Ungültige SMTP_FROM_EMAIL Adresse');
|
die('Ungültige SMTP_FROM_EMAIL Adresse');
|
||||||
}
|
}
|
||||||
@@ -59,7 +65,7 @@ if (!filter_var(SMTP_TO_EMAIL, FILTER_VALIDATE_EMAIL)) {
|
|||||||
die('Ungültige SMTP_TO_EMAIL Adresse');
|
die('Ungültige SMTP_TO_EMAIL Adresse');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging-Funktion
|
|
||||||
function logEmail($type, $data) {
|
function logEmail($type, $data) {
|
||||||
if (!LOG_EMAILS) return;
|
if (!LOG_EMAILS) return;
|
||||||
|
|
||||||
@@ -76,18 +82,18 @@ function logEmail($type, $data) {
|
|||||||
file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
|
file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hilfsfunktion für E-Mail-Validierung
|
|
||||||
function isValidEmail($email) {
|
function isValidEmail($email) {
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe Blacklist
|
|
||||||
if (in_array($email, BLACKLISTED_EMAILS)) {
|
if (in_array($email, BLACKLISTED_EMAILS)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe Domain-Whitelist (falls gesetzt)
|
|
||||||
if (!empty(ALLOWED_EMAIL_DOMAINS)) {
|
if (!empty(ALLOWED_EMAIL_DOMAINS)) {
|
||||||
$domain = substr(strrchr($email, "@"), 1);
|
$domain = substr(strrchr($email, "@"), 1);
|
||||||
if (!in_array($domain, ALLOWED_EMAIL_DOMAINS)) {
|
if (!in_array($domain, ALLOWED_EMAIL_DOMAINS)) {
|
||||||
@@ -98,29 +104,30 @@ function isValidEmail($email) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Hilfsfunktion zum Abrufen der Konfiguration als Array
|
|
||||||
* Kompatibilität mit contact-handler.php
|
|
||||||
*
|
|
||||||
* @param string|null $key Optional: einzelner Schlüssel
|
|
||||||
* @return mixed Konfigurationsarray oder einzelner Wert
|
|
||||||
*/
|
|
||||||
function getHexaHostConfig($key = null) {
|
function getHexaHostConfig($key = null) {
|
||||||
$config = [
|
$config = [
|
||||||
// Absender/Empfänger
|
|
||||||
|
'smtp_host' => SMTP_HOST,
|
||||||
|
'smtp_port' => SMTP_PORT,
|
||||||
|
'smtp_username' => SMTP_USERNAME,
|
||||||
|
'smtp_password' => SMTP_PASSWORD,
|
||||||
|
'smtp_encryption' => 'tls',
|
||||||
|
|
||||||
|
|
||||||
'from_email' => SMTP_FROM_EMAIL,
|
'from_email' => SMTP_FROM_EMAIL,
|
||||||
'from_name' => 'HexaHost.de Kontaktformular',
|
'from_name' => 'HexaHost.de Kontaktformular',
|
||||||
'to_email' => SMTP_TO_EMAIL,
|
'to_email' => SMTP_TO_EMAIL,
|
||||||
'to_name' => 'HexaHost Support',
|
'to_name' => 'HexaHost Support',
|
||||||
|
|
||||||
// Sicherheit
|
|
||||||
'max_requests_per_hour' => MAX_REQUESTS_PER_HOUR,
|
'max_requests_per_hour' => MAX_REQUESTS_PER_HOUR,
|
||||||
'honeypot_field' => 'website',
|
'honeypot_field' => 'website',
|
||||||
'enable_csrf' => ENABLE_CSRF_PROTECTION,
|
'enable_csrf' => ENABLE_CSRF_PROTECTION,
|
||||||
'min_message_length' => MIN_MESSAGE_LENGTH,
|
'min_message_length' => MIN_MESSAGE_LENGTH,
|
||||||
'max_message_length' => MAX_MESSAGE_LENGTH,
|
'max_message_length' => MAX_MESSAGE_LENGTH,
|
||||||
|
|
||||||
// Debug
|
|
||||||
'debug_mode' => DEBUG_MODE,
|
'debug_mode' => DEBUG_MODE,
|
||||||
'log_errors' => LOG_EMAILS,
|
'log_errors' => LOG_EMAILS,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,19 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* HexaHost.de Produkt-Konfiguration
|
|
||||||
*
|
|
||||||
* Hier können Sie alle Preise, Shop-Links und Produktinformationen zentral verwalten.
|
|
||||||
* Pro Paket: shop_url (WHMCS/Warenkorb-Link, z. B. https://shop.hexahost.de/cart.php?a=add&pid=123)
|
|
||||||
* Nach Änderungen: npm run build && npm run deploy
|
|
||||||
*
|
|
||||||
* Verwendung in PHP-Seiten:
|
|
||||||
* require_once 'config/products-config.php';
|
|
||||||
* $packages = getProductPackages('vpc');
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// VIRTUAL PRIVATE CONTAINER (VPC)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
$PRODUCTS['vpc'] = [
|
$PRODUCTS['vpc'] = [
|
||||||
'name' => 'Virtual Private Container',
|
'name' => 'Virtual Private Container',
|
||||||
'short_name' => 'VPC',
|
'short_name' => 'VPC',
|
||||||
@@ -31,7 +21,6 @@ $PRODUCTS['vpc'] = [
|
|||||||
'starter' => [
|
'starter' => [
|
||||||
'name' => 'VPC Starter',
|
'name' => 'VPC Starter',
|
||||||
'price' => '4,99',
|
'price' => '4,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'CPU Kerne', 'value' => '1 vCore'],
|
['label' => 'CPU Kerne', 'value' => '1 vCore'],
|
||||||
@@ -51,7 +40,6 @@ $PRODUCTS['vpc'] = [
|
|||||||
'business' => [
|
'business' => [
|
||||||
'name' => 'VPC Business',
|
'name' => 'VPC Business',
|
||||||
'price' => '9,99',
|
'price' => '9,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => true,
|
'featured' => true,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'CPU Kerne', 'value' => '2 vCores'],
|
['label' => 'CPU Kerne', 'value' => '2 vCores'],
|
||||||
@@ -72,7 +60,6 @@ $PRODUCTS['vpc'] = [
|
|||||||
'professional' => [
|
'professional' => [
|
||||||
'name' => 'VPC Professional',
|
'name' => 'VPC Professional',
|
||||||
'price' => '19,99',
|
'price' => '19,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'CPU Kerne', 'value' => '4 vCores'],
|
['label' => 'CPU Kerne', 'value' => '4 vCores'],
|
||||||
@@ -94,7 +81,6 @@ $PRODUCTS['vpc'] = [
|
|||||||
'enterprise' => [
|
'enterprise' => [
|
||||||
'name' => 'VPC Enterprise',
|
'name' => 'VPC Enterprise',
|
||||||
'price' => '39,99',
|
'price' => '39,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'CPU Kerne', 'value' => '8 vCores'],
|
['label' => 'CPU Kerne', 'value' => '8 vCores'],
|
||||||
@@ -117,9 +103,9 @@ $PRODUCTS['vpc'] = [
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// VIRTUAL PRIVATE SERVER (VPS)
|
|
||||||
// ============================================================================
|
|
||||||
$PRODUCTS['vps'] = [
|
$PRODUCTS['vps'] = [
|
||||||
'name' => 'Virtual Private Server',
|
'name' => 'Virtual Private Server',
|
||||||
'short_name' => 'VPS',
|
'short_name' => 'VPS',
|
||||||
@@ -137,7 +123,6 @@ $PRODUCTS['vps'] = [
|
|||||||
'starter' => [
|
'starter' => [
|
||||||
'name' => 'VPS Starter',
|
'name' => 'VPS Starter',
|
||||||
'price' => '9,99',
|
'price' => '9,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'CPU Kerne', 'value' => '1 vCore'],
|
['label' => 'CPU Kerne', 'value' => '1 vCore'],
|
||||||
@@ -157,7 +142,6 @@ $PRODUCTS['vps'] = [
|
|||||||
'business' => [
|
'business' => [
|
||||||
'name' => 'VPS Business',
|
'name' => 'VPS Business',
|
||||||
'price' => '19,99',
|
'price' => '19,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => true,
|
'featured' => true,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'CPU Kerne', 'value' => '2 vCores'],
|
['label' => 'CPU Kerne', 'value' => '2 vCores'],
|
||||||
@@ -178,7 +162,6 @@ $PRODUCTS['vps'] = [
|
|||||||
'professional' => [
|
'professional' => [
|
||||||
'name' => 'VPS Professional',
|
'name' => 'VPS Professional',
|
||||||
'price' => '39,99',
|
'price' => '39,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'CPU Kerne', 'value' => '4 vCores'],
|
['label' => 'CPU Kerne', 'value' => '4 vCores'],
|
||||||
@@ -200,7 +183,6 @@ $PRODUCTS['vps'] = [
|
|||||||
'enterprise' => [
|
'enterprise' => [
|
||||||
'name' => 'VPS Enterprise',
|
'name' => 'VPS Enterprise',
|
||||||
'price' => '79,99',
|
'price' => '79,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'CPU Kerne', 'value' => '8 vCores'],
|
['label' => 'CPU Kerne', 'value' => '8 vCores'],
|
||||||
@@ -223,9 +205,9 @@ $PRODUCTS['vps'] = [
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// MAIL GATEWAY
|
|
||||||
// ============================================================================
|
|
||||||
$PRODUCTS['mail-gateway'] = [
|
$PRODUCTS['mail-gateway'] = [
|
||||||
'name' => 'Mail Gateway',
|
'name' => 'Mail Gateway',
|
||||||
'short_name' => 'Mail',
|
'short_name' => 'Mail',
|
||||||
@@ -243,7 +225,6 @@ $PRODUCTS['mail-gateway'] = [
|
|||||||
'starter' => [
|
'starter' => [
|
||||||
'name' => 'Mail Starter',
|
'name' => 'Mail Starter',
|
||||||
'price' => '4,99',
|
'price' => '4,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'Postfächer', 'value' => '5'],
|
['label' => 'Postfächer', 'value' => '5'],
|
||||||
@@ -262,7 +243,6 @@ $PRODUCTS['mail-gateway'] = [
|
|||||||
'business' => [
|
'business' => [
|
||||||
'name' => 'Mail Business',
|
'name' => 'Mail Business',
|
||||||
'price' => '14,99',
|
'price' => '14,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => true,
|
'featured' => true,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'Postfächer', 'value' => '25'],
|
['label' => 'Postfächer', 'value' => '25'],
|
||||||
@@ -283,7 +263,6 @@ $PRODUCTS['mail-gateway'] = [
|
|||||||
'professional' => [
|
'professional' => [
|
||||||
'name' => 'Mail Professional',
|
'name' => 'Mail Professional',
|
||||||
'price' => '29,99',
|
'price' => '29,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'Postfächer', 'value' => '100'],
|
['label' => 'Postfächer', 'value' => '100'],
|
||||||
@@ -305,7 +284,6 @@ $PRODUCTS['mail-gateway'] = [
|
|||||||
'enterprise' => [
|
'enterprise' => [
|
||||||
'name' => 'Mail Enterprise',
|
'name' => 'Mail Enterprise',
|
||||||
'price' => '59,99',
|
'price' => '59,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'Postfächer', 'value' => 'Unbegrenzt'],
|
['label' => 'Postfächer', 'value' => 'Unbegrenzt'],
|
||||||
@@ -329,113 +307,101 @@ $PRODUCTS['mail-gateway'] = [
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// WEBHOSTING
|
|
||||||
// ============================================================================
|
|
||||||
$PRODUCTS['webhosting'] = [
|
$PRODUCTS['webhosting'] = [
|
||||||
'name' => 'Webhosting',
|
'name' => 'Webhosting',
|
||||||
'short_name' => 'Webhosting',
|
'short_name' => 'Webhosting',
|
||||||
'description' => 'Klassisches Hosting mit PHP, MySQL und SSL',
|
'description' => 'Klassisches Hosting mit PHP, MySQL und SSL',
|
||||||
'min_price' => '4,99',
|
'min_price' => '1,99',
|
||||||
'hero_highlight' => 'Alles für Ihre Website',
|
'hero_highlight' => 'Alles für Ihre Website',
|
||||||
'hero_description' => 'Klassisches Webhosting mit allem, was Sie für eine erfolgreiche Website benötigen. Plesk, PHP, SSL-Zertifikate und E-Mail-Postfächer - alles inklusive.',
|
'hero_description' => 'Klassisches Webhosting mit allem, was Sie für eine erfolgreiche Website benötigen. PHP, MySQL, SSL-Zertifikate und E-Mail-Postfächer - alles inklusive.',
|
||||||
'packages_title' => 'Webhosting Pakete',
|
'packages_title' => 'Webhosting Pakete',
|
||||||
'packages_description' => 'Von der ersten Website bis zum professionellen Online-Shop',
|
'packages_description' => 'Von der ersten Website bis zum professionellen Online-Shop',
|
||||||
'cta_title' => 'Bereit für Ihr Webhosting?',
|
'cta_title' => 'Bereit für Ihr Webhosting?',
|
||||||
'cta_description' => 'Starten Sie noch heute mit professionellem Webhosting',
|
'cta_description' => 'Starten Sie noch heute mit professionellem Webhosting',
|
||||||
'page_title' => 'Webhosting - Klassisches Hosting für Websites | HexaHost.de',
|
'page_title' => 'Webhosting - Klassisches Hosting für Websites | HexaHost.de',
|
||||||
'page_description' => 'Webhosting mit Plesk, PHP und SSL-Zertifikaten. Klassisches Hosting für Websites ab 4,99€/Monat bei HexaHost.de',
|
'page_description' => 'Webhosting mit PHP, MySQL und SSL-Zertifikaten. Klassisches Hosting für Websites ab 1,99€/Monat bei HexaHost.de',
|
||||||
'packages' => [
|
'packages' => [
|
||||||
'starter' => [
|
'starter' => [
|
||||||
'name' => 'Webhosting Starter',
|
'name' => 'Webhosting Starter',
|
||||||
'price' => '4,99',
|
'price' => '1,99',
|
||||||
'shop_url' => 'https://shop.hexahost.de/store/webserver/webhosting-starter',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'Webspace', 'value' => '10 GB'],
|
['label' => 'Webspace', 'value' => '5 GB'],
|
||||||
['label' => 'Domains inkl.', 'value' => '1'],
|
['label' => 'Domains', 'value' => '1'],
|
||||||
['label' => 'Subdomains', 'value' => '5'],
|
['label' => 'E-Mail-Postfächer', 'value' => '5'],
|
||||||
['label' => 'Domain-Alias', 'value' => '2'],
|
['label' => 'Datenbanken', 'value' => '1 MySQL'],
|
||||||
['label' => 'E-Mail-Postfächer', 'value' => '10'],
|
['label' => 'Traffic', 'value' => '10 GB'],
|
||||||
['label' => 'Datenbanken', 'value' => '2 MySQL'],
|
|
||||||
['label' => 'Traffic', 'value' => '100 GB'],
|
|
||||||
],
|
],
|
||||||
'features' => [
|
'features' => [
|
||||||
'Perfekt für kleine Websites und Blogs',
|
'cPanel/Webmin',
|
||||||
'Plesk',
|
'PHP 8.1',
|
||||||
'PHP 8.4 (FastCGI), Git, WP Toolkit, Composer',
|
'SSL-Zertifikat',
|
||||||
'SSL-Zertifikat (Let\'s Encrypt)',
|
'E-Mail-Postfächer',
|
||||||
'E-Mail-Postfächer à 100MB',
|
'MySQL Datenbank',
|
||||||
'1-Klick-Apps - WordPress, Joomla, TYPO3, MediaWiki u. v. m.',
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'business' => [
|
'business' => [
|
||||||
'name' => 'Webhosting Business',
|
'name' => 'Webhosting Business',
|
||||||
'price' => '7,99',
|
'price' => '4,99',
|
||||||
'shop_url' => 'https://shop.hexahost.de/store/webserver/webhosting-business',
|
|
||||||
'featured' => true,
|
'featured' => true,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'Webspace', 'value' => '30 GB'],
|
['label' => 'Webspace', 'value' => '20 GB'],
|
||||||
['label' => 'Domains inkl.', 'value' => '1'],
|
['label' => 'Domains', 'value' => '5'],
|
||||||
['label' => 'Subdomains', 'value' => '10'],
|
['label' => 'E-Mail-Postfächer', 'value' => '25'],
|
||||||
['label' => 'Domain-Alias', 'value' => '2'],
|
|
||||||
['label' => 'E-Mail-Postfächer', 'value' => '20'],
|
|
||||||
['label' => 'Datenbanken', 'value' => '5 MySQL'],
|
['label' => 'Datenbanken', 'value' => '5 MySQL'],
|
||||||
['label' => 'Traffic', 'value' => '100 GB'],
|
['label' => 'Traffic', 'value' => '50 GB'],
|
||||||
],
|
],
|
||||||
'features' => [
|
'features' => [
|
||||||
'Perfekt für mittlere Websites und Blogs',
|
'cPanel/Webmin',
|
||||||
'Plesk',
|
'PHP 8.1',
|
||||||
'PHP 8.4 (FastCGI), Git, WP Toolkit, Composer',
|
'SSL-Zertifikat',
|
||||||
'SSL-Zertifikat (Let\'s Encrypt)',
|
'E-Mail-Postfächer',
|
||||||
'E-Mail-Postfächer à 100MB',
|
'MySQL Datenbanken',
|
||||||
'1-Klick-Apps - WordPress, Joomla, TYPO3, MediaWiki u. v. m.',
|
'Backup-Service',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'professional' => [
|
'professional' => [
|
||||||
'name' => 'Webhosting Professional',
|
'name' => 'Webhosting Professional',
|
||||||
'price' => '9,99',
|
'price' => '9,99',
|
||||||
'shop_url' => 'https://shop.hexahost.de/store/webserver/webhosting-professional',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'Webspace', 'value' => '50 GB'],
|
['label' => 'Webspace', 'value' => '50 GB'],
|
||||||
['label' => 'Domains inkl.', 'value' => '3'],
|
['label' => 'Domains', 'value' => 'Unbegrenzt'],
|
||||||
['label' => 'Subdomains', 'value' => 'Unbegrenzt'],
|
|
||||||
['label' => 'Domain-Alias', 'value' => 'Unbegrenzt'],
|
|
||||||
['label' => 'E-Mail-Postfächer', 'value' => '100'],
|
['label' => 'E-Mail-Postfächer', 'value' => '100'],
|
||||||
['label' => 'Datenbanken', 'value' => '20 MySQL'],
|
['label' => 'Datenbanken', 'value' => 'Unbegrenzt'],
|
||||||
['label' => 'Traffic', 'value' => '100 GB'],
|
['label' => 'Traffic', 'value' => '200 GB'],
|
||||||
],
|
],
|
||||||
'features' => [
|
'features' => [
|
||||||
'Perfekt für größere Websites und Blogs',
|
'cPanel/Webmin',
|
||||||
'Plesk',
|
'PHP 8.1',
|
||||||
'PHP 8.4 (FastCGI), Git, WP Toolkit, Composer',
|
'SSL-Zertifikat',
|
||||||
'SSL-Zertifikat (Let\'s Encrypt)',
|
'E-Mail-Postfächer',
|
||||||
'E-Mail-Postfächer à 100MB',
|
'MySQL Datenbanken',
|
||||||
'1-Klick-Apps - WordPress, Joomla, TYPO3, MediaWiki u. v. m.',
|
'Backup-Service',
|
||||||
|
'Priority Support',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'enterprise' => [
|
'enterprise' => [
|
||||||
'name' => 'Webhosting Enterprise',
|
'name' => 'Webhosting Enterprise',
|
||||||
'price' => '29,99',
|
'price' => '19,99',
|
||||||
'shop_url' => '',
|
|
||||||
'featured' => false,
|
'featured' => false,
|
||||||
'specs' => [
|
'specs' => [
|
||||||
['label' => 'Webspace', 'value' => '200 GB'],
|
['label' => 'Webspace', 'value' => '100 GB'],
|
||||||
['label' => 'Domains inkl.', 'value' => '5'],
|
['label' => 'Domains', 'value' => 'Unbegrenzt'],
|
||||||
['label' => 'Subdomains', 'value' => 'Unbegrenzt'],
|
|
||||||
['label' => 'Domain-Alias', 'value' => 'Unbegrenzt'],
|
|
||||||
['label' => 'E-Mail-Postfächer', 'value' => 'Unbegrenzt'],
|
['label' => 'E-Mail-Postfächer', 'value' => 'Unbegrenzt'],
|
||||||
['label' => 'Datenbanken', 'value' => '50 MySQL'],
|
['label' => 'Datenbanken', 'value' => 'Unbegrenzt'],
|
||||||
['label' => 'Traffic', 'value' => '1 TB'],
|
['label' => 'Traffic', 'value' => '500 GB'],
|
||||||
],
|
],
|
||||||
'features' => [
|
'features' => [
|
||||||
'Perfekt für Enterprise-Websites und Blogs',
|
'cPanel/Webmin',
|
||||||
'Plesk',
|
'PHP 8.1',
|
||||||
'PHP 8.4 (FastCGI), Git, WP Toolkit, Composer',
|
'SSL-Zertifikat',
|
||||||
'SSL-Zertifikat (Let\'s Encrypt)',
|
'E-Mail-Postfächer',
|
||||||
'E-Mail-Postfächer à 100MB',
|
'MySQL Datenbanken',
|
||||||
'1-Klick-Apps - WordPress, Joomla, TYPO3, MediaWiki u. v. m.',
|
'Backup-Service',
|
||||||
'Priority Support',
|
'Priority Support',
|
||||||
'Individuelle Konfiguration',
|
'Individuelle Konfiguration',
|
||||||
],
|
],
|
||||||
@@ -443,133 +409,52 @@ $PRODUCTS['webhosting'] = [
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
// Sichtbarkeit in Navigation, Footer und auf der Startseite (Seiten bleiben per URL erreichbar)
|
|
||||||
$PRODUCT_VISIBILITY = [
|
|
||||||
'vpc' => false,
|
|
||||||
'vps' => false,
|
|
||||||
'mail-gateway' => false,
|
|
||||||
'webhosting' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// HILFSFUNKTIONEN
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prüft, ob eine Produktkategorie in der Navigation angezeigt wird
|
|
||||||
*/
|
|
||||||
function isProductVisible(string $productId): bool {
|
|
||||||
global $PRODUCT_VISIBILITY;
|
|
||||||
return $PRODUCT_VISIBILITY[$productId] ?? true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTML hidden-Attribut für ausgeblendete Produktkategorien
|
|
||||||
*/
|
|
||||||
function productHiddenAttr(string $productId): string {
|
|
||||||
return isProductVisible($productId) ? '' : ' hidden';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktive Navigationsseiten für sichtbare Produktkategorien
|
|
||||||
*
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
function getVisibleProductPageIds(): array {
|
|
||||||
global $PRODUCT_VISIBILITY;
|
|
||||||
return array_keys(array_filter($PRODUCT_VISIBILITY, static fn(bool $visible): bool => $visible));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Alle Produkte abrufen
|
|
||||||
*/
|
|
||||||
function getAllProducts() {
|
function getAllProducts() {
|
||||||
global $PRODUCTS;
|
global $PRODUCTS;
|
||||||
return $PRODUCTS;
|
return $PRODUCTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Ein Produkt abrufen
|
|
||||||
*/
|
|
||||||
function getProduct($productId) {
|
function getProduct($productId) {
|
||||||
global $PRODUCTS;
|
global $PRODUCTS;
|
||||||
return $PRODUCTS[$productId] ?? null;
|
return $PRODUCTS[$productId] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Alle Pakete eines Produkts abrufen
|
|
||||||
*/
|
|
||||||
function getProductPackages($productId) {
|
function getProductPackages($productId) {
|
||||||
global $PRODUCTS;
|
global $PRODUCTS;
|
||||||
return $PRODUCTS[$productId]['packages'] ?? [];
|
return $PRODUCTS[$productId]['packages'] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Ein bestimmtes Paket abrufen
|
|
||||||
*/
|
|
||||||
function getPackage($productId, $packageId) {
|
function getPackage($productId, $packageId) {
|
||||||
global $PRODUCTS;
|
global $PRODUCTS;
|
||||||
return $PRODUCTS[$productId]['packages'][$packageId] ?? null;
|
return $PRODUCTS[$productId]['packages'][$packageId] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Preis eines Pakets abrufen
|
|
||||||
*/
|
|
||||||
function getPackagePrice($productId, $packageId) {
|
function getPackagePrice($productId, $packageId) {
|
||||||
$package = getPackage($productId, $packageId);
|
$package = getPackage($productId, $packageId);
|
||||||
return $package['price'] ?? null;
|
return $package['price'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimalen Preis eines Produkts abrufen
|
|
||||||
*/
|
|
||||||
function getMinPrice($productId) {
|
function getMinPrice($productId) {
|
||||||
global $PRODUCTS;
|
global $PRODUCTS;
|
||||||
return $PRODUCTS[$productId]['min_price'] ?? null;
|
return $PRODUCTS[$productId]['min_price'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Preis formatiert ausgeben
|
|
||||||
*/
|
|
||||||
function formatPrice($price, $withCurrency = true) {
|
function formatPrice($price, $withCurrency = true) {
|
||||||
return $withCurrency ? $price . '€' : $price;
|
return $withCurrency ? $price . '€' : $price;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Bestell-Link für ein Paket (Online-Shop oder Kontaktformular)
|
|
||||||
*/
|
|
||||||
function getOrderUrl($productId, $packageId) {
|
|
||||||
$package = getPackage($productId, $packageId);
|
|
||||||
if ($package && !empty($package['shop_url'])) {
|
|
||||||
return $package['shop_url'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf('contact.php?package=%s-%s', $productId, $packageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bestell-Link für CTA (beliebtes Paket oder erstes Paket)
|
|
||||||
*/
|
|
||||||
function getProductOrderUrl($productId) {
|
|
||||||
$packages = getProductPackages($productId);
|
|
||||||
|
|
||||||
foreach ($packages as $packageId => $package) {
|
|
||||||
if (!empty($package['featured'])) {
|
|
||||||
return getOrderUrl($productId, $packageId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$firstPackageId = array_key_first($packages);
|
|
||||||
if ($firstPackageId !== null) {
|
|
||||||
return getOrderUrl($productId, $firstPackageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf('contact.php?product=%s', $productId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generiert HTML für eine Paket-Karte
|
|
||||||
*/
|
|
||||||
function renderPackageCard($productId, $packageId, $package) {
|
function renderPackageCard($productId, $packageId, $package) {
|
||||||
$featuredClass = $package['featured'] ? ' featured' : '';
|
$featuredClass = $package['featured'] ? ' featured' : '';
|
||||||
$featuredBadge = $package['featured'] ? '<div class="featured-badge">Beliebt</div>' : '';
|
$featuredBadge = $package['featured'] ? '<div class="featured-badge">Beliebt</div>' : '';
|
||||||
@@ -604,7 +489,7 @@ function renderPackageCard($productId, $packageId, $package) {
|
|||||||
<div class="package-features">
|
<div class="package-features">
|
||||||
%s
|
%s
|
||||||
</div>
|
</div>
|
||||||
<a href="%s" class="btn btn-primary">Jetzt bestellen</a>
|
<a href="contact.php?package=%s-%s" class="btn btn-primary">Jetzt bestellen</a>
|
||||||
</div>',
|
</div>',
|
||||||
$featuredClass,
|
$featuredClass,
|
||||||
$featuredBadge,
|
$featuredBadge,
|
||||||
@@ -612,13 +497,12 @@ function renderPackageCard($productId, $packageId, $package) {
|
|||||||
$package['price'],
|
$package['price'],
|
||||||
$specsHtml,
|
$specsHtml,
|
||||||
$featuresHtml,
|
$featuresHtml,
|
||||||
htmlspecialchars(getOrderUrl($productId, $packageId), ENT_QUOTES, 'UTF-8')
|
$productId,
|
||||||
|
$packageId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generiert HTML für alle Pakete eines Produkts
|
|
||||||
*/
|
|
||||||
function renderAllPackages($productId) {
|
function renderAllPackages($productId) {
|
||||||
$packages = getProductPackages($productId);
|
$packages = getProductPackages($productId);
|
||||||
$html = '';
|
$html = '';
|
||||||
|
|||||||
@@ -15,17 +15,10 @@
|
|||||||
<div class="footer-section">
|
<div class="footer-section">
|
||||||
<h4>Produkte</h4>
|
<h4>Produkte</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li<?php echo productHiddenAttr('vpc'); ?>><a href="/vpc">Virtual Private Container</a></li>
|
<li><a href="/vpc">Virtual Private Container</a></li>
|
||||||
<li<?php echo productHiddenAttr('vps'); ?>><a href="/vps">Virtual Private Server</a></li>
|
<li><a href="/vps">Virtual Private Server</a></li>
|
||||||
<li<?php echo productHiddenAttr('mail-gateway'); ?>><a href="/mail-gateway">Mail Gateway</a></li>
|
<li><a href="/mail-gateway">Mail Gateway</a></li>
|
||||||
<li<?php echo productHiddenAttr('webhosting'); ?>><a href="/webhosting">Webhosting</a></li>
|
<li><a href="/webhosting">Webhosting</a></li>
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="footer-section">
|
|
||||||
<h4>Andere Dienste</h4>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://hexadns.de" target="_blank" rel="noopener noreferrer">hexadns.de</a></li>
|
|
||||||
<li><a href="https://www.hexa-mail.de/" target="_blank" rel="noopener noreferrer">hexa-mail.de</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-section">
|
<div class="footer-section">
|
||||||
@@ -56,7 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<!-- Cookie Consent Banner -->
|
|
||||||
<div id="cookieConsent" class="cookie-consent" role="dialog" aria-labelledby="cookieConsentTitle" aria-describedby="cookieConsentDesc">
|
<div id="cookieConsent" class="cookie-consent" role="dialog" aria-labelledby="cookieConsentTitle" aria-describedby="cookieConsentDesc">
|
||||||
<div class="cookie-consent-container">
|
<div class="cookie-consent-container">
|
||||||
<div class="cookie-consent-content">
|
<div class="cookie-consent-content">
|
||||||
@@ -86,7 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Erweiterte Cookie-Einstellungen (standardmäßig versteckt) -->
|
|
||||||
<div id="cookieSettingsPanel" class="cookie-settings-panel" style="display: none;">
|
<div id="cookieSettingsPanel" class="cookie-settings-panel" style="display: none;">
|
||||||
<div class="cookie-settings-content">
|
<div class="cookie-settings-content">
|
||||||
<h4>Cookie-Einstellungen</h4>
|
<h4>Cookie-Einstellungen</h4>
|
||||||
@@ -128,7 +121,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Google Analytics (GA4) mit Consent Mode -->
|
|
||||||
<script>
|
<script>
|
||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){dataLayer.push(arguments);}
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Helper functions for HexaHost.de
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once __DIR__ . '/../config/products-config.php';
|
|
||||||
|
|
||||||
// Sichere Session-Konfiguration
|
|
||||||
if (session_status() === PHP_SESSION_NONE) {
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
// Session-Cookie-Sicherheit
|
|
||||||
ini_set('session.cookie_httponly', 1);
|
ini_set('session.cookie_httponly', 1);
|
||||||
ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) ? 1 : 0);
|
ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) ? 1 : 0);
|
||||||
ini_set('session.cookie_samesite', 'Strict');
|
ini_set('session.cookie_samesite', 'Strict');
|
||||||
@@ -16,14 +12,14 @@ if (session_status() === PHP_SESSION_NONE) {
|
|||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
// Session-ID regenerieren bei Login/wichtigen Aktionen (Schutz vor Session Fixation)
|
|
||||||
if (!isset($_SESSION['initiated'])) {
|
if (!isset($_SESSION['initiated'])) {
|
||||||
session_regenerate_id(true);
|
session_regenerate_id(true);
|
||||||
$_SESSION['initiated'] = true;
|
$_SESSION['initiated'] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PHP Error Display in Produktion deaktivieren
|
|
||||||
if (!defined('DEBUG_MODE') || !DEBUG_MODE) {
|
if (!defined('DEBUG_MODE') || !DEBUG_MODE) {
|
||||||
ini_set('display_errors', 0);
|
ini_set('display_errors', 0);
|
||||||
ini_set('display_startup_errors', 0);
|
ini_set('display_startup_errors', 0);
|
||||||
@@ -31,18 +27,11 @@ if (!defined('DEBUG_MODE') || !DEBUG_MODE) {
|
|||||||
ini_set('log_errors', 1);
|
ini_set('log_errors', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set page configuration and include header
|
|
||||||
*
|
|
||||||
* @param string $title The page title
|
|
||||||
* @param string $description The page description
|
|
||||||
* @param string $page The current page identifier
|
|
||||||
* @param array $scripts Additional scripts to include
|
|
||||||
*/
|
|
||||||
function includeHeader($title = '', $description = '', $page = '', $scripts = []) {
|
function includeHeader($title = '', $description = '', $page = '', $scripts = []) {
|
||||||
global $page_title, $page_description, $current_page, $additional_scripts;
|
global $page_title, $page_description, $current_page, $additional_scripts;
|
||||||
|
|
||||||
// Set page configuration from parameters
|
|
||||||
$page_title = !empty($title)
|
$page_title = !empty($title)
|
||||||
? $title
|
? $title
|
||||||
: 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern';
|
: 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern';
|
||||||
@@ -57,28 +46,22 @@ function includeHeader($title = '', $description = '', $page = '', $scripts = []
|
|||||||
include __DIR__ . '/header.php';
|
include __DIR__ . '/header.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Include footer
|
|
||||||
*/
|
|
||||||
function includeFooter() {
|
function includeFooter() {
|
||||||
include __DIR__ . '/footer.php';
|
include __DIR__ . '/footer.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate breadcrumb navigation
|
|
||||||
*
|
|
||||||
* @param array $breadcrumbs Array of breadcrumb items [['title' => 'Home', 'url' => 'index.html'], ...]
|
|
||||||
*/
|
|
||||||
function generateBreadcrumbs($breadcrumbs) {
|
function generateBreadcrumbs($breadcrumbs) {
|
||||||
echo '<div class="breadcrumb">';
|
echo '<div class="breadcrumb">';
|
||||||
$last_index = count($breadcrumbs) - 1;
|
$last_index = count($breadcrumbs) - 1;
|
||||||
|
|
||||||
foreach ($breadcrumbs as $index => $item) {
|
foreach ($breadcrumbs as $index => $item) {
|
||||||
if ($index === $last_index) {
|
if ($index === $last_index) {
|
||||||
// Last item (current page)
|
|
||||||
echo '<span>' . htmlspecialchars($item['title']) . '</span>';
|
echo '<span>' . htmlspecialchars($item['title']) . '</span>';
|
||||||
} else {
|
} else {
|
||||||
// Link to other pages
|
|
||||||
echo '<a href="' . htmlspecialchars($item['url']) . '">' . htmlspecialchars($item['title']) . '</a>';
|
echo '<a href="' . htmlspecialchars($item['url']) . '">' . htmlspecialchars($item['title']) . '</a>';
|
||||||
echo '<span>/</span>';
|
echo '<span>/</span>';
|
||||||
}
|
}
|
||||||
@@ -86,11 +69,7 @@ function generateBreadcrumbs($breadcrumbs) {
|
|||||||
echo '</div>';
|
echo '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate CSRF token for form security
|
|
||||||
*
|
|
||||||
* @return string CSRF token
|
|
||||||
*/
|
|
||||||
function generateCSRFToken() {
|
function generateCSRFToken() {
|
||||||
if (!isset($_SESSION['csrf_token'])) {
|
if (!isset($_SESSION['csrf_token'])) {
|
||||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||||
@@ -98,9 +77,7 @@ function generateCSRFToken() {
|
|||||||
return $_SESSION['csrf_token'];
|
return $_SESSION['csrf_token'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* CSRF-Token prüfen und nach Erfolg invalidieren (Replay-Schutz)
|
|
||||||
*/
|
|
||||||
function validateCSRFToken($token) {
|
function validateCSRFToken($token) {
|
||||||
if (!isset($_SESSION['csrf_token']) || !is_string($token)) {
|
if (!isset($_SESSION['csrf_token']) || !is_string($token)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -112,16 +89,12 @@ function validateCSRFToken($token) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Werte für E-Mail-Header bereinigen (Header-Injection verhindern)
|
|
||||||
*/
|
|
||||||
function sanitizeHeaderValue(string $value): string {
|
function sanitizeHeaderValue(string $value): string {
|
||||||
return str_replace(["\r", "\n", "\0"], '', trim($value));
|
return str_replace(["\r", "\n", "\0"], '', trim($value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Client-IP für Logging (Cloudflare / vertrauenswürdiger Reverse-Proxy)
|
|
||||||
*/
|
|
||||||
function getClientIP(): string {
|
function getClientIP(): string {
|
||||||
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])
|
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])
|
||||||
&& filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP)) {
|
&& filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP)) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
<!-- Performance: DNS Prefetch & Preconnect -->
|
|
||||||
<link rel="dns-prefetch" href="//fonts.googleapis.com">
|
<link rel="dns-prefetch" href="//fonts.googleapis.com">
|
||||||
<link rel="dns-prefetch" href="//fonts.gstatic.com">
|
<link rel="dns-prefetch" href="//fonts.gstatic.com">
|
||||||
<link rel="dns-prefetch" href="//cdn.hexahost.de">
|
<link rel="dns-prefetch" href="//cdn.hexahost.de">
|
||||||
@@ -12,37 +12,37 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link rel="preconnect" href="https://cdn.hexahost.de" crossorigin>
|
<link rel="preconnect" href="https://cdn.hexahost.de" crossorigin>
|
||||||
|
|
||||||
<!-- Performance: Preload kritischer Ressourcen -->
|
|
||||||
<link rel="preload" href="/assets/css/style.css" as="style">
|
<link rel="preload" href="/assets/css/style.css" as="style">
|
||||||
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" as="style">
|
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" as="style">
|
||||||
|
|
||||||
<title><?php echo isset($page_title) ? htmlspecialchars($page_title) : 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern'; ?></title>
|
<title><?php echo isset($page_title) ? htmlspecialchars($page_title) : 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern'; ?></title>
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
|
||||||
<meta name="description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'HexaHost.de - Zuverlässiges und preiswertes Hosting aus Niederbayern. VPS, VPC, Mail Gateway und Webhosting Lösungen.'; ?>">
|
<meta name="description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'HexaHost.de - Zuverlässiges und preiswertes Hosting aus Niederbayern. VPS, VPC, Mail Gateway und Webhosting Lösungen.'; ?>">
|
||||||
<meta name="robots" content="index, follow">
|
<meta name="robots" content="index, follow">
|
||||||
<meta name="author" content="HexaHost.de">
|
<meta name="author" content="HexaHost.de">
|
||||||
<meta name="theme-color" content="#0d0821">
|
<meta name="theme-color" content="#0d0821">
|
||||||
|
|
||||||
<!-- Open Graph / Social Media -->
|
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:site_name" content="HexaHost.de">
|
<meta property="og:site_name" content="HexaHost.de">
|
||||||
<meta property="og:title" content="<?php echo isset($page_title) ? htmlspecialchars($page_title) : 'HexaHost.de'; ?>">
|
<meta property="og:title" content="<?php echo isset($page_title) ? htmlspecialchars($page_title) : 'HexaHost.de'; ?>">
|
||||||
<meta property="og:description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'Zuverlässiges Hosting aus Niederbayern'; ?>">
|
<meta property="og:description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'Zuverlässiges Hosting aus Niederbayern'; ?>">
|
||||||
<meta property="og:locale" content="de_DE">
|
<meta property="og:locale" content="de_DE">
|
||||||
|
|
||||||
<!-- Main Stylesheets -->
|
|
||||||
<link rel="stylesheet" href="/assets/css/style.css">
|
<link rel="stylesheet" href="/assets/css/style.css">
|
||||||
<link rel="stylesheet" href="/assets/css/custom.css">
|
<link rel="stylesheet" href="/assets/css/custom.css">
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Russo+One&family=Source+Sans+Pro:wght@300;400;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Russo+One&family=Source+Sans+Pro:wght@300;400;600;700&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
<!-- Favicon -->
|
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||||
<link rel="apple-touch-icon" href="/favicon.svg">
|
<link rel="apple-touch-icon" href="/favicon.svg">
|
||||||
|
|
||||||
<!-- Canonical URL (falls gesetzt) -->
|
|
||||||
<?php if (isset($canonical_url)): ?>
|
<?php if (isset($canonical_url)): ?>
|
||||||
<link rel="canonical" href="<?php echo htmlspecialchars($canonical_url); ?>">
|
<link rel="canonical" href="<?php echo htmlspecialchars($canonical_url); ?>">
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -59,12 +59,12 @@
|
|||||||
<ul class="nav-menu">
|
<ul class="nav-menu">
|
||||||
<li><a href="/" class="nav-link <?php echo ($current_page === 'home') ? 'active' : ''; ?>">Home</a></li>
|
<li><a href="/" class="nav-link <?php echo ($current_page === 'home') ? 'active' : ''; ?>">Home</a></li>
|
||||||
<li class="nav-dropdown">
|
<li class="nav-dropdown">
|
||||||
<a href="#" class="nav-link <?php echo (in_array($current_page, getVisibleProductPageIds(), true)) ? 'active' : ''; ?>">Produkte</a>
|
<a href="#" class="nav-link <?php echo (in_array($current_page, ['vpc', 'vps', 'mail-gateway', 'webhosting'])) ? 'active' : ''; ?>">Produkte</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li<?php echo productHiddenAttr('vpc'); ?>><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
|
<li><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
|
||||||
<li<?php echo productHiddenAttr('vps'); ?>><a href="/vps" class="<?php echo ($current_page === 'vps') ? 'active' : ''; ?>">Virtual Private Server</a></li>
|
<li><a href="/vps" class="<?php echo ($current_page === 'vps') ? 'active' : ''; ?>">Virtual Private Server</a></li>
|
||||||
<li<?php echo productHiddenAttr('mail-gateway'); ?>><a href="/mail-gateway" class="<?php echo ($current_page === 'mail-gateway') ? 'active' : ''; ?>">Mail Gateway</a></li>
|
<li><a href="/mail-gateway" class="<?php echo ($current_page === 'mail-gateway') ? 'active' : ''; ?>">Mail Gateway</a></li>
|
||||||
<li<?php echo productHiddenAttr('webhosting'); ?>><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
|
<li><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="/it-dienstleistungen" class="nav-link <?php echo ($current_page === 'it-dienstleistungen') ? 'active' : ''; ?>">IT-Dienstleistungen</a></li>
|
<li><a href="/it-dienstleistungen" class="nav-link <?php echo ($current_page === 'it-dienstleistungen') ? 'active' : ''; ?>">IT-Dienstleistungen</a></li>
|
||||||
|
|||||||
@@ -1,34 +1,145 @@
|
|||||||
# HexaHost.de Kontaktformular - Status
|
# HexaHost.de Kontaktformular - Status-Überprüfung
|
||||||
|
|
||||||
## Aktueller Stand
|
## ✅ Behobene Probleme
|
||||||
|
|
||||||
- Kontaktformular und Handler sind funktionsfähig
|
### 1. Merge-Konflikt in contact-handler.php
|
||||||
- Versand erfolgt nativ über PHP `mail()`
|
- **Problem**: Git-Merge-Konflikt machte die Datei unbrauchbar
|
||||||
- Keine PHPMailer-/Composer-Abhängigkeit mehr
|
- **Lösung**: Konflikt aufgelöst, saubere Version erstellt
|
||||||
|
- **Status**: ✅ Behoben
|
||||||
|
|
||||||
## Sicherheitsfunktionen
|
### 2. CSRF-Token Problem
|
||||||
|
- **Problem**: HTML-Formular versuchte PHP-Code zu verwenden
|
||||||
|
- **Lösung**: CSRF-Token durch Honeypot-Feld ersetzt
|
||||||
|
- **Status**: ✅ Behoben
|
||||||
|
|
||||||
- CSRF-Token-Prüfung
|
### 3. JavaScript-Merge-Konflikt
|
||||||
- Rate Limiting pro IP
|
- **Problem**: Merge-Konflikt in contact.js
|
||||||
- Honeypot gegen Bots
|
- **Lösung**: Konflikt aufgelöst
|
||||||
- E-Mail-Validierung und Input-Sanitization
|
- **Status**: ✅ Behoben
|
||||||
|
|
||||||
## Konfiguration für Produktivbetrieb
|
## ⚠️ Noch zu behebende Probleme
|
||||||
|
|
||||||
Datei: `backend/config/mail-config.php`
|
### 1. SMTP-Konfiguration
|
||||||
|
- **Problem**: SMTP-Einstellungen sind noch auf Testwerte
|
||||||
|
- **Aktueller Status**:
|
||||||
|
```php
|
||||||
|
'smtp_host' => 'smtp.gmail.com',
|
||||||
|
'smtp_username' => 'test@hexahost.de',
|
||||||
|
'smtp_password' => 'your-app-password',
|
||||||
|
```
|
||||||
|
- **Erforderlich**: Echte SMTP-Daten eintragen
|
||||||
|
- **Status**: ⚠️ Zu konfigurieren
|
||||||
|
|
||||||
Zu prüfen:
|
### 2. PHPMailer-Installation
|
||||||
- `SMTP_FROM_EMAIL` ist eine gültige Absenderadresse
|
- **Problem**: Composer ist nicht installiert
|
||||||
- `SMTP_TO_EMAIL` ist das richtige Zielpostfach
|
- **Aktueller Status**: Fallback auf native PHP mail() Funktion
|
||||||
- `mail()` ist beim Hoster aktiv
|
- **Erforderlich**: Composer installieren und PHPMailer einrichten
|
||||||
|
- **Status**: ⚠️ Optional (Fallback funktioniert)
|
||||||
|
|
||||||
## Testempfehlung
|
## 📧 E-Mail-Funktionalität
|
||||||
|
|
||||||
1. `scripts/test-email.php` ausführen
|
### Aktuelle Konfiguration
|
||||||
2. Kontaktformular über `contact.php` absenden
|
- **SMTP-Host**: smtp.gmail.com
|
||||||
3. Empfang und Darstellung der E-Mail prüfen
|
- **Port**: 587
|
||||||
|
- **Verschlüsselung**: TLS
|
||||||
|
- **Fallback**: Native PHP mail() Funktion
|
||||||
|
|
||||||
## Hinweis
|
### Sicherheitsfeatures
|
||||||
|
- ✅ Rate Limiting (5 Anfragen/Stunde)
|
||||||
|
- ✅ Honeypot-Schutz
|
||||||
|
- ✅ Input-Sanitization
|
||||||
|
- ✅ E-Mail-Validierung
|
||||||
|
- ✅ Anti-Spam-Headers
|
||||||
|
|
||||||
Falls der Versand nicht funktioniert, liegt die Ursache in der Regel an der Server-Mailkonfiguration (MTA/`mail()`), nicht am Formular-Code.
|
### E-Mail-Templates
|
||||||
|
- ✅ HTML-Template mit HexaHost-Design
|
||||||
|
- ✅ Text-Version als Fallback
|
||||||
|
- ✅ Responsive Design
|
||||||
|
- ✅ Strukturierte Darstellung aller Daten
|
||||||
|
|
||||||
|
## 🧪 Test-Möglichkeiten
|
||||||
|
|
||||||
|
### 1. Test-Datei
|
||||||
|
- **Datei**: `test-email.php`
|
||||||
|
- **Zweck**: E-Mail-Funktionalität ohne Formular testen
|
||||||
|
- **Verwendung**: Im Browser öffnen und "Test-E-Mail senden" klicken
|
||||||
|
|
||||||
|
### 2. Kontaktformular
|
||||||
|
- **Datei**: `contact.html`
|
||||||
|
- **Zweck**: Vollständiges Formular testen
|
||||||
|
- **Verwendung**: Formular ausfüllen und absenden
|
||||||
|
|
||||||
|
## 🔧 Konfiguration erforderlich
|
||||||
|
|
||||||
|
### Für Produktivbetrieb:
|
||||||
|
|
||||||
|
1. **SMTP-Daten eintragen** in `config.php`:
|
||||||
|
```php
|
||||||
|
'smtp_username' => 'ihre-echte-email@gmail.com',
|
||||||
|
'smtp_password' => 'ihr-echtes-app-passwort',
|
||||||
|
'from_email' => 'ihre-echte-email@gmail.com',
|
||||||
|
'to_email' => 'info@hexahost.de',
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Composer installieren** (optional):
|
||||||
|
```bash
|
||||||
|
# Windows: Composer-Installer herunterladen
|
||||||
|
# Linux/macOS:
|
||||||
|
curl -sS https://getcomposer.org/installer | php
|
||||||
|
sudo mv composer.phar /usr/local/bin/composer
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **PHPMailer installieren** (optional):
|
||||||
|
```bash
|
||||||
|
cd public
|
||||||
|
composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 Funktionsfähigkeit
|
||||||
|
|
||||||
|
### ✅ Funktioniert
|
||||||
|
- Kontaktformular-HTML
|
||||||
|
- JavaScript-Validierung
|
||||||
|
- PHP-Backend-Verarbeitung
|
||||||
|
- Rate Limiting
|
||||||
|
- Spam-Schutz
|
||||||
|
- E-Mail-Templates
|
||||||
|
- Fallback auf native mail() Funktion
|
||||||
|
|
||||||
|
### ⚠️ Benötigt Konfiguration
|
||||||
|
- SMTP-Einstellungen
|
||||||
|
- PHPMailer (optional)
|
||||||
|
|
||||||
|
### ❌ Nicht funktioniert
|
||||||
|
- E-Mail-Versand ohne SMTP-Konfiguration
|
||||||
|
|
||||||
|
## 🚀 Nächste Schritte
|
||||||
|
|
||||||
|
1. **SMTP-Konfiguration anpassen**
|
||||||
|
- Echte SMTP-Daten in `config.php` eintragen
|
||||||
|
- Test mit `test-email.php`
|
||||||
|
|
||||||
|
2. **E-Mail-Funktionalität testen**
|
||||||
|
- Kontaktformular ausfüllen
|
||||||
|
- E-Mail-Empfang prüfen
|
||||||
|
|
||||||
|
3. **PHPMailer installieren** (optional)
|
||||||
|
- Composer installieren
|
||||||
|
- PHPMailer einrichten
|
||||||
|
|
||||||
|
4. **DNS-Einträge konfigurieren**
|
||||||
|
- SPF Record
|
||||||
|
- DMARC Record
|
||||||
|
- DKIM (über Mail-Server)
|
||||||
|
|
||||||
|
## 📞 Support
|
||||||
|
|
||||||
|
Bei Problemen:
|
||||||
|
1. `test-email.php` verwenden
|
||||||
|
2. PHP-Error-Logs prüfen
|
||||||
|
3. SMTP-Konfiguration überprüfen
|
||||||
|
4. Hosting-Provider kontaktieren
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status**: Kontaktformular ist funktionsfähig, benötigt nur SMTP-Konfiguration für E-Mail-Versand.
|
||||||
@@ -2,54 +2,172 @@
|
|||||||
|
|
||||||
## Übersicht
|
## Übersicht
|
||||||
|
|
||||||
Das Kontaktformular nutzt den nativen PHP-Mailversand über `mail()`.
|
Das Kontaktformular von HexaHost.de benötigt eine korrekte SMTP-Konfiguration, um E-Mails zu versenden. Diese Anleitung erklärt, wie Sie die E-Mail-Funktionalität einrichten.
|
||||||
Es wird keine zusätzliche Bibliothek und keine Composer-Installation benötigt.
|
|
||||||
|
|
||||||
## Erforderliche Konfiguration
|
## Aktuelle Probleme
|
||||||
|
|
||||||
Datei: `backend/config/mail-config.php`
|
### 1. ✅ Behoben: Merge-Konflikt in contact-handler.php
|
||||||
|
- Der Git-Merge-Konflikt wurde aufgelöst
|
||||||
|
- Die Datei ist jetzt funktionsfähig
|
||||||
|
|
||||||
Mindestens diese Werte müssen korrekt gesetzt sein:
|
### 2. ⚠️ Zu beheben: SMTP-Konfiguration
|
||||||
|
- Die SMTP-Einstellungen sind noch auf Testwerte gesetzt
|
||||||
|
- Sie müssen mit echten SMTP-Daten konfiguriert werden
|
||||||
|
|
||||||
|
### 3. ⚠️ Zu beheben: PHPMailer-Installation
|
||||||
|
- Composer ist nicht installiert
|
||||||
|
- PHPMailer ist nicht verfügbar
|
||||||
|
- Fallback auf native PHP mail() Funktion ist aktiv
|
||||||
|
|
||||||
|
## SMTP-Konfiguration
|
||||||
|
|
||||||
|
### Option 1: Gmail SMTP (Empfohlen für Tests)
|
||||||
|
|
||||||
|
1. **Gmail-Konto einrichten:**
|
||||||
|
- Gehen Sie zu Ihren Google-Kontoeinstellungen
|
||||||
|
- Aktivieren Sie "2-Schritt-Verifizierung"
|
||||||
|
- Erstellen Sie ein "App-Passwort"
|
||||||
|
|
||||||
|
2. **config.php bearbeiten:**
|
||||||
```php
|
```php
|
||||||
define('SMTP_FROM_EMAIL', 'kontakt@hexahost.de');
|
'smtp_host' => 'smtp.gmail.com',
|
||||||
define('SMTP_TO_EMAIL', 'info@hexahost.de');
|
'smtp_port' => 587,
|
||||||
|
'smtp_username' => 'ihre-email@gmail.com',
|
||||||
|
'smtp_password' => 'ihr-app-passwort',
|
||||||
|
'smtp_encryption' => 'tls',
|
||||||
|
'from_email' => 'ihre-email@gmail.com',
|
||||||
|
'to_email' => 'info@hexahost.de',
|
||||||
```
|
```
|
||||||
|
|
||||||
## Voraussetzungen auf dem Server
|
### Option 2: Eigener Mail-Server
|
||||||
|
|
||||||
- `mail()` muss in der PHP-Umgebung aktiviert sein
|
1. **SMTP-Daten von Ihrem Hosting-Provider erhalten**
|
||||||
- Ein Mail Transfer Agent (MTA) bzw. Mailversand beim Hoster muss funktionieren
|
2. **config.php bearbeiten:**
|
||||||
|
```php
|
||||||
|
'smtp_host' => 'mail.ihre-domain.de',
|
||||||
|
'smtp_port' => 587,
|
||||||
|
'smtp_username' => 'kontakt@ihre-domain.de',
|
||||||
|
'smtp_password' => 'ihr-smtp-passwort',
|
||||||
|
'smtp_encryption' => 'tls',
|
||||||
|
'from_email' => 'kontakt@ihre-domain.de',
|
||||||
|
'to_email' => 'info@hexahost.de',
|
||||||
|
```
|
||||||
|
|
||||||
## Test der E-Mail-Funktion
|
### Option 3: Andere E-Mail-Provider
|
||||||
|
|
||||||
1. Per Script testen:
|
#### Outlook/Hotmail:
|
||||||
- `scripts/test-email.php`
|
```php
|
||||||
2. Kontaktformular testen:
|
'smtp_host' => 'smtp-mail.outlook.com',
|
||||||
- Seite `contact.php` öffnen
|
'smtp_port' => 587,
|
||||||
- Formular absenden
|
'smtp_encryption' => 'tls',
|
||||||
- Empfang im Zielpostfach prüfen
|
```
|
||||||
|
|
||||||
|
#### GMX:
|
||||||
|
```php
|
||||||
|
'smtp_host' => 'mail.gmx.net',
|
||||||
|
'smtp_port' => 587,
|
||||||
|
'smtp_encryption' => 'tls',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Web.de:
|
||||||
|
```php
|
||||||
|
'smtp_host' => 'smtp.web.de',
|
||||||
|
'smtp_port' => 587,
|
||||||
|
'smtp_encryption' => 'tls',
|
||||||
|
```
|
||||||
|
|
||||||
|
## PHPMailer-Installation
|
||||||
|
|
||||||
|
### Composer installieren:
|
||||||
|
|
||||||
|
1. **Windows:**
|
||||||
|
- Laden Sie Composer von https://getcomposer.org/download/
|
||||||
|
- Führen Sie den Installer aus
|
||||||
|
|
||||||
|
2. **Linux/macOS:**
|
||||||
|
```bash
|
||||||
|
curl -sS https://getcomposer.org/installer | php
|
||||||
|
sudo mv composer.phar /usr/local/bin/composer
|
||||||
|
```
|
||||||
|
|
||||||
|
### PHPMailer installieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd public
|
||||||
|
composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test der E-Mail-Funktionalität
|
||||||
|
|
||||||
|
### 1. Test-Datei verwenden:
|
||||||
|
- Öffnen Sie `test-email.php` im Browser
|
||||||
|
- Klicken Sie auf "Test-E-Mail senden"
|
||||||
|
|
||||||
|
### 2. Kontaktformular testen:
|
||||||
|
- Öffnen Sie `contact.html`
|
||||||
|
- Füllen Sie das Formular aus
|
||||||
|
- Überprüfen Sie die Antwort
|
||||||
|
|
||||||
|
## Sicherheitseinstellungen
|
||||||
|
|
||||||
|
### DNS-Einträge für Spam-Schutz:
|
||||||
|
|
||||||
|
1. **SPF Record (TXT):**
|
||||||
|
```
|
||||||
|
v=spf1 include:_spf.hexahost.de ~all
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **DMARC Record (TXT):**
|
||||||
|
```
|
||||||
|
v=DMARC1; p=quarantine; rua=mailto:dmarc@hexahost.de
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **DKIM (wird vom Mail-Server konfiguriert)**
|
||||||
|
|
||||||
## Fehlerbehebung
|
## Fehlerbehebung
|
||||||
|
|
||||||
### Meldung: "Mail function not available"
|
### Häufige Probleme:
|
||||||
- `mail()` ist auf dem Server deaktiviert
|
|
||||||
- Hoster kontaktieren und Mailfunktion aktivieren lassen
|
|
||||||
|
|
||||||
### Nachricht kommt nicht an
|
1. **"SMTP connect() failed"**
|
||||||
- Spam-Ordner prüfen
|
- Überprüfen Sie Host und Port
|
||||||
- Absenderadresse (`SMTP_FROM_EMAIL`) auf gültige Domain setzen
|
- Prüfen Sie Firewall-Einstellungen
|
||||||
- PHP-Error-Log prüfen
|
|
||||||
|
|
||||||
### Versand funktioniert lokal nicht
|
2. **"Authentication failed"**
|
||||||
- Unter Windows/Lokalumgebung ist oft kein SMTP in `php.ini` konfiguriert
|
- Überprüfen Sie Benutzername und Passwort
|
||||||
- Auf dem echten Webserver testen
|
- Bei Gmail: App-Passwort verwenden
|
||||||
|
|
||||||
## Sicherheit
|
3. **"Connection timeout"**
|
||||||
|
- Prüfen Sie Internetverbindung
|
||||||
|
- Überprüfen Sie SMTP-Host
|
||||||
|
|
||||||
Das Kontaktformular beinhaltet bereits:
|
4. **"Mail function not available"**
|
||||||
- CSRF-Schutz
|
- PHP mail() Funktion ist deaktiviert
|
||||||
- Rate Limiting
|
- Kontaktieren Sie Ihren Hosting-Provider
|
||||||
- Honeypot-Feld
|
|
||||||
- Serverseitige Validierung und Sanitization
|
|
||||||
|
|
||||||
|
## Debug-Modus aktivieren
|
||||||
|
|
||||||
|
In `config.php` setzen Sie:
|
||||||
|
```php
|
||||||
|
'debug_mode' => true,
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logs überprüfen
|
||||||
|
|
||||||
|
E-Mail-Fehler werden in den PHP-Error-Logs gespeichert:
|
||||||
|
- Windows: Event Viewer
|
||||||
|
- Linux: `/var/log/php_errors.log`
|
||||||
|
|
||||||
|
## Nächste Schritte
|
||||||
|
|
||||||
|
1. ✅ Merge-Konflikt behoben
|
||||||
|
2. ⚠️ SMTP-Konfiguration anpassen
|
||||||
|
3. ⚠️ PHPMailer installieren (optional)
|
||||||
|
4. ⚠️ E-Mail-Funktionalität testen
|
||||||
|
5. ⚠️ DNS-Einträge für Spam-Schutz konfigurieren
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Bei Problemen:
|
||||||
|
- Überprüfen Sie die PHP-Error-Logs
|
||||||
|
- Testen Sie mit `test-email.php`
|
||||||
|
- Kontaktieren Sie Ihren Hosting-Provider
|
||||||
|
|||||||
@@ -52,6 +52,15 @@
|
|||||||
Deny from all
|
Deny from all
|
||||||
</Files>
|
</Files>
|
||||||
|
|
||||||
|
<Files "composer.json">
|
||||||
|
Order allow,deny
|
||||||
|
Deny from all
|
||||||
|
</Files>
|
||||||
|
|
||||||
|
<Files "composer.lock">
|
||||||
|
Order allow,deny
|
||||||
|
Deny from all
|
||||||
|
</Files>
|
||||||
|
|
||||||
# Config-Verzeichnis schützen
|
# Config-Verzeichnis schützen
|
||||||
<IfModule mod_rewrite.c>
|
<IfModule mod_rewrite.c>
|
||||||
@@ -68,6 +77,11 @@
|
|||||||
RewriteRule ^logs/ - [F,L]
|
RewriteRule ^logs/ - [F,L]
|
||||||
</IfModule>
|
</IfModule>
|
||||||
|
|
||||||
|
# Vendor-Verzeichnis schützen
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteRule ^vendor/ - [F,L]
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
# Cache-Header für statische Dateien
|
# Cache-Header für statische Dateien
|
||||||
<IfModule mod_expires.c>
|
<IfModule mod_expires.c>
|
||||||
ExpiresActive On
|
ExpiresActive On
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = '404 - Seite nicht gefunden | HexaHost.de';
|
$page_title = '404 - Seite nicht gefunden | HexaHost.de';
|
||||||
$page_description = 'Die angeforderte Seite wurde nicht gefunden.';
|
$page_description = 'Die angeforderte Seite wurde nicht gefunden.';
|
||||||
$current_page = '404';
|
$current_page = '404';
|
||||||
|
|
||||||
// Set 404 header
|
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = '500 - Serverfehler | HexaHost.de';
|
$page_title = '500 - Serverfehler | HexaHost.de';
|
||||||
$page_description = 'Ein interner Serverfehler ist aufgetreten.';
|
$page_description = 'Ein interner Serverfehler ist aufgetreten.';
|
||||||
$current_page = '500';
|
$current_page = '500';
|
||||||
|
|
||||||
// Set 500 header
|
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = 'Über mich - HexaHost.de | Hosting aus Niederbayern';
|
$page_title = 'Über mich - HexaHost.de | Hosting aus Niederbayern';
|
||||||
$page_description = 'Erfahren Sie mehr über HexaHost.de - Ihr zuverlässiger Hosting-Partner aus Niederbayern. Moderne Technologie mit persönlichem Service.';
|
$page_description = 'Erfahren Sie mehr über HexaHost.de - Ihr zuverlässiger Hosting-Partner aus Niederbayern. Moderne Technologie mit persönlichem Service.';
|
||||||
$current_page = 'about';
|
$current_page = 'about';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- About Hero -->
|
|
||||||
<section class="about-hero">
|
<section class="about-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="about-hero-content">
|
<div class="about-hero-content">
|
||||||
@@ -33,7 +33,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Company Story -->
|
|
||||||
<section class="company-story">
|
<section class="company-story">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="story-content">
|
<div class="story-content">
|
||||||
@@ -41,9 +41,9 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
<h2 class="section-title">Unsere Geschichte</h2>
|
<h2 class="section-title">Unsere Geschichte</h2>
|
||||||
<p>
|
<p>
|
||||||
HexaHost.de wurde von mir, Samuel Müller, mit der Vision gegründet, zuverlässiges
|
HexaHost.de wurde von mir, Samuel Müller, mit der Vision gegründet, zuverlässiges
|
||||||
und preiswertes Hosting und IT-Lösungen direkt aus Bayern anzubieten. Als regionales
|
und preiswertes Hosting und IT-Lösungen direkt aus Deutschland anzubieten. Als regionales
|
||||||
Unternehmen aus Niederbayern verstehe ich die Bedürfnisse meiner Kunden
|
Unternehmen aus Niederbayern verstehe ich die Bedürfnisse meiner Kunden
|
||||||
und biete persönlichen Support.
|
und bieten persönlichen Support.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Meine Expertise liegt in der Bereitstellung moderner Hosting- und IT-Lösungen
|
Meine Expertise liegt in der Bereitstellung moderner Hosting- und IT-Lösungen
|
||||||
@@ -78,7 +78,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Values -->
|
|
||||||
<section class="values">
|
<section class="values">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -128,53 +128,9 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!--
|
|
||||||
<section class="team">
|
|
||||||
<div class="container">
|
|
||||||
<div class="section-header">
|
|
||||||
<h2 class="section-title">Mein Team</h2>
|
|
||||||
<p class="section-description">
|
|
||||||
Die Menschen, die hinter HexaHost.de stehen
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="team-content">
|
|
||||||
<div class="team-text">
|
|
||||||
<p>
|
|
||||||
Mein Team besteht aus erfahrenen IT-Experten, die langjährige Erfahrung
|
|
||||||
im Bereich Hosting und Server-Management. Ich bin leidenschaftlich
|
|
||||||
daran interessiert, Ihnen die bestmöglichen Hosting- und IT-Lösungen zu bieten.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Als regionales Unternehmen aus Niederbayern kennen wir die lokalen
|
|
||||||
Bedürfnisse und bieten persönlichen Support in deutscher Sprache.
|
|
||||||
Unser Ziel ist es, Ihnen nicht nur technische Lösungen, sondern
|
|
||||||
auch eine echte Partnerschaft zu bieten.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="team-stats glass-card">
|
|
||||||
<div class="stat-item">
|
|
||||||
<span class="stat-number">5+</span>
|
|
||||||
<span class="stat-label">Jahre Erfahrung</span>
|
|
||||||
</div>
|
|
||||||
<div class="stat-item">
|
|
||||||
<span class="stat-number">500+</span>
|
|
||||||
<span class="stat-label">Zufriedene Kunden</span>
|
|
||||||
</div>
|
|
||||||
<div class="stat-item">
|
|
||||||
<span class="stat-number">99.9%</span>
|
|
||||||
<span class="stat-label">Uptime</span>
|
|
||||||
</div>
|
|
||||||
<div class="stat-item">
|
|
||||||
<span class="stat-number">24/7</span>
|
|
||||||
<span class="stat-label">Support</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- Technology -->
|
|
||||||
|
|
||||||
<section class="technology">
|
<section class="technology">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -229,7 +185,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CTA Section -->
|
|
||||||
<section class="cta">
|
<section class="cta">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="cta-content glass-card">
|
<div class="cta-content glass-card">
|
||||||
@@ -245,6 +201,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = 'Allgemeine Geschäftsbedingungen - HexaHost.de | AGB';
|
$page_title = 'Allgemeine Geschäftsbedingungen - HexaHost.de | AGB';
|
||||||
$page_description = 'Allgemeine Geschäftsbedingungen (AGB) von HexaHost.de für Hosting-Dienstleistungen.';
|
$page_description = 'Allgemeine Geschäftsbedingungen (AGB) von HexaHost.de für Hosting-Dienstleistungen.';
|
||||||
$current_page = 'agb';
|
$current_page = 'agb';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- AGB Hero -->
|
|
||||||
<section class="legal-hero">
|
<section class="legal-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="legal-hero-content">
|
<div class="legal-hero-content">
|
||||||
@@ -29,12 +29,12 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- AGB Content -->
|
|
||||||
<section class="legal-content">
|
<section class="legal-content">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="legal-container">
|
<div class="legal-container">
|
||||||
|
|
||||||
<!-- § 1 Geltungsbereich -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 1 Geltungsbereich</h2>
|
<h2>§ 1 Geltungsbereich</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -67,7 +67,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 2 Vertragsschluss -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 2 Vertragsschluss</h2>
|
<h2>§ 2 Vertragsschluss</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -98,7 +98,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 3 Leistungsbeschreibung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 3 Leistungsbeschreibung</h2>
|
<h2>§ 3 Leistungsbeschreibung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -129,7 +129,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 4 Preise und Zahlung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 4 Preise und Zahlungsbedingungen</h2>
|
<h2>§ 4 Preise und Zahlungsbedingungen</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -168,7 +168,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 5 Vertragslaufzeit und Kündigung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 5 Vertragslaufzeit und Kündigung</h2>
|
<h2>§ 5 Vertragslaufzeit und Kündigung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -207,7 +207,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 6 Widerrufsrecht für Verbraucher -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 6 Widerrufsrecht für Verbraucher</h2>
|
<h2>§ 6 Widerrufsrecht für Verbraucher</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -252,7 +252,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 7 Pflichten des Kunden -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 7 Pflichten des Kunden</h2>
|
<h2>§ 7 Pflichten des Kunden</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -286,7 +286,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 8 Verbotene Nutzung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 8 Verbotene Nutzung</h2>
|
<h2>§ 8 Verbotene Nutzung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -320,7 +320,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 9 Sperrung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 9 Sperrung von Diensten</h2>
|
<h2>§ 9 Sperrung von Diensten</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -350,7 +350,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 10 Haftung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 10 Haftung</h2>
|
<h2>§ 10 Haftung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -384,7 +384,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 11 Datensicherung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 11 Datensicherung</h2>
|
<h2>§ 11 Datensicherung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -406,7 +406,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 12 Datenschutz -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 12 Datenschutz</h2>
|
<h2>§ 12 Datenschutz</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -430,7 +430,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 13 Geheimhaltung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 13 Geheimhaltung</h2>
|
<h2>§ 13 Geheimhaltung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -455,7 +455,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 14 Änderungen der AGB -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 14 Änderungen der AGB</h2>
|
<h2>§ 14 Änderungen der AGB</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -478,7 +478,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- § 15 Schlussbestimmungen -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>§ 15 Schlussbestimmungen</h2>
|
<h2>§ 15 Schlussbestimmungen</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -506,7 +506,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Kontakt -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Kontakt bei Fragen</h2>
|
<h2>Kontakt bei Fragen</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -527,6 +527,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -1,112 +1 @@
|
|||||||
.btn-tertiary {
|
.btn-tertiary{color:var(--text-primary);background:0 0;border:1px solid rgba(255,255,255,.25);transition:.3s}.btn-tertiary:hover{border-color:var(--primary-color);color:var(--primary-color);background:rgba(255,81,249,.08)}.it-services-actions{justify-content:center;margin-top:2rem}
|
||||||
color: var(--text-primary);
|
|
||||||
background: transparent;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-tertiary:hover {
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
color: var(--primary-color);
|
|
||||||
background: rgba(255, 81, 249, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.it-services-actions {
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Legal pages: plain white content with black text */
|
|
||||||
.legal-hero,
|
|
||||||
.legal-content {
|
|
||||||
background: #ffffff;
|
|
||||||
color: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-hero {
|
|
||||||
margin-top: 70px;
|
|
||||||
padding: 2rem 0 1.5rem;
|
|
||||||
border-bottom: 1px solid #e5e5e5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-content {
|
|
||||||
padding-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-hero-title {
|
|
||||||
background: none;
|
|
||||||
-webkit-text-fill-color: #000000;
|
|
||||||
color: #000000;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-hero-description,
|
|
||||||
.legal-section h2,
|
|
||||||
.legal-section h3,
|
|
||||||
.legal-block p,
|
|
||||||
.legal-block li,
|
|
||||||
.legal-hero .breadcrumb,
|
|
||||||
.legal-hero .breadcrumb span,
|
|
||||||
.legal-content .breadcrumb,
|
|
||||||
.legal-content .breadcrumb span {
|
|
||||||
color: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-section,
|
|
||||||
.legal-section.glass-card {
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
box-shadow: none;
|
|
||||||
backdrop-filter: none;
|
|
||||||
-webkit-backdrop-filter: none;
|
|
||||||
border-radius: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-section:hover,
|
|
||||||
.legal-section.glass-card:hover {
|
|
||||||
transform: none;
|
|
||||||
box-shadow: none;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-content .glass-card:hover {
|
|
||||||
transform: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-section h2 {
|
|
||||||
border-bottom: 1px solid #e5e5e5;
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
margin-bottom: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-block a,
|
|
||||||
.legal-hero .breadcrumb a,
|
|
||||||
.legal-content .breadcrumb a {
|
|
||||||
color: #0b57d0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legal-block a:hover,
|
|
||||||
.legal-hero .breadcrumb a:hover,
|
|
||||||
.legal-content .breadcrumb a:hover {
|
|
||||||
color: #0b57d0;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure absolutely no hover effects on legal text/content */
|
|
||||||
.legal-hero *,
|
|
||||||
.legal-content *,
|
|
||||||
.legal-hero *:hover,
|
|
||||||
.legal-content *:hover,
|
|
||||||
.legal-hero *:focus,
|
|
||||||
.legal-content *:focus,
|
|
||||||
.legal-hero *:active,
|
|
||||||
.legal-content *:active {
|
|
||||||
transform: none !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
text-shadow: none !important;
|
|
||||||
transition: none !important;
|
|
||||||
animation: none !important;
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
19
public/composer.json
Normal file
19
public/composer.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "hexahost/contact-form",
|
||||||
|
"description": "HexaHost.de Contact Form with PHPMailer",
|
||||||
|
"type": "project",
|
||||||
|
"require": {
|
||||||
|
"phpmailer/phpmailer": "^6.8"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"HexaHost\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"optimize-autoloader": true,
|
||||||
|
"sort-packages": true
|
||||||
|
},
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"prefer-stable": true
|
||||||
|
}
|
||||||
6
public/config/config.php
Normal file
6
public/config/config.php
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
require_once __DIR__ . '/mail-config.php';
|
||||||
|
?>
|
||||||
64
public/config/contact-config.php
Normal file
64
public/config/contact-config.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zentrale Betreff-Konfiguration für das Kontaktformular
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string> Betreff-Schlüssel => Anzeigename
|
||||||
|
*/
|
||||||
|
function getContactSubjectMap(): array {
|
||||||
|
return [
|
||||||
|
'allgemeine-anfrage' => 'Allgemeine Anfrage',
|
||||||
|
'vpc-anfrage' => 'Virtual Private Container Anfrage',
|
||||||
|
'vps-anfrage' => 'Virtual Private Server Anfrage',
|
||||||
|
'mail-gateway-anfrage' => 'Mail Gateway Anfrage',
|
||||||
|
'webhosting-anfrage' => 'Webhosting Anfrage',
|
||||||
|
'it-beratung' => 'IT-Beratung',
|
||||||
|
'it-support' => 'IT-Support & Fehlerbehebung',
|
||||||
|
'netzwerk-wlan' => 'Netzwerk & WLAN-Einrichtung',
|
||||||
|
'it-sicherheit-backup' => 'IT-Sicherheit & Backup',
|
||||||
|
'webseiten-hosting-service' => 'Webseiten- & Hosting-Service',
|
||||||
|
'wartung-betreuung' => 'Wartung & Betreuung',
|
||||||
|
'support' => 'Technischer Support',
|
||||||
|
'beratung' => 'Persönliche Beratung',
|
||||||
|
'migration' => 'Migration/Umzug',
|
||||||
|
'sonstiges' => 'Sonstige Anfrage',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $subjectKey
|
||||||
|
*/
|
||||||
|
function isAllowedContactSubject(string $subjectKey): bool {
|
||||||
|
return array_key_exists($subjectKey, getContactSubjectMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Betreff aus ?product= oder ?package= für die Kontaktseite ableiten
|
||||||
|
*/
|
||||||
|
function getPreselectedContactSubject(): string {
|
||||||
|
$productMap = [
|
||||||
|
'vpc' => 'vpc-anfrage',
|
||||||
|
'vps' => 'vps-anfrage',
|
||||||
|
'mail-gateway' => 'mail-gateway-anfrage',
|
||||||
|
'webhosting' => 'webhosting-anfrage',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!empty($_GET['product'])) {
|
||||||
|
$product = strtolower(preg_replace('/[^a-z0-9-]/', '', (string) $_GET['product']));
|
||||||
|
if (isset($productMap[$product])) {
|
||||||
|
return $productMap[$product];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($_GET['package'])) {
|
||||||
|
$package = strtolower(preg_replace('/[^a-z0-9-]/', '', (string) $_GET['package']));
|
||||||
|
foreach ($productMap as $productId => $subjectKey) {
|
||||||
|
if (str_starts_with($package, $productId . '-')) {
|
||||||
|
return $subjectKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
@@ -1,5 +1,141 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Kompatibilitäts-Wrapper – leitet auf die zentrale Backend-Konfiguration um.
|
|
||||||
*/
|
|
||||||
require_once __DIR__ . '/../../backend/config/mail-config.php';
|
define('SMTP_HOST', 'smtp.ihre-domain.de');
|
||||||
|
define('SMTP_PORT', 587);
|
||||||
|
define('SMTP_USERNAME', 'kontakt@ihre-domain.de');
|
||||||
|
define('SMTP_PASSWORD', 'ihr-smtp-passwort');
|
||||||
|
|
||||||
|
|
||||||
|
define('SMTP_FROM_EMAIL', 'kontakt@hexahost.de');
|
||||||
|
define('SMTP_TO_EMAIL', 'info@hexahost.de');
|
||||||
|
|
||||||
|
|
||||||
|
define('ENABLE_CSRF_PROTECTION', true);
|
||||||
|
define('ENABLE_RATE_LIMITING', true);
|
||||||
|
define('MAX_REQUESTS_PER_HOUR', 10);
|
||||||
|
|
||||||
|
|
||||||
|
define('ENABLE_SPAM_PROTECTION', true);
|
||||||
|
define('MAX_MESSAGE_LENGTH', 5000);
|
||||||
|
define('MIN_MESSAGE_LENGTH', 10);
|
||||||
|
|
||||||
|
|
||||||
|
define('DEBUG_MODE', false);
|
||||||
|
define('LOG_EMAILS', true);
|
||||||
|
|
||||||
|
|
||||||
|
define('ADDITIONAL_HEADERS', [
|
||||||
|
'X-Mailer' => 'HexaHost.de Contact Form',
|
||||||
|
'X-Priority' => '3',
|
||||||
|
'X-MSMail-Priority' => 'Normal',
|
||||||
|
'Importance' => 'Normal',
|
||||||
|
'X-Report-Abuse' => 'Please report abuse here: abuse@hexahost.de',
|
||||||
|
'List-Unsubscribe' => '<mailto:unsubscribe@hexahost.de>',
|
||||||
|
'Precedence' => 'bulk'
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
define('ALLOWED_EMAIL_DOMAINS', [
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
define('BLACKLISTED_EMAILS', [
|
||||||
|
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
if (!defined('SMTP_HOST') || !defined('SMTP_USERNAME') || !defined('SMTP_PASSWORD')) {
|
||||||
|
die('SMTP-Konfiguration ist unvollständig. Bitte überprüfen Sie die mail-config.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!filter_var(SMTP_FROM_EMAIL, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
die('Ungültige SMTP_FROM_EMAIL Adresse');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_var(SMTP_TO_EMAIL, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
die('Ungültige SMTP_TO_EMAIL Adresse');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function logEmail($type, $data) {
|
||||||
|
if (!LOG_EMAILS) return;
|
||||||
|
|
||||||
|
$logFile = __DIR__ . '/../logs/email.log';
|
||||||
|
$logDir = dirname($logFile);
|
||||||
|
|
||||||
|
if (!is_dir($logDir)) {
|
||||||
|
mkdir($logDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$timestamp = date('Y-m-d H:i:s');
|
||||||
|
$logEntry = "[$timestamp] $type: " . json_encode($data) . "\n";
|
||||||
|
|
||||||
|
file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function isValidEmail($email) {
|
||||||
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (in_array($email, BLACKLISTED_EMAILS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!empty(ALLOWED_EMAIL_DOMAINS)) {
|
||||||
|
$domain = substr(strrchr($email, "@"), 1);
|
||||||
|
if (!in_array($domain, ALLOWED_EMAIL_DOMAINS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getHexaHostConfig($key = null) {
|
||||||
|
$config = [
|
||||||
|
|
||||||
|
'smtp_host' => SMTP_HOST,
|
||||||
|
'smtp_port' => SMTP_PORT,
|
||||||
|
'smtp_username' => SMTP_USERNAME,
|
||||||
|
'smtp_password' => SMTP_PASSWORD,
|
||||||
|
'smtp_encryption' => 'tls',
|
||||||
|
|
||||||
|
|
||||||
|
'from_email' => SMTP_FROM_EMAIL,
|
||||||
|
'from_name' => 'HexaHost.de Kontaktformular',
|
||||||
|
'to_email' => SMTP_TO_EMAIL,
|
||||||
|
'to_name' => 'HexaHost Support',
|
||||||
|
|
||||||
|
|
||||||
|
'max_requests_per_hour' => MAX_REQUESTS_PER_HOUR,
|
||||||
|
'honeypot_field' => 'website',
|
||||||
|
'enable_csrf' => ENABLE_CSRF_PROTECTION,
|
||||||
|
'min_message_length' => MIN_MESSAGE_LENGTH,
|
||||||
|
'max_message_length' => MAX_MESSAGE_LENGTH,
|
||||||
|
|
||||||
|
|
||||||
|
'debug_mode' => DEBUG_MODE,
|
||||||
|
'log_errors' => LOG_EMAILS,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($key === null) {
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $config[$key] ?? null;
|
||||||
|
}
|
||||||
|
?>
|
||||||
514
public/config/products-config.php
Normal file
514
public/config/products-config.php
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$PRODUCTS['vpc'] = [
|
||||||
|
'name' => 'Virtual Private Container',
|
||||||
|
'short_name' => 'VPC',
|
||||||
|
'description' => 'Effiziente LXC-Container auf Proxmox-Basis',
|
||||||
|
'min_price' => '4,99',
|
||||||
|
'hero_highlight' => 'auf Proxmox LXC',
|
||||||
|
'hero_description' => 'Erleben Sie die Effizienz von Linux-Containern mit der Zuverlässigkeit von Proxmox. Unsere VPC-Lösungen bieten optimale Performance bei minimalem Ressourcenverbrauch.',
|
||||||
|
'packages_title' => 'VPC Pakete',
|
||||||
|
'packages_description' => 'Wählen Sie das perfekte Container-Paket für Ihre Anforderungen',
|
||||||
|
'cta_title' => 'Bereit für Ihren VPC?',
|
||||||
|
'cta_description' => 'Starten Sie noch heute mit einem Virtual Private Container',
|
||||||
|
'page_title' => 'Virtual Private Container - Effiziente LXC Container | HexaHost.de',
|
||||||
|
'page_description' => 'Virtual Private Container auf Proxmox LXC-Basis. Effiziente und preiswerte Container-Lösungen ab 4,99€/Monat bei HexaHost.de',
|
||||||
|
'packages' => [
|
||||||
|
'starter' => [
|
||||||
|
'name' => 'VPC Starter',
|
||||||
|
'price' => '4,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'CPU Kerne', 'value' => '1 vCore'],
|
||||||
|
['label' => 'RAM', 'value' => '1 GB'],
|
||||||
|
['label' => 'SSD Speicher', 'value' => '20 GB'],
|
||||||
|
['label' => 'Traffic', 'value' => '1 TB'],
|
||||||
|
['label' => 'IPv4 Adressen', 'value' => '1'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Proxmox LXC Container',
|
||||||
|
'Root-Zugriff',
|
||||||
|
'SSH-Zugang',
|
||||||
|
'Backup inklusive',
|
||||||
|
'24/7 Monitoring',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'business' => [
|
||||||
|
'name' => 'VPC Business',
|
||||||
|
'price' => '9,99',
|
||||||
|
'featured' => true,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'CPU Kerne', 'value' => '2 vCores'],
|
||||||
|
['label' => 'RAM', 'value' => '4 GB'],
|
||||||
|
['label' => 'SSD Speicher', 'value' => '80 GB'],
|
||||||
|
['label' => 'Traffic', 'value' => '3 TB'],
|
||||||
|
['label' => 'IPv4 Adressen', 'value' => '1'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Proxmox LXC Container',
|
||||||
|
'Root-Zugriff',
|
||||||
|
'SSH-Zugang',
|
||||||
|
'Tägliches Backup',
|
||||||
|
'24/7 Monitoring',
|
||||||
|
'Snapshot-Funktion',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'professional' => [
|
||||||
|
'name' => 'VPC Professional',
|
||||||
|
'price' => '19,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'CPU Kerne', 'value' => '4 vCores'],
|
||||||
|
['label' => 'RAM', 'value' => '8 GB'],
|
||||||
|
['label' => 'SSD Speicher', 'value' => '160 GB'],
|
||||||
|
['label' => 'Traffic', 'value' => '5 TB'],
|
||||||
|
['label' => 'IPv4 Adressen', 'value' => '2'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Proxmox LXC Container',
|
||||||
|
'Root-Zugriff',
|
||||||
|
'SSH-Zugang',
|
||||||
|
'Stündliches Backup',
|
||||||
|
'24/7 Monitoring',
|
||||||
|
'Snapshot-Funktion',
|
||||||
|
'Priority Support',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'enterprise' => [
|
||||||
|
'name' => 'VPC Enterprise',
|
||||||
|
'price' => '39,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'CPU Kerne', 'value' => '8 vCores'],
|
||||||
|
['label' => 'RAM', 'value' => '16 GB'],
|
||||||
|
['label' => 'SSD Speicher', 'value' => '320 GB'],
|
||||||
|
['label' => 'Traffic', 'value' => '10 TB'],
|
||||||
|
['label' => 'IPv4 Adressen', 'value' => '3'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Proxmox LXC Container',
|
||||||
|
'Root-Zugriff',
|
||||||
|
'SSH-Zugang',
|
||||||
|
'Stündliches Backup',
|
||||||
|
'24/7 Monitoring',
|
||||||
|
'Snapshot-Funktion',
|
||||||
|
'Priority Support',
|
||||||
|
'Individuelle Konfiguration',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$PRODUCTS['vps'] = [
|
||||||
|
'name' => 'Virtual Private Server',
|
||||||
|
'short_name' => 'VPS',
|
||||||
|
'description' => 'Vollwertige KVM-Virtualisierung mit Root-Zugriff',
|
||||||
|
'min_price' => '9,99',
|
||||||
|
'hero_highlight' => 'auf Proxmox KVM',
|
||||||
|
'hero_description' => 'Maximale Flexibilität und Kontrolle mit vollwertiger KVM-Virtualisierung. Installieren Sie jedes Betriebssystem und genießen Sie vollständigen Root-Zugriff.',
|
||||||
|
'packages_title' => 'VPS Pakete',
|
||||||
|
'packages_description' => 'Wählen Sie das perfekte VPS-Paket für Ihre Anforderungen',
|
||||||
|
'cta_title' => 'Bereit für Ihren VPS?',
|
||||||
|
'cta_description' => 'Starten Sie noch heute mit einem Virtual Private Server',
|
||||||
|
'page_title' => 'Virtual Private Server - KVM Virtualisierung | HexaHost.de',
|
||||||
|
'page_description' => 'Virtual Private Server auf Proxmox KVM-Basis. Vollwertige Virtualisierung mit Root-Zugriff ab 9,99€/Monat bei HexaHost.de',
|
||||||
|
'packages' => [
|
||||||
|
'starter' => [
|
||||||
|
'name' => 'VPS Starter',
|
||||||
|
'price' => '9,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'CPU Kerne', 'value' => '1 vCore'],
|
||||||
|
['label' => 'RAM', 'value' => '2 GB'],
|
||||||
|
['label' => 'SSD Speicher', 'value' => '40 GB'],
|
||||||
|
['label' => 'Traffic', 'value' => '2 TB'],
|
||||||
|
['label' => 'IPv4 Adressen', 'value' => '1'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Proxmox KVM Virtualisierung',
|
||||||
|
'Root-Zugriff',
|
||||||
|
'SSH-Zugang',
|
||||||
|
'Backup inklusive',
|
||||||
|
'24/7 Monitoring',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'business' => [
|
||||||
|
'name' => 'VPS Business',
|
||||||
|
'price' => '19,99',
|
||||||
|
'featured' => true,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'CPU Kerne', 'value' => '2 vCores'],
|
||||||
|
['label' => 'RAM', 'value' => '4 GB'],
|
||||||
|
['label' => 'SSD Speicher', 'value' => '80 GB'],
|
||||||
|
['label' => 'Traffic', 'value' => '4 TB'],
|
||||||
|
['label' => 'IPv4 Adressen', 'value' => '1'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Proxmox KVM Virtualisierung',
|
||||||
|
'Root-Zugriff',
|
||||||
|
'SSH-Zugang',
|
||||||
|
'Tägliches Backup',
|
||||||
|
'24/7 Monitoring',
|
||||||
|
'Snapshot-Funktion',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'professional' => [
|
||||||
|
'name' => 'VPS Professional',
|
||||||
|
'price' => '39,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'CPU Kerne', 'value' => '4 vCores'],
|
||||||
|
['label' => 'RAM', 'value' => '8 GB'],
|
||||||
|
['label' => 'SSD Speicher', 'value' => '160 GB'],
|
||||||
|
['label' => 'Traffic', 'value' => '8 TB'],
|
||||||
|
['label' => 'IPv4 Adressen', 'value' => '2'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Proxmox KVM Virtualisierung',
|
||||||
|
'Root-Zugriff',
|
||||||
|
'SSH-Zugang',
|
||||||
|
'Stündliches Backup',
|
||||||
|
'24/7 Monitoring',
|
||||||
|
'Snapshot-Funktion',
|
||||||
|
'Priority Support',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'enterprise' => [
|
||||||
|
'name' => 'VPS Enterprise',
|
||||||
|
'price' => '79,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'CPU Kerne', 'value' => '8 vCores'],
|
||||||
|
['label' => 'RAM', 'value' => '16 GB'],
|
||||||
|
['label' => 'SSD Speicher', 'value' => '320 GB'],
|
||||||
|
['label' => 'Traffic', 'value' => '15 TB'],
|
||||||
|
['label' => 'IPv4 Adressen', 'value' => '3'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Proxmox KVM Virtualisierung',
|
||||||
|
'Root-Zugriff',
|
||||||
|
'SSH-Zugang',
|
||||||
|
'Stündliches Backup',
|
||||||
|
'24/7 Monitoring',
|
||||||
|
'Snapshot-Funktion',
|
||||||
|
'Priority Support',
|
||||||
|
'Individuelle Konfiguration',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$PRODUCTS['mail-gateway'] = [
|
||||||
|
'name' => 'Mail Gateway',
|
||||||
|
'short_name' => 'Mail',
|
||||||
|
'description' => 'Professioneller E-Mail-Schutz für Unternehmen',
|
||||||
|
'min_price' => '4,99',
|
||||||
|
'hero_highlight' => 'für Unternehmen',
|
||||||
|
'hero_description' => 'Professionelle E-Mail-Infrastruktur mit maximalem Schutz vor Spam und Malware. Sichern Sie Ihre geschäftliche Kommunikation mit unseren Mail Gateway Lösungen.',
|
||||||
|
'packages_title' => 'Mail Gateway Pakete',
|
||||||
|
'packages_description' => 'Wählen Sie das passende Mail Gateway Paket für Ihr Unternehmen',
|
||||||
|
'cta_title' => 'Bereit für professionelle E-Mail-Kommunikation?',
|
||||||
|
'cta_description' => 'Starten Sie noch heute mit unserem Mail Gateway',
|
||||||
|
'page_title' => 'Mail Gateway - Professionelle E-Mail-Lösungen | HexaHost.de',
|
||||||
|
'page_description' => 'Professionelle Mail Gateway Lösungen für Unternehmen. Spam-Schutz, E-Mail-Archivierung und sichere E-Mail-Kommunikation bei HexaHost.de',
|
||||||
|
'packages' => [
|
||||||
|
'starter' => [
|
||||||
|
'name' => 'Mail Starter',
|
||||||
|
'price' => '4,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'Postfächer', 'value' => '5'],
|
||||||
|
['label' => 'Speicher/Postfach', 'value' => '5 GB'],
|
||||||
|
['label' => 'Domains', 'value' => '1'],
|
||||||
|
['label' => 'E-Mails/Tag', 'value' => '500'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Spam-Filter',
|
||||||
|
'Virus-Schutz',
|
||||||
|
'Webmail',
|
||||||
|
'IMAP/POP3',
|
||||||
|
'SSL/TLS Verschlüsselung',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'business' => [
|
||||||
|
'name' => 'Mail Business',
|
||||||
|
'price' => '14,99',
|
||||||
|
'featured' => true,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'Postfächer', 'value' => '25'],
|
||||||
|
['label' => 'Speicher/Postfach', 'value' => '10 GB'],
|
||||||
|
['label' => 'Domains', 'value' => '3'],
|
||||||
|
['label' => 'E-Mails/Tag', 'value' => '2.000'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Spam-Filter (erweitert)',
|
||||||
|
'Virus-Schutz',
|
||||||
|
'Webmail',
|
||||||
|
'IMAP/POP3',
|
||||||
|
'SSL/TLS Verschlüsselung',
|
||||||
|
'E-Mail Archivierung (30 Tage)',
|
||||||
|
'Kalender & Kontakte',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'professional' => [
|
||||||
|
'name' => 'Mail Professional',
|
||||||
|
'price' => '29,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'Postfächer', 'value' => '100'],
|
||||||
|
['label' => 'Speicher/Postfach', 'value' => '25 GB'],
|
||||||
|
['label' => 'Domains', 'value' => '10'],
|
||||||
|
['label' => 'E-Mails/Tag', 'value' => '10.000'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Spam-Filter (KI-gestützt)',
|
||||||
|
'Virus-Schutz',
|
||||||
|
'Webmail',
|
||||||
|
'IMAP/POP3',
|
||||||
|
'SSL/TLS Verschlüsselung',
|
||||||
|
'E-Mail Archivierung (1 Jahr)',
|
||||||
|
'Kalender & Kontakte',
|
||||||
|
'ActiveSync für Mobile',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'enterprise' => [
|
||||||
|
'name' => 'Mail Enterprise',
|
||||||
|
'price' => '59,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'Postfächer', 'value' => 'Unbegrenzt'],
|
||||||
|
['label' => 'Speicher/Postfach', 'value' => '50 GB'],
|
||||||
|
['label' => 'Domains', 'value' => 'Unbegrenzt'],
|
||||||
|
['label' => 'E-Mails/Tag', 'value' => 'Unbegrenzt'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'Spam-Filter (KI-gestützt)',
|
||||||
|
'Virus-Schutz',
|
||||||
|
'Webmail',
|
||||||
|
'IMAP/POP3',
|
||||||
|
'SSL/TLS Verschlüsselung',
|
||||||
|
'E-Mail Archivierung (10 Jahre)',
|
||||||
|
'Kalender & Kontakte',
|
||||||
|
'ActiveSync für Mobile',
|
||||||
|
'Dedizierte IP',
|
||||||
|
'Priority Support',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$PRODUCTS['webhosting'] = [
|
||||||
|
'name' => 'Webhosting',
|
||||||
|
'short_name' => 'Webhosting',
|
||||||
|
'description' => 'Klassisches Hosting mit PHP, MySQL und SSL',
|
||||||
|
'min_price' => '1,99',
|
||||||
|
'hero_highlight' => 'Alles für Ihre Website',
|
||||||
|
'hero_description' => 'Klassisches Webhosting mit allem, was Sie für eine erfolgreiche Website benötigen. PHP, MySQL, SSL-Zertifikate und E-Mail-Postfächer - alles inklusive.',
|
||||||
|
'packages_title' => 'Webhosting Pakete',
|
||||||
|
'packages_description' => 'Von der ersten Website bis zum professionellen Online-Shop',
|
||||||
|
'cta_title' => 'Bereit für Ihr Webhosting?',
|
||||||
|
'cta_description' => 'Starten Sie noch heute mit professionellem Webhosting',
|
||||||
|
'page_title' => 'Webhosting - Klassisches Hosting für Websites | HexaHost.de',
|
||||||
|
'page_description' => 'Webhosting mit PHP, MySQL und SSL-Zertifikaten. Klassisches Hosting für Websites ab 1,99€/Monat bei HexaHost.de',
|
||||||
|
'packages' => [
|
||||||
|
'starter' => [
|
||||||
|
'name' => 'Webhosting Starter',
|
||||||
|
'price' => '1,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'Webspace', 'value' => '5 GB'],
|
||||||
|
['label' => 'Domains', 'value' => '1'],
|
||||||
|
['label' => 'E-Mail-Postfächer', 'value' => '5'],
|
||||||
|
['label' => 'Datenbanken', 'value' => '1 MySQL'],
|
||||||
|
['label' => 'Traffic', 'value' => '10 GB'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'cPanel/Webmin',
|
||||||
|
'PHP 8.1',
|
||||||
|
'SSL-Zertifikat',
|
||||||
|
'E-Mail-Postfächer',
|
||||||
|
'MySQL Datenbank',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'business' => [
|
||||||
|
'name' => 'Webhosting Business',
|
||||||
|
'price' => '4,99',
|
||||||
|
'featured' => true,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'Webspace', 'value' => '20 GB'],
|
||||||
|
['label' => 'Domains', 'value' => '5'],
|
||||||
|
['label' => 'E-Mail-Postfächer', 'value' => '25'],
|
||||||
|
['label' => 'Datenbanken', 'value' => '5 MySQL'],
|
||||||
|
['label' => 'Traffic', 'value' => '50 GB'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'cPanel/Webmin',
|
||||||
|
'PHP 8.1',
|
||||||
|
'SSL-Zertifikat',
|
||||||
|
'E-Mail-Postfächer',
|
||||||
|
'MySQL Datenbanken',
|
||||||
|
'Backup-Service',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'professional' => [
|
||||||
|
'name' => 'Webhosting Professional',
|
||||||
|
'price' => '9,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'Webspace', 'value' => '50 GB'],
|
||||||
|
['label' => 'Domains', 'value' => 'Unbegrenzt'],
|
||||||
|
['label' => 'E-Mail-Postfächer', 'value' => '100'],
|
||||||
|
['label' => 'Datenbanken', 'value' => 'Unbegrenzt'],
|
||||||
|
['label' => 'Traffic', 'value' => '200 GB'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'cPanel/Webmin',
|
||||||
|
'PHP 8.1',
|
||||||
|
'SSL-Zertifikat',
|
||||||
|
'E-Mail-Postfächer',
|
||||||
|
'MySQL Datenbanken',
|
||||||
|
'Backup-Service',
|
||||||
|
'Priority Support',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'enterprise' => [
|
||||||
|
'name' => 'Webhosting Enterprise',
|
||||||
|
'price' => '19,99',
|
||||||
|
'featured' => false,
|
||||||
|
'specs' => [
|
||||||
|
['label' => 'Webspace', 'value' => '100 GB'],
|
||||||
|
['label' => 'Domains', 'value' => 'Unbegrenzt'],
|
||||||
|
['label' => 'E-Mail-Postfächer', 'value' => 'Unbegrenzt'],
|
||||||
|
['label' => 'Datenbanken', 'value' => 'Unbegrenzt'],
|
||||||
|
['label' => 'Traffic', 'value' => '500 GB'],
|
||||||
|
],
|
||||||
|
'features' => [
|
||||||
|
'cPanel/Webmin',
|
||||||
|
'PHP 8.1',
|
||||||
|
'SSL-Zertifikat',
|
||||||
|
'E-Mail-Postfächer',
|
||||||
|
'MySQL Datenbanken',
|
||||||
|
'Backup-Service',
|
||||||
|
'Priority Support',
|
||||||
|
'Individuelle Konfiguration',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function getAllProducts() {
|
||||||
|
global $PRODUCTS;
|
||||||
|
return $PRODUCTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getProduct($productId) {
|
||||||
|
global $PRODUCTS;
|
||||||
|
return $PRODUCTS[$productId] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getProductPackages($productId) {
|
||||||
|
global $PRODUCTS;
|
||||||
|
return $PRODUCTS[$productId]['packages'] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getPackage($productId, $packageId) {
|
||||||
|
global $PRODUCTS;
|
||||||
|
return $PRODUCTS[$productId]['packages'][$packageId] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getPackagePrice($productId, $packageId) {
|
||||||
|
$package = getPackage($productId, $packageId);
|
||||||
|
return $package['price'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getMinPrice($productId) {
|
||||||
|
global $PRODUCTS;
|
||||||
|
return $PRODUCTS[$productId]['min_price'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatPrice($price, $withCurrency = true) {
|
||||||
|
return $withCurrency ? $price . '€' : $price;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function renderPackageCard($productId, $packageId, $package) {
|
||||||
|
$featuredClass = $package['featured'] ? ' featured' : '';
|
||||||
|
$featuredBadge = $package['featured'] ? '<div class="featured-badge">Beliebt</div>' : '';
|
||||||
|
|
||||||
|
$specsHtml = '';
|
||||||
|
foreach ($package['specs'] as $spec) {
|
||||||
|
$specsHtml .= sprintf(
|
||||||
|
'<div class="spec-item"><span class="spec-label">%s:</span><span class="spec-value">%s</span></div>',
|
||||||
|
htmlspecialchars($spec['label']),
|
||||||
|
htmlspecialchars($spec['value'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$featuresHtml = '';
|
||||||
|
foreach ($package['features'] as $feature) {
|
||||||
|
$featuresHtml .= sprintf('<div class="feature">✓ %s</div>', htmlspecialchars($feature));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('
|
||||||
|
<div class="package-card glass-card%s">
|
||||||
|
%s
|
||||||
|
<div class="package-header">
|
||||||
|
<h3 class="package-name">%s</h3>
|
||||||
|
<div class="package-price">
|
||||||
|
<span class="price">%s€</span>
|
||||||
|
<span class="period">/Monat</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="package-specs">
|
||||||
|
%s
|
||||||
|
</div>
|
||||||
|
<div class="package-features">
|
||||||
|
%s
|
||||||
|
</div>
|
||||||
|
<a href="contact.php?package=%s-%s" class="btn btn-primary">Jetzt bestellen</a>
|
||||||
|
</div>',
|
||||||
|
$featuredClass,
|
||||||
|
$featuredBadge,
|
||||||
|
htmlspecialchars($package['name']),
|
||||||
|
$package['price'],
|
||||||
|
$specsHtml,
|
||||||
|
$featuresHtml,
|
||||||
|
$productId,
|
||||||
|
$packageId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function renderAllPackages($productId) {
|
||||||
|
$packages = getProductPackages($productId);
|
||||||
|
$html = '';
|
||||||
|
foreach ($packages as $packageId => $package) {
|
||||||
|
$html .= renderPackageCard($productId, $packageId, $package);
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* HexaHost.de Contact Form Handler
|
* HexaHost.de Contact Form Handler
|
||||||
* E-Mail-Verarbeitung mit nativer PHP-mail()-Funktion und Spam-Schutz
|
* E-Mail-Verarbeitung mit SMTP-Integration und Spam-Schutz
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
require_once __DIR__ . '/../backend/config/mail-config.php';
|
require_once __DIR__ . '/../backend/config/mail-config.php';
|
||||||
require_once __DIR__ . '/../backend/config/contact-config.php';
|
require_once __DIR__ . '/../backend/config/contact-config.php';
|
||||||
|
|
||||||
|
// PHPMailer Autoload (falls via Composer installiert)
|
||||||
|
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||||
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
}
|
||||||
|
|
||||||
$config = getHexaHostConfig();
|
$config = getHexaHostConfig();
|
||||||
|
|
||||||
// CORS Headers für AJAX-Requests (nur eigene Domain erlauben)
|
// CORS Headers für AJAX-Requests (nur eigene Domain erlauben)
|
||||||
@@ -97,6 +102,53 @@ function getSubjectLabel($subjectKey) {
|
|||||||
function sendEmail($data) {
|
function sendEmail($data) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
|
if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||||
|
return sendEmailNative($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
|
||||||
|
|
||||||
|
$mail->isSMTP();
|
||||||
|
$mail->Host = $config['smtp_host'];
|
||||||
|
$mail->SMTPAuth = true;
|
||||||
|
$mail->Username = $config['smtp_username'];
|
||||||
|
$mail->Password = $config['smtp_password'];
|
||||||
|
$mail->SMTPSecure = $config['smtp_encryption'];
|
||||||
|
$mail->Port = $config['smtp_port'];
|
||||||
|
$mail->CharSet = 'UTF-8';
|
||||||
|
|
||||||
|
$mail->setFrom($config['from_email'], $config['from_name']);
|
||||||
|
$mail->addReplyTo(
|
||||||
|
sanitizeHeaderValue($data['email']),
|
||||||
|
sanitizeHeaderValue($data['firstName'] . ' ' . $data['lastName'])
|
||||||
|
);
|
||||||
|
$mail->addAddress($config['to_email'], $config['to_name']);
|
||||||
|
|
||||||
|
$subject = getSubjectLabel($data['subject']);
|
||||||
|
$mail->Subject = '[HexaHost.de] ' . $subject;
|
||||||
|
|
||||||
|
$mail->isHTML(true);
|
||||||
|
$mail->Body = generateEmailHTML($data);
|
||||||
|
$mail->AltBody = generateEmailText($data);
|
||||||
|
|
||||||
|
$mail->addCustomHeader('X-Mailer', 'HexaHost Contact Form');
|
||||||
|
$mail->addCustomHeader('X-Priority', '3');
|
||||||
|
$mail->addCustomHeader('X-MSMail-Priority', 'Normal');
|
||||||
|
$mail->addCustomHeader('Importance', 'Normal');
|
||||||
|
$mail->addCustomHeader('X-Report-Abuse', 'Please report abuse here: abuse@hexahost.de');
|
||||||
|
|
||||||
|
$mail->send();
|
||||||
|
return true;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('HexaHost Contact Form Error: ' . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendEmailNative($data) {
|
||||||
|
global $config;
|
||||||
|
|
||||||
$subject = '[HexaHost.de] ' . getSubjectLabel($data['subject']);
|
$subject = '[HexaHost.de] ' . getSubjectLabel($data['subject']);
|
||||||
$replyName = sanitizeHeaderValue($data['firstName'] . ' ' . $data['lastName']);
|
$replyName = sanitizeHeaderValue($data['firstName'] . ' ' . $data['lastName']);
|
||||||
$replyEmail = sanitizeHeaderValue($data['email']);
|
$replyEmail = sanitizeHeaderValue($data['email']);
|
||||||
@@ -113,7 +165,6 @@ function sendEmail($data) {
|
|||||||
'X-Report-Abuse: Please report abuse here: abuse@hexahost.de',
|
'X-Report-Abuse: Please report abuse here: abuse@hexahost.de',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Native PHP Mailversand ohne externe Libraries
|
|
||||||
return mail($config['to_email'], $subject, generateEmailHTML($data), implode("\r\n", $headers));
|
return mail($config['to_email'], $subject, generateEmailHTML($data), implode("\r\n", $headers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ require_once __DIR__ . '/../backend/config/contact-config.php';
|
|||||||
|
|
||||||
$preselected_subject = getPreselectedContactSubject();
|
$preselected_subject = getPreselectedContactSubject();
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = 'Kontakt - HexaHost.de | Hosting aus Niederbayern';
|
$page_title = 'Kontakt - HexaHost.de | Hosting aus Niederbayern';
|
||||||
$page_description = 'Kontaktieren Sie HexaHost.de - Ihr Hosting-Partner aus Niederbayern. Persönlicher Support und kompetente Beratung.';
|
$page_description = 'Kontaktieren Sie HexaHost.de - Ihr Hosting-Partner aus Niederbayern. Persönlicher Support und kompetente Beratung.';
|
||||||
$current_page = 'contact';
|
$current_page = 'contact';
|
||||||
$additional_scripts = ['assets/js/contact.js'];
|
$additional_scripts = ['assets/js/contact.js'];
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page, $additional_scripts);
|
includeHeader($page_title, $page_description, $current_page, $additional_scripts);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Contact Hero -->
|
|
||||||
<section class="contact-hero">
|
<section class="contact-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="contact-hero-content">
|
<div class="contact-hero-content">
|
||||||
@@ -36,7 +36,7 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Contact Options -->
|
|
||||||
<section class="contact-options">
|
<section class="contact-options">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="contact-grid">
|
<div class="contact-grid">
|
||||||
@@ -88,7 +88,7 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Contact Form -->
|
|
||||||
<section class="contact-form-section">
|
<section class="contact-form-section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
@@ -100,7 +100,7 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
|
|||||||
</div>
|
</div>
|
||||||
<form class="contact-form glass-card" id="contactForm" action="contact-handler.php" method="POST">
|
<form class="contact-form glass-card" id="contactForm" action="contact-handler.php" method="POST">
|
||||||
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
|
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
|
||||||
<!-- Honeypot-Feld für Bot-Schutz (versteckt via CSS) -->
|
|
||||||
<div style="position: absolute; left: -9999px;" aria-hidden="true">
|
<div style="position: absolute; left: -9999px;" aria-hidden="true">
|
||||||
<input type="text" name="website" tabindex="-1" autocomplete="off">
|
<input type="text" name="website" tabindex="-1" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
@@ -156,7 +156,7 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- FAQ Section -->
|
|
||||||
<section class="faq-section">
|
<section class="faq-section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -224,7 +224,7 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Response Time -->
|
|
||||||
<section class="response-time">
|
<section class="response-time">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="response-content glass-card">
|
<div class="response-content glass-card">
|
||||||
@@ -252,6 +252,6 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = 'Datenschutzerklärung - HexaHost.de | Datenschutz';
|
$page_title = 'Datenschutzerklärung - HexaHost.de | Datenschutz';
|
||||||
$page_description = 'Datenschutzerklärung von HexaHost.de - Informationen zum Schutz Ihrer personenbezogenen Daten.';
|
$page_description = 'Datenschutzerklärung von HexaHost.de - Informationen zum Schutz Ihrer personenbezogenen Daten.';
|
||||||
$current_page = 'datenschutz';
|
$current_page = 'datenschutz';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Datenschutz Hero -->
|
|
||||||
<section class="legal-hero">
|
<section class="legal-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="legal-hero-content">
|
<div class="legal-hero-content">
|
||||||
@@ -29,12 +29,12 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Datenschutz Content -->
|
|
||||||
<section class="legal-content">
|
<section class="legal-content">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="legal-container">
|
<div class="legal-container">
|
||||||
|
|
||||||
<!-- Verantwortlicher -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>1. Verantwortlicher</h2>
|
<h2>1. Verantwortlicher</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -53,7 +53,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Allgemeine Hinweise -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>2. Allgemeine Hinweise zur Datenverarbeitung</h2>
|
<h2>2. Allgemeine Hinweise zur Datenverarbeitung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -75,7 +75,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Rechtsgrundlagen -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>3. Rechtsgrundlagen der Verarbeitung</h2>
|
<h2>3. Rechtsgrundlagen der Verarbeitung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -89,7 +89,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Server-Logfiles -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>4. Server-Logfiles</h2>
|
<h2>4. Server-Logfiles</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -119,7 +119,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Cookies -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>5. Cookies</h2>
|
<h2>5. Cookies</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -146,7 +146,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Kontaktformular -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>6. Kontaktformular</h2>
|
<h2>6. Kontaktformular</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -168,7 +168,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hosting und Vertragsabwicklung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>7. Hosting-Dienstleistungen und Vertragsabwicklung</h2>
|
<h2>7. Hosting-Dienstleistungen und Vertragsabwicklung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -193,7 +193,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- SSL-Verschlüsselung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>8. SSL- bzw. TLS-Verschlüsselung</h2>
|
<h2>8. SSL- bzw. TLS-Verschlüsselung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -212,7 +212,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Speicherdauer -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>9. Speicherdauer</h2>
|
<h2>9. Speicherdauer</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -229,7 +229,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Betroffenenrechte -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>10. Ihre Rechte als betroffene Person</h2>
|
<h2>10. Ihre Rechte als betroffene Person</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -281,7 +281,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Beschwerderecht -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>11. Beschwerderecht bei einer Aufsichtsbehörde</h2>
|
<h2>11. Beschwerderecht bei einer Aufsichtsbehörde</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -302,7 +302,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Datensicherheit -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>12. Datensicherheit</h2>
|
<h2>12. Datensicherheit</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -320,7 +320,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Änderungen -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>13. Aktualität und Änderung dieser Datenschutzerklärung</h2>
|
<h2>13. Aktualität und Änderung dieser Datenschutzerklärung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -344,6 +344,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = 'Impressum - HexaHost.de | Rechtliche Angaben';
|
$page_title = 'Impressum - HexaHost.de | Rechtliche Angaben';
|
||||||
$page_description = 'Impressum und rechtliche Angaben von HexaHost.de - Hosting aus Niederbayern.';
|
$page_description = 'Impressum und rechtliche Angaben von HexaHost.de - Hosting aus Niederbayern.';
|
||||||
$current_page = 'impressum';
|
$current_page = 'impressum';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Impressum Hero -->
|
|
||||||
<section class="legal-hero">
|
<section class="legal-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="legal-hero-content">
|
<div class="legal-hero-content">
|
||||||
@@ -29,12 +29,12 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Impressum Content -->
|
|
||||||
<section class="legal-content">
|
<section class="legal-content">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="legal-container">
|
<div class="legal-container">
|
||||||
|
|
||||||
<!-- Anbieterkennung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Angaben gemäß § 5 DDG</h2>
|
<h2>Angaben gemäß § 5 DDG</h2>
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Kontakt -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Kontakt</h2>
|
<h2>Kontakt</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -61,7 +61,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Umsatzsteuer-ID (falls vorhanden) -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Umsatzsteuer-ID</h2>
|
<h2>Umsatzsteuer-ID</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -72,7 +72,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Verantwortlich für den Inhalt -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Redaktionell verantwortlich</h2>
|
<h2>Redaktionell verantwortlich</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -85,7 +85,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- EU-Streitschlichtung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>EU-Streitschlichtung</h2>
|
<h2>EU-Streitschlichtung</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -101,7 +101,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Verbraucherstreitbeilegung -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Verbraucherstreitbeilegung / Universalschlichtungsstelle</h2>
|
<h2>Verbraucherstreitbeilegung / Universalschlichtungsstelle</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -112,7 +112,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Haftungsausschluss -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Haftung für Inhalte</h2>
|
<h2>Haftung für Inhalte</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -133,7 +133,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Haftung für Links -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Haftung für Links</h2>
|
<h2>Haftung für Links</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -153,7 +153,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Urheberrecht -->
|
|
||||||
<div class="legal-section glass-card">
|
<div class="legal-section glass-card">
|
||||||
<h2>Urheberrecht</h2>
|
<h2>Urheberrecht</h2>
|
||||||
<div class="legal-block">
|
<div class="legal-block">
|
||||||
@@ -180,6 +180,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
112
public/includes/api-helpers.php
Normal file
112
public/includes/api-helpers.php
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Gemeinsame Hilfsfunktionen für öffentliche DNS/API-Endpunkte
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client-IP für Rate-Limiting (Cloudflare-sicher, kein blindes X-Forwarded-For)
|
||||||
|
*/
|
||||||
|
function getApiClientIp(): string {
|
||||||
|
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])
|
||||||
|
&& filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP)) {
|
||||||
|
return $_SERVER['HTTP_CF_CONNECTING_IP'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
||||||
|
$isTrustedProxy = filter_var(
|
||||||
|
$remoteAddr,
|
||||||
|
FILTER_VALIDATE_IP,
|
||||||
|
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||||
|
) === false;
|
||||||
|
|
||||||
|
if ($isTrustedProxy) {
|
||||||
|
foreach (['HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR'] as $header) {
|
||||||
|
if (empty($_SERVER[$header])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$ip = trim(explode(',', $_SERVER[$header])[0]);
|
||||||
|
if (filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $remoteAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Einfaches Rate-Limiting pro Endpunkt und IP
|
||||||
|
*/
|
||||||
|
function checkApiRateLimit(string $endpoint, int $maxPerHour = 120): bool {
|
||||||
|
$ip = getApiClientIp();
|
||||||
|
$cacheFile = sys_get_temp_dir() . '/hexahost_api_' . md5($endpoint . '_' . $ip) . '.txt';
|
||||||
|
$currentTime = time();
|
||||||
|
$data = ['requests' => []];
|
||||||
|
|
||||||
|
$handle = @fopen($cacheFile, 'c+');
|
||||||
|
if ($handle === false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!flock($handle, LOCK_EX)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents = stream_get_contents($handle);
|
||||||
|
if ($contents !== false && $contents !== '') {
|
||||||
|
$decoded = json_decode($contents, true);
|
||||||
|
if (is_array($decoded) && isset($decoded['requests'])) {
|
||||||
|
$data = $decoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['requests'] = array_values(array_filter(
|
||||||
|
$data['requests'],
|
||||||
|
static fn($timestamp) => ($currentTime - (int) $timestamp) < 3600
|
||||||
|
));
|
||||||
|
|
||||||
|
if (count($data['requests']) >= $maxPerHour) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['requests'][] = $currentTime;
|
||||||
|
ftruncate($handle, 0);
|
||||||
|
rewind($handle);
|
||||||
|
fwrite($handle, json_encode($data));
|
||||||
|
} finally {
|
||||||
|
flock($handle, LOCK_UN);
|
||||||
|
fclose($handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain aus GET-Parameter normalisieren und validieren
|
||||||
|
*/
|
||||||
|
function getValidatedDomainParam(string $param = 'domain'): ?string {
|
||||||
|
if (empty($_GET[$param])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$domain = trim((string) $_GET[$param]);
|
||||||
|
$domain = preg_replace('/^(https?:\/\/)?/', '', $domain);
|
||||||
|
$domain = explode('/', $domain)[0];
|
||||||
|
$domain = explode(':', $domain)[0];
|
||||||
|
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9\-\.]*\.[a-zA-Z]{2,}$/', $domain)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rate-Limit-JSON-Antwort senden und beenden
|
||||||
|
*/
|
||||||
|
function rejectApiRateLimit(): void {
|
||||||
|
http_response_code(429);
|
||||||
|
echo json_encode(['error' => 'Zu viele Anfragen. Bitte versuchen Sie es später erneut.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
167
public/includes/footer.php
Normal file
167
public/includes/footer.php
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-content">
|
||||||
|
<div class="footer-section">
|
||||||
|
<h4>HexaHost.de</h4>
|
||||||
|
<p>Zuverlässiges Hosting aus Niederbayern</p>
|
||||||
|
<div class="footer-location">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/>
|
||||||
|
<circle cx="12" cy="10" r="3"/>
|
||||||
|
</svg>
|
||||||
|
<span>Niederbayern, Deutschland</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-section">
|
||||||
|
<h4>Produkte</h4>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/vpc">Virtual Private Container</a></li>
|
||||||
|
<li><a href="/vps">Virtual Private Server</a></li>
|
||||||
|
<li><a href="/mail-gateway">Mail Gateway</a></li>
|
||||||
|
<li><a href="/webhosting">Webhosting</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="footer-section">
|
||||||
|
<h4>Unternehmen</h4>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/about">Über mich</a></li>
|
||||||
|
<li><a href="/contact">Kontakt</a></li>
|
||||||
|
<li><a href="/impressum">Impressum</a></li>
|
||||||
|
<li><a href="/datenschutz">Datenschutz</a></li>
|
||||||
|
<li><a href="/agb">AGB</a></li>
|
||||||
|
<li><a href="/widerruf">Widerrufsbelehrung</a></li>
|
||||||
|
<li><a href="#" id="openCookieSettings" onclick="CookieConsent.resetConsent(); return false;">Cookie-Einstellungen</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="footer-section">
|
||||||
|
<h4>Support</h4>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://shop.hexahost.de/clientarea.php">Kunden-Center</a></li>
|
||||||
|
<li><a href="https://shop.hexahost.de/serverstatus.php">Status</a></li>
|
||||||
|
<li><a href="https://shop.hexahost.de/supporttickets.php">Support-Ticket</a></li>
|
||||||
|
<li><a href="#">FAQ</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<p>© <?php echo date('Y'); ?> HexaHost.de - Alle Rechte vorbehalten</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cookieConsent" class="cookie-consent" role="dialog" aria-labelledby="cookieConsentTitle" aria-describedby="cookieConsentDesc">
|
||||||
|
<div class="cookie-consent-container">
|
||||||
|
<div class="cookie-consent-content">
|
||||||
|
<div class="cookie-consent-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<circle cx="8" cy="9" r="1" fill="currentColor"/>
|
||||||
|
<circle cx="15" cy="8" r="1" fill="currentColor"/>
|
||||||
|
<circle cx="10" cy="14" r="1" fill="currentColor"/>
|
||||||
|
<circle cx="16" cy="13" r="1" fill="currentColor"/>
|
||||||
|
<circle cx="13" cy="17" r="1" fill="currentColor"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="cookie-consent-text">
|
||||||
|
<h3 id="cookieConsentTitle">Cookie-Einstellungen</h3>
|
||||||
|
<p id="cookieConsentDesc">
|
||||||
|
Wir verwenden Cookies, um Ihnen die bestmögliche Erfahrung auf unserer Website zu bieten.
|
||||||
|
Technisch notwendige Cookies sind für die Funktionalität erforderlich.
|
||||||
|
<a href="/datenschutz">Mehr erfahren</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cookie-consent-actions">
|
||||||
|
<button type="button" id="cookieAcceptAll" class="btn btn-primary">Alle akzeptieren</button>
|
||||||
|
<button type="button" id="cookieAcceptEssential" class="btn btn-secondary">Nur notwendige</button>
|
||||||
|
<button type="button" id="cookieSettings" class="btn btn-text">Einstellungen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cookieSettingsPanel" class="cookie-settings-panel" style="display: none;">
|
||||||
|
<div class="cookie-settings-content">
|
||||||
|
<h4>Cookie-Einstellungen</h4>
|
||||||
|
<div class="cookie-option">
|
||||||
|
<div class="cookie-option-info">
|
||||||
|
<strong>Notwendige Cookies</strong>
|
||||||
|
<p>Diese Cookies sind für die Grundfunktionen der Website erforderlich.</p>
|
||||||
|
</div>
|
||||||
|
<label class="cookie-toggle disabled">
|
||||||
|
<input type="checkbox" checked disabled>
|
||||||
|
<span class="cookie-toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="cookie-option">
|
||||||
|
<div class="cookie-option-info">
|
||||||
|
<strong>Analyse-Cookies</strong>
|
||||||
|
<p>Helfen uns zu verstehen, wie Besucher unsere Website nutzen.</p>
|
||||||
|
</div>
|
||||||
|
<label class="cookie-toggle">
|
||||||
|
<input type="checkbox" id="cookieAnalytics">
|
||||||
|
<span class="cookie-toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="cookie-option">
|
||||||
|
<div class="cookie-option-info">
|
||||||
|
<strong>Marketing-Cookies</strong>
|
||||||
|
<p>Werden verwendet, um relevante Werbung anzuzeigen.</p>
|
||||||
|
</div>
|
||||||
|
<label class="cookie-toggle">
|
||||||
|
<input type="checkbox" id="cookieMarketing">
|
||||||
|
<span class="cookie-toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="cookie-settings-actions">
|
||||||
|
<button type="button" id="cookieSaveSettings" class="btn btn-primary">Einstellungen speichern</button>
|
||||||
|
<button type="button" id="cookieCloseSettings" class="btn btn-secondary">Abbrechen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
|
||||||
|
// Standard: keine Analyse/Marketing-Cookies bis zur Einwilligung
|
||||||
|
gtag('consent', 'default', {
|
||||||
|
analytics_storage: 'denied',
|
||||||
|
ad_storage: 'denied',
|
||||||
|
ad_user_data: 'denied',
|
||||||
|
ad_personalization: 'denied'
|
||||||
|
});
|
||||||
|
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', 'G-EF0E9VPMTD', {
|
||||||
|
anonymize_ip: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Übergibt Consent-Änderungen aus dem eigenen Cookie-Banner an GA
|
||||||
|
window.addEventListener('cookieConsentUpdated', function (event) {
|
||||||
|
var payload = event && event.detail ? event.detail : {};
|
||||||
|
var consent = payload.consent ? payload.consent : payload;
|
||||||
|
var analyticsGranted = !!(consent && consent.analytics);
|
||||||
|
var marketingGranted = !!(consent && consent.marketing);
|
||||||
|
|
||||||
|
gtag('consent', 'update', {
|
||||||
|
analytics_storage: analyticsGranted ? 'granted' : 'denied',
|
||||||
|
ad_storage: marketingGranted ? 'granted' : 'denied',
|
||||||
|
ad_user_data: marketingGranted ? 'granted' : 'denied',
|
||||||
|
ad_personalization: marketingGranted ? 'granted' : 'denied'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-EF0E9VPMTD"></script>
|
||||||
|
|
||||||
|
<script src="/assets/js/main.js" defer></script>
|
||||||
|
<script src="/assets/js/cookie-consent.js" defer></script>
|
||||||
|
<?php if (isset($additional_scripts)): ?>
|
||||||
|
<?php foreach ($additional_scripts as $script): ?>
|
||||||
|
<script src="<?php echo htmlspecialchars($script, ENT_QUOTES, 'UTF-8'); ?>" defer></script>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
125
public/includes/functions.php
Normal file
125
public/includes/functions.php
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
|
||||||
|
ini_set('session.cookie_httponly', 1);
|
||||||
|
ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) ? 1 : 0);
|
||||||
|
ini_set('session.cookie_samesite', 'Strict');
|
||||||
|
ini_set('session.use_strict_mode', 1);
|
||||||
|
ini_set('session.use_only_cookies', 1);
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
|
||||||
|
if (!isset($_SESSION['initiated'])) {
|
||||||
|
session_regenerate_id(true);
|
||||||
|
$_SESSION['initiated'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!defined('DEBUG_MODE') || !DEBUG_MODE) {
|
||||||
|
ini_set('display_errors', 0);
|
||||||
|
ini_set('display_startup_errors', 0);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function includeHeader($title = '', $description = '', $page = '', $scripts = []) {
|
||||||
|
global $page_title, $page_description, $current_page, $additional_scripts;
|
||||||
|
|
||||||
|
|
||||||
|
$page_title = !empty($title)
|
||||||
|
? $title
|
||||||
|
: 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern';
|
||||||
|
|
||||||
|
$page_description = !empty($description)
|
||||||
|
? $description
|
||||||
|
: 'HexaHost.de - Zuverlässiges und preiswertes Hosting aus Niederbayern. VPS, VPC, Mail Gateway und Webhosting Lösungen.';
|
||||||
|
|
||||||
|
$current_page = $page;
|
||||||
|
$additional_scripts = $scripts;
|
||||||
|
|
||||||
|
include __DIR__ . '/header.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function includeFooter() {
|
||||||
|
include __DIR__ . '/footer.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function generateBreadcrumbs($breadcrumbs) {
|
||||||
|
echo '<div class="breadcrumb">';
|
||||||
|
$last_index = count($breadcrumbs) - 1;
|
||||||
|
|
||||||
|
foreach ($breadcrumbs as $index => $item) {
|
||||||
|
if ($index === $last_index) {
|
||||||
|
|
||||||
|
echo '<span>' . htmlspecialchars($item['title']) . '</span>';
|
||||||
|
} else {
|
||||||
|
|
||||||
|
echo '<a href="' . htmlspecialchars($item['url']) . '">' . htmlspecialchars($item['title']) . '</a>';
|
||||||
|
echo '<span>/</span>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function generateCSRFToken() {
|
||||||
|
if (!isset($_SESSION['csrf_token'])) {
|
||||||
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||||
|
}
|
||||||
|
return $_SESSION['csrf_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function validateCSRFToken($token) {
|
||||||
|
if (!isset($_SESSION['csrf_token']) || !is_string($token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!hash_equals($_SESSION['csrf_token'], $token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unset($_SESSION['csrf_token']);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function sanitizeHeaderValue(string $value): string {
|
||||||
|
return str_replace(["\r", "\n", "\0"], '', trim($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getClientIP(): string {
|
||||||
|
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])
|
||||||
|
&& filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP)) {
|
||||||
|
return $_SERVER['HTTP_CF_CONNECTING_IP'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
||||||
|
$isTrustedProxy = filter_var(
|
||||||
|
$remoteAddr,
|
||||||
|
FILTER_VALIDATE_IP,
|
||||||
|
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||||
|
) === false;
|
||||||
|
|
||||||
|
if ($isTrustedProxy) {
|
||||||
|
foreach (['HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR'] as $header) {
|
||||||
|
if (empty($_SERVER[$header])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$ip = trim(explode(',', $_SERVER[$header])[0]);
|
||||||
|
if (filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $remoteAddr;
|
||||||
|
}
|
||||||
|
?>
|
||||||
81
public/includes/header.php
Normal file
81
public/includes/header.php
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="dns-prefetch" href="//fonts.googleapis.com">
|
||||||
|
<link rel="dns-prefetch" href="//fonts.gstatic.com">
|
||||||
|
<link rel="dns-prefetch" href="//cdn.hexahost.de">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdn.hexahost.de" crossorigin>
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="preload" href="/assets/css/style.css" as="style">
|
||||||
|
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" as="style">
|
||||||
|
|
||||||
|
<title><?php echo isset($page_title) ? htmlspecialchars($page_title) : 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern'; ?></title>
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'HexaHost.de - Zuverlässiges und preiswertes Hosting aus Niederbayern. VPS, VPC, Mail Gateway und Webhosting Lösungen.'; ?>">
|
||||||
|
<meta name="robots" content="index, follow">
|
||||||
|
<meta name="author" content="HexaHost.de">
|
||||||
|
<meta name="theme-color" content="#0d0821">
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:site_name" content="HexaHost.de">
|
||||||
|
<meta property="og:title" content="<?php echo isset($page_title) ? htmlspecialchars($page_title) : 'HexaHost.de'; ?>">
|
||||||
|
<meta property="og:description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'Zuverlässiges Hosting aus Niederbayern'; ?>">
|
||||||
|
<meta property="og:locale" content="de_DE">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/assets/css/style.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/custom.css">
|
||||||
|
|
||||||
|
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Russo+One&family=Source+Sans+Pro:wght@300;400;600;700&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||||
|
<link rel="apple-touch-icon" href="/favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<?php if (isset($canonical_url)): ?>
|
||||||
|
<link rel="canonical" href="<?php echo htmlspecialchars($canonical_url); ?>">
|
||||||
|
<?php endif; ?>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="header">
|
||||||
|
<nav class="nav">
|
||||||
|
<div class="nav-container">
|
||||||
|
<div class="nav-logo">
|
||||||
|
<a href="/">
|
||||||
|
<img src="https://cdn.hexahost.de/assets/img/logo/8iFs123BynHQWHI5.png" alt="HexaHost.de Logo" class="logo-image">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<ul class="nav-menu">
|
||||||
|
<li><a href="/" class="nav-link <?php echo ($current_page === 'home') ? 'active' : ''; ?>">Home</a></li>
|
||||||
|
<li class="nav-dropdown">
|
||||||
|
<a href="#" class="nav-link <?php echo (in_array($current_page, ['vpc', 'vps', 'mail-gateway', 'webhosting'])) ? 'active' : ''; ?>">Produkte</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
|
||||||
|
<li><a href="/vps" class="<?php echo ($current_page === 'vps') ? 'active' : ''; ?>">Virtual Private Server</a></li>
|
||||||
|
<li><a href="/mail-gateway" class="<?php echo ($current_page === 'mail-gateway') ? 'active' : ''; ?>">Mail Gateway</a></li>
|
||||||
|
<li><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="/it-dienstleistungen" class="nav-link <?php echo ($current_page === 'it-dienstleistungen') ? 'active' : ''; ?>">IT-Dienstleistungen</a></li>
|
||||||
|
<li><a href="/about" class="nav-link <?php echo ($current_page === 'about') ? 'active' : ''; ?>">Über mich</a></li>
|
||||||
|
<li><a href="/contact" class="nav-link <?php echo ($current_page === 'contact') ? 'active' : ''; ?>">Kontakt</a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="nav-toggle">
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern';
|
$page_title = 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern';
|
||||||
$page_description = 'HexaHost.de - Zuverlässiges und preiswertes Hosting aus Niederbayern. VPS, VPC, Mail Gateway und Webhosting Lösungen.';
|
$page_description = 'HexaHost.de - Zuverlässiges und preiswertes Hosting aus Niederbayern. VPS, VPC, Mail Gateway und Webhosting Lösungen.';
|
||||||
$current_page = 'home';
|
$current_page = 'home';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Hero Section -->
|
|
||||||
<section class="hero">
|
<section class="hero">
|
||||||
<div class="hero-container">
|
<div class="hero-container">
|
||||||
<div class="hero-content">
|
<div class="hero-content">
|
||||||
@@ -44,7 +44,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Products Section -->
|
|
||||||
<section id="products" class="products">
|
<section id="products" class="products">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -54,7 +54,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="products-grid">
|
<div class="products-grid">
|
||||||
<div class="product-card glass-card"<?php echo productHiddenAttr('vpc'); ?>>
|
<div class="product-card glass-card">
|
||||||
<div class="product-icon">
|
<div class="product-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M4 7V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v3"/>
|
<path d="M4 7V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v3"/>
|
||||||
@@ -74,7 +74,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</ul>
|
</ul>
|
||||||
<a href="/vpc" class="btn btn-primary">Mehr erfahren</a>
|
<a href="/vpc" class="btn btn-primary">Mehr erfahren</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="product-card glass-card"<?php echo productHiddenAttr('vps'); ?>>
|
<div class="product-card glass-card">
|
||||||
<div class="product-icon">
|
<div class="product-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||||||
@@ -92,7 +92,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</ul>
|
</ul>
|
||||||
<a href="/vps" class="btn btn-primary">Mehr erfahren</a>
|
<a href="/vps" class="btn btn-primary">Mehr erfahren</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="product-card glass-card"<?php echo productHiddenAttr('mail-gateway'); ?>>
|
<div class="product-card glass-card">
|
||||||
<div class="product-icon">
|
<div class="product-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
|
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
|
||||||
@@ -150,7 +150,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- IT Services Section -->
|
|
||||||
<section class="features">
|
<section class="features">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -192,7 +192,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Features Section -->
|
|
||||||
<section class="features">
|
<section class="features">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -248,7 +248,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CTA Section -->
|
|
||||||
<section class="cta">
|
<section class="cta">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="cta-content glass-card">
|
<div class="cta-content glass-card">
|
||||||
@@ -265,6 +265,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = 'IT-Dienstleistungen - HexaHost.de | Privat & Gewerblich';
|
$page_title = 'IT-Dienstleistungen - HexaHost.de | Privat & Gewerblich';
|
||||||
$page_description = 'IT-Dienstleistungen von HexaHost.de mit Fokus auf Privatkunden und ergänzend für gewerbliche Anforderungen.';
|
$page_description = 'IT-Dienstleistungen von HexaHost.de mit Fokus auf Privatkunden und ergänzend für gewerbliche Anforderungen.';
|
||||||
$current_page = 'it-dienstleistungen';
|
$current_page = 'it-dienstleistungen';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Services Hero -->
|
|
||||||
<section class="about-hero">
|
<section class="about-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="about-hero-content">
|
<div class="about-hero-content">
|
||||||
@@ -32,7 +32,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Target Groups -->
|
|
||||||
<section class="values">
|
<section class="values">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -60,7 +60,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Services Grid -->
|
|
||||||
<section class="products">
|
<section class="products">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -128,7 +128,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CTA -->
|
|
||||||
<section class="cta">
|
<section class="cta">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="cta-content glass-card">
|
<div class="cta-content glass-card">
|
||||||
@@ -143,6 +143,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
require_once __DIR__ . '/../backend/config/products-config.php';
|
require_once __DIR__ . '/../backend/config/products-config.php';
|
||||||
|
|
||||||
// Produkt-Daten aus Config laden
|
|
||||||
$product = getProduct('mail-gateway');
|
$product = getProduct('mail-gateway');
|
||||||
$packages = getProductPackages('mail-gateway');
|
$packages = getProductPackages('mail-gateway');
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = $product['page_title'];
|
$page_title = $product['page_title'];
|
||||||
$page_description = $product['page_description'];
|
$page_description = $product['page_description'];
|
||||||
$current_page = 'mail-gateway';
|
$current_page = 'mail-gateway';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Product Hero -->
|
|
||||||
<section class="product-hero">
|
<section class="product-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="product-hero-content">
|
<div class="product-hero-content">
|
||||||
@@ -59,7 +59,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Mail Gateway Packages -->
|
|
||||||
<section class="packages">
|
<section class="packages">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -74,7 +74,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Security Features -->
|
|
||||||
<section class="technical-details">
|
<section class="technical-details">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -129,7 +129,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Use Cases -->
|
|
||||||
<section class="use-cases">
|
<section class="use-cases">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -159,15 +159,15 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CTA Section -->
|
|
||||||
<section class="cta">
|
<section class="cta">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="cta-content glass-card">
|
<div class="cta-content glass-card">
|
||||||
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
|
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
|
||||||
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
|
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
|
||||||
<div class="cta-actions">
|
<div class="cta-actions">
|
||||||
<a href="<?php echo htmlspecialchars(getProductOrderUrl('mail-gateway'), ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-primary">Jetzt bestellen</a>
|
<a href="contact.php?product=mail-gateway" class="btn btn-primary">Jetzt bestellen</a>
|
||||||
<a href="contact.php" class="btn btn-secondary">Beratung anfordern</a>
|
<a href="/contact" class="btn btn-secondary">Beratung anfordern</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,6 +175,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -2,43 +2,43 @@
|
|||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hexahost.de/</loc>
|
<loc>https://hexahost.de/</loc>
|
||||||
<lastmod>2026-05-28</lastmod>
|
<lastmod>2024-01-01</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>1.0</priority>
|
<priority>1.0</priority>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hexahost.de/vpc.html</loc>
|
<loc>https://hexahost.de/vpc.html</loc>
|
||||||
<lastmod>2026-05-28</lastmod>
|
<lastmod>2024-01-01</lastmod>
|
||||||
<changefreq>monthly</changefreq>
|
<changefreq>monthly</changefreq>
|
||||||
<priority>0.9</priority>
|
<priority>0.9</priority>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hexahost.de/vps.html</loc>
|
<loc>https://hexahost.de/vps.html</loc>
|
||||||
<lastmod>2026-05-28</lastmod>
|
<lastmod>2024-01-01</lastmod>
|
||||||
<changefreq>monthly</changefreq>
|
<changefreq>monthly</changefreq>
|
||||||
<priority>0.9</priority>
|
<priority>0.9</priority>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hexahost.de/mail-gateway.html</loc>
|
<loc>https://hexahost.de/mail-gateway.html</loc>
|
||||||
<lastmod>2026-05-28</lastmod>
|
<lastmod>2024-01-01</lastmod>
|
||||||
<changefreq>monthly</changefreq>
|
<changefreq>monthly</changefreq>
|
||||||
<priority>0.9</priority>
|
<priority>0.9</priority>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hexahost.de/webhosting.html</loc>
|
<loc>https://hexahost.de/webhosting.html</loc>
|
||||||
<lastmod>2026-05-28</lastmod>
|
<lastmod>2024-01-01</lastmod>
|
||||||
<changefreq>monthly</changefreq>
|
<changefreq>monthly</changefreq>
|
||||||
<priority>0.9</priority>
|
<priority>0.9</priority>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hexahost.de/about.html</loc>
|
<loc>https://hexahost.de/about.html</loc>
|
||||||
<lastmod>2026-05-28</lastmod>
|
<lastmod>2024-01-01</lastmod>
|
||||||
<changefreq>monthly</changefreq>
|
<changefreq>monthly</changefreq>
|
||||||
<priority>0.7</priority>
|
<priority>0.7</priority>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hexahost.de/contact.html</loc>
|
<loc>https://hexahost.de/contact.html</loc>
|
||||||
<lastmod>2026-05-28</lastmod>
|
<lastmod>2024-01-01</lastmod>
|
||||||
<changefreq>monthly</changefreq>
|
<changefreq>monthly</changefreq>
|
||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
</url>
|
</url>
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
require_once __DIR__ . '/../backend/config/products-config.php';
|
require_once __DIR__ . '/../backend/config/products-config.php';
|
||||||
|
|
||||||
// Produkt-Daten aus Config laden
|
|
||||||
$product = getProduct('vpc');
|
$product = getProduct('vpc');
|
||||||
$packages = getProductPackages('vpc');
|
$packages = getProductPackages('vpc');
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = $product['page_title'];
|
$page_title = $product['page_title'];
|
||||||
$page_description = $product['page_description'];
|
$page_description = $product['page_description'];
|
||||||
$current_page = 'vpc';
|
$current_page = 'vpc';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Product Hero -->
|
|
||||||
<section class="product-hero">
|
<section class="product-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="product-hero-content">
|
<div class="product-hero-content">
|
||||||
@@ -58,7 +58,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- VPC Packages -->
|
|
||||||
<section class="packages">
|
<section class="packages">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -73,7 +73,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Technical Details -->
|
|
||||||
<section class="technical-details">
|
<section class="technical-details">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -129,7 +129,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Use Cases -->
|
|
||||||
<section class="use-cases">
|
<section class="use-cases">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -159,15 +159,15 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CTA Section -->
|
|
||||||
<section class="cta">
|
<section class="cta">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="cta-content glass-card">
|
<div class="cta-content glass-card">
|
||||||
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
|
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
|
||||||
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
|
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
|
||||||
<div class="cta-actions">
|
<div class="cta-actions">
|
||||||
<a href="<?php echo htmlspecialchars(getProductOrderUrl('vpc'), ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-primary">Jetzt bestellen</a>
|
<a href="contact.php?product=vpc" class="btn btn-primary">Jetzt bestellen</a>
|
||||||
<a href="contact.php" class="btn btn-secondary">Beratung anfordern</a>
|
<a href="/contact" class="btn btn-secondary">Beratung anfordern</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,6 +175,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
require_once __DIR__ . '/../backend/config/products-config.php';
|
require_once __DIR__ . '/../backend/config/products-config.php';
|
||||||
|
|
||||||
// Produkt-Daten aus Config laden
|
|
||||||
$product = getProduct('vps');
|
$product = getProduct('vps');
|
||||||
$packages = getProductPackages('vps');
|
$packages = getProductPackages('vps');
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = $product['page_title'];
|
$page_title = $product['page_title'];
|
||||||
$page_description = $product['page_description'];
|
$page_description = $product['page_description'];
|
||||||
$current_page = 'vps';
|
$current_page = 'vps';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Product Hero -->
|
|
||||||
<section class="product-hero">
|
<section class="product-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="product-hero-content">
|
<div class="product-hero-content">
|
||||||
@@ -63,7 +63,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- VPS Packages -->
|
|
||||||
<section class="packages">
|
<section class="packages">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -78,7 +78,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Technical Details -->
|
|
||||||
<section class="technical-details">
|
<section class="technical-details">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -134,7 +134,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Use Cases -->
|
|
||||||
<section class="use-cases">
|
<section class="use-cases">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -164,15 +164,15 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CTA Section -->
|
|
||||||
<section class="cta">
|
<section class="cta">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="cta-content glass-card">
|
<div class="cta-content glass-card">
|
||||||
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
|
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
|
||||||
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
|
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
|
||||||
<div class="cta-actions">
|
<div class="cta-actions">
|
||||||
<a href="<?php echo htmlspecialchars(getProductOrderUrl('vps'), ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-primary">Jetzt bestellen</a>
|
<a href="contact.php?product=vps" class="btn btn-primary">Jetzt bestellen</a>
|
||||||
<a href="contact.php" class="btn btn-secondary">Beratung anfordern</a>
|
<a href="/contact" class="btn btn-secondary">Beratung anfordern</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -180,6 +180,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
require_once __DIR__ . '/../backend/config/products-config.php';
|
require_once __DIR__ . '/../backend/config/products-config.php';
|
||||||
|
|
||||||
// Produkt-Daten aus Config laden
|
|
||||||
$product = getProduct('webhosting');
|
$product = getProduct('webhosting');
|
||||||
$packages = getProductPackages('webhosting');
|
$packages = getProductPackages('webhosting');
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = $product['page_title'];
|
$page_title = $product['page_title'];
|
||||||
$page_description = $product['page_description'];
|
$page_description = $product['page_description'];
|
||||||
$current_page = 'webhosting';
|
$current_page = 'webhosting';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<!-- Product Hero -->
|
|
||||||
<section class="product-hero">
|
<section class="product-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="product-hero-content">
|
<div class="product-hero-content">
|
||||||
@@ -60,7 +60,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Webhosting Packages -->
|
|
||||||
<section class="packages">
|
<section class="packages">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -75,7 +75,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Technical Details -->
|
|
||||||
<section class="technical-details">
|
<section class="technical-details">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -95,7 +95,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
<polyline points="10,9 9,9 8,9"/>
|
<polyline points="10,9 9,9 8,9"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3>Plesk</h3>
|
<h3>cPanel/Webmin</h3>
|
||||||
<p>Benutzerfreundliche Verwaltungsoberfläche für einfache Website-Verwaltung und E-Mail-Konfiguration.</p>
|
<p>Benutzerfreundliche Verwaltungsoberfläche für einfache Website-Verwaltung und E-Mail-Konfiguration.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card glass-card">
|
<div class="detail-card glass-card">
|
||||||
@@ -133,7 +133,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Use Cases -->
|
|
||||||
<section class="use-cases">
|
<section class="use-cases">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -163,15 +163,15 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CTA Section -->
|
|
||||||
<section class="cta">
|
<section class="cta">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="cta-content glass-card">
|
<div class="cta-content glass-card">
|
||||||
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
|
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
|
||||||
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
|
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
|
||||||
<div class="cta-actions">
|
<div class="cta-actions">
|
||||||
<a href="<?php echo htmlspecialchars(getProductOrderUrl('webhosting'), ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-primary">Jetzt bestellen</a>
|
<a href="contact.php?product=webhosting" class="btn btn-primary">Jetzt bestellen</a>
|
||||||
<a href="contact.php" class="btn btn-secondary">Beratung anfordern</a>
|
<a href="/contact" class="btn btn-secondary">Beratung anfordern</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -179,6 +179,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../backend/includes/functions.php';
|
require_once __DIR__ . '/../backend/includes/functions.php';
|
||||||
|
|
||||||
// Page configuration
|
|
||||||
$page_title = 'Widerrufsbelehrung - HexaHost.de';
|
$page_title = 'Widerrufsbelehrung - HexaHost.de';
|
||||||
$page_description = 'Widerrufsbelehrung und Muster-Widerrufsformular von HexaHost Inh. Samuel Müller.';
|
$page_description = 'Widerrufsbelehrung und Muster-Widerrufsformular von HexaHost Inh. Samuel Müller.';
|
||||||
$current_page = 'widerruf';
|
$current_page = 'widerruf';
|
||||||
|
|
||||||
// Include header
|
|
||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
@@ -131,6 +131,6 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Include footer
|
|
||||||
includeFooter();
|
includeFooter();
|
||||||
?>
|
?>
|
||||||
|
|||||||
Binary file not shown.
@@ -1,463 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import hashlib
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
from collections import defaultdict
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
TEXT_EXTENSIONS = {".php", ".html", ".htm", ".xml", ".txt", ".js", ".css"}
|
|
||||||
HASH_SUFFIX_RE = re.compile(r"\.[a-f0-9]{12}$", re.I)
|
|
||||||
|
|
||||||
|
|
||||||
def strip_comments_keep_strings(text: str) -> str:
|
|
||||||
out = []
|
|
||||||
i = 0
|
|
||||||
n = len(text)
|
|
||||||
in_single = False
|
|
||||||
in_double = False
|
|
||||||
in_template = False
|
|
||||||
escape = False
|
|
||||||
in_line_comment = False
|
|
||||||
in_block_comment = False
|
|
||||||
|
|
||||||
while i < n:
|
|
||||||
ch = text[i]
|
|
||||||
nxt = text[i + 1] if i + 1 < n else ""
|
|
||||||
|
|
||||||
if in_line_comment:
|
|
||||||
if ch == "\n":
|
|
||||||
in_line_comment = False
|
|
||||||
out.append(ch)
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if in_block_comment:
|
|
||||||
if ch == "*" and nxt == "/":
|
|
||||||
in_block_comment = False
|
|
||||||
i += 2
|
|
||||||
else:
|
|
||||||
if ch == "\n":
|
|
||||||
out.append("\n")
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if in_single or in_double or in_template:
|
|
||||||
out.append(ch)
|
|
||||||
if escape:
|
|
||||||
escape = False
|
|
||||||
elif ch == "\\":
|
|
||||||
escape = True
|
|
||||||
elif in_single and ch == "'":
|
|
||||||
in_single = False
|
|
||||||
elif in_double and ch == '"':
|
|
||||||
in_double = False
|
|
||||||
elif in_template and ch == "`":
|
|
||||||
in_template = False
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if ch == "/" and nxt == "/":
|
|
||||||
in_line_comment = True
|
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
if ch == "/" and nxt == "*":
|
|
||||||
in_block_comment = True
|
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
|
|
||||||
if ch == "'":
|
|
||||||
in_single = True
|
|
||||||
out.append(ch)
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
if ch == '"':
|
|
||||||
in_double = True
|
|
||||||
out.append(ch)
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
if ch == "`":
|
|
||||||
in_template = True
|
|
||||||
out.append(ch)
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
out.append(ch)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
return "".join(out)
|
|
||||||
|
|
||||||
|
|
||||||
def strip_php_comments(text: str) -> str:
|
|
||||||
out = []
|
|
||||||
i = 0
|
|
||||||
n = len(text)
|
|
||||||
in_single = False
|
|
||||||
in_double = False
|
|
||||||
in_line_comment = False
|
|
||||||
in_block_comment = False
|
|
||||||
escape = False
|
|
||||||
|
|
||||||
while i < n:
|
|
||||||
ch = text[i]
|
|
||||||
nxt = text[i + 1] if i + 1 < n else ""
|
|
||||||
|
|
||||||
if in_line_comment:
|
|
||||||
if ch == "\n":
|
|
||||||
in_line_comment = False
|
|
||||||
out.append("\n")
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if in_block_comment:
|
|
||||||
if ch == "*" and nxt == "/":
|
|
||||||
in_block_comment = False
|
|
||||||
i += 2
|
|
||||||
else:
|
|
||||||
if ch == "\n":
|
|
||||||
out.append("\n")
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if in_single or in_double:
|
|
||||||
out.append(ch)
|
|
||||||
if escape:
|
|
||||||
escape = False
|
|
||||||
elif ch == "\\":
|
|
||||||
escape = True
|
|
||||||
elif in_single and ch == "'":
|
|
||||||
in_single = False
|
|
||||||
elif in_double and ch == '"':
|
|
||||||
in_double = False
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if ch == "/" and nxt == "/":
|
|
||||||
in_line_comment = True
|
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
if ch == "#":
|
|
||||||
in_line_comment = True
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
if ch == "/" and nxt == "*":
|
|
||||||
in_block_comment = True
|
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
|
|
||||||
if ch == "'":
|
|
||||||
in_single = True
|
|
||||||
elif ch == '"':
|
|
||||||
in_double = True
|
|
||||||
|
|
||||||
out.append(ch)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
return "".join(out)
|
|
||||||
|
|
||||||
|
|
||||||
def minify_css_fallback(text: str) -> str:
|
|
||||||
text = strip_comments_keep_strings(text)
|
|
||||||
text = re.sub(r"\s+", " ", text)
|
|
||||||
text = re.sub(r"\s*([{}:;,>+~])\s*", r"\1", text)
|
|
||||||
return text.strip()
|
|
||||||
|
|
||||||
|
|
||||||
def minify_js_fallback(text: str) -> str:
|
|
||||||
text = strip_comments_keep_strings(text)
|
|
||||||
text = re.sub(r"\s+", " ", text)
|
|
||||||
text = re.sub(r"\s*([{}:;,()=+\-*/<>!&|?])\s*", r"\1", text)
|
|
||||||
return text.strip()
|
|
||||||
|
|
||||||
|
|
||||||
def canonical_asset_base(stem: str) -> str:
|
|
||||||
name = stem
|
|
||||||
while HASH_SUFFIX_RE.search(name):
|
|
||||||
name = HASH_SUFFIX_RE.sub("", name)
|
|
||||||
return name
|
|
||||||
|
|
||||||
|
|
||||||
def is_skipped_asset(path: Path) -> bool:
|
|
||||||
lowered = path.as_posix().lower()
|
|
||||||
if ".min." in path.name or ".obf." in path.name or ".deob." in path.name:
|
|
||||||
return True
|
|
||||||
if "deobfuscated" in lowered:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_valid_source_content(content: str) -> bool:
|
|
||||||
if "[javascript-obfuscator-cli]" in content:
|
|
||||||
return False
|
|
||||||
return len(content.strip()) >= 20
|
|
||||||
|
|
||||||
|
|
||||||
def collect_asset_groups(asset_root: Path) -> dict[tuple[Path, str, str], list[Path]]:
|
|
||||||
groups: dict[tuple[Path, str, str], list[Path]] = defaultdict(list)
|
|
||||||
for ext in (".js", ".css"):
|
|
||||||
for file_path in sorted(asset_root.rglob(f"*{ext}")):
|
|
||||||
if is_skipped_asset(file_path):
|
|
||||||
continue
|
|
||||||
base = canonical_asset_base(file_path.stem)
|
|
||||||
key = (file_path.parent, base, ext)
|
|
||||||
groups[key].append(file_path)
|
|
||||||
return groups
|
|
||||||
|
|
||||||
|
|
||||||
def pick_source_file(paths: list[Path], base: str, ext: str) -> Path | None:
|
|
||||||
if not paths:
|
|
||||||
return None
|
|
||||||
|
|
||||||
parent = paths[0].parent
|
|
||||||
plain = parent / f"{base}{ext}"
|
|
||||||
ordered: list[Path] = []
|
|
||||||
if plain in paths:
|
|
||||||
ordered.append(plain)
|
|
||||||
for candidate in sorted(paths, key=lambda p: len(p.name)):
|
|
||||||
if candidate not in ordered:
|
|
||||||
ordered.append(candidate)
|
|
||||||
|
|
||||||
for candidate in ordered:
|
|
||||||
try:
|
|
||||||
content = candidate.read_text(encoding="utf-8")
|
|
||||||
except (OSError, UnicodeDecodeError):
|
|
||||||
continue
|
|
||||||
if is_valid_source_content(content):
|
|
||||||
return candidate
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def cleanup_invalid_siblings(paths: list[Path], source: Path) -> None:
|
|
||||||
for path in paths:
|
|
||||||
if path == source or not path.exists():
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
content = path.read_text(encoding="utf-8")
|
|
||||||
except (OSError, UnicodeDecodeError):
|
|
||||||
content = ""
|
|
||||||
if not is_valid_source_content(content):
|
|
||||||
path.unlink()
|
|
||||||
|
|
||||||
|
|
||||||
def run_cmd(command: list[str], cwd: Path) -> None:
|
|
||||||
proc = subprocess.run(
|
|
||||||
command,
|
|
||||||
cwd=str(cwd),
|
|
||||||
text=True,
|
|
||||||
capture_output=True,
|
|
||||||
check=False,
|
|
||||||
)
|
|
||||||
if proc.returncode != 0:
|
|
||||||
raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or "command failed")
|
|
||||||
|
|
||||||
|
|
||||||
def process_js(path: Path, cwd: Path) -> None:
|
|
||||||
original = path.read_text(encoding="utf-8")
|
|
||||||
if not is_valid_source_content(original):
|
|
||||||
raise ValueError(
|
|
||||||
f"invalid or corrupted JS source: {path} "
|
|
||||||
f"(restore e.g. 'git checkout dev -- {path.as_posix()}')"
|
|
||||||
)
|
|
||||||
|
|
||||||
if shutil.which("npx"):
|
|
||||||
tmpdir = Path(tempfile.mkdtemp())
|
|
||||||
try:
|
|
||||||
src = tmpdir / "input.js"
|
|
||||||
out = tmpdir / "output.js"
|
|
||||||
src.write_text(original, encoding="utf-8")
|
|
||||||
run_cmd(
|
|
||||||
[
|
|
||||||
"npx",
|
|
||||||
"--yes",
|
|
||||||
"terser",
|
|
||||||
str(src),
|
|
||||||
"-o",
|
|
||||||
str(src),
|
|
||||||
"--compress",
|
|
||||||
"--mangle",
|
|
||||||
"--comments",
|
|
||||||
"false",
|
|
||||||
],
|
|
||||||
cwd,
|
|
||||||
)
|
|
||||||
run_cmd(
|
|
||||||
[
|
|
||||||
"npx",
|
|
||||||
"--yes",
|
|
||||||
"javascript-obfuscator",
|
|
||||||
str(src),
|
|
||||||
"--output",
|
|
||||||
str(out),
|
|
||||||
"--compact",
|
|
||||||
"true",
|
|
||||||
"--control-flow-flattening",
|
|
||||||
"true",
|
|
||||||
"--dead-code-injection",
|
|
||||||
"true",
|
|
||||||
"--string-array",
|
|
||||||
"true",
|
|
||||||
"--string-array-encoding",
|
|
||||||
"base64",
|
|
||||||
"--target",
|
|
||||||
"browser-no-eval",
|
|
||||||
"--source-map",
|
|
||||||
"false",
|
|
||||||
],
|
|
||||||
cwd,
|
|
||||||
)
|
|
||||||
if not out.exists():
|
|
||||||
raise RuntimeError("obfuscator produced no output file")
|
|
||||||
result = out.read_text(encoding="utf-8")
|
|
||||||
if not is_valid_source_content(result):
|
|
||||||
raise RuntimeError("obfuscator output looks invalid")
|
|
||||||
path.write_text(result.strip() + "\n", encoding="utf-8")
|
|
||||||
return
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
|
||||||
|
|
||||||
path.write_text(minify_js_fallback(original) + "\n", encoding="utf-8")
|
|
||||||
|
|
||||||
|
|
||||||
def process_css(path: Path, cwd: Path) -> None:
|
|
||||||
original = path.read_text(encoding="utf-8")
|
|
||||||
if shutil.which("npx"):
|
|
||||||
tmpdir = Path(tempfile.mkdtemp())
|
|
||||||
try:
|
|
||||||
src = tmpdir / "input.css"
|
|
||||||
out = tmpdir / "output.css"
|
|
||||||
src.write_text(original, encoding="utf-8")
|
|
||||||
run_cmd(
|
|
||||||
[
|
|
||||||
"npx",
|
|
||||||
"--yes",
|
|
||||||
"clean-css-cli",
|
|
||||||
str(src),
|
|
||||||
"-o",
|
|
||||||
str(out),
|
|
||||||
"--skip-rebase",
|
|
||||||
"-O2",
|
|
||||||
],
|
|
||||||
cwd,
|
|
||||||
)
|
|
||||||
path.write_text(out.read_text(encoding="utf-8").strip() + "\n", encoding="utf-8")
|
|
||||||
return
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
|
||||||
path.write_text(minify_css_fallback(original) + "\n", encoding="utf-8")
|
|
||||||
|
|
||||||
|
|
||||||
def process_php(path: Path) -> None:
|
|
||||||
original = path.read_text(encoding="utf-8")
|
|
||||||
stripped = strip_php_comments(original)
|
|
||||||
path.write_text(stripped, encoding="utf-8")
|
|
||||||
|
|
||||||
|
|
||||||
def hash_file(path: Path) -> str:
|
|
||||||
return hashlib.sha256(path.read_bytes()).hexdigest()[:12]
|
|
||||||
|
|
||||||
|
|
||||||
def replace_references(root: Path, mapping: dict[str, str]) -> None:
|
|
||||||
for candidate in root.rglob("*"):
|
|
||||||
if not candidate.is_file() or candidate.suffix.lower() not in TEXT_EXTENSIONS:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
content = candidate.read_text(encoding="utf-8")
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
continue
|
|
||||||
updated = content
|
|
||||||
for src, dst in sorted(mapping.items(), key=lambda item: len(item[0]), reverse=True):
|
|
||||||
updated = updated.replace(src, dst)
|
|
||||||
updated = updated.replace("/" + src, "/" + dst)
|
|
||||||
if updated != content:
|
|
||||||
candidate.write_text(updated, encoding="utf-8")
|
|
||||||
|
|
||||||
|
|
||||||
def build_hash_mapping(public_root: Path) -> dict[str, str]:
|
|
||||||
mapping: dict[str, str] = {}
|
|
||||||
asset_root = public_root / "assets"
|
|
||||||
if not asset_root.exists():
|
|
||||||
return mapping
|
|
||||||
|
|
||||||
groups = collect_asset_groups(asset_root)
|
|
||||||
for (parent, base, ext), paths in groups.items():
|
|
||||||
source = pick_source_file(paths, base, ext)
|
|
||||||
if source is None:
|
|
||||||
continue
|
|
||||||
digest = hash_file(source)
|
|
||||||
target = parent / f"{base}.{digest}{ext}"
|
|
||||||
rel_new = target.relative_to(public_root).as_posix()
|
|
||||||
|
|
||||||
for old in paths:
|
|
||||||
rel_old = old.relative_to(public_root).as_posix()
|
|
||||||
if rel_old != rel_new:
|
|
||||||
mapping[rel_old] = rel_new
|
|
||||||
|
|
||||||
if source != target:
|
|
||||||
if target.exists():
|
|
||||||
target.unlink()
|
|
||||||
source.replace(target)
|
|
||||||
|
|
||||||
for old in paths:
|
|
||||||
if old != target and old.exists():
|
|
||||||
old.unlink()
|
|
||||||
|
|
||||||
return mapping
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
|
||||||
parser = argparse.ArgumentParser(description="Release obfuscation build.")
|
|
||||||
parser.add_argument("--root", default=".", help="Repository root")
|
|
||||||
parser.add_argument("--hash-assets", action="store_true", help="Hash JS/CSS file names")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
repo_root = Path(args.root).resolve()
|
|
||||||
public_root = repo_root / "public"
|
|
||||||
|
|
||||||
if not public_root.exists():
|
|
||||||
print("public directory not found", file=sys.stderr)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
asset_root = public_root / "assets"
|
|
||||||
if asset_root.exists():
|
|
||||||
groups = collect_asset_groups(asset_root)
|
|
||||||
for (parent, base, ext), paths in sorted(groups.items()):
|
|
||||||
source = pick_source_file(paths, base, ext)
|
|
||||||
if source is None:
|
|
||||||
rel = (parent / f"{base}{ext}").relative_to(public_root)
|
|
||||||
print(
|
|
||||||
f"ERROR: No valid source for {rel}. "
|
|
||||||
f"Restore from dev, e.g.: git checkout dev -- {rel}",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
return 1
|
|
||||||
cleanup_invalid_siblings(paths, source)
|
|
||||||
if ext == ".js":
|
|
||||||
process_js(source, repo_root)
|
|
||||||
else:
|
|
||||||
process_css(source, repo_root)
|
|
||||||
|
|
||||||
for php in sorted(public_root.rglob("*.php")):
|
|
||||||
process_php(php)
|
|
||||||
for php in sorted((repo_root / "backend").rglob("*.php")):
|
|
||||||
process_php(php)
|
|
||||||
|
|
||||||
if args.hash_assets:
|
|
||||||
mapping = build_hash_mapping(public_root)
|
|
||||||
replace_references(repo_root, mapping)
|
|
||||||
|
|
||||||
print("Release obfuscation complete.")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
raise SystemExit(main())
|
|
||||||
185
scripts/publish-to-main.ps1
Normal file
185
scripts/publish-to-main.ps1
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Erstellt einen Production-Build und veroeffentlicht ihn auf den Branch main.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
1. Wechselt auf main und setzt ihn auf den Stand von dev
|
||||||
|
2. Entfernt Kommentare, minifiziert CSS, obfuskiert JavaScript
|
||||||
|
3. Committet und pusht main (optional)
|
||||||
|
4. Wechselt zurueck auf dev (Quellcode bleibt unveraendert)
|
||||||
|
|
||||||
|
.PARAMETER Push
|
||||||
|
Pusht main nach origin (Standard: nur lokaler Commit)
|
||||||
|
|
||||||
|
.PARAMETER DryRun
|
||||||
|
Fuehrt Git-Schritte nur simuliert aus (Build wird trotzdem erstellt)
|
||||||
|
|
||||||
|
.PARAMETER AllowDirty
|
||||||
|
Erlaubt uncommittete Aenderungen
|
||||||
|
|
||||||
|
.PARAMETER Message
|
||||||
|
Commit-Nachricht fuer den Production-Build
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\scripts\publish-to-main.ps1
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\scripts\publish-to-main.ps1 -Push
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[switch]$Push,
|
||||||
|
[switch]$DryRun,
|
||||||
|
[switch]$AllowDirty,
|
||||||
|
[string]$Message = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$Root = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||||
|
$BuildDir = Join-Path $Root "scripts\build"
|
||||||
|
$OriginalBranch = ""
|
||||||
|
|
||||||
|
function Write-Step([string]$Text) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "==> $Text" -ForegroundColor Cyan
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-GitClean {
|
||||||
|
$status = git -C $Root status --porcelain
|
||||||
|
if ($status) {
|
||||||
|
throw "Uncommittete Aenderungen im Repository. Bitte zuerst committen oder stashen."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Resolve-NodeTool([string]$ToolName) {
|
||||||
|
$command = Get-Command $ToolName -ErrorAction SilentlyContinue
|
||||||
|
if ($command) {
|
||||||
|
return $command.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
$candidates = @(
|
||||||
|
(Join-Path $env:ProgramFiles "nodejs\$ToolName.cmd"),
|
||||||
|
(Join-Path ${env:ProgramFiles(x86)} "nodejs\$ToolName.cmd"),
|
||||||
|
(Join-Path $env:LOCALAPPDATA "Programs\nodejs\$ToolName.cmd"),
|
||||||
|
"c:\Program Files\cursor\resources\app\resources\helpers\node.exe"
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($candidate in $candidates) {
|
||||||
|
if ($ToolName -eq "node" -and (Test-Path $candidate)) {
|
||||||
|
return $candidate
|
||||||
|
}
|
||||||
|
if ($ToolName -ne "node" -and (Test-Path $candidate)) {
|
||||||
|
return $candidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-Node {
|
||||||
|
$script:NodeExe = Resolve-NodeTool "node"
|
||||||
|
$script:NpmExe = Resolve-NodeTool "npm"
|
||||||
|
|
||||||
|
if (-not $script:NodeExe) {
|
||||||
|
throw "Node.js ist nicht installiert. Bitte Node.js 18+ installieren: https://nodejs.org/"
|
||||||
|
}
|
||||||
|
if (-not $script:NpmExe) {
|
||||||
|
throw "npm wurde nicht gefunden. Bitte Node.js inkl. npm installieren und PATH setzen."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Set-Location $Root
|
||||||
|
Ensure-Node
|
||||||
|
if (-not $AllowDirty) {
|
||||||
|
Ensure-GitClean
|
||||||
|
} else {
|
||||||
|
Write-Warning "AllowDirty aktiv - uncommittete Aenderungen werden mit veroeffentlicht."
|
||||||
|
}
|
||||||
|
|
||||||
|
$OriginalBranch = (git branch --show-current).Trim()
|
||||||
|
if ($OriginalBranch -ne "dev") {
|
||||||
|
Write-Warning "Empfohlen: Auf Branch 'dev' starten (aktuell: $OriginalBranch)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($Message)) {
|
||||||
|
$Message = "chore(release): production build $(Get-Date -Format 'yyyy-MM-dd HH:mm')"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Step "Installiere Build-Abhaengigkeiten"
|
||||||
|
Set-Location $BuildDir
|
||||||
|
if (-not $DryRun) {
|
||||||
|
& $NpmExe ci --no-fund --no-audit
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "npm ci fehlgeschlagen" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Step "Wechsle auf main und synchronisiere mit dev"
|
||||||
|
Set-Location $Root
|
||||||
|
if ($DryRun) {
|
||||||
|
Write-Host '[DryRun] git checkout main'
|
||||||
|
Write-Host '[DryRun] git reset --hard dev'
|
||||||
|
} else {
|
||||||
|
git checkout main
|
||||||
|
git reset --hard dev
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Step "Production-Build (Kommentare entfernen, JS obfuscaten)"
|
||||||
|
Set-Location $BuildDir
|
||||||
|
if ($DryRun) {
|
||||||
|
Write-Host '[DryRun] npm run build:in-place'
|
||||||
|
} else {
|
||||||
|
& $NpmExe run build:in-place
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "Production-Build fehlgeschlagen" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Step "Production-Build committen"
|
||||||
|
Set-Location $Root
|
||||||
|
if ($DryRun) {
|
||||||
|
Write-Host '[DryRun] git add -A'
|
||||||
|
Write-Host ('[DryRun] git commit -m "' + $Message + '"')
|
||||||
|
} else {
|
||||||
|
git add -A
|
||||||
|
$null = git diff --cached --quiet
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Warning "Keine Build-Aenderungen - nichts zu committen."
|
||||||
|
} else {
|
||||||
|
git commit -m $Message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Push) {
|
||||||
|
Write-Step "Push nach origin/main"
|
||||||
|
if ($DryRun) {
|
||||||
|
Write-Host '[DryRun] git push origin main'
|
||||||
|
} else {
|
||||||
|
git push origin main
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "Hinweis: Ohne -Push wurde nur lokal auf main gebaut." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Step "Zurueck auf $OriginalBranch"
|
||||||
|
if (-not $DryRun) {
|
||||||
|
if ([string]::IsNullOrWhiteSpace($OriginalBranch)) {
|
||||||
|
git checkout dev
|
||||||
|
} else {
|
||||||
|
git checkout $OriginalBranch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Production-Release abgeschlossen." -ForegroundColor Green
|
||||||
|
if (-not $Push -and -not $DryRun) {
|
||||||
|
Write-Host "Zum Veroeffentlichen: git push origin main" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host ('FEHLER: ' + $_.Exception.Message) -ForegroundColor Red
|
||||||
|
Set-Location $Root
|
||||||
|
if ($OriginalBranch -and -not $DryRun) {
|
||||||
|
git checkout $OriginalBranch 2>$null
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
187
scripts/publish-to-main.sh
Normal file
187
scripts/publish-to-main.sh
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Erstellt einen Production-Build und veröffentlicht ihn auf den Branch main.
|
||||||
|
#
|
||||||
|
# 1. Wechselt auf main und setzt ihn auf den Stand von dev
|
||||||
|
# 2. Entfernt Kommentare, minifiziert CSS, obfuskiert JavaScript
|
||||||
|
# 3. Committet und pusht main (optional)
|
||||||
|
# 4. Wechselt zurück auf den ursprünglichen Branch (dev bleibt unverändert)
|
||||||
|
#
|
||||||
|
# Nutzung:
|
||||||
|
# ./scripts/publish-to-main.sh
|
||||||
|
# ./scripts/publish-to-main.sh --push
|
||||||
|
# ./scripts/publish-to-main.sh --dry-run
|
||||||
|
# ./scripts/publish-to-main.sh --allow-dirty --message "chore(release): v1.2"
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PUSH=false
|
||||||
|
DRY_RUN=false
|
||||||
|
ALLOW_DIRTY=false
|
||||||
|
MESSAGE=""
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: publish-to-main.sh [OPTIONS]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--push Push nach origin/main
|
||||||
|
--dry-run Git-Schritte nur anzeigen (Build wird ausgeführt)
|
||||||
|
--allow-dirty Uncommittete Änderungen erlauben
|
||||||
|
--message TEXT Commit-Nachricht
|
||||||
|
-h, --help Hilfe anzeigen
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--push)
|
||||||
|
PUSH=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
DRY_RUN=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--allow-dirty)
|
||||||
|
ALLOW_DIRTY=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--message)
|
||||||
|
MESSAGE="${2:-}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unbekannte Option: $1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
BUILD_DIR="$ROOT/scripts/build"
|
||||||
|
ORIGINAL_BRANCH=""
|
||||||
|
|
||||||
|
step() {
|
||||||
|
echo ""
|
||||||
|
echo "==> $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_command() {
|
||||||
|
if ! command -v "$1" >/dev/null 2>&1; then
|
||||||
|
echo "FEHLER: '$1' nicht gefunden. Bitte installieren und PATH setzen." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_git_clean() {
|
||||||
|
if [[ -n "$(git -C "$ROOT" status --porcelain)" ]]; then
|
||||||
|
echo "FEHLER: Uncommittete Änderungen. Bitte zuerst committen oder stashen." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_on_error() {
|
||||||
|
echo ""
|
||||||
|
echo "FEHLER: Abgebrochen." >&2
|
||||||
|
cd "$ROOT" || true
|
||||||
|
if [[ -n "$ORIGINAL_BRANCH" && "$DRY_RUN" == false ]]; then
|
||||||
|
git checkout "$ORIGINAL_BRANCH" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup_on_error ERR
|
||||||
|
|
||||||
|
require_command node
|
||||||
|
require_command npm
|
||||||
|
require_command git
|
||||||
|
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
if [[ "$ALLOW_DIRTY" == false ]]; then
|
||||||
|
ensure_git_clean
|
||||||
|
else
|
||||||
|
echo "WARNUNG: --allow-dirty aktiv – uncommittete Änderungen werden mit veröffentlicht." >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
ORIGINAL_BRANCH="$(git branch --show-current | tr -d '[:space:]')"
|
||||||
|
if [[ "$ORIGINAL_BRANCH" != "dev" ]]; then
|
||||||
|
echo "WARNUNG: Empfohlen auf Branch 'dev' zu starten (aktuell: ${ORIGINAL_BRANCH:-detached})" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$MESSAGE" ]]; then
|
||||||
|
MESSAGE="chore(release): production build $(date '+%Y-%m-%d %H:%M')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "Installiere Build-Abhängigkeiten"
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
if [[ "$DRY_RUN" == false ]]; then
|
||||||
|
npm ci --no-fund --no-audit
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "Wechsle auf main und synchronisiere mit dev"
|
||||||
|
cd "$ROOT"
|
||||||
|
if [[ "$DRY_RUN" == true ]]; then
|
||||||
|
echo "[DryRun] git checkout main"
|
||||||
|
echo "[DryRun] git reset --hard dev"
|
||||||
|
else
|
||||||
|
git checkout main
|
||||||
|
git reset --hard dev
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "Production-Build (Kommentare entfernen, JS obfuscaten)"
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
if [[ "$DRY_RUN" == true ]]; then
|
||||||
|
echo "[DryRun] npm run build:in-place"
|
||||||
|
else
|
||||||
|
npm run build:in-place
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "Production-Build committen"
|
||||||
|
cd "$ROOT"
|
||||||
|
if [[ "$DRY_RUN" == true ]]; then
|
||||||
|
echo "[DryRun] git add -A"
|
||||||
|
echo "[DryRun] git commit -m \"$MESSAGE\""
|
||||||
|
else
|
||||||
|
git add -A
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
echo "WARNUNG: Keine Build-Änderungen – nichts zu committen." >&2
|
||||||
|
else
|
||||||
|
git commit -m "$MESSAGE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$PUSH" == true ]]; then
|
||||||
|
step "Push nach origin/main"
|
||||||
|
if [[ "$DRY_RUN" == true ]]; then
|
||||||
|
echo "[DryRun] git push origin main"
|
||||||
|
else
|
||||||
|
git push origin main
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Hinweis: Ohne --push wurde nur lokal auf main gebaut."
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "Zurück auf ${ORIGINAL_BRANCH:-dev}"
|
||||||
|
if [[ "$DRY_RUN" == false ]]; then
|
||||||
|
if [[ -n "$ORIGINAL_BRANCH" ]]; then
|
||||||
|
git checkout "$ORIGINAL_BRANCH"
|
||||||
|
else
|
||||||
|
git checkout dev
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
trap - ERR
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Production-Release abgeschlossen."
|
||||||
|
if [[ "$PUSH" == false && "$DRY_RUN" == false ]]; then
|
||||||
|
echo "Zum Veröffentlichen: git push origin main"
|
||||||
|
fi
|
||||||
46
scripts/run-build.ps1
Normal file
46
scripts/run-build.ps1
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Erstellt ein Production-Bundle unter dist/ (ohne Branch-Wechsel).
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[switch]$InPlace
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$Root = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||||
|
$BuildDir = Join-Path $Root "scripts\build"
|
||||||
|
|
||||||
|
function Resolve-NodeTool([string]$ToolName) {
|
||||||
|
$command = Get-Command $ToolName -ErrorAction SilentlyContinue
|
||||||
|
if ($command) { return $command.Source }
|
||||||
|
|
||||||
|
$candidates = @(
|
||||||
|
(Join-Path $env:ProgramFiles "nodejs\$ToolName.cmd"),
|
||||||
|
(Join-Path ${env:ProgramFiles(x86)} "nodejs\$ToolName.cmd")
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($candidate in $candidates) {
|
||||||
|
if (Test-Path $candidate) { return $candidate }
|
||||||
|
}
|
||||||
|
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$npm = Resolve-NodeTool "npm"
|
||||||
|
if (-not $npm) {
|
||||||
|
throw "npm nicht gefunden. Bitte Node.js installieren."
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Location $BuildDir
|
||||||
|
& $npm ci --no-fund --no-audit
|
||||||
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||||
|
|
||||||
|
if ($InPlace) {
|
||||||
|
& $npm run build:in-place
|
||||||
|
} else {
|
||||||
|
& $npm run build
|
||||||
|
}
|
||||||
|
|
||||||
|
exit $LASTEXITCODE
|
||||||
58
scripts/run-build.sh
Normal file
58
scripts/run-build.sh
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Erstellt ein Production-Bundle unter dist/ (ohne Branch-Wechsel).
|
||||||
|
#
|
||||||
|
# Nutzung:
|
||||||
|
# ./scripts/run-build.sh
|
||||||
|
# ./scripts/run-build.sh --in-place
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
IN_PLACE=false
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: run-build.sh [OPTIONS]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--in-place Build direkt im Repository (statt dist/)
|
||||||
|
-h, --help Hilfe anzeigen
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--in-place)
|
||||||
|
IN_PLACE=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unbekannte Option: $1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
BUILD_DIR="$ROOT/scripts/build"
|
||||||
|
|
||||||
|
if ! command -v npm >/dev/null 2>&1; then
|
||||||
|
echo "FEHLER: npm nicht gefunden. Bitte Node.js installieren." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
npm ci --no-fund --no-audit
|
||||||
|
|
||||||
|
if [[ "$IN_PLACE" == true ]]; then
|
||||||
|
npm run build:in-place
|
||||||
|
else
|
||||||
|
npm run build
|
||||||
|
fi
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Einmal pro Clone ausführen: Commit-Template + Conventional-Commits-Hook aktivieren
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
|
|
||||||
|
|
||||||
Push-Location $repoRoot
|
|
||||||
try {
|
|
||||||
git config --local commit.template .gitmessage
|
|
||||||
git config --local core.hooksPath .githooks
|
|
||||||
|
|
||||||
Write-Host "Git Hooks aktiv:" -ForegroundColor Green
|
|
||||||
Write-Host " commit.template = .gitmessage"
|
|
||||||
Write-Host " core.hooksPath = .githooks"
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Commit-Format: feat(scope): beschreibung"
|
|
||||||
} finally {
|
|
||||||
Pop-Location
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user