Zurück
Download
Lade das vollständige Rizo CMS herunter: Editor, Login, Server-Speicherung und Zugriffsschutz.
Urheberrechtlich geschützt
Diese Software ist urheberrechtlich geschützt. Weiterverkauf, Weitergabe und Redistribution sind nicht gestattet. Durch den Download akzeptierst du die Lizenzbestimmungen.
Dateistruktur
deine-website/ ├── index.html ← Deine einzige HTML-Seite ├── rizocms.js ← Rizo CMS Editor ├── login.php ← Login & Session ├── save.php ← Speichern & Backup └── .htaccess ← Schutzdatei
Die Download-Buttons laden immer die aktuelle Rizo CMS Version:
rizocms.js, login.php, save.php und .htaccess. Kein Token und kein Hash müssen in JavaScript eingetragen werden.rizocms.js
/**
* ============================================================
* Rizo CMS - PROPRIETÄRE SOFTWARE
* ============================================================
* Copyright (c) 2026 Rizo CMS. Alle Rechte vorbehalten.
*
* LIZENZHINWEIS:
* Diese Software ist urheberrechtlich geschützt. Die Nutzung
* ist nur für den persönlichen/geschäftlichen Gebrauch auf
* eigenen Webseiten gestattet.
*
* VERBOTEN IST:
* - Weiterverkauf oder kommerzielle Weitergabe
* - Weitergabe an Dritte (kostenpflichtig)
* - Modifikation und Redistribution
* - Entfernen dieses Copyright-Hinweises
*
* Bei Verstößen behalten wir uns rechtliche Schritte vor.
* Kontakt: [hello@rizocms.com]
* ============================================================
*/
/**
* Rizo CMS v2.0.0
* Ein leichtgewichtiges Rizo-CMS für statische HTML-Seiten
* MIT SEO SCORE & PHP AUTHENTIFIZIERUNG & BILD-UPLOAD
*
* Verwendung:
* 1. config.php, api.php und .htaccess im selben Ordner platzieren
* 2. Script in HTML-Seite einbinden: <script src="rizocms.js"></script>
* 3. Elemente mit data-editable="name" markieren
* 4. Bilder mit data-editable="name" data-editable-type="image" markieren
* 5. STRG+E drücken zum Editieren (Mobil: Stift-Symbol)
*/
(function() {
'use strict';
// ===== KONFIGURATION =====
const CONFIG = {
LOGIN_ENDPOINT: 'login.php',
SAVE_ENDPOINT: 'save.php',
SHORTCUT_KEY: 'KeyE',
HIGHLIGHT_COLOR: '#3b82f6',
SEO_ENABLED: true
};
// ===== STATE =====
let isEditMode = false;
let isLoggedIn = false;
let currentElement = null;
let csrfToken = null;
// ===== STYLES =====
const STYLES = `
.icms-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 999998;
display: flex;
align-items: center;
justify-content: center;
}
.icms-modal {
background: #1a1a2e;
border-radius: 12px;
padding: 32px;
max-width: 500px;
width: 90%;
box-shadow: 0 25px 50px rgba(0,0,0,0.5);
max-height: 80vh;
overflow-y: auto;
}
.icms-modal h2 {
color: #fff;
margin: 0 0 8px 0;
font-size: 24px;
}
.icms-modal p {
color: #888;
margin: 0 0 24px 0;
font-size: 14px;
}
.icms-input {
width: 100%;
padding: 12px 16px;
border: 1px solid #333;
border-radius: 8px;
background: #0f0f1a;
color: #fff;
font-size: 14px;
margin-bottom: 12px;
box-sizing: border-box;
}
.icms-input:focus {
outline: none;
border-color: ${CONFIG.HIGHLIGHT_COLOR};
}
.icms-btn {
width: 100%;
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.icms-btn-primary {
background: ${CONFIG.HIGHLIGHT_COLOR};
color: #fff;
}
.icms-btn-primary:hover {
opacity: 0.9;
}
.icms-btn-secondary {
background: #2a2a3e;
color: #fff;
margin-top: 8px;
}
.icms-btn-secondary:hover {
background: #3a3a4e;
}
.icms-error {
color: #ef4444;
font-size: 12px;
margin-top: 8px;
}
.icms-image-preview {
width: 100%;
max-height: 300px;
object-fit: cover;
border-radius: 8px;
margin-bottom: 16px;
border: 2px solid #333;
}
.icms-file-input-wrapper {
position: relative;
margin-bottom: 16px;
}
.icms-file-input {
width: 100%;
padding: 12px;
border: 2px dashed #333;
border-radius: 8px;
background: #0f0f1a;
color: #888;
cursor: pointer;
text-align: center;
transition: all 0.2s;
}
.icms-file-input:hover {
border-color: ${CONFIG.HIGHLIGHT_COLOR};
color: #fff;
}
.icms-toolbar {
position: fixed;
top: 20px;
right: 20px;
background: #1a1a2e;
border-radius: 12px;
padding: 12px;
display: flex;
gap: 8px;
z-index: 999999;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
}
.icms-toolbar button {
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
background: #2a2a3e;
color: #fff;
}
.icms-toolbar button:hover {
background: #3a3a4e;
}
.icms-toolbar button.active {
background: ${CONFIG.HIGHLIGHT_COLOR};
}
.icms-editable {
outline: 2px dashed ${CONFIG.HIGHLIGHT_COLOR}44;
outline-offset: 4px;
transition: all 0.2s;
}
.icms-editable:hover {
outline-color: ${CONFIG.HIGHLIGHT_COLOR};
cursor: pointer;
}
.icms-editing {
outline: 2px solid ${CONFIG.HIGHLIGHT_COLOR};
outline-offset: 4px;
}
.icms-seo-panel {
position: fixed;
top: 80px;
right: 20px;
width: 320px;
background: #1a1a2e;
border-radius: 12px;
padding: 20px;
z-index: 999998;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
max-height: 70vh;
overflow-y: auto;
}
.icms-seo-panel h3 {
color: #fff;
margin: 0 0 16px 0;
font-size: 16px;
display: flex;
align-items: center;
gap: 8px;
}
.icms-seo-score {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: #0f0f1a;
border-radius: 8px;
margin-bottom: 12px;
}
.icms-score-circle {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 16px;
color: #fff;
}
.icms-score-good { background: #22c55e; }
.icms-score-medium { background: #f59e0b; }
.icms-score-bad { background: #ef4444; }
.icms-seo-item {
padding: 12px;
background: #0f0f1a;
border-radius: 8px;
margin-bottom: 8px;
}
.icms-seo-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
}
.icms-seo-item-title {
color: #fff;
font-size: 13px;
font-weight: 500;
}
.icms-seo-item-value {
color: #888;
font-size: 12px;
}
.icms-seo-bar {
height: 4px;
background: #333;
border-radius: 2px;
overflow: hidden;
}
.icms-seo-bar-fill {
height: 100%;
border-radius: 2px;
transition: width 0.3s;
}
.icms-copyright {
font-size: 10px;
color: #666;
text-align: center;
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid #333;
}
`;
// ===== AUTH FUNKTIONEN =====
async function checkAuth() {
try {
const res = await fetch(CONFIG.AUTH_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'check' })
});
const data = await res.json();
isLoggedIn = data.logged_in;
csrfToken = data.csrf_token;
return isLoggedIn;
} catch (e) {
console.warn('Auth check failed, running in standalone mode');
isLoggedIn = true;
return true;
}
}
async function login(username, password) {
try {
const res = await fetch(CONFIG.AUTH_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'login', username, password })
});
const data = await res.json();
if (data.success) {
isLoggedIn = true;
csrfToken = data.csrf_token;
}
return data;
} catch (e) {
return { success: false, message: 'Verbindungsfehler' };
}
}
async function logout() {
try {
await fetch(CONFIG.AUTH_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'logout' })
});
} catch (e) {}
isLoggedIn = false;
csrfToken = null;
exitEditMode();
}
// ===== UI FUNKTIONEN =====
function injectStyles() {
const style = document.createElement('style');
style.textContent = STYLES;
document.head.appendChild(style);
}
function showLoginModal() {
const overlay = document.createElement('div');
overlay.className = 'icms-overlay';
overlay.innerHTML = `
<div class="icms-modal">
<h2>🔐 Rizo CMS</h2>
<p>Melde dich an, um Inhalte zu bearbeiten</p>
<input type="text" class="icms-input" id="icms-username" placeholder="Benutzername">
<input type="password" class="icms-input" id="icms-password" placeholder="Passwort">
<button class="icms-btn icms-btn-primary" id="icms-login-btn">Anmelden</button>
<div class="icms-error" id="icms-error" style="display:none"></div>
<div class="icms-copyright">© 2026 Rizo CMS - Urheberrechtlich geschützt</div>
</div>
`;
document.body.appendChild(overlay);
const loginBtn = document.getElementById('icms-login-btn');
const usernameInput = document.getElementById('icms-username');
const passwordInput = document.getElementById('icms-password');
const errorDiv = document.getElementById('icms-error');
async function doLogin() {
const result = await login(usernameInput.value, passwordInput.value);
if (result.success) {
overlay.remove();
enterEditMode();
} else {
errorDiv.textContent = result.message;
errorDiv.style.display = 'block';
}
}
loginBtn.addEventListener('click', doLogin);
passwordInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') doLogin();
});
overlay.addEventListener('click', (e) => {
if (e.target === overlay) overlay.remove();
});
usernameInput.focus();
}
function showImageUploadModal(element) {
const overlay = document.createElement('div');
overlay.className = 'icms-overlay';
const currentSrc = element.src || element.style.backgroundImage.replace(/url$$['"](.+)['"]$$/, '$1');
let newImageData = null;
overlay.innerHTML = `
<div class="icms-modal">
<h2>🖼️ Bild ändern</h2>
<p>Aktuelles Bild oder neues Bild hochladen</p>
<div style="margin-bottom: 16px;">
<p style="font-size: 12px; color: #888; margin-bottom: 8px;">Aktuelles Bild:</p>
<img src="${currentSrc}" class="icms-image-preview" alt="Current" />
</div>
<div class="icms-file-input-wrapper">
<label for="icms-file-input" class="icms-file-input">
📁 Neues Bild auswählen
</label>
<input type="file" id="icms-file-input" accept="image/*" style="display: none;" />
</div>
<div id="icms-new-preview" style="display: none; margin-bottom: 16px;">
<p style="font-size: 12px; color: #888; margin-bottom: 8px;">Neues Bild:</p>
<img id="icms-new-image" class="icms-image-preview" alt="New" />
</div>
<button class="icms-btn icms-btn-primary" id="icms-save-image" disabled>Bild speichern</button>
<button class="icms-btn icms-btn-secondary" id="icms-cancel-image">Abbrechen</button>
<div class="icms-copyright">© 2026 Rizo CMS</div>
</div>
`;
document.body.appendChild(overlay);
const fileInput = document.getElementById('icms-file-input');
const fileLabel = fileInput.previousElementSibling;
const newPreview = document.getElementById('icms-new-preview');
const newImage = document.getElementById('icms-new-image');
const saveBtn = document.getElementById('icms-save-image');
const cancelBtn = document.getElementById('icms-cancel-image');
fileLabel.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
newImageData = event.target.result;
newImage.src = newImageData;
newPreview.style.display = 'block';
saveBtn.disabled = false;
fileLabel.textContent = '✓ ' + file.name;
fileLabel.style.borderColor = CONFIG.HIGHLIGHT_COLOR;
fileLabel.style.color = '#fff';
};
reader.readAsDataURL(file);
}
});
saveBtn.addEventListener('click', () => {
if (newImageData) {
if (element.tagName === 'IMG') {
element.src = newImageData;
} else {
element.style.backgroundImage = `url('${newImageData}')`;
}
const key = element.getAttribute('data-editable');
const data = JSON.parse(localStorage.getItem(CONFIG.STORAGE_KEY) || '{}');
data[key] = { type: 'image', value: newImageData };
localStorage.setItem(CONFIG.STORAGE_KEY, JSON.stringify(data));
overlay.remove();
}
});
cancelBtn.addEventListener('click', () => overlay.remove());
overlay.addEventListener('click', (e) => {
if (e.target === overlay) overlay.remove();
});
}
function createToolbar() {
const toolbar = document.createElement('div');
toolbar.className = 'icms-toolbar';
toolbar.id = 'icms-toolbar';
toolbar.innerHTML = `
<button id="icms-btn-save">💾 Speichern</button>
<button id="icms-btn-export">📄 Export</button>
<button id="icms-btn-seo">📊 SEO</button>
<button id="icms-btn-reset">🔄 Reset</button>
<button id="icms-btn-logout">🚪 Logout</button>
<button id="icms-btn-exit">✕</button>
`;
document.body.appendChild(toolbar);
document.getElementById('icms-btn-save').addEventListener('click', saveChanges);
document.getElementById('icms-btn-export').addEventListener('click', exportHTML);
document.getElementById('icms-btn-seo').addEventListener('click', toggleSEOPanel);
document.getElementById('icms-btn-reset').addEventListener('click', resetChanges);
document.getElementById('icms-btn-logout').addEventListener('click', logout);
document.getElementById('icms-btn-exit').addEventListener('click', exitEditMode);
}
// ===== SEO FUNKTIONEN =====
function calculateReadability(text) {
const words = text.split(/\s+/).filter(w => w.length > 0);
const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0);
const syllables = words.reduce((acc, word) => {
return acc + (word.match(/[aeiouyäöü]/gi) || []).length;
}, 0);
if (words.length === 0 || sentences.length === 0) return 0;
const avgWordsPerSentence = words.length / sentences.length;
const avgSyllablesPerWord = syllables / words.length;
// Flesch-Reading-Ease (German adaptation)
const score = 180 - avgWordsPerSentence - (58.5 * avgSyllablesPerWord);
return Math.max(0, Math.min(100, score));
}
function getKeywords(text) {
const stopWords = ['der', 'die', 'das', 'und', 'ist', 'in', 'zu', 'den', 'mit', 'von', 'für', 'auf', 'ein', 'eine', 'einer', 'eines', 'einem', 'einen', 'dem', 'des', 'im', 'am', 'zum', 'zur', 'als', 'sich', 'bei', 'nach', 'aus', 'um', 'oder', 'auch', 'nicht', 'werden', 'wird', 'kann', 'sind', 'hat', 'haben'];
const words = text.toLowerCase().match(/[a-zäöüß]+/gi) || [];
const filtered = words.filter(w => w.length > 3 && !stopWords.includes(w));
const freq = {};
filtered.forEach(w => freq[w] = (freq[w] || 0) + 1);
return Object.entries(freq).sort((a, b) => b[1] - a[1]).slice(0, 5).map(e => e[0]);
}
function analyzeSEO() {
const title = document.title || '';
const description = document.querySelector('meta[name="description"]')?.content || '';
const h1 = document.querySelector('h1')?.textContent || '';
const bodyText = document.body.textContent;
const checks = {
title: {
label: 'Title',
value: title.length,
min: 30,
max: 60,
score: title.length >= 30 && title.length <= 60 ? 100 : Math.max(0, 100 - Math.abs(45 - title.length) * 2)
},
description: {
label: 'Meta Description',
value: description.length,
min: 120,
max: 160,
score: description.length >= 120 && description.length <= 160 ? 100 : Math.max(0, 100 - Math.abs(140 - description.length))
},
h1: {
label: 'H1 Überschrift',
value: h1.length,
min: 20,
max: 70,
score: h1.length >= 20 && h1.length <= 70 ? 100 : Math.max(0, 100 - Math.abs(45 - h1.length) * 2)
},
readability: {
label: 'Lesbarkeit',
value: Math.round(calculateReadability(bodyText)),
min: 60,
max: 100,
score: calculateReadability(bodyText)
},
keywords: {
label: 'Keywords',
value: getKeywords(bodyText).join(', '),
score: getKeywords(bodyText).length >= 3 ? 100 : getKeywords(bodyText).length * 33
}
};
const totalScore = Math.round(
Object.values(checks).reduce((acc, check) => acc + check.score, 0) / Object.keys(checks).length
);
return { checks, totalScore };
}
function createSEOPanel() {
const existing = document.getElementById('icms-seo-panel');
if (existing) {
existing.remove();
return;
}
const { checks, totalScore } = analyzeSEO();
const panel = document.createElement('div');
panel.className = 'icms-seo-panel';
panel.id = 'icms-seo-panel';
const scoreClass = totalScore >= 80 ? 'icms-score-good' : totalScore >= 50 ? 'icms-score-medium' : 'icms-score-bad';
let html = `
<h3>📊 SEO Score</h3>
<div class="icms-seo-score">
<div class="icms-score-circle ${scoreClass}">${totalScore}</div>
<div>
<div style="color: #fff; font-weight: 600; margin-bottom: 4px;">
${totalScore >= 80 ? 'Sehr gut!' : totalScore >= 50 ? 'OK' : 'Verbesserung nötig'}
</div>
<div style="color: #888; font-size: 12px;">Gesamt-Score</div>
</div>
</div>
`;
for (const [key, check] of Object.entries(checks)) {
const percent = Math.min(100, check.score);
const color = check.score >= 80 ? '#22c55e' : check.score >= 50 ? '#f59e0b' : '#ef4444';
html += `
<div class="icms-seo-item">
<div class="icms-seo-item-header">
<span class="icms-seo-item-title">${check.label}</span>
<span class="icms-seo-item-value">${check.value}${key !== 'keywords' ? '/' + check.max : ''}</span>
</div>
<div class="icms-seo-bar">
<div class="icms-seo-bar-fill" style="width: ${percent}%; background: ${color};"></div>
</div>
</div>
`;
}
html += `<div class="icms-copyright">© 2026 Rizo CMS</div>`;
panel.innerHTML = html;
document.body.appendChild(panel);
}
function toggleSEOPanel() {
createSEOPanel();
}
// ===== STORAGE FUNKTIONEN =====
function saveChanges() {
const data = {};
const editables = document.querySelectorAll('[data-editable]');
editables.forEach(el => {
const key = el.getAttribute('data-editable');
const type = el.getAttribute('data-editable-type') || 'text';
if (type === 'image') {
const value = el.tagName === 'IMG' ? el.src : el.style.backgroundImage;
data[key] = { type, value };
} else {
data[key] = { type, value: el.innerHTML };
}
});
localStorage.setItem(CONFIG.STORAGE_KEY, JSON.stringify(data));
alert('✓ Änderungen gespeichert!');
}
function loadChanges() {
const data = JSON.parse(localStorage.getItem(CONFIG.STORAGE_KEY) || '{}');
Object.entries(data).forEach(([key, item]) => {
const el = document.querySelector(`[data-editable="${key}"]`);
if (el) {
if (item.type === 'image') {
if (el.tagName === 'IMG') {
el.src = item.value;
} else {
el.style.backgroundImage = item.value;
}
} else {
el.innerHTML = item.value;
}
}
});
}
function resetChanges() {
if (confirm('Alle Änderungen zurücksetzen?')) {
localStorage.removeItem(CONFIG.STORAGE_KEY);
location.reload();
}
}
// ===== EXPORT FUNKTIONEN =====
function exportHTML() {
const clone = document.documentElement.cloneNode(true);
// Remove CMS elements
clone.querySelectorAll('.icms-toolbar, .icms-seo-panel, .icms-overlay').forEach(el => el.remove());
clone.querySelectorAll('[data-editable]').forEach(el => {
el.classList.remove('icms-editable', 'icms-editing');
el.removeAttribute('contenteditable');
});
const html = '<!DOCTYPE html>\n' + clone.outerHTML;
const blob = new Blob([html], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `exported-${Date.now()}.html`;
a.click();
URL.revokeObjectURL(url);
}
// ===== EDIT FUNKTIONEN =====
function enterEditMode() {
isEditMode = true;
createToolbar();
const editables = document.querySelectorAll('[data-editable]');
editables.forEach(el => {
el.classList.add('icms-editable');
el.addEventListener('click', handleElementClick);
});
loadChanges();
}
function exitEditMode() {
isEditMode = false;
const toolbar = document.getElementById('icms-toolbar');
if (toolbar) toolbar.remove();
const seoPanel = document.getElementById('icms-seo-panel');
if (seoPanel) seoPanel.remove();
const editables = document.querySelectorAll('[data-editable]');
editables.forEach(el => {
el.classList.remove('icms-editable', 'icms-editing');
el.contentEditable = 'false';
el.removeEventListener('click', handleElementClick);
});
currentElement = null;
}
function handleElementClick(e) {
e.preventDefault();
e.stopPropagation();
const element = e.currentTarget;
const editableType = element.getAttribute('data-editable-type');
// Handle image editing
if (editableType === 'image') {
showImageUploadModal(element);
return;
}
// Handle text editing
if (currentElement) {
currentElement.classList.remove('icms-editing');
currentElement.contentEditable = 'false';
}
currentElement = element;
currentElement.classList.add('icms-editing');
currentElement.contentEditable = 'true';
currentElement.focus();
}
// ===== INITIALIZATION =====
async function init() {
injectStyles();
// Keyboard shortcut
document.addEventListener('keydown', async (e) => {
if (e.altKey && e.code === CONFIG.SHORTCUT_KEY) {
e.preventDefault();
if (!isEditMode) {
const authed = await checkAuth();
if (!authed) {
showLoginModal();
} else {
enterEditMode();
}
} else {
exitEditMode();
}
}
});
}
// Start when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
Schnellstart
- Lade
rizocms.js,login.php,save.phpund.htaccessherunter - Platziere alle vier Dateien im selben Ordner wie deine HTML-Seiten
- Ein separates
config.phpist nicht erforderlich. Beim ersten Login legst du dein Passwort fest; danach bleibt es serverseitig gespeichert. - RizoCMS erkennt editierbare Elemente automatisch; manuelle Marker sind optional
- Bilder werden im Edit-Modus automatisch erkannt und können direkt ersetzt werden
- Binde das Script ein:
<script src="rizocms.js"></script> - Drücke STRG + E zum Editieren. Mobil nutzt du das Stift-Symbol.
Konfigurierbare Features
SEO Analyzer
Live SEO-Score beim Bearbeiten
Bild-Upload
Bilder direkt hochladen
HTML Export
Bereinigte HTML-Datei exportieren
Server-Speicherung
Sicheres Speichern mit Backup über save.php
Keyboard Shortcuts
STRG+E am Desktop, Stift-Symbol auf Mobilgeräten
CSRF Schutz
Sicherheit gegen Angriffe