Slim ist ein leichtes Gerüst, das aufgrund seines geringen Fußabdrucks sehr viel Druck bietet. Es verfügt über ein unglaubliches Routing-System und bietet eine solide Basis, auf der Sie arbeiten können, ohne sich in die Quere kommen zu lassen. Lass mich dir zeigen!
Das heißt aber nicht, dass Slim keine Probleme hat. Das Ein-Datei-Setup wird mit dem Wachstum Ihrer Anwendung unübersichtlich. In diesem Artikel erfahren Sie, wie Sie eine Slim-Anwendung strukturieren, um nicht nur die Funktionalität zu erhalten, sondern auch die Funktionalität zu verbessern und die Dinge ordentlich und systematisch zu halten.
Beginnen wir mit einem allgemeinen Slim-Code, um das Problem zu identifizieren. Nachdem Sie Slim über Composer installiert haben, müssen Sie eine Instanz von erstellen Schlank
Objekt und definiere deine Routen:
get ('/', function () echo "Home Page";); $ app-> get ('/ testPage') function () use ($ app) $ app-> render ('testpage.php');); $ app-> run ();
Lassen Sie uns das Slim-Objekt in den "Controller" verwandeln.
Der erste Methodenaufruf legt eine neue Route für den Root-URI fest (/
) und verbindet die angegebene Funktion mit dieser Route. Dies ist ziemlich wortreich, aber einfach einzurichten. Der zweite Methodenaufruf definiert eine Route für den URI testPage
. In der mitgelieferten Methode verwenden wir Slim's machen()
Methode zum Rendern einer Ansicht.
Hier liegt das erste Problem: Diese Funktion (Schließung) wird im aktuellen Kontext nicht aufgerufen und hat keine Möglichkeit, auf die Funktionen von Slim zuzugreifen. Deshalb müssen wir die verwenden benutzen
Schlüsselwort, um den Verweis an die Slim-App zu übergeben.
Die zweite Ausgabe stammt aus der Architektur von Slim. es soll alles in einer Datei definiert werden. Sie können die Variable natürlich in eine andere Datei auslagern, aber sie wird nur unübersichtlich. Idealerweise möchten wir Steuerungen hinzufügen, um das Framework in einzelne Komponenten zu modularisieren. Als Bonus wäre es schön, wenn diese Controller nativen Zugriff auf die Funktionen von Slim bieten würden, sodass keine Referenzen in die Schließungen weitergeleitet werden müssen.
Es ist fraglich, ob das Lesen von Quellcode aus einem Open-Source-Projekt als Reverse Engineering betrachtet wird, aber es ist der Begriff, mit dem ich bleibe. Wir verstehen, wie man Slim benutzt, aber was passiert unter der Haube? Lassen Sie uns einen komplizierteren Weg betrachten, um an die Wurzel dieser Frage zu gelangen:
$ app-> get ('/ users /: name', Funktion ($ name) echo "Hallo". $ name;);
Diese Routendefinition verwendet einen Doppelpunkt mit dem Wort, Name
. Dies ist ein Platzhalter, und der an seiner Stelle verwendete Wert wird an die Funktion übergeben. Zum Beispiel, / Benutzer / Gabriel
stimmt mit dieser Route überein, und "Gabriel" wird an die Funktion übergeben. Die Route, / Benutzer
, Auf der anderen Seite ist keine Übereinstimmung, da der Parameter fehlt.
Wenn Sie logisch darüber nachdenken, müssen einige Schritte ausgeführt werden, um eine Route zu verarbeiten.
Um den Prozess besser zu optimieren, speichert Slim mithilfe von Regex-Rückrufen und -Gruppen die Platzhalter, während Übereinstimmungen geprüft werden. Dies kombiniert zwei Schritte in einem, so dass nur die Notwendigkeit besteht, die verbundene Funktion auszuführen, wenn Slim bereit ist. Es wird deutlich, dass das Routenobjekt in sich abgeschlossen ist und, offen gesagt, alles was benötigt wird.
Im vorherigen Beispiel hatten wir beim Analysieren der Routen Zugriff auf die Funktionen von Slim, aber wir mussten eine Slim-Objektreferenz übergeben, da diese sonst im Ausführungskontext der Funktion nicht verfügbar wäre. Das ist alles, was Sie für die meisten Anwendungen benötigen, da Ihre Anwendungslogik in der Steuerung vorkommen sollte.
Aus diesem Grund extrahieren wir den "routing" -Anteil in eine Klasse und machen aus dem Slim-Objekt den "Controller".
Lassen Sie uns "vanilla Slim" herunterladen und installieren, wenn Sie dies noch nicht getan haben. Ich gehe davon aus, dass Sie Composer installiert haben. Wenn nicht, folgen Sie den Schritten .
Erstellen Sie in einem neuen Verzeichnis eine Datei mit dem Namen composer.json
, und füge folgendes hinzu:
"name": "nettuts / slim-mvc", "erfordern": "slim / slim": "*", "slim / extras": "*", "twig / twig": "*"
Navigieren Sie in einem Terminalfenster zu diesem Verzeichnis und geben Sie diesen ein Komponist installieren
. Ich gehe Sie durch diese Pakete, wenn Sie zum ersten Mal Slim verwenden.
Technisch benötigen Sie die Slim-Extras oder Twig für dieses Tutorial nicht, aber ich mag es, Twig anstelle von Standard-PHP-Templates zu verwenden. Wenn Sie Twig verwenden, benötigen Sie jedoch die Slim-Extras, da sie eine Schnittstelle zwischen Twig und Slim bilden.
Jetzt können wir unsere benutzerdefinierten Dateien hinzufügen, und wir beginnen, indem wir ein Verzeichnis hinzufügen Anbieter
Mappe. Ich werde meine nennen Nettuts
, Sie können jedoch gerne Ihren Namen nennen, wie Sie möchten. Wenn Sie sich noch im Terminal befinden, stellen Sie sicher, dass sich Ihr Terminalfenster im Verzeichnis des Projekts befindet, und geben Sie Folgendes ein:
mkdir Verkäufer / Nettuts
Bearbeiten Sie jetzt composer.json
indem Sie die Referenz zu diesem neuen Ordner hinzufügen:
"name": "nettuts / slim-mvc", "erfordern": "slim / slim": "*", "slim / extras": "*", "twig / twig": "*", " autoload ": " psr-0 ": " Nettuts ":" vendor / "
Wir möchten, dass unsere App automatisch Klassen aus der Nettuts
Namespace, so dass Composer alle Anforderungen zuordnen kann Nettuts
zum PSR-0-Standard ab dem Verkäufer
Mappe.
Jetzt ausführen:
composer dump-autoload
Dadurch wird der Autoloader neu kompiliert, um die neue Referenz aufzunehmen. Als Nächstes erstellen Sie eine Datei mit dem Namen Router.php
, innerhalb des Nettuts
Verzeichnis und geben Sie Folgendes ein:
Wir haben gesehen, dass jedes Routenobjekt eine eigenständige Funktion hat, die bestimmt, ob es mit dem bereitgestellten URI übereinstimmt. Wir wollen also eine Reihe von Routen und eine Funktion, um sie zu analysieren. Wir benötigen auch eine weitere Funktion, um neue Routen hinzuzufügen, und eine Möglichkeit, den URI von der aktuellen HTTP-Anforderung abzurufen.
Beginnen wir mit dem Hinzufügen einiger Mitgliedsvariablen und des Konstruktors:
Klassenrouter protected $ routen; Geschützte $ Anfrage; öffentliche Funktion __construct () $ env = \ Slim \ Environment :: getInstance (); $ this-> request = new \ Slim \ Http \ Request ($ env); $ this-> routes = array ();Wir setzen die
Routen
Variable, die die Routen enthält, und dieanfordern
Variable zum Speichern des SlimAnfordern
Objekt. Als nächstes benötigen wir die Möglichkeit, Routen hinzuzufügen. Um bei den Best Practices zu bleiben, teile ich dies in zwei Schritten auf:öffentliche Funktion addRoutes ($ routes) foreach ($ routes als $ route => $ path) $ method = "any"; if (strpos ($ path, "@")! == false) list ($ path, $ method) = explodieren ("@", $ path); $ func = $ this-> processCallback ($ path); $ r = new \ Slim \ Route ($ route, $ func); $ r-> setHttpMethods (strtoupper ($ -Methode)); array_push ($ this-> routen, $ r);Diese öffentliche Funktion akzeptiert ein assoziatives Array von Routen im Format von
route => Pfad
, woherRoute
ist eine Standard-Slim-Route undPfad
ist eine Zeichenfolge mit der folgenden Konvention:Optional können Sie bestimmte Parameter auslassen, um einen Standardwert zu verwenden. Beispielsweise wird der Klassenname durch ersetzt
Main
wenn Sie es auslassen,Index
ist der Standard für ausgelassene Funktionsnamen, und der Standard für die HTTP-Methode istirgendein
. Na sicher,irgendein
ist keine echte HTTP-Methode, sondern ein Wert, den Slim verwendet, um alle HTTP-Methodentypen abzugleichen.Das
addRoutes
Funktion beginnt mit afür jeden
Schleife, die die Routen durchläuft. Als Nächstes legen wir die Standard-HTTP-Methode fest, die optional mit der bereitgestellten Methode überschrieben wird@
Symbol ist vorhanden. Dann übergeben wir den Rest des Pfads an eine Funktion, um einen Rückruf abzurufen, und hängen ihn an eine Route an. Zum Schluss fügen wir die Route zum Array hinzu.Nun schauen wir uns das an
processCallback ()
Funktion:geschützte Funktion processCallback ($ path) $ class = "Main"; if (strpos ($ path, ":")! == false) list ($ class, $ path) = explodieren (":", $ path); $ function = ($ path! = "")? $ path: "index"; $ func = function () use ($ class, $ function) $ class = '\ Controller \\'. $ class; $ class = neue $ class (); $ args = func_get_args (); return call_user_func_array (array ($ class, $ function), $ args); ; return $ func;Die zweite Ausgabe stammt aus der Architektur von Slim. es soll alles in einer Datei definiert werden.
Zuerst setzen wir die Standardklasse auf
Main
, und überschreiben Sie diese Klasse, wenn das Doppelpunktsymbol gefunden wird. Als Nächstes ermitteln wir, ob eine Funktion definiert ist, und verwenden die StandardmethodeIndex
wenn erforderlich. Anschließend übergeben wir die Klassen- und Funktionsnamen an eine Schließung und geben sie an die Route zurück.In der Schließung wird der Klassenname mit dem Namespace vorangestellt. Dann erstellen wir eine neue Instanz der angegebenen Klasse und rufen die Liste der an diese Funktion übergebenen Argumente ab. Wenn Sie sich erinnern, während Slim prüft, ob eine Route passt, wird langsam eine Liste von Parametern erstellt, die auf Platzhaltern der Route basieren. Diese Funktion (
func_get_args ()
) kann verwendet werden, um die übergebenen Parameter in einem Array abzurufen. Dann mit dercall_user_func_array ()
Mit der Methode können wir die Klasse und die Funktion angeben, während die Parameter an die Steuerung übergeben werden.Es ist keine sehr komplizierte Funktion, wenn Sie es verstanden haben, aber es ist ein sehr gutes Beispiel, wenn sich Verschlüsse als nützlich erweisen.
Um es noch einmal zusammenzufassen, haben wir unserer Funktion eine Funktion hinzugefügt
Router
Auf diese Weise können Sie ein assoziatives Array übergeben, das Routen und Pfade enthält, die Klassen und Funktionen zugeordnet sind. Der letzte Schritt besteht darin, die Routen zu verarbeiten und die entsprechenden Übereinstimmungen auszuführen. Halten wir uns an die schlanke Namenskonvention, nennen wir esLauf
:öffentliche Funktion run () $ display404 = true; $ uri = $ this-> request-> getResourceUri (); $ method = $ this-> request-> getMethod (); foreach ($ this-> routen als $ i => $ route) if ($ route-> entspricht ($ uri)) if ($ route-> unterstützt HttpMethod ($ -Methode) || $ route-> unterstütztHttpMethod ("ANY ")) call_user_func_array ($ route-> getCallable (), array_values ($ route-> getParams ())); $ display404 = falsch; if ($ display404) echo "404 - Route nicht gefunden";Wir beginnen mit der Einstellung der
display404
Variable, die keine gefundenen Routen darstellt, anwahr
. Wenn wir eine passende Route finden, setzen wir diese auffalsch
und umgehen Sie die Fehlermeldung. Als Nächstes verwenden wir das Anforderungsobjekt von Slim, um die aktuelle URI- und HTTP-Methode abzurufen.Wir verwenden diese Informationen, um durch unser Array zu blättern und Übereinstimmungen zu finden.
Sobald das Routenobjekt ist
Streichhölzer()
Funktion ausgeführt wird, können Sie aufrufengetParams ()
um die geparsten Parameter abzurufen. Verwenden Sie diese Funktion und diegetCallable ()
Methode sind wir in der Lage, den Abschluss durchzuführen und die erforderlichen Parameter zu übergeben. Schließlich wird eine 404-Nachricht angezeigt, wenn keine Route mit der aktuellen URI übereinstimmt.Erstellen wir die Controller-Klasse, die die Rückrufe für diese Routen enthält. Wenn Sie mitverfolgt haben, haben Sie möglicherweise erkannt, dass wir niemals ein Protokoll oder einen Klassentyp erzwungen haben. Wenn Sie keine Controller-Klasse erstellen möchten, funktioniert jede Klasse einwandfrei.
Warum also eine Controller-Klasse erstellen? Die kurze Antwort ist, dass wir Slim noch nicht wirklich benutzt haben! Wir haben Teile von Slim für die HTTP-Anfrage und die Routen verwendet, aber der springende Punkt war, einfachen Zugriff auf alle Eigenschaften von Slim zu haben. Unsere Controller-Klasse erweitert die eigentliche Slim-Klasse und erhält Zugriff auf alle Methoden von Slim.
Sie können dies ebenso einfach überspringen und Slim direkt von Ihren Controllern aus unterteilen.
Controller aufbauen
Mit diesem Controller können Sie im Wesentlichen Slim modifizieren und dabei Vanille behalten. Benennen Sie die Datei
Controller.php
, und schreibe den folgenden Code:Daten = $ Einstellungen ['Modell']; parent :: __ construct ($ settings);Wenn Sie Slim initialisieren, können Sie eine Reihe von Einstellungen übergeben, vom Debug-Modus der Anwendung bis zum Templating Engine. Anstatt die Werte im Konstruktor fest zu codieren, lade ich sie aus einer Datei namens
einstellungen.php
und übergeben Sie dieses Array an den Konstruktor des übergeordneten Elements.Da wir Slim erweitern, dachte ich, es wäre cool, eine "Modell" -Einstellung hinzuzufügen, mit der die Leute ihr Datenobjekt direkt in den Controller einhaken können.
Das ist der Abschnitt, den Sie in der Mitte des obigen Codes sehen können. Wir prüfen, ob die
Modell-
Die Einstellung wurde eingestellt und der Steuerung zugewiesenDaten
Eigentum, wenn nötig.Erstellen Sie nun eine Datei mit dem Namen
einstellungen.php
im Stammverzeichnis Ihres Projekts (der Ordner mit dercomposer.json
Datei) und geben Sie Folgendes ein:neu \ Slim \ Extras \ Views \ Twig (), 'templates.path' => '… / Views', 'model' => (Object) -Array ("message" => "Hello World")); $ Einstellungen zurückgeben;Dies sind die Standardeinstellungen von Slim mit Ausnahme des Modells. Welcher Wert dem zugewiesen wird
Modell-
Eigentum wird an die übergebenDaten
Variable; Dies kann ein Array, eine andere Klasse, eine Zeichenfolge usw. sein. Ich setze es auf ein Objekt, weil ich das mag->
Notation anstelle der Klammer (Array) Notation.Wir können das System jetzt testen. Wenn Sie sich an die erinnern
Router
Klasse setzen wir den Klassennamen mit "Regler
"Namespace. Öffnen Sie sichcomposer.json
Fügen Sie direkt nach der Definition von psr-0 für Folgendes Folgendes hinzu:Nettuts
Namespace:"name": "nettuts / slim_advanced", "required": "slim / slim": "2.2.0", "slim / extras": "*", "twig / twig": "*", " Autoload ": " psr-0 ": " Nettuts ":" Hersteller / "," Controller ":" ./ "Dann wie zuvor einfach den Autoloader ausgeben:
composer dump-autoloadWenn wir nur den Basispfad auf das Stammverzeichnis setzen, dann den Namespace
Regler
wird einem Ordner mit dem Namen "" zugeordnetRegler
"im Stammverzeichnis unserer App. Erstellen Sie also diesen Ordner:mkdir ControllerErstellen Sie in diesem Ordner eine neue Datei mit dem Namen
Main.php
. In der Datei müssen wir den Namespace deklarieren und eine Klasse erstellen, die unser erweitertRegler
Basisklasse:Daten-> Nachricht; public function test () echo "Testseite";Das ist nicht kompliziert, aber nehmen wir es in Maßen. In dieser Klasse definieren wir zwei Funktionen. Ihre Namen spielen keine Rolle, da wir sie später Routen zuordnen werden. Es ist wichtig zu wissen, dass ich direkt auf die Eigenschaften des Controllers (d. H. Des Modells) in der ersten Funktion zugreife. In der Tat haben Sie vollen Zugriff auf alle Befehle von Slim.
Lassen Sie uns nun die tatsächliche öffentliche Datei erstellen. Erstellen Sie ein neues Verzeichnis im Stammverzeichnis Ihres Projekts und benennen Sie es
Öffentlichkeit
. Wie der Name schon sagt, werden hier alle öffentlichen Dinge wohnen. Erstellen Sie in diesem Ordner eine Datei mit dem Namenindex.php
und geben Sie folgendes ein:'Main: index @ get', '/ test' => 'main: test @ get'); $ router-> addRoutes ($ routen); $ router-> run ();Wir enthalten die Autoloading-Bibliothek von Composer und erstellen eine neue Instanz unseres Routers. Dann definieren wir zwei Routen, fügen sie dem Router-Objekt hinzu und führen es aus.
Sie müssen auch mod_rewrite in Apache (oder einem gleichwertigen Server mit einem anderen Webserver) aktivieren. Um dies einzurichten, erstellen Sie eine Datei mit dem Namen
.htaccess
in derÖffentlichkeit
Verzeichnis und füllen Sie es mit dem folgenden:RewriteEngine On RewriteCond% REQUEST_FILENAME! -F RewriteRule ^ index.php [QSA, L]Nun werden alle Anforderungen an diesen Ordner (die nicht mit einer tatsächlichen Datei übereinstimmen) übertragen
index.php
.Navigieren Sie in Ihrem Browser zu Ihrem
Öffentlichkeit
Verzeichnis, und Sie sollten eine Seite mit der Aufschrift "Hallo Welt" sehen. Navigiere zu "/Prüfung
", und Sie sollten die Meldung" Testseite "sehen. Es ist nicht besonders aufregend, aber wir haben den gesamten Logikcode erfolgreich in einzelne Steuerungen verschoben.
Runde Zwei
Slim ist kein CodeIgniter, kein Symfony und kein Laravel.
Wir haben also grundlegende Funktionen, aber es gibt ein paar Ecken und Kanten. Beginnen wir mit dem Router.
Ab sofort wird eine einfache Fehlermeldung angezeigt, wenn keine Route vorhanden ist. In einer realen Anwendung möchten wir die gleiche Funktionalität wie das Laden einer normalen Seite. Wir möchten die Fähigkeit von Slim nutzen, Ansichten zu laden und den Fehlercode der Antwort festzulegen.
Fügen wir eine neue Klassenvariable hinzu, die einen optionalen Pfad enthält (genau wie die anderen Routen). Fügen Sie am Anfang der Datei die folgende Zeile direkt nach der Definition des Anforderungsobjekts ein:
protected $ errorHandler;Als Nächstes erstellen wir eine Funktion, die einen Pfad akzeptiert und diesem eine Callback-Funktion zuweist. Dies ist relativ einfach, da wir diese Funktionalität bereits abstrahiert haben:
öffentliche Funktion set404Handler ($ path) $ this-> errorHandler = $ this-> processCallback ($ path);Nun lass uns das einstellen
Lauf
Befehl, um optional den Rückruf auszuführen, anstatt nur die Fehlermeldung anzuzeigen:if ($ display404) if (is_callable ($ this-> errorHandler)) call_user_func ($ this-> errorHandler); else echo "404 - Route nicht gefunden";Öffnen Sie die Controller-Klasse. Hier können Sie die Funktionalität von Slim an Ihre persönlichen Vorlieben anpassen. Ich möchte zum Beispiel die Option, die Dateierweiterung beim Laden von Ansichten wegzulassen. Also anstatt zu schreiben
$ this-> render ("home.php");
, Ich möchte nur schreiben:$ this-> render ("home");
. Um dies zu tun, überschreiben wir die Render-Methode:public function render ($ name, $ data = array (), $ status = null) if (strpos ($ name, ".php") === false) $ name = $ name. ".php"; parent :: render ($ name, $ data, $ status);Wir akzeptieren dieselben Parameter wie die übergeordnete Funktion, überprüfen jedoch, ob die Dateierweiterung angegeben ist, und fügen sie bei Bedarf hinzu. Nach dieser Änderung übergeben wir die Datei zur Verarbeitung an die übergeordnete Methode.
Dies ist nur ein einziges Beispiel, wir sollten jedoch alle anderen Änderungen hier einfügen
machen()
Methode. Wenn Sie beispielsweise in alle Ihre Dokumente die gleichen Kopf- und Fußzeilenseiten laden, können Sie eine Funktion hinzufügenrenderPage ()
. Diese Funktion würde die übergebene Ansicht zwischen den Aufrufen laden, um die reguläre Kopf- und Fußzeile zu laden.Lassen Sie uns als Nächstes einige Ansichten laden. Erstellen Sie im Stammverzeichnis Ihres Projekts einen Ordner mit dem Namen "
Ansichten
"(Ort und Name können imeinstellungen.php
Datei). Erstellen wir einfach zwei Ansichten mit dem Namentest.php
underror.php
.Innerhalb
test.php
, Folgendes hinzufügen:Titel
Dies ist die Seite Name!
Und in der
error.php
Datei, geben Sie folgendes ein:404
Die von Ihnen gesuchte Route konnte nicht gefunden werden
Ändern Sie auch die
Main
Controller durch Ändern derIndex()
Funktion auf Folgendes:public function index () $ this-> render ("test", array ("title" => $ this-> data-> message, "name" => "Home"));Hier rendern wir die gerade erstellte Testansicht und übergeben sie Daten zur Anzeige. Als Nächstes versuchen wir eine Route mit Parametern. Ändere das
Prüfung()
Funktion auf Folgendes:öffentliche Funktion test ($ title) $ this-> render ("test", array ("title" => $ title, "name" => "test"));Hier gehen wir noch einen Schritt weiter, indem wir den Titel der Seite vom URI selbst abrufen. Fügen Sie noch eine Funktion für die 404-Seite hinzu:
public function notFound () $ this-> render ('error', array (), 404);Wir nehmen das
machen()
dritter optionaler Parameter der Funktion, der den HTTP-Statuscode der Antwort festlegt.Unsere letzte Bearbeitung ist in
index.php
um unsere neuen Routen aufzunehmen:$ routes = array ('/' => ", '/ test /: title' => 'Main: test @ get'); $ router-> addRoutes ($ routes); $ router-> set404Handler (" main: notFound ") "); $ router-> run ();Sie sollten nun in der Lage sein, zu den drei Routen zu navigieren und die jeweiligen Ansichten zu sehen.
Fazit
Bei allem, was wir erreicht haben, haben Sie sicherlich einige Fragen, warum Slim diese Modifikationen nicht bereits anbietet. Sie erscheinen logisch, sie weichen von der Implementierung von Slim nicht zu weit ab und sind sehr sinnvoll. Josh Lockhart (der Schöpfer von Slim) hat es am besten ausgedrückt:
"Slim ist kein CodeIgniter, es ist kein Symfony und kein Laravel. Slim ist Slim. Es wurde so gebaut, dass es leicht und spaßig ist und trotzdem immer noch etwa 80% der häufigsten Probleme lösen kann. Statt sich um den Rand zu sorgen In den meisten Fällen konzentriert es sich darauf, einfach zu sein und eine leicht lesbare Codebasis zu haben. "
Manchmal sind wir als Entwickler so mit den verrückten Szenarien beschäftigt, dass wir vergessen, was wirklich wichtig ist: der Code. Mods wie die in diesem Tutorial sind nur aufgrund der Einfachheit und Ausführlichkeit des Codes möglich. Ja, es mag einige Randfälle geben, die besondere Aufmerksamkeit erfordern, aber Sie erhalten eine aktive Community, die meiner Meinung nach die Kosten stark überwiegt.
Ich hoffe, Ihnen hat dieser Artikel gefallen. Wenn Sie Fragen oder Kommentare haben, lassen Sie unten eine Nachricht. Sie können mich auch über den IRC-Kanal auf Freenode unter der #nettuts Kanal.