An den großen Contentmanagement-Systemen hat mich immer der enorme Umfang genervt. Da werden Unmengen an MBs auf den Webserver geladen und diejenigen, die im Alltag die Inhaltspflege übernehmen sollen, müssen aufwendig angelernt werden. Mal ehrlich: es ist fast einfacher, HTML, CSS und JavaScript von der Pike auf zu erlernen als die Redaktionsoberfäche von Typo3 (oder WordPress 😉 ) zu bedienen. Das hat mich dazu animiert, das onefile_cms zu schreiben. Eine einzige kleine PHP-Script-Datei und ein HTML-Template mit nur 5 Variablen sind die Zutaten. Natürlich kann damit kein Enterprise-Portal entwickelt werden, aber für eine mehrseitige kleine Homepage mit 1-stufigem Menü reicht’s.
<?php // onefile_cms by G. Drinkmann Ver 0.12 (29.05.2013) // Contentmanagement-System mit Wiki-Dialekt zur Contentbearbeitung // Dieser Quelltext kann völlig frei verwendet werden error_reporting(E_ALL); // ############################ HTML-Template ########################################## // das Template sollte folgendes enthalten: // Variablen im Template: // <!-- {sitetitle} --> // wird ersetzt durch Homepage-Titel // <!-- {menutitle} --> // der Menüname der angezeigten Seite // <!-- {ul-menu} --> // Menü als automatisch erzeugte ul-Liste (CSS s.u.) // <!-- {content-width} --> // wird ersetzt durch Content-Breite // <!-- {content} --> // der eigentliche Seiteninhalt aus der Redaktionsseite // CSS: // #menu id des ul-Elements // #menu li z.B.{display:inline; list-style:none;} // #menu a.menunormal class-Attribut des a-Elements im Menü // #menu a.menucurrent class-Attribut des aktiven a-Elements im Menü // img.Lfloat class-Attribut von linksbündig formatierten Bildern mit Text-Umlauf // img.Rfloat class-Attribut von rechtsbündig formatierten Bildern mit Text-Umlauf // Konvention: // Namen der Bilder des Templates sollten mit "ONEFILECMS_" beginnen // ------- HTML-Template-Datei --------------------- $ggtplfile = "tpl1.html"; // ############################ Script-Variablen ####################################### // ------- Homepage-Titel -------------------------------------------------------------- $ggsitetitel = "Kiosk JOJO"; // ------- md5-Passwort (zu erstellen bei z.B. http://www.functions-online.com/md5.html) $ggpass = "e6b3cd51a7afb493493d0c4a0bb0c8b2"; // jo33jo (bitte comment löschen) // ------- Edit-URL-Parameter (m=) zum Aufruf der Redaktionsseite ---------------------- $ggeditpara = "edit"; // ohne Leer- oder Sonderzeichen ! // ------- Template ist XHTML ---------------------------------------------------------- $ggisxhtml = false; // ------- Content-Breite -------------------------------------------------------------- $ggcontwidth = "750px"; // ############################ ab hier Chefsache !! ################################### $ggcontfile = "content1file.txt"; $ggxsl = ($ggisxhtml) ? " /" : ""; function ggerror($ggmsg) { global $ggcontent, $ggsitetitel, $ggxsl; $ggcontent[0]['mtitle'] = "FEHLER"; $ggcontent[0]['read'] = "<i>".$ggmsg."</i><br".$ggxsl."><br".$ggxsl.">Die Seite \"".$ggsitetitel."\" ist momentan nicht verfügbar.<br".$ggxsl.">Versuchen Sie es bitte später nocheinmal.<br".$ggxsl.">Danke !"; } if (isset($_GET['m'])) { // Check des GET-Parameter if ($_GET['m'] === $ggeditpara) $ggpar = "e"; else $ggpar = intval($_GET['m']); } else $ggpar = 0; if ($ggpar === "e") { // Seite editieren if (md5($_POST['pass']) === $ggpass && isset($_POST['content'])) { file_put_contents("./".$ggcontfile, urldecode($_POST['content'])); if (isset($_FILES['pic'])) { if (preg_match("/\.(jpg|gif|png)$/i", $_FILES['pic']['name']) || ($ggtplfile === $_FILES['pic']['name'])) { move_uploaded_file($_FILES['pic']['tmp_name'], "./".$_FILES['pic']['name']); } } if (isset($_POST['delimg'])) { for ($i=0; $i<count($_POST['delimg']); $i++) { @unlink("./".urldecode($_POST['delimg'][$i])); } } } if (file_exists("./".$ggcontfile)) { $ggfstr = file_get_contents("./".$ggcontfile); } else $ggfstr = utf8_encode("; Bitte mit Inhalt füllen"); $ggpiclis = ""; // vorhandene Bilder listen if ($gghandle = opendir('.')) { while (false !== ($ggfile = readdir($gghandle))) { if (preg_match("/\.(jpg|gif|png)$/i", $ggfile) && (!preg_match("/^ONEFILECMS_/", $ggfile))) { $ggpiclis .= "{{".$ggfile."}}<input type='checkbox' name='delimg[]' value='".$ggfile."' title='Bild löschen'><img onmouseover='document.getElementById(\"preview\").src = this.src; document.getElementById(\"preview\").className=\"gvisible\"' onmouseout='document.getElementById(\"preview\").className=\"ghidden\"' class='pici' src='".$ggfile."'> "; } } closedir($gghandle); } if (!$ggpiclis) $ggpiclis = "<i>Keine</i>"; $ggaction = $_SERVER['PHP_SELF']."?m=".$ggeditpara; $ggeditsite = <<<EOTE <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>{$ggsitetitel} editieren</title> <style type="text/css"> * {font-family:arial} img.pici {border:0;padding:0;margin:0;height:18px} img.gvisible {visibility:visible} img.ghidden {visibility:hidden} </style> </head> <body style="background-color:#ebebeb"> <h2>Website <a href="{$_SERVER['PHP_SELF']}" style="color:red" target="_blank"><i>{$ggsitetitel}</i></a> editieren (Inhalts-Breite <span style="color:red">{$ggcontwidth}</span>):</h2> <p style="font-size:10px">Zeile mit ; am Anfang = Kommentar<br> M--- am Anfang der Zeile = neuer Menütitel<br> HTML-Tags werden ausgeführt<br> == am Anfang der Zeile = große Überschrift<br> === am Anfang der Zeile = kleinere Überschrift<br> | am Anfang der Zeile = Tabelle (weitere Zellen mit | trennen)<br> * am Anfang der Zeile = Liste<br> {{*.jpg oder gif oder png}} = Bild in Originalgröße<br> {{*.jpg oder gif oder png|L oder R}} = Bild links bzw. rechts mit Text-Umlauf<br> [[Menüindex|Linktext oder -bild]] = interner Link (Index beginnt bei 0)<br> [[Linkadresse|Linktext oder -bild]] = externer Link<br> **Wörter** = Fett<br> //Wörter// = Kursiv<br> ---- = horizontale Linie<br> ((x)) am Anfang = Text-Umlauf (Float) beenden</p> <form name="f1" action="{$ggaction}" method="post" enctype="multipart/form-data"> <p><b>Inhalt</b><br> <textarea name="content" style="width: 600px; height: 300px; font-size: 12pt">{$ggfstr}</textarea></p> <p id="piclist"><b>Hochgeladene Bilder:</b><br> {$ggpiclis}</p> <p><b>Datei hochladen:</b> jpg, gif, png oder Template <i>{$ggtplfile}</i><br> <input type="file" name="pic" size="61"></p> <p>Passwort <input type="password" onkeydown="document.getElementsByName('OK')[0].disabled=false" name="pass" style="width: 200px;"> <input style="font-weight:bold" type="submit" name="OK" value="Seite speichern" disabled="disabled"></p> </form> <img class="ghidden" id="preview" src="nixda" style="position:absolute; left:3px; top:3px; border:solid #808080 30px;"> </body> </html> EOTE; echo $ggeditsite; } else { // normaler Seitenaufruf if (file_exists("./".$ggtplfile)) { $ggsitestr = file_get_contents("./".$ggtplfile); } else die("TEMPLATE NICHT VORHANDEN !"); $ggcontent = array(); // Initialisierung des Content-Array $ggcount=-1; if (file_exists("./".$ggcontfile)) { // Steuerdatei ins Content-Array einlesen $ggf = fopen("./".$ggcontfile, 'rb'); while (!feof($ggf)) { $ggtmp = rtrim(fgets($ggf)); if (substr(ltrim($ggtmp),0,4)==="M---") { $ggcount++; $ggcontent[$ggcount]['mtitle'] = ltrim(substr(ltrim($ggtmp),4)); $ggcontent[$ggcount]['mtitleclass'] = "menunormal"; $ggcontent[$ggcount]['read'] = ""; } elseif (substr(ltrim($ggtmp),0,1)!==";") { $ggcontent[$ggcount]['read'] .= $ggtmp."<brbr>"; } } fclose($ggf); if ($ggcount === -1) ggerror("Fehler: Kein Menü in Steuer-Datei eingetragen"); } else ggerror("Fehler: Steuer-Datei nicht vorhanden"); if ($ggpar>$ggcount) $ggpar = 0; $ggcontent[$ggpar]['mtitleclass'] = "menucurrent"; $ggsitestr = str_replace("<!-- {sitetitle} -->", $ggsitetitel, $ggsitestr); $ggsitestr = str_replace("<!-- {menutitle} -->", $ggcontent[$ggpar]['mtitle'], $ggsitestr); $ggsitestr = str_replace("<!-- {content-width} -->", $ggcontwidth, $ggsitestr); // --- Menü zusammenbauen --- $ggmenustr = "<ul id=\"menu\">\n"; for ($i=0; $i<count($ggcontent); $i++) { $ggmenustr .= "<li><a href=\"".$_SERVER['PHP_SELF']."?m=".$i."\" class=\"".$ggcontent[$i]['mtitleclass']."\" target=\"_self\">".$ggcontent[$i]['mtitle']."</a></li>\n"; } $ggmenustr .= "</ul>\n"; $ggsitestr = str_replace("<!-- {ul-menu} -->", $ggmenustr, $ggsitestr); // --- Content zusammenbauen --- $ggcont = $ggcontent[$ggpar]['read']; $ggcont = explode("<brbr>",$ggcont); $ggcontstr = ""; $istab = 0; // Tabelle $isul = false; // Bullet-Liste $ggcleardiv = "<div style='clear:both;visibility:hidden;width:0;height:0;margin:0;padding:0;border:0;'></div>\n"; for ($i=0; $i<count($ggcont); $i++) { if (substr(ltrim($ggcont[$i]),0,5)==="((x))") { $ggisclear = " style='clear:both'"; $ggcont[$i] = substr(ltrim($ggcont[$i]),5); } else $ggisclear = ""; if (substr(ltrim($ggcont[$i]),0,1)==="|") { $ggtra = explode("|",substr(ltrim($ggcont[$i]),1)); if (!$istab) { $ggcontstr .= "<table".$ggisclear.">\n"; } elseif ($istab !== count($ggtra)) { $ggcontstr .= "</table>\n<table".$ggisclear.">\n"; } $istab = count($ggtra); $ggcontstr .= "<tr>"; for ($j=0; $j<$istab; $j++) { $ggcontstr .= "<td>".trim($ggtra[$j])."</td>"; } $ggcontstr .= "</tr>"; } else { if ($istab) $ggcontstr .= "</table>\n"; $istab = 0; if ((substr(ltrim($ggcont[$i]),0,1)==="*") && (substr(ltrim($ggcont[$i]),1,1)!=="*")) { if (!$isul) $ggcontstr .= "<ul".$ggisclear.">\n"; $isul = true; $ggcontstr .= "<li>".trim(substr(ltrim($ggcont[$i]),1))."</li>"; } else { if ($isul) $ggcontstr .= "</ul>\n"; $isul = false; if (substr(ltrim($ggcont[$i]),0,3)==="===") { $ggcontstr .= "<h2".$ggisclear.">".substr(ltrim($ggcont[$i]),3)."</h2>"; } elseif (substr(ltrim($ggcont[$i]),0,2)==="==") { $ggcontstr .= "<h1".$ggisclear.">".substr(ltrim($ggcont[$i]),2)."</h1>"; } elseif (trim($ggcont[$i])==="----") { $ggcontstr .= "<hr".$ggisclear.">"; } elseif ($ggisclear) { $ggcontstr .= $ggcleardiv.$ggcont[$i]."<br".$ggxsl.">"; } else $ggcontstr .= $ggcont[$i]."<br".$ggxsl.">"; } } $ggcontstr .= "\n"; } $ggcontstr = preg_replace("/{{(\S.*\.(jpg|JPG|gif|GIF|png|PNG))\|L}}/", "<img src=\"$1\" style=\"float:left\" class=\"Lfloat\"".$ggx.">", $ggcontstr); // Bilder mit float links $ggcontstr = preg_replace("/{{(\S.*\.(jpg|JPG|gif|GIF|png|PNG))\|R}}/", "<img src=\"$1\" style=\"float:right\" class=\"Rfloat\"".$ggx.">", $ggcontstr); // Bilder mit float rechts $ggcontstr = preg_replace("/{{(\S.*\.(jpg|gif|png))}}/i", "<img src=\"$1\"".$ggx.">", $ggcontstr); // Bilder $ggcontstr = preg_replace("/\[\[(\d+)\|(\S.*\S|\S)]]/", "<a href=\"".$_SERVER['PHP_SELF']."?m=$1\" target=\"_self\">$2</a>", $ggcontstr); // interne Links $ggcontstr = preg_replace("/\[\[(\S+)\|(\S.*\S|\S)]]/", "<a href=\"$1\" target=\"_blank\" title=\"Link in neuem Fenster\">$2</a>", $ggcontstr); // externe Links $ggcontstr = preg_replace("/ /", " ", $ggcontstr); // Leerzeichen $ggcontstr = preg_replace("/ (\S)/", " $1", $ggcontstr); $ggcontstr = preg_replace("/\*\*(\S.*\S|\S)\*\*/", "<strong>$1</strong>", $ggcontstr); // Fett $ggcontstr = preg_replace("#//(\S.*\S|\S)//#", "<em>$1</em>", $ggcontstr); // Kursiv $ggsitestr = str_replace("<!-- {content} -->", $ggcontstr, $ggsitestr); $ggsitestr .= $ggcleardiv; echo $ggsitestr; } ?>
Also, man nehme den Quelltext, erstelle daraus eine Datei names index.php, fülle die Variablen aus, erstelle eine Template-Datei (mit dem Namen wie bei den Variablen angegeben) und lade beide Dateien (inklusive der zum Template gehörigen Bilder) auf den Webserver. Die index.php-Datei beinhaltet beides: die Maschinerie der eigentlichen Website für den Betrachter und die der Redaktion. Die Redaktionsseite wird über den Link <DeineURL>/index.php?m=<Variable URL-Parameter> aufgerufen. Ok, es sind mehr als nur eine Datei im Spiel, doch das eigentliche Programm besteht in der Tat nur aus dieser einen PHP-Datei.
Das Template sollte eine ganz normale HTML-Seite sein. Die Namen der Templatebilder sollten mit „ONEFILECMS_“ beginnen. Folgende Variablen können in diesem Template plaziert sein:
- <!– {sitetitle} –> der Homepagetitel
- <!– {menutitle} –> der Menüname der angezeigten Seite
- <!– {ul-menu} –> Seiten-Menü als automatisch erzeugte ul-Liste
- <!– {content-width} –> Breite des Inhaltbereichs
- <!– {content} –> der eigentliche Seiteninhalt
Hier ist eine kleine Testseite zur Anschauung:
der Kiosk des fiktiven Jojo

Das zugehörige Template ist die Datei tpl1.html.
Im Quelltext dieser Seite sind die Variablen sichtbar.
Jojo’s Kiosk kann mit der Edit-Seite bearbeitet werden.

Dabei wird zur leicht erlernbaren Bearbeitung ein Wiki-Dialekt angewendet. Hat Ähnlichkeit mit Creole. Zum Speichern wird JEDESMAL das Paßwort abgefragt. Das ist ein wenig lästig, aber sicher.